Get rid of nextFieldSubr;
dont change user args in tsTextxxx
This commit is contained in:
@@ -58,7 +58,6 @@ LIBSRCS += fdmgr.c
|
||||
LIBSRCS += freeListLib.c
|
||||
LIBSRCS += gpHashLib.c
|
||||
LIBSRCS += memDebugLib.c
|
||||
LIBSRCS += nextFieldSubr.c
|
||||
LIBSRCS += postfix.c
|
||||
LIBSRCS += realpath.c
|
||||
LIBSRCS += tsSubr.c
|
||||
@@ -99,9 +98,9 @@ LIBTYPE:=SHARED
|
||||
# libs needed for PROD and TESTPRODUCT
|
||||
PROD_LIBS = Com
|
||||
|
||||
# tsTest does not use the default tsTest.c:
|
||||
#USR_CFLAGS += -DTS_TEST
|
||||
#TESTPROD_SRCS=tsSubr.c
|
||||
#TESTPROD=tsTest
|
||||
#TESTPROD=testtsLib
|
||||
#TESTPROD=envtest
|
||||
#TESTPROD=osiTimeTest fdManagerTest
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ SRCS.c += ../ellLib.c
|
||||
SRCS.c += ../envSubr.c
|
||||
SRCS.c += envData.c
|
||||
SRCS.c += ../errSymLib.c
|
||||
SRCS.c += ../nextFieldSubr.c
|
||||
SRCS.c += ../postfix.c
|
||||
SRCS.c += ../bucketLib.c
|
||||
SRCS.c += ../memDebugLib.c
|
||||
@@ -41,7 +40,6 @@ LIBOBJS += envData.o
|
||||
LIBOBJS += envSubr.o
|
||||
LIBOBJS += errSymLib.o
|
||||
LIBOBJS += errSymTbl.o
|
||||
LIBOBJS += nextFieldSubr.o
|
||||
LIBOBJS += postfix.o
|
||||
LIBOBJS += bucketLib.o
|
||||
LIBOBJS += tsSubr.o
|
||||
|
||||
@@ -1,369 +0,0 @@
|
||||
/* $Id$
|
||||
* Author: Roger A. Cole
|
||||
* Date: 10-10-90
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991-92, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 10-10-90 rac initial version
|
||||
* .01 06-18-91 rac installed in SCCS
|
||||
* .02 06-25-91 rac changed nextNonSpaceField to handle quotes
|
||||
* .03 03-04-92 rac fixed nextNonSpaceField to honor '\0'
|
||||
*
|
||||
* make options
|
||||
* -DvxWorks makes a version for VxWorks
|
||||
* -DNDEBUG don't compile assert() checking
|
||||
* -DDEBUG compile various debug code, including checks on
|
||||
* malloc'd memory
|
||||
*/
|
||||
/*+/mod***********************************************************************
|
||||
* TITLE nextFieldSubr.c - text field scanning routines
|
||||
*
|
||||
* GENERAL DESCRIPTION
|
||||
* The routines in this module provide for scanning fields in text
|
||||
* strings. They can be used as the basis for parsing text input
|
||||
* to a program.
|
||||
*
|
||||
* QUICK REFERENCE
|
||||
* char (*pText)[];
|
||||
* char (*pField)[];
|
||||
* char *pDelim;
|
||||
*
|
||||
* int nextAlphField( <>pText, >pField, >pDelim )
|
||||
* int nextAlph1UCField( <>pText, >pField, >pDelim )
|
||||
* int nextANField( <>pText, >pField, >pDelim )
|
||||
* int nextChanNameField( <>pText, >pField, >pDelim )
|
||||
* int nextFltField( <>pText, >pField, >pDelim )
|
||||
* int nextFltFieldAsDbl( <>pText, >pDblVal, >pDelim )
|
||||
* int nextIntField( <>pText, >pField, >pDelim )
|
||||
* int nextIntFieldAsInt( <>pText, >pIntVal, >pDelim )
|
||||
* int nextIntFieldAsLong( <>pText, >pLongVal, >pDelim )
|
||||
* int nextNonSpace( <>pText )
|
||||
* int nextNonSpaceField( <>pText, >pField, >pDelim )
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The input text string is scanned to identify the beginning and
|
||||
* end of a field. At return, the input pointer points to the character
|
||||
* following the delimiter and the delimiter has been returned through
|
||||
* its pointer; the field contents are `returned' either as a pointer
|
||||
* to the first character of the field or as a value returned through
|
||||
* a pointer.
|
||||
*
|
||||
* For nextNonSpaceField, the field is defined as either:
|
||||
* 1) from the next non-white-space character up to the following
|
||||
* white-space character, or
|
||||
* 2) from a " through a matching ", with the "s not being included
|
||||
* in the characters returned to the caller. The delimeter will
|
||||
* be the character following the closing ".
|
||||
*
|
||||
* In the input string, a '\0' is stored in place of the delimiter,
|
||||
* so that standard string handling tools can be used for text fields.
|
||||
*
|
||||
* nextAlphField scans the next alphabetic field
|
||||
* nextAlph1UCField scans the next alphabetic field, changes
|
||||
* the first character to upper case, and
|
||||
* changes the rest to lower case
|
||||
* nextANField scans the next alpha-numeric field
|
||||
* nextChanNameField scans the next field as a channel name,
|
||||
* delimited by white space or a comma
|
||||
* nextFltField scans the next float field
|
||||
* nextFltFieldAsDbl scans the next float field as a double
|
||||
* nextIntField scans the next integer field
|
||||
* nextIntFieldAsInt scans the next integer field as an int
|
||||
* nextIntFieldAsLong scans the next integer field as a long
|
||||
* nextNonSpace scans to the next non-space character
|
||||
* nextNonSpaceField scans the next field, delimited by white
|
||||
* space
|
||||
*
|
||||
* RETURNS
|
||||
* count of characters in field, including the delimiter. A special
|
||||
* case exists when only '\0' is encountered; in this case 0 is returned.
|
||||
* (For quoted alpha strings, the count will include the " characters.)
|
||||
*
|
||||
* BUGS
|
||||
* o use of type checking macros isn't protected by isascii()
|
||||
* o for nextANField, with string in quotes: embedded " isn't handled;
|
||||
* if " isn't encountered before end of line, no error message is
|
||||
* generated.
|
||||
*
|
||||
* SEE ALSO
|
||||
* tsTextToStamp()
|
||||
*
|
||||
* NOTES
|
||||
* 1. fields involving alpha types consider underscore ('_') to be
|
||||
* alphabetic.
|
||||
*
|
||||
* EXAMPLE
|
||||
* char text[]="process 30 samples"
|
||||
* char *pText; pointer into text string
|
||||
* char *pCmd; pointer to first field, to use as a command
|
||||
* int count; value of second field, number of items to process
|
||||
* char *pUnits; pointer to third field, needed for command processing
|
||||
* int length; length of field
|
||||
* char delim; delimiter for field
|
||||
*
|
||||
* pText = text;
|
||||
* if (nextAlphField(&pText, &pCmd, &delim) <= 1)
|
||||
* error action if empty field
|
||||
* if (nextIntFieldAsInt(&pText, &count, &delim) <= 1)
|
||||
* error action if empty field
|
||||
* if (nextAlphField(&pText, &pUnits, &delim) <= 1)
|
||||
* error action if empty field
|
||||
* printf("command=%s, count=%d, units=%s\n", pCmd, count, pUnits);
|
||||
*
|
||||
*-***************************************************************************/
|
||||
#ifdef vxWorks
|
||||
# include <vxWorks.h>
|
||||
# include <stdioLib.h>
|
||||
# include <ctype.h>
|
||||
#else
|
||||
# include <ctype.h>
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAssert.h"
|
||||
#include "tsDefs.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* the preamble skips over leading white space, stopping either at
|
||||
* end of string or at a non-white-space character. If EOS is encountered,
|
||||
* then the appropriate return conditions are set up and a return 0 is done.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define NEXT_PREAMBLE \
|
||||
char *pDlm; /* pointer to field delimiter */ \
|
||||
int count; /* count of characters (plus delim) */ \
|
||||
\
|
||||
assert(ppText != NULL); \
|
||||
assert(*ppText != NULL); \
|
||||
assert(ppField != NULL); \
|
||||
assert(pDelim != NULL); \
|
||||
\
|
||||
if (**ppText == '\0') { \
|
||||
*ppField = *ppText; \
|
||||
*pDelim = **ppText; \
|
||||
return 0; \
|
||||
} \
|
||||
while (**ppText != '\0' && isspace(**ppText)) \
|
||||
(*ppText)++; /* skip leading white space */ \
|
||||
pDlm = *ppField = *ppText; \
|
||||
if (*pDlm == '\0') { \
|
||||
*pDelim = **ppText; \
|
||||
return 0; \
|
||||
} \
|
||||
count = 1; /* include delimiter in count */
|
||||
/*-----------------------------------------------------------------------------
|
||||
* the postamble is called for each character in the field. It moves
|
||||
* the pointers and increments the count. If the loop terminates, then
|
||||
* the caller is informed of the delimiter and the source character
|
||||
* string has '\0' inserted in place of the delimiter, so that the field
|
||||
* is now a proper '\0' terminated string.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define NEXT_POSTAMBLE \
|
||||
pDlm++; \
|
||||
count++; \
|
||||
} \
|
||||
*pDelim = *pDlm; \
|
||||
*ppText = pDlm; \
|
||||
if (*pDlm != '\0') { \
|
||||
(*ppText)++; /* point to next available character */ \
|
||||
*pDlm = '\0'; \
|
||||
}
|
||||
|
||||
int
|
||||
epicsShareAPI nextAlphField(ppText, ppField, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
char **ppField; /* O pointer to pointer to field */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
while (isalpha(*pDlm) || *pDlm == '_') {
|
||||
NEXT_POSTAMBLE
|
||||
return count;
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI
|
||||
nextAlph1UCField(ppText, ppField, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
char **ppField; /* O pointer to pointer to field */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
while (isalpha(*pDlm) || *pDlm == '_') {
|
||||
if (count == 1) {
|
||||
if (islower(*pDlm))
|
||||
*pDlm = toupper(*pDlm);
|
||||
}
|
||||
else {
|
||||
if (isupper(*pDlm))
|
||||
*pDlm = tolower(*pDlm);
|
||||
}
|
||||
NEXT_POSTAMBLE
|
||||
return count;
|
||||
}
|
||||
int
|
||||
epicsShareAPI nextANField(ppText, ppField, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
char **ppField; /* O pointer to pointer to field */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
while (isalnum(*pDlm) || *pDlm == '_') {
|
||||
NEXT_POSTAMBLE
|
||||
return count;
|
||||
}
|
||||
int
|
||||
epicsShareAPI nextChanNameField(ppText, ppField, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
char **ppField; /* O pointer to pointer to field */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
while (!isspace(*pDlm)) {
|
||||
if (*pDlm == '\0')
|
||||
break;
|
||||
else if (*pDlm == ',')
|
||||
break;
|
||||
NEXT_POSTAMBLE
|
||||
return count;
|
||||
}
|
||||
int
|
||||
epicsShareAPI nextFltField(ppText, ppField, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
char **ppField; /* O pointer to pointer to field */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
while (isdigit(*pDlm) || *pDlm=='-' || *pDlm=='+' || *pDlm=='.') {
|
||||
NEXT_POSTAMBLE
|
||||
return count;
|
||||
}
|
||||
int
|
||||
epicsShareAPI nextFltFieldAsDbl(ppText, pDblVal, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
double *pDblVal; /* O pointer to return field's value */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
char *pField; /* pointer to field */
|
||||
int count; /* count of char in field, including delim */
|
||||
|
||||
assert(pDblVal != NULL);
|
||||
|
||||
count = nextFltField(ppText, &pField, pDelim);
|
||||
if (count > 1) {
|
||||
if (sscanf(pField, "%lf", pDblVal) != 1)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
int
|
||||
epicsShareAPI nextIntField(ppText, ppField, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
char **ppField; /* O pointer to pointer to field */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
while (isdigit(*pDlm) || ((*pDlm=='-' || *pDlm=='+') && count==1)) {
|
||||
NEXT_POSTAMBLE
|
||||
return count;
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI
|
||||
nextIntFieldAsInt(ppText, pIntVal, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
int *pIntVal; /* O pointer to return field's value */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
char *pField; /* pointer to field */
|
||||
int count; /* count of char in field, including delim */
|
||||
|
||||
assert(pIntVal != NULL);
|
||||
|
||||
count = nextIntField(ppText, &pField, pDelim);
|
||||
if (count > 1) {
|
||||
if (sscanf(pField, "%d", pIntVal) != 1)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI
|
||||
nextIntFieldAsLong(ppText, pLongVal, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
long *pLongVal; /* O pointer to return field's value */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
char *pField; /* pointer to field */
|
||||
int count; /* count of char in field, including delim */
|
||||
|
||||
assert(pLongVal != NULL);
|
||||
|
||||
count = nextIntField(ppText, &pField, pDelim);
|
||||
if (count > 1) {
|
||||
if (sscanf(pField, "%ld", pLongVal) != 1)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
int
|
||||
epicsShareAPI nextNonSpace(ppText)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
{
|
||||
while (isspace(**ppText))
|
||||
(*ppText)++;
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
epicsShareAPI nextNonSpaceField(ppText, ppField, pDelim)
|
||||
char **ppText; /* I/O pointer to pointer to text to scan */
|
||||
char **ppField; /* O pointer to pointer to field */
|
||||
char *pDelim; /* O pointer to return field's delimiter */
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
if (**ppField == '"') {
|
||||
(*ppField)++; /* skip over leading double quote */
|
||||
count++;
|
||||
pDlm++;
|
||||
while (*pDlm != '"') { /* scan until find another " */
|
||||
NEXT_POSTAMBLE
|
||||
if (*pDelim == '"') {
|
||||
pDlm++;
|
||||
while (isspace(*pDlm))
|
||||
pDlm++; /* skip trailing white space */
|
||||
if (*pDlm == '"')
|
||||
pDlm--;
|
||||
*pDelim = *pDlm; /* give caller the delim and set */
|
||||
*ppText = pDlm; /* for scanning the next field */
|
||||
if (*pDlm != '\0')
|
||||
(*ppText)++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (!isspace(*pDlm)) {
|
||||
if (*pDlm == '\0')
|
||||
break;
|
||||
NEXT_POSTAMBLE
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -31,6 +31,8 @@
|
||||
* .02 06-18-91 rac installed in SCCS
|
||||
* .03 08-03-92 rac added tsRound routines
|
||||
* .04 07-02-96 joh added ANSI prototypes
|
||||
* .05 02-05-98 mrk move pvt stuff to source file;
|
||||
* TsAddDouble just invokes tsAddDouble
|
||||
*
|
||||
*/
|
||||
/*+/mod***********************************************************************
|
||||
@@ -49,12 +51,13 @@
|
||||
* 1990 are treated as `dateless' times.
|
||||
*
|
||||
*-***************************************************************************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "epicsTypes.h"
|
||||
|
||||
#include "errMdef.h" /* get M_ts for this subsystem's `number' */
|
||||
|
||||
@@ -72,8 +75,8 @@ extern "C" {
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned secPastEpoch; /* seconds since 0000 Jan 1, 1990 */
|
||||
unsigned nsec; /* nanoseconds within second */
|
||||
epicsUInt32 secPastEpoch; /* seconds since 0000 Jan 1, 1990 */
|
||||
epicsUInt32 nsec; /* nanoseconds within second */
|
||||
} TS_STAMP;
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@@ -89,146 +92,16 @@ enum tsTextType{
|
||||
TS_TEXT_MMDDYY
|
||||
};
|
||||
|
||||
/*/subhead configuration------------------------------------------------------
|
||||
* C O N F I G U R A T I O N D E F I N I T I O N S
|
||||
*
|
||||
* TS_DST_BEGIN the day number for starting DST
|
||||
* TS_DST_END the day number for ending DST
|
||||
* TS_MIN_WEST the number of minutes west of GMT for time zone (zones east
|
||||
* will have negative values)
|
||||
* TS_DST_HOUR_ON the hour (standard time) when DST turns on
|
||||
* TS_DST_HOUR_OFF the hour (standard time) when DST turns off
|
||||
* TS_DST_HRS_ADD hours to add when DST is on
|
||||
*
|
||||
* day numbers start with 0 for Jan 1; day numbers in these defines are
|
||||
* based on a NON-leap year. The start and end days for DST are assumed to be
|
||||
* Sundays. A negative day indicates that the following Sunday is to be used;
|
||||
* a positive day indicates the prior Sunday. If the begin date is larger than
|
||||
* the end date, then DST overlaps the change of the year (e.g., for southern
|
||||
* hemisphere).
|
||||
*
|
||||
* Note well that TS_DST_HOUR_ON and TS_DST_HOUR_OFF are both STANDARD time.
|
||||
* So, if dst begins at 2 a.m. (standard time) and ends at 2 a.m. (daylight
|
||||
* time), the two values would be 2 and 1, respectively (assuming
|
||||
* TS_DST_HRS_ADD is 1).
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define TS_DST_BEGIN -90 /* first Sun in Apr (Apr 1 = 90) */
|
||||
#define TS_DST_END 303 /* last Sun in Oct (Oct 31 = 303) */
|
||||
#define TS_DST_HOUR_ON 2 /* 2 a.m. (standard time) */
|
||||
#define TS_DST_HOUR_OFF 1 /* 2 a.m. (1 a.m. standard time) */
|
||||
#define TS_DST_HRS_ADD 1 /* add one hour */
|
||||
#define TS_MIN_WEST 7 * 60 /* USA mountain time zone */
|
||||
#if 0 /* first set is for testing only */
|
||||
#define TS_EPOCH_YEAR 1989
|
||||
#define TS_EPOCH_SEC_PAST_1970 6940*86400 /* 1/1/89 19 yr (5 leap) of seconds */
|
||||
#define TS_EPOCH_WDAY_NUM 0 /* Jan 1 1989 was Sun (wkday num = 0) */
|
||||
#else
|
||||
#define TS_EPOCH_YEAR 1990
|
||||
#define TS_EPOCH_SEC_PAST_1970 7305*86400 /* 1/1/90 20 yr (5 leap) of seconds */
|
||||
#define TS_EPOCH_WDAY_NUM 1 /* Jan 1 1990 was Mon (wkday num = 1) */
|
||||
#endif
|
||||
#define TS_MAX_YEAR TS_EPOCH_YEAR+134 /* ULONG can handle 135 years */
|
||||
#define TS_TRUNC 1000000 /* truncate to milli-second significance */
|
||||
|
||||
/*/subhead struct tsDetail----------------------------------------------------
|
||||
* breakdown structure for working with secPastEpoch
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
struct tsDetail {
|
||||
int year; /* 4 digit year */
|
||||
int dayYear; /* day number in year; 0 = Jan 1 */
|
||||
int monthNum; /* month number; 0 = Jan */
|
||||
int dayMonth; /* day number; 0 = 1st of month */
|
||||
int hours; /* hours within day */
|
||||
int minutes; /* minutes within hour */
|
||||
int seconds; /* seconds within minute */
|
||||
int dayOfWeek; /* weekday number; 0 = Sun */
|
||||
int leapYear; /* (0, 1) for year (isn't, is) a leap year */
|
||||
char dstOverlapChar; /* indicator for distinguishing duplicate
|
||||
times in the `switch to standard' time period:
|
||||
':'--time isn't ambiguous;
|
||||
's'--time is standard time
|
||||
'd'--time is daylight time */
|
||||
};
|
||||
|
||||
/*/subhead status codes-------------------------------------------------------
|
||||
* S T A T U S C O D E S
|
||||
*
|
||||
*
|
||||
* Status codes for time stamp routines have the form S_ts_briefMessage .
|
||||
*
|
||||
* The macro TsStatusToText(stat) can be used to obtain a text string
|
||||
* corresponding to a status code.
|
||||
*
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define S_ts_OK 0
|
||||
#define S_ts_sysTimeError (M_ts|1| 1<<1) /* error getting system time */
|
||||
#define S_ts_badTextCode (M_ts|1| 2<<1) /* invalid TS_TEXT_xxx code */
|
||||
#define S_ts_inputTextError (M_ts|1| 3<<1) /* error in text date or time */
|
||||
#define S_ts_timeSkippedDST (M_ts|1| 4<<1) /* time skipped on switch to DST */
|
||||
#define S_ts_badRoundInterval (M_ts|1| 5<<1) /* invalid rounding interval */
|
||||
|
||||
#define TS_S_PAST 6 /* one past last legal code */
|
||||
|
||||
#define TsStatusToIndex(status) \
|
||||
( ((status&0xffff0000)!=M_ts) \
|
||||
? TS_S_PAST \
|
||||
: ( (((status&0xffff)>>1)>=TS_S_PAST) \
|
||||
? TS_S_PAST \
|
||||
: ((status&0xffff)>>1) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define TsStatusToText(status) \
|
||||
(glTsStatText[TsStatusToIndex(status)])
|
||||
|
||||
#ifndef TS_PRIVATE_DATA
|
||||
epicsShareExtern char *glTsStatText[7];
|
||||
#else
|
||||
epicsShareDef char *glTsStatText[] = {
|
||||
/* S_ts_OK */ "success",
|
||||
/* S_ts_sysTimeError */ "error getting system time",
|
||||
/* S_ts_badTextCode */ "invalid TS_TEXT_xxx code",
|
||||
/* S_ts_inputTextError */ "error in text date or time",
|
||||
/* S_ts_timeSkippedDST */ "time skipped on switch to DST",
|
||||
/* S_ts_badRoundInterval */ "rounding interval is invalid",
|
||||
|
||||
/* TS_S_PAST */ "illegal TS status code",
|
||||
};
|
||||
#endif
|
||||
|
||||
/*/subhead macros-------------------------------------------------------------
|
||||
* arithmetic macros
|
||||
*
|
||||
* care has been taken in writing these macros that the result can
|
||||
* be stored back into either operand time stamp. For example,
|
||||
* both of the following (as well as other variations) are legal:
|
||||
* TsAddStamps(pS1, pS1, pS2);
|
||||
* TsDiffAsStamp(pS2, pS1, pS2);
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if _WIN32 /* the microsoft compiler will not compile the TsAddDouble() macro */
|
||||
/*TsAddDouble was originally a macro. Now just use tsAddDouble */
|
||||
#define TsAddDouble(pSum, pS1, dbl) tsAddDouble(pSum, pS1, dbl)
|
||||
#else /*_WIN32*/
|
||||
#define TsAddDouble(pSum, pS1, dbl) \
|
||||
(void)( \
|
||||
dbl >= 0. \
|
||||
? ((*pSum).secPastEpoch = (*pS1).secPastEpoch + (unsigned long)dbl, \
|
||||
( ((*pSum).nsec = (*pS1).nsec + (unsigned long)(1000000000. * \
|
||||
(dbl - (double)((unsigned long)dbl))) ) ) \
|
||||
>= 1000000000 \
|
||||
?((*pSum).secPastEpoch += (*pSum).nsec/1000000000, \
|
||||
(*pSum).nsec %= 1000000000) \
|
||||
:0) \
|
||||
: ((*pSum).secPastEpoch = (*pS1).secPastEpoch - (unsigned long)(-dbl), \
|
||||
(*pS1).nsec >= (unsigned long)(1000000000. * \
|
||||
((-dbl) - (double)((unsigned long)(-dbl)))) \
|
||||
?( (*pSum).nsec = (*pS1).nsec - (unsigned long)(1000000000.* \
|
||||
((-dbl) - (double)((unsigned long)(-dbl))))) \
|
||||
:( (*pSum).nsec = (*pS1).nsec + 1000000000 - \
|
||||
(unsigned long)(1000000000.* \
|
||||
((-dbl) - (double)((unsigned long)(-dbl)))), \
|
||||
(*pSum).secPastEpoch -= 1) ) )
|
||||
#endif /*_WIN32*/
|
||||
#define TsAddStamps(pSum, pS1, pS2) \
|
||||
(void)( \
|
||||
((*pSum).secPastEpoch = (*pS1).secPastEpoch + (*pS2).secPastEpoch) , \
|
||||
@@ -281,30 +154,13 @@ struct tsDetail {
|
||||
:((((*pS1).secPastEpoch) == ((*pS2).secPastEpoch)) \
|
||||
?((((*pS1).nsec) <= ((*pS2).nsec)) ? 1 : 0) \
|
||||
:0 ))
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* `prototypes'
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(__STDC__) || defined(__cplusplus)
|
||||
|
||||
epicsShareFunc int epicsShareAPI nextIntFieldAsInt(
|
||||
char **ppText, /* I/O pointer to pointer to text to scan */
|
||||
int *pIntVal, /* O pointer to return field's value */
|
||||
char *pDelim /* O pointer to return field's delimiter */
|
||||
);
|
||||
|
||||
epicsShareFunc int epicsShareAPI nextAlph1UCField(
|
||||
char **ppText, /* I/O pointer to pointer to text to scan */
|
||||
char **ppField, /* O pointer to pointer to field */
|
||||
char *pDelim /* O pointer to return field's delimiter */
|
||||
);
|
||||
|
||||
epicsShareFunc int epicsShareAPI nextIntFieldAsLong(
|
||||
char **ppText, /* I/O pointer to pointer to text to scan */
|
||||
long *pLongVal, /* O pointer to return field's value */
|
||||
char *pDelim /* O pointer to return field's delimiter */
|
||||
);
|
||||
|
||||
epicsShareFunc long epicsShareAPI tsLocalTime (TS_STAMP *pStamp);
|
||||
|
||||
epicsShareFunc void epicsShareAPI tsAddDouble(
|
||||
@@ -346,9 +202,6 @@ char **pText /* IO ptr to ptr to string containing time and date */
|
||||
|
||||
#else /* !defined(__STDC__) && !defined(__cplusplus) */
|
||||
|
||||
epicsShareFunc int epicsShareAPI nextIntFieldAsInt();
|
||||
epicsShareFunc int epicsShareAPI nextAlph1UCField();
|
||||
epicsShareFunc int epicsShareAPI nextIntFieldAsLong();
|
||||
epicsShareFunc long epicsShareAPI tsLocalTime ();
|
||||
epicsShareFunc void epicsShareAPI tsAddDouble();
|
||||
epicsShareFunc int epicsShareAPI tsCmpStamps();
|
||||
@@ -358,10 +211,56 @@ epicsShareFunc char * epicsShareAPI tsStampToText();
|
||||
epicsShareFunc long epicsShareAPI tsTextToStamp();
|
||||
epicsShareFunc long epicsShareAPI tsTimeTextToStamp();
|
||||
|
||||
#endif
|
||||
#endif /*defined(__STDC__) || defined(__cplusplus) */
|
||||
|
||||
/*/subhead status codes-------------------------------------------------------
|
||||
* S T A T U S C O D E S
|
||||
*
|
||||
*
|
||||
* Status codes for time stamp routines have the form S_ts_briefMessage .
|
||||
*
|
||||
* The macro TsStatusToText(stat) can be used to obtain a text string
|
||||
* corresponding to a status code.
|
||||
*
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define S_ts_OK 0
|
||||
#define S_ts_sysTimeError (M_ts|1| 1<<1) /* error getting system time */
|
||||
#define S_ts_badTextCode (M_ts|1| 2<<1) /* invalid TS_TEXT_xxx code */
|
||||
#define S_ts_inputTextError (M_ts|1| 3<<1) /* error in text date or time */
|
||||
#define S_ts_timeSkippedDST (M_ts|1| 4<<1) /* time skipped on switch to DST */
|
||||
#define S_ts_badRoundInterval (M_ts|1| 5<<1) /* invalid rounding interval */
|
||||
|
||||
#define TS_S_PAST 6 /* one past last legal code */
|
||||
|
||||
#define TsStatusToIndex(status) \
|
||||
( ((status&0xffff0000)!=M_ts) \
|
||||
? TS_S_PAST \
|
||||
: ( (((status&0xffff)>>1)>=TS_S_PAST) \
|
||||
? TS_S_PAST \
|
||||
: ((status&0xffff)>>1) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define TsStatusToText(status) \
|
||||
(glTsStatText[TsStatusToIndex(status)])
|
||||
|
||||
#ifndef TS_PRIVATE_DATA
|
||||
epicsShareExtern char *glTsStatText[7];
|
||||
#else
|
||||
epicsShareDef char *glTsStatText[] = {
|
||||
/* S_ts_OK */ "success",
|
||||
/* S_ts_sysTimeError */ "error getting system time",
|
||||
/* S_ts_badTextCode */ "invalid TS_TEXT_xxx code",
|
||||
/* S_ts_inputTextError */ "error in text date or time",
|
||||
/* S_ts_timeSkippedDST */ "time skipped on switch to DST",
|
||||
/* S_ts_badRoundInterval */ "rounding interval is invalid",
|
||||
|
||||
/* TS_S_PAST */ "illegal TS status code",
|
||||
};
|
||||
#endif /*TS_PRIVATE_DATA*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__cplusplus */
|
||||
|
||||
#endif
|
||||
#endif /*INC_tsDefs_h*/
|
||||
|
||||
@@ -45,12 +45,12 @@
|
||||
* so I left TsAddDouble() code - which works -
|
||||
* at the end of the file but commented it out
|
||||
*
|
||||
* make options
|
||||
* -DvxWorks makes a version for VxWorks
|
||||
* -DNDEBUG don't compile assert() checking
|
||||
* -DDEBUG compile various debug code, including checks on
|
||||
* malloc'd memory
|
||||
* .05 02-05-98 mrk move pvt stuff from tsDefs.h to here
|
||||
* move code for nextXXX to here and made static
|
||||
* use standard C function declarations everywhere
|
||||
*/
|
||||
|
||||
/*+/mod***********************************************************************
|
||||
* TITLE tsSubr.c - time stamp routines
|
||||
*
|
||||
@@ -113,17 +113,19 @@
|
||||
* (Some of the code here is based somewhat on time-related routines from
|
||||
* 4.2 BSD.)
|
||||
*-***************************************************************************/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TS_PRIVATE_DATA
|
||||
#include "tsDefs.h"
|
||||
#undef TS_PRIVATE_DATA
|
||||
|
||||
#if defined(vxWorks)
|
||||
# include <vxWorks.h>
|
||||
# include <stdioLib.h>
|
||||
# include <strLib.h>
|
||||
# include "drvTS.h"
|
||||
#elif defined(VMS)
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
@@ -139,13 +141,78 @@
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsAssert.h"
|
||||
#include "envDefs.h"
|
||||
#define TS_PRIVATE_DATA
|
||||
#include "tsDefs.h"
|
||||
|
||||
/*/subhead configuration------------------------------------------------------
|
||||
* C O N F I G U R A T I O N D E F I N I T I O N S
|
||||
*
|
||||
* TS_DST_BEGIN the day number for starting DST
|
||||
* TS_DST_END the day number for ending DST
|
||||
* TS_MIN_WEST the number of minutes west of GMT for time zone (zones east
|
||||
* will have negative values)
|
||||
* TS_DST_HOUR_ON the hour (standard time) when DST turns on
|
||||
* TS_DST_HOUR_OFF the hour (standard time) when DST turns off
|
||||
* TS_DST_HRS_ADD hours to add when DST is on
|
||||
*
|
||||
* day numbers start with 0 for Jan 1; day numbers in these defines are
|
||||
* based on a NON-leap year. The start and end days for DST are assumed to be
|
||||
* Sundays. A negative day indicates that the following Sunday is to be used;
|
||||
* a positive day indicates the prior Sunday. If the begin date is larger than
|
||||
* the end date, then DST overlaps the change of the year (e.g., for southern
|
||||
* hemisphere).
|
||||
*
|
||||
* Note well that TS_DST_HOUR_ON and TS_DST_HOUR_OFF are both STANDARD time.
|
||||
* So, if dst begins at 2 a.m. (standard time) and ends at 2 a.m. (daylight
|
||||
* time), the two values would be 2 and 1, respectively (assuming
|
||||
* TS_DST_HRS_ADD is 1).
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define TS_DST_BEGIN -90 /* first Sun in Apr (Apr 1 = 90) */
|
||||
#define TS_DST_END 303 /* last Sun in Oct (Oct 31 = 303) */
|
||||
#define TS_DST_HOUR_ON 2 /* 2 a.m. (standard time) */
|
||||
#define TS_DST_HOUR_OFF 1 /* 2 a.m. (1 a.m. standard time) */
|
||||
#define TS_DST_HRS_ADD 1 /* add one hour */
|
||||
#define TS_MIN_WEST 7 * 60 /* USA mountain time zone */
|
||||
#if 0 /* first set is for testing only */
|
||||
#define TS_EPOCH_YEAR 1989
|
||||
#define TS_EPOCH_SEC_PAST_1970 6940*86400 /* 1/1/89 19 yr (5 leap) of seconds */
|
||||
#define TS_EPOCH_WDAY_NUM 0 /* Jan 1 1989 was Sun (wkday num = 0) */
|
||||
#else
|
||||
#define TS_EPOCH_YEAR 1990
|
||||
#define TS_EPOCH_SEC_PAST_1970 7305*86400 /* 1/1/90 20 yr (5 leap) of seconds */
|
||||
#define TS_EPOCH_WDAY_NUM 1 /* Jan 1 1990 was Mon (wkday num = 1) */
|
||||
#endif
|
||||
#define TS_MAX_YEAR TS_EPOCH_YEAR+134 /* ULONG can handle 135 years */
|
||||
#define TS_TRUNC 1000000 /* truncate to milli-second significance */
|
||||
|
||||
static void tsStampFromLocal();
|
||||
static void tsStampToLocal();
|
||||
static void tsStampToLocalZone();
|
||||
static void tsInitMinWest();
|
||||
/*/subhead struct tsDetail----------------------------------------------------
|
||||
* breakdown structure for working with secPastEpoch
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
struct tsDetail {
|
||||
int year; /* 4 digit year */
|
||||
int dayYear; /* day number in year; 0 = Jan 1 */
|
||||
int monthNum; /* month number; 0 = Jan */
|
||||
int dayMonth; /* day number; 0 = 1st of month */
|
||||
int hours; /* hours within day */
|
||||
int minutes; /* minutes within hour */
|
||||
int seconds; /* seconds within minute */
|
||||
int dayOfWeek; /* weekday number; 0 = Sun */
|
||||
int leapYear; /* (0, 1) for year (isn't, is) a leap year */
|
||||
char dstOverlapChar; /* indicator for distinguishing duplicate
|
||||
times in the `switch to standard' time period:
|
||||
':'--time isn't ambiguous;
|
||||
's'--time is standard time
|
||||
'd'--time is daylight time */
|
||||
};
|
||||
|
||||
static void tsStampFromLocal(TS_STAMP *pStamp, struct tsDetail *pT);
|
||||
static void tsStampToLocal(TS_STAMP stamp,struct tsDetail *pT);
|
||||
static void tsStampToLocalZone(TS_STAMP *pStamp,struct tsDetail *pT);
|
||||
static void tsInitMinWest(void);
|
||||
|
||||
static int nextAlph1UCField(char **ppText,char **ppField, char *pDelim);
|
||||
static int nextIntField(char **ppText,char **ppField,char *pDelim);
|
||||
static int nextIntFieldAsInt(char **ppText,int *pIntVal,char *pDelim);
|
||||
static int nextIntFieldAsLong(char **ppText,long *pLongVal,char *pDelim);
|
||||
|
||||
static int needToInitMinWest=1;
|
||||
static long tsMinWest=TS_MIN_WEST;
|
||||
@@ -154,6 +221,7 @@ static int daysInMonth[] = {31,28,31,30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
static int dayYear1stOfMon[] = {0,31,59,90,120,151,181,212,243,273,304,334};
|
||||
static char monthText[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
|
||||
#define TEXTBUFSIZE 40
|
||||
|
||||
/*/subhead tsTest-------------------------------------------------------------
|
||||
* some test code.
|
||||
@@ -161,12 +229,13 @@ static char monthText[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
#if TS_TEST || LINT
|
||||
|
||||
# ifndef vxWorks
|
||||
main()
|
||||
int tsTest(void);
|
||||
int main()
|
||||
{
|
||||
return tsTest();
|
||||
}
|
||||
# endif
|
||||
tsTest()
|
||||
int tsTest()
|
||||
{
|
||||
long stat;
|
||||
double dbl;
|
||||
@@ -326,9 +395,9 @@ tsTest()
|
||||
(void)printf("%s\n", TsStatusToText(stat));
|
||||
}
|
||||
else {
|
||||
(void)printf("stamp is: %lu %lu %s\n", inStamp.secPastEpoch,
|
||||
(void)printf("stamp is: %u %u %s\n", inStamp.secPastEpoch,
|
||||
inStamp.nsec,
|
||||
tsStampToText(&inStamp, TS_TEXT_MMDDYY, inStampTxt));
|
||||
tsStampToText(&inStamp, TS_TEXT_MONDDYYYY, inStampTxt));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,8 +418,7 @@ tsTest()
|
||||
* void
|
||||
*
|
||||
*-*/
|
||||
void
|
||||
date()
|
||||
void date()
|
||||
{
|
||||
TS_STAMP now;
|
||||
char nowText[32];
|
||||
@@ -372,12 +440,11 @@ date()
|
||||
* day of year for the desired Sunday
|
||||
*
|
||||
*-*/
|
||||
static
|
||||
int sunday(day, leap, dayYear, dayOfWeek)
|
||||
int day; /* I day of year to find closest Sunday */
|
||||
int leap; /* I 0, 1 for not leap year, leap year, respectively */
|
||||
int dayYear; /* I known day of year */
|
||||
int dayOfWeek; /* I day of week for dayYear */
|
||||
static int sunday(
|
||||
int day, /* I day of year to find closest Sunday */
|
||||
int leap, /* I 0, 1 for not leap year, leap year, respectively */
|
||||
int dayYear, /* I known day of year */
|
||||
int dayOfWeek) /* I day of week for dayYear */
|
||||
{
|
||||
int offset; /* controls direction of offset */
|
||||
|
||||
@@ -458,10 +525,7 @@ int dayOfWeek; /* I day of week for dayYear */
|
||||
*
|
||||
*-*/
|
||||
void epicsShareAPI
|
||||
tsAddDouble(pSum, pStamp, dbl)
|
||||
TS_STAMP *pSum; /* O sum time stamp */
|
||||
TS_STAMP *pStamp; /* I addend time stamp */
|
||||
double dbl; /* I number of seconds to add */
|
||||
tsAddDouble(TS_STAMP *pSum,TS_STAMP *pStamp, double dbl)
|
||||
{
|
||||
TS_STAMP stamp; /* stamp equivalent of the double */
|
||||
|
||||
@@ -523,10 +587,7 @@ double dbl; /* I number of seconds to add */
|
||||
* printf("first stamp is later\n");
|
||||
*
|
||||
*-*/
|
||||
int epicsShareAPI
|
||||
tsCmpStamps(pStamp1, pStamp2)
|
||||
TS_STAMP *pStamp1; /* pointer to first stamp */
|
||||
TS_STAMP *pStamp2; /* pointer to second stamp */
|
||||
int epicsShareAPI tsCmpStamps(TS_STAMP *pStamp1,TS_STAMP *pStamp2)
|
||||
{
|
||||
if (pStamp1->secPastEpoch < pStamp2->secPastEpoch)
|
||||
return -1;
|
||||
@@ -599,51 +660,54 @@ TS_STAMP *pStamp2; /* pointer to second stamp */
|
||||
*-*/
|
||||
long epicsShareAPI tsLocalTime(TS_STAMP *pStamp)
|
||||
{
|
||||
long retStat=S_ts_OK;/* return status to caller */
|
||||
long retStat=S_ts_OK;/* return status to caller */
|
||||
|
||||
assert(pStamp != NULL);
|
||||
|
||||
{
|
||||
# if defined(vxWorks)
|
||||
retStat = TScurrentTimeStamp((struct timespec*)pStamp);
|
||||
if (retStat == 0) {
|
||||
return S_ts_OK;
|
||||
}
|
||||
else {
|
||||
return S_ts_sysTimeError;
|
||||
}
|
||||
# elif defined(_WIN32)
|
||||
DWORD win_sys_time_ms; /* time (ms) since windows started */
|
||||
static DWORD prev_time_ms; /* time (ms) of previous call */
|
||||
static long start_time_s=0; /* time (sec) from 1990 when windows started */
|
||||
|
||||
if (start_time_s == 0) {
|
||||
prev_time_ms = timeGetTime();
|
||||
start_time_s = time(NULL)
|
||||
- TS_EPOCH_SEC_PAST_1970 - (long)prev_time_ms/1000;
|
||||
}
|
||||
win_sys_time_ms = timeGetTime();
|
||||
if (prev_time_ms > win_sys_time_ms) {
|
||||
/* must have been a timer roll-over */
|
||||
|
||||
start_time_s += 4294967; /* add number of seconds in 49.7 days */
|
||||
}
|
||||
/* time (sec) since 1990 */
|
||||
pStamp->secPastEpoch = (long)win_sys_time_ms/1000 + start_time_s;
|
||||
pStamp->nsec = (long)((win_sys_time_ms % 1000) * 1000000);
|
||||
prev_time_ms = win_sys_time_ms;
|
||||
# else
|
||||
struct timeval curtime;
|
||||
|
||||
assert(pStamp != NULL);
|
||||
|
||||
{
|
||||
# if defined(vxWorks)
|
||||
retStat = TScurrentTimeStamp((struct timespec*)pStamp);
|
||||
if (retStat == 0) {
|
||||
return S_ts_OK;
|
||||
}
|
||||
else {
|
||||
return S_ts_sysTimeError;
|
||||
}
|
||||
# elif defined(_WIN32)
|
||||
DWORD win_sys_time_ms; /* time (ms) since windows started */
|
||||
static DWORD prev_time_ms; /* time (ms) of previous call */
|
||||
static long start_time_s=0; /* time (sec) from 1990 when windows started */
|
||||
|
||||
if (start_time_s == 0) {
|
||||
prev_time_ms = timeGetTime();
|
||||
start_time_s = time(NULL) - TS_EPOCH_SEC_PAST_1970 - (long)prev_time_ms/1000;
|
||||
}
|
||||
win_sys_time_ms = timeGetTime();
|
||||
if (prev_time_ms > win_sys_time_ms) { /* must have been a timer roll-over */
|
||||
start_time_s += 4294967; /* add number of seconds in 49.7 days */
|
||||
}
|
||||
pStamp->secPastEpoch = (long)win_sys_time_ms/1000 + start_time_s; /* time (sec) since 1990 */
|
||||
pStamp->nsec = (long)((win_sys_time_ms % 1000) * 1000000);
|
||||
prev_time_ms = win_sys_time_ms;
|
||||
# else
|
||||
struct timeval curtime;
|
||||
|
||||
assert(pStamp != NULL);
|
||||
if (gettimeofday(&curtime, (struct timezone *)NULL) == -1)
|
||||
retStat = S_ts_sysTimeError;
|
||||
else {
|
||||
pStamp->nsec = ( curtime.tv_usec/1000 ) * 1000000;
|
||||
pStamp->secPastEpoch = curtime.tv_sec -
|
||||
TS_EPOCH_SEC_PAST_1970;
|
||||
}
|
||||
# endif
|
||||
if (gettimeofday(&curtime, (struct timezone *)NULL) == -1)
|
||||
retStat = S_ts_sysTimeError;
|
||||
else {
|
||||
pStamp->nsec = ( curtime.tv_usec/1000 ) * 1000000;
|
||||
pStamp->secPastEpoch = curtime.tv_sec - TS_EPOCH_SEC_PAST_1970;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
pStamp->nsec = pStamp->nsec - (pStamp->nsec % TS_TRUNC);
|
||||
return retStat;
|
||||
pStamp->nsec = pStamp->nsec - (pStamp->nsec % TS_TRUNC);
|
||||
return retStat;
|
||||
}
|
||||
|
||||
/*+/subr**********************************************************************
|
||||
@@ -665,10 +729,7 @@ long epicsShareAPI tsLocalTime(TS_STAMP *pStamp)
|
||||
* tsRoundDownLocal(&now, 86400);
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI
|
||||
tsRoundDownLocal(pStamp, interval)
|
||||
TS_STAMP *pStamp; /* IO pointer to time stamp buffer */
|
||||
unsigned long interval; /* I rounding interval, in seconds */
|
||||
long epicsShareAPI tsRoundDownLocal(TS_STAMP *pStamp, unsigned long interval)
|
||||
{
|
||||
long retStat=S_ts_OK;/* return status to caller */
|
||||
struct tsDetail detail;
|
||||
@@ -710,10 +771,7 @@ unsigned long interval; /* I rounding interval, in seconds */
|
||||
* tsRoundUpLocal(&now, 86400);
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI
|
||||
tsRoundUpLocal(pStamp, interval)
|
||||
TS_STAMP *pStamp; /* IO pointer to time stamp buffer */
|
||||
unsigned long interval; /* I rounding interval, in seconds */
|
||||
long epicsShareAPI tsRoundUpLocal(TS_STAMP *pStamp, unsigned long interval)
|
||||
{
|
||||
long retStat=S_ts_OK;/* return status to caller */
|
||||
struct tsDetail detail;
|
||||
@@ -752,10 +810,7 @@ unsigned long interval; /* I rounding interval, in seconds */
|
||||
* o doesn't handle 0 time stamps for time zones west of Greenwich
|
||||
*
|
||||
*-*/
|
||||
static void
|
||||
tsStampFromLocal(pStamp, pT)
|
||||
TS_STAMP *pStamp;/* O EPICS time stamp resulting from conversion */
|
||||
struct tsDetail *pT; /* I pointer to time structure to convert */
|
||||
static void tsStampFromLocal(TS_STAMP *pStamp, struct tsDetail *pT)
|
||||
{
|
||||
long retStat=S_ts_OK;/* return status to caller */
|
||||
|
||||
@@ -830,7 +885,7 @@ struct tsDetail *pT; /* I pointer to time structure to convert */
|
||||
stamp.secPastEpoch += tsMinWest*60;
|
||||
*pStamp = stamp;
|
||||
}
|
||||
|
||||
|
||||
/*+/internal******************************************************************
|
||||
* NAME tsStampToLocal - convert time stamp to local time
|
||||
*
|
||||
@@ -845,10 +900,7 @@ struct tsDetail *pT; /* I pointer to time structure to convert */
|
||||
* o doesn't handle 0 time stamps for time zones west of Greenwich
|
||||
*
|
||||
*-*/
|
||||
static void
|
||||
tsStampToLocal(stamp, pT)
|
||||
TS_STAMP stamp; /* I EPICS time stamp to convert */
|
||||
struct tsDetail *pT; /* O pointer to time structure for conversion */
|
||||
static void tsStampToLocal(TS_STAMP stamp,struct tsDetail *pT)
|
||||
{
|
||||
int dstBegin; /* day DST begins */
|
||||
int dstEnd; /* day DST ends */
|
||||
@@ -905,9 +957,8 @@ struct tsDetail *pT; /* O pointer to time structure for conversion */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
tsInitMinWest()
|
||||
|
||||
static void tsInitMinWest()
|
||||
{
|
||||
int error=0;
|
||||
|
||||
@@ -925,10 +976,7 @@ EPICS_TS_MIN_WEST.name, tsMinWest);
|
||||
needToInitMinWest = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
tsStampToLocalZone(pStamp, pT)
|
||||
TS_STAMP *pStamp;/* pointer to EPICS time stamp to convert */
|
||||
struct tsDetail *pT; /* pointer to time structure for conversion */
|
||||
static void tsStampToLocalZone(TS_STAMP *pStamp,struct tsDetail *pT)
|
||||
{
|
||||
int ndays; /* number of days in this month or year */
|
||||
unsigned long secPastEpoch; /* time from stamp, in local zone */
|
||||
@@ -1164,10 +1212,9 @@ char *textBuffer; /* O buffer to receive text */
|
||||
* tsTextToStamp(&equiv, &text);
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI
|
||||
tsTextToStamp(pStamp, pText)
|
||||
TS_STAMP *pStamp; /* O time stamp corresponding to text */
|
||||
char **pText; /* IO ptr to ptr to string containing time and date */
|
||||
long epicsShareAPI tsTextToStamp(
|
||||
TS_STAMP *pStamp, /* O time stamp corresponding to text */
|
||||
char **pCallerText) /* IO ptr to ptr to string containing time and date */
|
||||
{
|
||||
long retStat=S_ts_OK;/* status return to caller */
|
||||
long stat; /* status from calls */
|
||||
@@ -1177,14 +1224,20 @@ char **pText; /* IO ptr to ptr to string containing time and date */
|
||||
char delim; /* delimiter character */
|
||||
long nsec; /* temp for nano-seconds */
|
||||
int count; /* count from scan of next field */
|
||||
char textbuf[TEXTBUFSIZE];
|
||||
char *ptextbuf;
|
||||
char **pText;
|
||||
|
||||
if (needToInitMinWest)
|
||||
tsInitMinWest();
|
||||
|
||||
assert(pStamp != NULL);
|
||||
assert(pText != NULL);
|
||||
assert(*pText != NULL);
|
||||
|
||||
assert(pCallerText != NULL);
|
||||
assert(*pCallerText != NULL);
|
||||
/*Lets be nice and not modify *pCallerText or **pCallerText */
|
||||
strncpy(textbuf,*pCallerText,TEXTBUFSIZE);
|
||||
textbuf[TEXTBUFSIZE-1] = 0;
|
||||
ptextbuf = textbuf;
|
||||
pText = &ptextbuf;
|
||||
/*----------------------------------------------------------------------------
|
||||
* skip over leading white space
|
||||
*----------------------------------------------------------------------------*/
|
||||
@@ -1410,9 +1463,9 @@ char **pText; /* IO ptr to ptr to string containing time and date */
|
||||
*
|
||||
*-*/
|
||||
long epicsShareAPI
|
||||
tsTimeTextToStamp(pStamp, pText)
|
||||
tsTimeTextToStamp(pStamp, pCallerText)
|
||||
TS_STAMP *pStamp; /* O time stamp corresponding to text */
|
||||
char **pText; /* IO ptr to ptr to string containing time and date */
|
||||
char **pCallerText; /* IO ptr to ptr to string containing time and date */
|
||||
{
|
||||
long retStat=S_ts_OK;/* status return to caller */
|
||||
struct tsDetail t; /* detailed breakdown of text */
|
||||
@@ -1420,11 +1473,18 @@ char **pText; /* IO ptr to ptr to string containing time and date */
|
||||
char delim; /* delimiter character */
|
||||
int count; /* count from scan of next field */
|
||||
long nsec; /* temp for nano-seconds */
|
||||
char textbuf[TEXTBUFSIZE];
|
||||
char *ptextbuf;
|
||||
char **pText;
|
||||
|
||||
assert(pStamp != NULL);
|
||||
assert(pText != NULL);
|
||||
assert(*pText != NULL);
|
||||
|
||||
assert(pCallerText != NULL);
|
||||
assert(*pCallerText != NULL);
|
||||
/*Lets be nice and not modify *pCallerText or **pCallerText */
|
||||
strncpy(textbuf,*pCallerText,TEXTBUFSIZE);
|
||||
textbuf[TEXTBUFSIZE-1] = 0;
|
||||
ptextbuf = textbuf;
|
||||
pText = &ptextbuf;
|
||||
/*----------------------------------------------------------------------------
|
||||
* skip over leading white space
|
||||
*----------------------------------------------------------------------------*/
|
||||
@@ -1504,4 +1564,171 @@ char **pText; /* IO ptr to ptr to string containing time and date */
|
||||
*pStamp = stamp;
|
||||
return retStat;
|
||||
}
|
||||
|
||||
/*+/mod***********************************************************************
|
||||
* TITLE nextFieldSubr.c - text field scanning routines
|
||||
*
|
||||
* GENERAL DESCRIPTION
|
||||
* The routines in this module provide for scanning fields in text
|
||||
* strings. They can be used as the basis for parsing text input
|
||||
* to a program.
|
||||
*
|
||||
* QUICK REFERENCE
|
||||
* char (*pText)[];
|
||||
* char (*pField)[];
|
||||
* char *pDelim;
|
||||
*
|
||||
* int nextAlph1UCField( <>pText, >pField, >pDelim )
|
||||
* int nextIntField( <>pText, >pField, >pDelim )
|
||||
* int nextIntFieldAsInt( <>pText, >pIntVal, >pDelim )
|
||||
* int nextIntFieldAsLong( <>pText, >pLongVal, >pDelim )
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The input text string is scanned to identify the beginning and
|
||||
* end of a field. At return, the input pointer points to the character
|
||||
* following the delimiter and the delimiter has been returned through
|
||||
* its pointer; the field contents are `returned' either as a pointer
|
||||
* to the first character of the field or as a value returned through
|
||||
* a pointer.
|
||||
*
|
||||
* In the input string, a '\0' is stored in place of the delimiter,
|
||||
* so that standard string handling tools can be used for text fields.
|
||||
*
|
||||
* nextAlph1UCField scans the next alphabetic field, changes
|
||||
* the first character to upper case, and
|
||||
* changes the rest to lower case
|
||||
* nextIntField scans the next integer field
|
||||
* nextIntFieldAsInt scans the next integer field as an int
|
||||
* nextIntFieldAsLong scans the next integer field as a long
|
||||
*
|
||||
* RETURNS
|
||||
* count of characters in field, including the delimiter. A special
|
||||
* case exists when only '\0' is encountered; in this case 0 is returned.
|
||||
* (For quoted alpha strings, the count will include the " characters.)
|
||||
*
|
||||
* BUGS
|
||||
* o use of type checking macros isn't protected by isascii()
|
||||
*
|
||||
* SEE ALSO
|
||||
* tsTextToStamp()
|
||||
*
|
||||
* NOTES
|
||||
* 1. fields involving alpha types consider underscore ('_') to be
|
||||
* alphabetic.
|
||||
*
|
||||
* EXAMPLE
|
||||
* char text[]="process 30 samples"
|
||||
* char *pText; pointer into text string
|
||||
* char *pCmd; pointer to first field, to use as a command
|
||||
* int count; value of second field, number of items to process
|
||||
* char *pUnits; pointer to third field, needed for command processing
|
||||
* int length; length of field
|
||||
* char delim; delimiter for field
|
||||
*
|
||||
* pText = text;
|
||||
* if (nextIntFieldAsInt(&pText, &count, &delim) <= 1)
|
||||
* error action if empty field
|
||||
* printf("command=%s, count=%d, units=%s\n", pCmd, count, pUnits);
|
||||
*
|
||||
*-***************************************************************************/
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* the preamble skips over leading white space, stopping either at
|
||||
* end of string or at a non-white-space character. If EOS is encountered,
|
||||
* then the appropriate return conditions are set up and a return 0 is done.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define NEXT_PREAMBLE \
|
||||
char *pDlm; /* pointer to field delimiter */ \
|
||||
int count; /* count of characters (plus delim) */ \
|
||||
\
|
||||
assert(ppText != NULL); \
|
||||
assert(*ppText != NULL); \
|
||||
assert(ppField != NULL); \
|
||||
assert(pDelim != NULL); \
|
||||
\
|
||||
if (**ppText == '\0') { \
|
||||
*ppField = *ppText; \
|
||||
*pDelim = **ppText; \
|
||||
return 0; \
|
||||
} \
|
||||
while (**ppText != '\0' && isspace(**ppText)) \
|
||||
(*ppText)++; /* skip leading white space */ \
|
||||
pDlm = *ppField = *ppText; \
|
||||
if (*pDlm == '\0') { \
|
||||
*pDelim = **ppText; \
|
||||
return 0; \
|
||||
} \
|
||||
count = 1; /* include delimiter in count */
|
||||
/*-----------------------------------------------------------------------------
|
||||
* the postamble is called for each character in the field. It moves
|
||||
* the pointers and increments the count. If the loop terminates, then
|
||||
* the caller is informed of the delimiter and the source character
|
||||
* string has '\0' inserted in place of the delimiter, so that the field
|
||||
* is now a proper '\0' terminated string.
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define NEXT_POSTAMBLE \
|
||||
pDlm++; \
|
||||
count++; \
|
||||
} \
|
||||
*pDelim = *pDlm; \
|
||||
*ppText = pDlm; \
|
||||
if (*pDlm != '\0') { \
|
||||
(*ppText)++; /* point to next available character */ \
|
||||
*pDlm = '\0'; \
|
||||
}
|
||||
|
||||
static int nextAlph1UCField(char **ppText,char **ppField, char *pDelim)
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
while (isalpha(*pDlm) || *pDlm == '_') {
|
||||
if (count == 1) {
|
||||
if (islower(*pDlm))
|
||||
*pDlm = toupper(*pDlm);
|
||||
}
|
||||
else {
|
||||
if (isupper(*pDlm))
|
||||
*pDlm = tolower(*pDlm);
|
||||
}
|
||||
NEXT_POSTAMBLE
|
||||
return count;
|
||||
}
|
||||
|
||||
static int nextIntField(char **ppText,char **ppField,char *pDelim)
|
||||
{
|
||||
NEXT_PREAMBLE
|
||||
while (isdigit(*pDlm) || ((*pDlm=='-' || *pDlm=='+') && count==1)) {
|
||||
NEXT_POSTAMBLE
|
||||
return count;
|
||||
}
|
||||
|
||||
static int nextIntFieldAsInt(char **ppText,int *pIntVal,char *pDelim)
|
||||
{
|
||||
char *pField; /* pointer to field */
|
||||
int count; /* count of char in field, including delim */
|
||||
|
||||
assert(pIntVal != NULL);
|
||||
|
||||
count = nextIntField(ppText, &pField, pDelim);
|
||||
if (count > 1) {
|
||||
if (sscanf(pField, "%d", pIntVal) != 1)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int nextIntFieldAsLong(char **ppText,long *pLongVal,char *pDelim)
|
||||
{
|
||||
char *pField; /* pointer to field */
|
||||
int count; /* count of char in field, including delim */
|
||||
|
||||
assert(pLongVal != NULL);
|
||||
|
||||
count = nextIntField(ppText, &pField, pDelim);
|
||||
if (count > 1) {
|
||||
if (sscanf(pField, "%ld", pLongVal) != 1)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user