parse.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 1996 by Sun Microsystems, Inc.
* All Rights Reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*
* parse.c,v 3.43 1997/01/26 18:12:21 kardel Exp
*
* Parser module for reference clock
*
* PARSEKERNEL define switches between two personalities of the module
* if PARSEKERNEL is defined this module can be used
* as kernel module. In this case the time stamps will be
* a struct timeval.
* when PARSEKERNEL is not defined NTP time stamps will be used.
*
* Copyright (c) 1992,1993,1994,1995,1996, 1997 by Frank Kardel
* Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef NeXT
/*
* This is lame, but gets us a symbol for the libparse library so the NeXTstep
* ranlib doesn't stop the compile.
*/
void token_libparse_symbol()
{
}
#endif
#endif
#include "ntp_fp.h"
#include "ntp_unixtime.h"
#include "ntp_calendar.h"
#include "ntp_machine.h"
#include "parse.h"
#include "ntp_stdlib.h"
#ifdef STREAM
#include <sys/parsestreams.h>
#endif
/*
* Sorry, but in SunOS 4.x AND Solaris 2.x kernels there are no
* mem* operations. I don't want them - bcopy, bzero
* are fine in the kernel
*/
#ifndef bzero
#endif
#endif
extern clockformat_t *clockformats[];
extern unsigned short nformats;
static int Strlen P((char *));
static int Strcmp P((char *, char *));
static int setup_bitmaps P((parse_t *, unsigned int, unsigned int));
/*
* strings support usually not in kernel - duplicated, but what the heck
*/
static int
Strlen(s)
register char *s;
{
register int c;
c = 0;
if (s)
{
while (*s++)
{
c++;
}
}
return c;
}
static int
Strcmp(s, t)
register char *s;
register char *t;
{
register int c = 0;
if (!s || !t || (s == t))
{
return 0;
}
while (!(c = *s++ - *t++) && *s && *t)
/* empty loop */;
return c;
}
static int
register timestamp_t *ctime;
{
#ifdef PARSEKERNEL
{
}
#else
extern long tstouslo[];
extern long tstousmid[];
extern long tstoushi[];
#endif
{
return 1;
}
else
{
return 0;
}
}
/*
* setup_bitmaps
* WARNING: NOT TO BE CALLED CONCURRENTLY WITH
* parse_ioread, parse_ioend, parse_ioinit
*/
static int
register unsigned int low;
register unsigned int high;
{
register unsigned short i;
register int f = 0;
register clockformat_t *fmt;
{
parseprintf(DD_PARSE, ("setup_bitmaps: failed: bounds error (low=%d, high=%d, nformats=%d)\n", low, high, nformats));
return 0;
}
plen = 0;
parseio->parse_syncflags = 0;
/*
* gather bitmaps of possible start and end values
*/
{
fmt = clockformats[i];
continue;
}
{
{
#ifdef PARSEKERNEL
printf("parse: setup_bitmaps: failed: START symbol collides with END symbol (format %d)\n", i);
#else
msyslog(LOG_ERR, "parse: setup_bitmaps: failed: START symbol collides with END symbol (format %d)\n", i);
#endif
return 0;
}
else
{
f = 1;
}
}
{
{
#ifdef PARSEKERNEL
printf("parse: setup_bitmaps: failed: END symbol collides with START symbol (format %d)\n", i);
#else
msyslog(LOG_ERR, "parse: setup_bitmaps: failed: END symbol collides with START symbol (format %d)\n", i);
#endif
return 0;
}
else
{
f = 1;
}
}
{
}
parseio->parse_syncflags |= fmt->flags & (SYNC_START|SYNC_END|SYNC_CHAR|SYNC_ONE|SYNC_ZERO|SYNC_TIMEOUT|SYNC_SYNTHESIZE);
((parseio->parse_timeout.tv_sec || parseio->parse_timeout.tv_usec) ? timercmp(&parseio->parse_timeout, &fmt->timeout, >) : 1))
{
}
}
if (parseio->parse_pdata)
{
parseio->parse_plen = 0;
parseio->parse_pdata = (void *)0;
}
{
/*
* need at least one start or end symbol
*/
#ifdef PARSEKERNEL
printf("parse: setup_bitmaps: failed: neither START nor END symbol defined\n");
#else
#endif
return 0;
}
{
if (!parseio->parse_pdata)
{
/*
* no memory
*/
#ifdef PARSEKERNEL
printf("parse: setup_bitmaps: failed: no memory for private data\n");
#else
#endif
return 0;
}
}
return 1;
}
/*ARGSUSED*/
int
{
parseio->parse_plen = 0;
parseio->parse_pdata = (void *)0;
return 0;
if (!parseio->parse_data)
{
return 0;
}
/*
* leave room for '\0'
*/
parseio->parse_lformat = 0;
parseio->parse_badformat = 0;
parseio->parse_index = 0;
parseio->parse_ldsize = 0;
return 1;
}
/*ARGSUSED*/
void
{
if (parseio->parse_pdata)
if (parseio->parse_data)
}
/*ARGSUSED*/
int
register unsigned int ch;
register timestamp_t *ctime;
{
/*
* within STREAMS CSx (x < 8) chars still have the upper bits set
* so we normalize the characters by masking unecessary bits off.
*/
{
case PARSE_IO_CS5:
ch &= 0x1F;
break;
case PARSE_IO_CS6:
ch &= 0x3F;
break;
case PARSE_IO_CS7:
ch &= 0x7F;
break;
case PARSE_IO_CS8:
ch &= 0xFF;
break;
}
parseprintf(DD_PARSE, ("parse_ioread(0x%lx, char=0x%x, ..., ...)\n", (unsigned long)parseio, ch & 0xFF));
{
{
return CVT_NONE;
}
{
}
else
{
}
}
else
{
low = 0;
}
{
{
register clockformat_t *fmt;
register unsigned short i;
/*
* got a sync event - call sync routine
*/
{
fmt = clockformats[i];
{
}
}
}
(parseio->parse_index == 0)) ||
{
register unsigned short i;
/*
* packet start - re-fill buffer
*/
if (parseio->parse_index)
{
/*
* filled buffer - thus not end character found
* do processing now
*/
}
/*
* could be a sync event - call sync routine if needed
*/
{
if ((parseio->parse_index == 0) ||
{
}
}
}
else
{
register unsigned short i;
{
/*
* collect into buffer
*/
}
{
/*
* packet end - process buffer
*/
{
{
}
}
parseio->parse_index = 0;
}
}
}
{
}
/*
* remember last character time
*/
#ifdef DEBUG
{
}
#endif
}
/*
* parse_iopps
*
* take status line indication and derive synchronisation information
* from it.
* It can also be used to decode a serial serial data format (such as the
* ONE, ZERO, MINUTE sync data stream from DCF77)
*/
/*ARGSUSED*/
int
register int status;
register timestamp_t *ptime;
{
/*
* PPS pulse information will only be delivered to ONE clock format
* this is either the last successful conversion module with a ppssync
* routine, or a fixed format with a ppssync routine
*/
{
}
else
{
}
}
/*
* parse_iodone
*
* clean up internal status for new round
*/
/*ARGSUSED*/
void
{
/*
* we need to clean up certain flags for the next round
*/
}
/*---------- conversion implementation --------------------*/
/*
* convert a struct clock to UTC since Jan, 1st 1970 0:00 (the UNIX EPOCH)
*/
register clocktime_t *clock;
{
static int days_of_month[] =
{
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
register int i;
time_t t;
{
return -1;
}
/*
* sorry, slow section here - but it's not time critical anyway
*/
/* month */
{
return -1; /* bad month */
}
/* adjust leap year */
t--;
{
t += days_of_month[i];
}
/* day */
{
return -1; /* bad day */
}
/* hour */
{
return -1; /* bad hour */
}
/* min */
{
return -1; /* bad min */
}
/* sec */
{
return -1; /* bad sec */
}
/* done */
return t;
}
/*--------------- format conversion -----------------------------------*/
int
char *s;
long *zp;
int cnt;
{
char *b = s;
int f,z,v;
char c;
f=z=v=0;
while(*s == ' ')
s++;
if (*s == '-')
{
s++;
v = 1;
}
else
if (*s == '+')
s++;
for(;;)
{
c = *s++;
{
if (f == 0)
{
return(-1);
}
if (v)
z = -z;
*zp = z;
return(0);
}
z = (z << 3) + (z << 1) + ( c - '0' );
f=1;
}
}
int
Strok(s, m)
char *s;
char *m;
{
if (!s || !m)
return 0;
while(*s && *m)
{
if ((*m == ' ') ? 1 : (*s == *m))
{
s++;
m++;
}
else
{
return 0;
}
}
return !*m;
}
register time_t t;
{
register long usecoff;
#ifdef PARSEKERNEL
#else
extern long tstouslo[];
extern long tstousmid[];
extern long tstoushi[];
+ usec;
#endif
#ifdef PARSEKERNEL
{
int s = splhigh();
#endif
#ifdef PARSEKERNEL
(void)splx(s);
}
#endif
return CVT_OK; /* everything fine and dandy... */
}
/*
* syn_simple
*
* handle a sync time stamp
*/
/*ARGSUSED*/
void
register timestamp_t *ts;
register void *vf;
{
}
/*
* pps_simple
*
* handle a pps time stamp
*/
/*ARGSUSED*/
register int status;
register timestamp_t *ptime;
{
return CVT_NONE;
}
/*
* timepacket
*
* process a data packet
*/
static u_long
{
register int k;
register unsigned short format;
register time_t t;
k = 0;
{
switch ((cvtrtc = clockformats[format]->convert ? clockformats[format]->convert(parseio->parse_data, parseio->parse_index, clockformats[format]->data, &clock, parseio->parse_pdata) : CVT_NONE) & CVT_MASK)
{
case CVT_FAIL:
break;
case CVT_NONE:
/*
* too bad - pretend bad format
*/
cvtsum = CVT_BADFMT;
break;
case CVT_OK:
k = 1;
break;
case CVT_SKIP:
k = 2;
break;
default:
/* shouldn't happen */
#ifdef PARSEKERNEL
printf("parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name);
#else
msyslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name);
#endif
}
}
else
{
/*
* find correct conversion routine
* and convert time packet
* RR search starting at last successful conversion routine
*/
if (nformats) /* very careful ... */
{
do
{
switch ((cvtrtc = (clockformats[format]->convert && !(clockformats[format]->flags & CVT_FIXEDONLY)) ?
clockformats[format]->convert(parseio->parse_data, parseio->parse_index, clockformats[format]->data, &clock, parseio->parse_pdata) :
{
case CVT_FAIL:
/*FALLTHROUGH*/
case CVT_NONE:
format++;
break;
case CVT_OK:
k = 1;
break;
default:
/* shouldn't happen */
#ifdef PARSEKERNEL
printf("parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name);
#else
msyslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name);
#endif
return CVT_BADFMT;
}
format = 0;
}
}
}
if (!k)
{
}
if (k == 2) return CVT_OK;
{
}
/*
* time stamp
*/
#ifdef PARSEKERNEL
#else
#endif
}
/*ARGSUSED*/
int
{
/*
* move out current bad packet count
* user program is expected to sum these up
* this is not a problem, as "parse" module are
* exclusive open only
*/
parse->parse_badformat = 0;
{
return 1;
}
else
{
return 0;
}
}
/*ARGSUSED*/
int
{
{
{
register unsigned short i;
for (i = 0; i < nformats; i++)
{
{
parse->parse_lformat = i;
}
}
return 0;
}
else
{
}
}
else
{
return 0;
}
}
/*ARGSUSED*/
int
{
{
bcopy(clockformats[dct->parseformat.parse_format]->name, dct->parseformat.parse_buffer, dct->parseformat.parse_count);
return 1;
}
else
{
return 0;
}
}
/*ARGSUSED*/
int
{
return 1;
}
#else /* not (REFCLOCK && (PARSE || PARSEPPS)) */
int parse_bs;
#endif /* not (REFCLOCK && (PARSE || PARSEPPS)) */
/*
* History:
*
* parse.c,v
* Revision 3.43 1997/01/26 18:12:21 kardel
* 3-5.88.2 reconciliation
*
* Revision 3.42 1997/01/19 14:37:19 kardel
* fixed comments
*
* Revision 3.41 1997/01/19 12:44:43 kardel
* 3-5.88.1 reconcilation
*
* Revision 3.40 1996/12/01 16:04:16 kardel
* freeze for 5.86.12.2 PARSE-Patch
*
* Revision 3.39 1996/11/30 20:45:18 kardel
* initial compilable SunOS 4 version of parse autoconfigure
*
* Revision 3.38 1996/11/24 23:16:32 kardel
* checkpoint - partial autoconfigure update for parse modules
*
* Revision 3.37 1996/11/24 20:09:48 kardel
* RELEASE_5_86_12_2 reconcilation
*
* Revision 3.36 1996/10/05 13:30:22 kardel
* general update
*
* Revision 3.35 1995/07/30 21:08:38 kardel
* mask ch instead of cd
*
* Revision 3.34 1995/07/29 08:04:07 kardel
*
* Revision 3.33 1995/07/02 19:54:41 kardel
* keep ANSI happy...
*
* Revision 3.32 1995/06/18 12:10:47 kardel
* removed dispersion calulation from parse subsystem
*
* Revision 3.31 1995/02/16 22:59:40 kardel
* rcs id fixed
*
* Revision 3.30 1995/02/16 22:52:11 kardel
* OSF cc choked on string.h
*
* Revision 3.29 1994/10/03 21:59:33 kardel
* 3.4e cleanup/integration
*
* Revision 3.28 1994/10/03 10:04:13 kardel
* 3.4e reconcilation
*
* Revision 3.27 1994/06/01 08:18:33 kardel
* more debug info
*
* Revision 3.26 1994/05/30 10:20:07 kardel
* LONG cleanup
*
* Revision 3.25 1994/05/12 12:49:12 kardel
*
* Revision 3.24 1994/03/27 15:01:36 kardel
* reorder include file to cope with PTX
*
* Revision 3.23 1994/03/25 13:09:02 kardel
* considering FIXEDONLY entries only in FIXEDONLY mode
*
* Revision 3.22 1994/02/25 12:34:49 kardel
* allow for converter generated utc times
*
* Revision 3.21 1994/02/02 17:45:30 kardel
* rcs ids fixed
*
* Revision 3.19 1994/01/25 19:05:20 kardel
* 94/01/23 reconcilation
*
* Revision 3.18 1994/01/23 17:21:59 kardel
* 1994 reconcilation
*
* Revision 3.17 1993/11/11 11:20:29 kardel
* declaration fixes
*
* Revision 3.16 1993/11/06 22:26:07 duwe
* Linux cleanup after config change
*
* Revision 3.15 1993/11/04 11:14:18 kardel
* ansi/K&R traps
*
* Revision 3.14 1993/11/04 10:03:28 kardel
* disarmed ansiism
*
* Revision 3.13 1993/11/01 20:14:13 kardel
* useless comparision removed
*
* Revision 3.12 1993/11/01 20:00:22 kardel
* parse Solaris support (initial version)
*
* Revision 3.11 1993/10/30 09:41:25 kardel
* minor optimizations
*
* Revision 3.10 1993/10/22 14:27:51 kardel
* Oct. 22nd 1993 reconcilation
*
* Revision 3.9 1993/10/05 23:15:09 kardel
* more STREAM protection
*
* Revision 3.8 1993/09/27 21:08:00 kardel
* utcoffset now in seconds
*
* Revision 3.7 1993/09/26 23:40:16 kardel
* new parse driver logic
*
* Revision 3.6 1993/09/07 10:12:46 kardel
* September 7th reconcilation - 3.2 (alpha)
*
* Revision 3.5 1993/09/01 21:44:48 kardel
* conditional cleanup
*
* Revision 3.4 1993/08/27 00:29:39 kardel
* compilation cleanup
*
* Revision 3.3 1993/08/24 22:27:13 kardel
* cleaned up AUTOCONF DCF77 mess 8-) - wasn't too bad
*
* Revision 3.2 1993/07/09 11:37:11 kardel
* Initial restructured version + GPS support
*
* Revision 3.1 1993/07/06 10:00:08 kardel
* DCF77 driver goes generic...
*
*/