154359Sroberto/*
2182007Sroberto * /src/NTP/ntp4-dev/libparse/parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A
3282408Scy *
4182007Sroberto * parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A
554359Sroberto *
654359Sroberto * Parser module for reference clock
754359Sroberto *
854359Sroberto * PARSEKERNEL define switches between two personalities of the module
954359Sroberto * if PARSEKERNEL is defined this module can be used
1054359Sroberto * as kernel module. In this case the time stamps will be
1154359Sroberto * a struct timeval.
1254359Sroberto * when PARSEKERNEL is not defined NTP time stamps will be used.
1354359Sroberto *
14182007Sroberto * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
15282408Scy * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
1654359Sroberto *
17182007Sroberto * Redistribution and use in source and binary forms, with or without
18182007Sroberto * modification, are permitted provided that the following conditions
19182007Sroberto * are met:
20182007Sroberto * 1. Redistributions of source code must retain the above copyright
21182007Sroberto *    notice, this list of conditions and the following disclaimer.
22182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright
23182007Sroberto *    notice, this list of conditions and the following disclaimer in the
24182007Sroberto *    documentation and/or other materials provided with the distribution.
25182007Sroberto * 3. Neither the name of the author nor the names of its contributors
26182007Sroberto *    may be used to endorse or promote products derived from this software
27182007Sroberto *    without specific prior written permission.
28182007Sroberto *
29182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30182007Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31182007Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32182007Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33182007Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34182007Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35182007Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36182007Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37182007Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38182007Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39182007Sroberto * SUCH DAMAGE.
40182007Sroberto *
4154359Sroberto */
4254359Sroberto
4354359Sroberto#ifdef HAVE_CONFIG_H
4454359Sroberto# include <config.h>
4554359Sroberto#endif
4654359Sroberto
4754359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE)
4854359Sroberto
4954359Sroberto#if	!(defined(lint) || defined(__GNUC__))
50182007Srobertostatic char rcsid[] = "parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A";
5154359Sroberto#endif
5254359Sroberto
5354359Sroberto#include "ntp_fp.h"
54280849Scy#include "timevalops.h"
5554359Sroberto#include "ntp_calendar.h"
5654359Sroberto#include "ntp_stdlib.h"
5754359Sroberto#include "ntp_machine.h"
5854359Sroberto#include "ntp.h"		/* (get Y2KFixes definitions) 	Y2KFixes */
5954359Sroberto
6054359Sroberto#include "parse.h"
6154359Sroberto
6254359Sroberto#ifndef PARSESTREAM
6382498Sroberto# include <stdio.h>
6454359Sroberto#else
6582498Sroberto# include "sys/parsestreams.h"
6654359Sroberto#endif
6754359Sroberto
6854359Srobertoextern clockformat_t *clockformats[];
6954359Srobertoextern unsigned short nformats;
7054359Sroberto
71280849Scystatic u_long timepacket (parse_t *);
7254359Sroberto
7354359Sroberto/*
7454359Sroberto * strings support usually not in kernel - duplicated, but what the heck
7554359Sroberto */
7654359Srobertostatic int
7754359SrobertoStrlen(
7854359Sroberto	register const char *s
7954359Sroberto	)
8054359Sroberto{
8154359Sroberto	register int c;
8254359Sroberto
8354359Sroberto	c = 0;
8454359Sroberto	if (s)
8554359Sroberto	{
8654359Sroberto		while (*s++)
8754359Sroberto		{
8854359Sroberto			c++;
8954359Sroberto		}
9054359Sroberto	}
9154359Sroberto	return c;
9254359Sroberto}
9354359Sroberto
9454359Srobertostatic int
9554359SrobertoStrcmp(
9654359Sroberto	register const char *s,
9754359Sroberto	register const char *t
9854359Sroberto	)
9954359Sroberto{
10054359Sroberto	register int c = 0;
10154359Sroberto
10254359Sroberto	if (!s || !t || (s == t))
10354359Sroberto	{
10454359Sroberto		return 0;
10554359Sroberto	}
10654359Sroberto
10754359Sroberto	while (!(c = *s++ - *t++) && *s && *t)
10854359Sroberto	    /* empty loop */;
109282408Scy
11054359Sroberto	return c;
11154359Sroberto}
11254359Sroberto
11354359Srobertoint
11454359Srobertoparse_timedout(
11554359Sroberto	       parse_t *parseio,
11654359Sroberto	       timestamp_t *tstamp,
11754359Sroberto	       struct timeval *del
11854359Sroberto	       )
11954359Sroberto{
12054359Sroberto	struct timeval delta;
12154359Sroberto
12254359Sroberto#ifdef PARSEKERNEL
12354359Sroberto	delta.tv_sec = tstamp->tv.tv_sec - parseio->parse_lastchar.tv.tv_sec;
12454359Sroberto	delta.tv_usec = tstamp->tv.tv_usec - parseio->parse_lastchar.tv.tv_usec;
12554359Sroberto	if (delta.tv_usec < 0)
12654359Sroberto	{
12754359Sroberto		delta.tv_sec  -= 1;
12854359Sroberto		delta.tv_usec += 1000000;
12954359Sroberto	}
13054359Sroberto#else
13154359Sroberto	l_fp delt;
13254359Sroberto
13354359Sroberto	delt = tstamp->fp;
13454359Sroberto	L_SUB(&delt, &parseio->parse_lastchar.fp);
13554359Sroberto	TSTOTV(&delt, &delta);
13654359Sroberto#endif
13754359Sroberto
13854359Sroberto	if (timercmp(&delta, del, >))
13954359Sroberto	{
14054359Sroberto		parseprintf(DD_PARSE, ("parse: timedout: TRUE\n"));
14154359Sroberto		return 1;
14254359Sroberto	}
14354359Sroberto	else
14454359Sroberto	{
14554359Sroberto		parseprintf(DD_PARSE, ("parse: timedout: FALSE\n"));
14654359Sroberto		return 0;
14754359Sroberto	}
14854359Sroberto}
14954359Sroberto
15054359Sroberto/*ARGSUSED*/
15154359Srobertoint
15254359Srobertoparse_ioinit(
15354359Sroberto	register parse_t *parseio
15454359Sroberto	)
15554359Sroberto{
15654359Sroberto	parseprintf(DD_PARSE, ("parse_iostart\n"));
157282408Scy
15854359Sroberto	parseio->parse_plen = 0;
15954359Sroberto	parseio->parse_pdata = (void *)0;
160282408Scy
16154359Sroberto	parseio->parse_data = 0;
16254359Sroberto	parseio->parse_ldata = 0;
16354359Sroberto	parseio->parse_dsize = 0;
16454359Sroberto
16554359Sroberto	parseio->parse_badformat = 0;
16654359Sroberto	parseio->parse_ioflags   = PARSE_IO_CS7;	/* usual unix default */
16754359Sroberto	parseio->parse_index     = 0;
16854359Sroberto	parseio->parse_ldsize    = 0;
169282408Scy
17054359Sroberto	return 1;
17154359Sroberto}
17254359Sroberto
17354359Sroberto/*ARGSUSED*/
17454359Srobertovoid
17554359Srobertoparse_ioend(
17654359Sroberto	register parse_t *parseio
17754359Sroberto	)
17854359Sroberto{
17954359Sroberto	parseprintf(DD_PARSE, ("parse_ioend\n"));
18054359Sroberto
18154359Sroberto	if (parseio->parse_pdata)
18254359Sroberto	    FREE(parseio->parse_pdata, parseio->parse_plen);
18354359Sroberto
18454359Sroberto	if (parseio->parse_data)
18554359Sroberto	    FREE(parseio->parse_data, (unsigned)(parseio->parse_dsize * 2 + 2));
18654359Sroberto}
18754359Sroberto
18854359Srobertounsigned int
18954359Srobertoparse_restart(
19054359Sroberto	      parse_t *parseio,
191282408Scy	      char ch
19254359Sroberto	      )
19354359Sroberto{
19454359Sroberto	unsigned int updated = PARSE_INP_SKIP;
195282408Scy
19654359Sroberto	/*
19754359Sroberto	 * re-start packet - timeout - overflow - start symbol
19854359Sroberto	 */
199282408Scy
20054359Sroberto	if (parseio->parse_index)
20154359Sroberto	{
20254359Sroberto		/*
20354359Sroberto		 * filled buffer - thus not end character found
20454359Sroberto		 * do processing now
20554359Sroberto		 */
20654359Sroberto		parseio->parse_data[parseio->parse_index] = '\0';
20754359Sroberto		memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
208182007Sroberto		parseio->parse_ldsize = parseio->parse_index;
20954359Sroberto		updated = PARSE_INP_TIME;
21054359Sroberto	}
211282408Scy
21254359Sroberto	parseio->parse_index = 1;
21354359Sroberto	parseio->parse_data[0] = ch;
21454359Sroberto	parseprintf(DD_PARSE, ("parse: parse_restart: buffer start (updated = %x)\n", updated));
21554359Sroberto	return updated;
21654359Sroberto}
217282408Scy
21854359Srobertounsigned int
21954359Srobertoparse_addchar(
22054359Sroberto	      parse_t *parseio,
221282408Scy	      char ch
22254359Sroberto	      )
22354359Sroberto{
22454359Sroberto	/*
22554359Sroberto	 * add to buffer
22654359Sroberto	 */
22754359Sroberto	if (parseio->parse_index < parseio->parse_dsize)
22854359Sroberto	{
22954359Sroberto		/*
23054359Sroberto		 * collect into buffer
23154359Sroberto		 */
23254359Sroberto		parseprintf(DD_PARSE, ("parse: parse_addchar: buffer[%d] = 0x%x\n", parseio->parse_index, ch));
233280849Scy		parseio->parse_data[parseio->parse_index++] = (char)ch;
23454359Sroberto		return PARSE_INP_SKIP;
23554359Sroberto	}
23654359Sroberto	else
23754359Sroberto		/*
23854359Sroberto		 * buffer overflow - attempt to make the best of it
23954359Sroberto		 */
24054359Sroberto		return parse_restart(parseio, ch);
24154359Sroberto}
242282408Scy
24354359Srobertounsigned int
24454359Srobertoparse_end(
24554359Sroberto	  parse_t *parseio
24654359Sroberto	  )
24754359Sroberto{
24854359Sroberto	/*
24954359Sroberto	 * message complete processing
25054359Sroberto	 */
25154359Sroberto	parseio->parse_data[parseio->parse_index] = '\0';
25254359Sroberto	memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
253182007Sroberto	parseio->parse_ldsize = parseio->parse_index;
25454359Sroberto	parseio->parse_index = 0;
25554359Sroberto	parseprintf(DD_PARSE, ("parse: parse_end: buffer end\n"));
25654359Sroberto	return PARSE_INP_TIME;
25754359Sroberto}
25854359Sroberto
25954359Sroberto/*ARGSUSED*/
26054359Srobertoint
26154359Srobertoparse_ioread(
26254359Sroberto	register parse_t *parseio,
263282408Scy	register char ch,
26454359Sroberto	register timestamp_t *tstamp
26554359Sroberto	)
26654359Sroberto{
267282408Scy	register u_int updated = CVT_NONE;
26854359Sroberto	/*
26954359Sroberto	 * within STREAMS CSx (x < 8) chars still have the upper bits set
27054359Sroberto	 * so we normalize the characters by masking unecessary bits off.
27154359Sroberto	 */
27254359Sroberto	switch (parseio->parse_ioflags & PARSE_IO_CSIZE)
27354359Sroberto	{
27454359Sroberto	    case PARSE_IO_CS5:
27554359Sroberto		ch &= 0x1F;
27654359Sroberto		break;
27754359Sroberto
27854359Sroberto	    case PARSE_IO_CS6:
27954359Sroberto		ch &= 0x3F;
28054359Sroberto		break;
28154359Sroberto
28254359Sroberto	    case PARSE_IO_CS7:
28354359Sroberto		ch &= 0x7F;
28454359Sroberto		break;
285282408Scy
28654359Sroberto	    case PARSE_IO_CS8:
287282408Scy		ch &= (char) 0xFFU;
28854359Sroberto		break;
28954359Sroberto	}
29054359Sroberto
291293423Sdelphij	parseprintf(DD_PARSE, ("parse_ioread(0x%p, char=0x%x, ..., ...)\n", (void*)parseio, ch & 0xFF));
29254359Sroberto
29354359Sroberto	if (!clockformats[parseio->parse_lformat]->convert)
29454359Sroberto	{
29554359Sroberto		parseprintf(DD_PARSE, ("parse_ioread: input dropped.\n"));
29654359Sroberto		return CVT_NONE;
29754359Sroberto	}
29854359Sroberto
29954359Sroberto	if (clockformats[parseio->parse_lformat]->input)
30054359Sroberto	{
30154359Sroberto		unsigned long input_status;
30254359Sroberto
30354359Sroberto		input_status = clockformats[parseio->parse_lformat]->input(parseio, ch, tstamp);
30454359Sroberto
30554359Sroberto		if (input_status & PARSE_INP_SYNTH)
30654359Sroberto		{
30754359Sroberto			updated = CVT_OK;
30854359Sroberto		}
309282408Scy
31054359Sroberto		if (input_status & PARSE_INP_TIME)	/* time sample is available */
31154359Sroberto		{
312282408Scy			updated = (u_int) timepacket(parseio);
31354359Sroberto		}
314282408Scy
31554359Sroberto		if (input_status & PARSE_INP_DATA) /* got additional data */
31654359Sroberto		{
31754359Sroberto			updated |= CVT_ADDITIONAL;
31854359Sroberto		}
31954359Sroberto	}
32054359Sroberto
321282408Scy
32254359Sroberto	/*
32354359Sroberto	 * remember last character time
32454359Sroberto	 */
32554359Sroberto	parseio->parse_lastchar = *tstamp;
32654359Sroberto
32754359Sroberto#ifdef DEBUG
32854359Sroberto	if ((updated & CVT_MASK) != CVT_NONE)
32954359Sroberto	{
33054359Sroberto		parseprintf(DD_PARSE, ("parse_ioread: time sample accumulated (status=0x%x)\n", updated));
33154359Sroberto	}
33254359Sroberto#endif
33354359Sroberto
33454359Sroberto	parseio->parse_dtime.parse_status = updated;
33554359Sroberto
33654359Sroberto	return (((updated & CVT_MASK) != CVT_NONE) ||
33754359Sroberto		((updated & CVT_ADDITIONAL) != 0));
33854359Sroberto}
33954359Sroberto
34054359Sroberto/*
34154359Sroberto * parse_iopps
34254359Sroberto *
34354359Sroberto * take status line indication and derive synchronisation information
34454359Sroberto * from it.
34554359Sroberto * It can also be used to decode a serial serial data format (such as the
34654359Sroberto * ONE, ZERO, MINUTE sync data stream from DCF77)
34754359Sroberto */
34854359Sroberto/*ARGSUSED*/
34954359Srobertoint
35054359Srobertoparse_iopps(
35154359Sroberto	register parse_t *parseio,
35254359Sroberto	register int status,
35354359Sroberto	register timestamp_t *ptime
35454359Sroberto	)
35554359Sroberto{
356282408Scy	register u_int updated = CVT_NONE;
35754359Sroberto
35854359Sroberto	/*
35954359Sroberto	 * PPS pulse information will only be delivered to ONE clock format
36054359Sroberto	 * this is either the last successful conversion module with a ppssync
36154359Sroberto	 * routine, or a fixed format with a ppssync routine
36254359Sroberto	 */
36354359Sroberto	parseprintf(DD_PARSE, ("parse_iopps: STATUS %s\n", (status == SYNC_ONE) ? "ONE" : "ZERO"));
36454359Sroberto
36554359Sroberto	if (clockformats[parseio->parse_lformat]->syncpps)
36654359Sroberto	{
367282408Scy		updated = (u_int) clockformats[parseio->parse_lformat]->syncpps(parseio, status == SYNC_ONE, ptime);
36854359Sroberto		parseprintf(DD_PARSE, ("parse_iopps: updated = 0x%x\n", updated));
36954359Sroberto	}
37054359Sroberto
37154359Sroberto	return (updated & CVT_MASK) != CVT_NONE;
37254359Sroberto}
37354359Sroberto
37454359Sroberto/*
37554359Sroberto * parse_iodone
37654359Sroberto *
37754359Sroberto * clean up internal status for new round
37854359Sroberto */
37954359Sroberto/*ARGSUSED*/
38054359Srobertovoid
38154359Srobertoparse_iodone(
38254359Sroberto	register parse_t *parseio
38354359Sroberto	)
38454359Sroberto{
38554359Sroberto	/*
38654359Sroberto	 * we need to clean up certain flags for the next round
38754359Sroberto	 */
38854359Sroberto	parseprintf(DD_PARSE, ("parse_iodone: DONE\n"));
38954359Sroberto	parseio->parse_dtime.parse_state = 0; /* no problems with ISRs */
39054359Sroberto}
39154359Sroberto
39254359Sroberto/*---------- conversion implementation --------------------*/
39354359Sroberto
39454359Sroberto/*
39554359Sroberto * convert a struct clock to UTC since Jan, 1st 1970 0:00 (the UNIX EPOCH)
39654359Sroberto */
39754359Sroberto#define days_per_year(x)	((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
39854359Sroberto
39954359Srobertotime_t
40054359Srobertoparse_to_unixtime(
40154359Sroberto	register clocktime_t   *clock_time,
40254359Sroberto	register u_long *cvtrtc
40354359Sroberto	)
40454359Sroberto{
40554359Sroberto#define SETRTC(_X_)	{ if (cvtrtc) *cvtrtc = (_X_); }
406282408Scy	static int days_of_month[] =
40754359Sroberto	{
40854359Sroberto		0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
40954359Sroberto	};
41054359Sroberto	register int i;
41154359Sroberto	time_t t;
412282408Scy
41354359Sroberto	if (clock_time->utctime)
41454359Sroberto	    return clock_time->utctime;	/* if the conversion routine gets it right away - why not */
41554359Sroberto
41654359Sroberto	if ( clock_time->year < YEAR_PIVOT )			/* Y2KFixes [ */
41754359Sroberto	    clock_time->year += 100;	/* convert 20xx%100 to 20xx-1900 */
41854359Sroberto	if ( clock_time->year < YEAR_BREAK )	/* expand to full four-digits */
41954359Sroberto	    clock_time->year += 1900;
42054359Sroberto
42154359Sroberto	if (clock_time->year < 1970 )				/* Y2KFixes ] */
42254359Sroberto	{
42354359Sroberto		SETRTC(CVT_FAIL|CVT_BADDATE);
42454359Sroberto		return -1;
42554359Sroberto	}
426282408Scy
42754359Sroberto	/*
42854359Sroberto	 * sorry, slow section here - but it's not time critical anyway
42954359Sroberto	 */
43054359Sroberto	t = julian0(clock_time->year) - julian0(1970);		/* Y2kFixes */
431282408Scy				/* month */
43254359Sroberto	if (clock_time->month <= 0 || clock_time->month > 12)
43354359Sroberto	{
43454359Sroberto		SETRTC(CVT_FAIL|CVT_BADDATE);
43554359Sroberto		return -1;		/* bad month */
43654359Sroberto	}
43754359Sroberto
43854359Sroberto#if 0								/* Y2KFixes */
43954359Sroberto				/* adjust leap year */
44054359Sroberto	if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
44154359Sroberto	    t--;
44254359Sroberto#else								/* Y2KFixes [ */
44354359Sroberto	if ( clock_time->month >= 3  &&  isleap_4(clock_time->year) )
44454359Sroberto	    t++;		/* add one more if within leap year */
44554359Sroberto#endif								/* Y2KFixes ] */
44654359Sroberto
44754359Sroberto	for (i = 1; i < clock_time->month; i++)
44854359Sroberto	{
44954359Sroberto		t += days_of_month[i];
45054359Sroberto	}
45154359Sroberto				/* day */
45254359Sroberto	if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ?
45354359Sroberto			       clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month]))
45454359Sroberto	{
45554359Sroberto		SETRTC(CVT_FAIL|CVT_BADDATE);
45654359Sroberto		return -1;		/* bad day */
45754359Sroberto	}
45854359Sroberto
45954359Sroberto	t += clock_time->day - 1;
46054359Sroberto				/* hour */
46154359Sroberto	if (clock_time->hour < 0 || clock_time->hour >= 24)
46254359Sroberto	{
46354359Sroberto		SETRTC(CVT_FAIL|CVT_BADTIME);
46454359Sroberto		return -1;		/* bad hour */
46554359Sroberto	}
46654359Sroberto
46754359Sroberto	t = TIMES24(t) + clock_time->hour;
46854359Sroberto
469282408Scy				/* min */
47054359Sroberto	if (clock_time->minute < 0 || clock_time->minute > 59)
47154359Sroberto	{
47254359Sroberto		SETRTC(CVT_FAIL|CVT_BADTIME);
47354359Sroberto		return -1;		/* bad min */
47454359Sroberto	}
47554359Sroberto
47654359Sroberto	t = TIMES60(t) + clock_time->minute;
47754359Sroberto				/* sec */
478282408Scy
47954359Sroberto	if (clock_time->second < 0 || clock_time->second > 60)	/* allow for LEAPs */
48054359Sroberto	{
48154359Sroberto		SETRTC(CVT_FAIL|CVT_BADTIME);
48254359Sroberto		return -1;		/* bad sec */
48354359Sroberto	}
48454359Sroberto
48554359Sroberto	t  = TIMES60(t) + clock_time->second;
48654359Sroberto
48754359Sroberto	t += clock_time->utcoffset;	/* warp to UTC */
48854359Sroberto
48954359Sroberto				/* done */
49054359Sroberto
49154359Sroberto	clock_time->utctime = t;		/* documentray only */
49254359Sroberto
49354359Sroberto	return t;
49454359Sroberto}
49554359Sroberto
49654359Sroberto/*--------------- format conversion -----------------------------------*/
49754359Sroberto
49854359Srobertoint
49954359SrobertoStoi(
50054359Sroberto	const unsigned char *s,
50154359Sroberto	long *zp,
50254359Sroberto	int cnt
50354359Sroberto	)
50454359Sroberto{
50554359Sroberto	char unsigned const *b = s;
50654359Sroberto	int f,z,v;
50754359Sroberto	char unsigned c;
50854359Sroberto
50954359Sroberto	f=z=v=0;
51054359Sroberto
51154359Sroberto	while(*s == ' ')
51254359Sroberto	    s++;
513282408Scy
51454359Sroberto	if (*s == '-')
51554359Sroberto	{
51654359Sroberto		s++;
51754359Sroberto		v = 1;
51854359Sroberto	}
51954359Sroberto	else
52054359Sroberto	    if (*s == '+')
52154359Sroberto		s++;
522282408Scy
52354359Sroberto	for(;;)
52454359Sroberto	{
52554359Sroberto		c = *s++;
52654359Sroberto		if (c == '\0' || c < '0' || c > '9' || (cnt && ((s-b) > cnt)))
52754359Sroberto		{
52854359Sroberto			if (f == 0)
52954359Sroberto			{
53054359Sroberto				return(-1);
53154359Sroberto			}
53254359Sroberto			if (v)
53354359Sroberto			    z = -z;
53454359Sroberto			*zp = z;
53554359Sroberto			return(0);
53654359Sroberto		}
53754359Sroberto		z = (z << 3) + (z << 1) + ( c - '0' );
53854359Sroberto		f=1;
53954359Sroberto	}
54054359Sroberto}
54154359Sroberto
54254359Srobertoint
54354359SrobertoStrok(
54454359Sroberto	const unsigned char *s,
54554359Sroberto	const unsigned char *m
54654359Sroberto	)
54754359Sroberto{
54854359Sroberto	if (!s || !m)
54954359Sroberto	    return 0;
55054359Sroberto
55154359Sroberto	while(*s && *m)
55254359Sroberto	{
55354359Sroberto		if ((*m == ' ') ? 1 : (*s == *m))
55454359Sroberto		{
55554359Sroberto			s++;
55654359Sroberto			m++;
55754359Sroberto		}
55854359Sroberto		else
55954359Sroberto		{
56054359Sroberto			return 0;
56154359Sroberto		}
56254359Sroberto	}
56354359Sroberto	return !*m;
56454359Sroberto}
56554359Sroberto
56654359Srobertou_long
56754359Srobertoupdatetimeinfo(
56854359Sroberto	       register parse_t *parseio,
56954359Sroberto	       register u_long   flags
57054359Sroberto	       )
57154359Sroberto{
57254359Sroberto#ifdef PARSEKERNEL
57354359Sroberto	{
57454359Sroberto		int s = splhigh();
57554359Sroberto#endif
576282408Scy
57754359Sroberto		parseio->parse_lstate          = parseio->parse_dtime.parse_state | flags | PARSEB_TIMECODE;
578282408Scy
57954359Sroberto		parseio->parse_dtime.parse_state = parseio->parse_lstate;
58054359Sroberto
58154359Sroberto#ifdef PARSEKERNEL
58254359Sroberto		(void)splx((unsigned int)s);
58354359Sroberto	}
58454359Sroberto#endif
58554359Sroberto
586282408Scy
58754359Sroberto#ifdef PARSEKERNEL
58854359Sroberto	parseprintf(DD_PARSE, ("updatetimeinfo status=0x%x, time=%x\n", parseio->parse_dtime.parse_state,
58954359Sroberto			       parseio->parse_dtime.parse_time.tv.tv_sec));
59054359Sroberto#else
59154359Sroberto	parseprintf(DD_PARSE, ("updatetimeinfo status=0x%lx, time=%x\n", (long)parseio->parse_dtime.parse_state,
59254359Sroberto	                       parseio->parse_dtime.parse_time.fp.l_ui));
59354359Sroberto#endif
594282408Scy
59554359Sroberto	return CVT_OK;		/* everything fine and dandy... */
59654359Sroberto}
59754359Sroberto
59854359Sroberto
59954359Sroberto/*
60054359Sroberto * syn_simple
60154359Sroberto *
60254359Sroberto * handle a sync time stamp
60354359Sroberto */
60454359Sroberto/*ARGSUSED*/
60554359Srobertovoid
60654359Srobertosyn_simple(
60754359Sroberto	register parse_t *parseio,
60854359Sroberto	register timestamp_t *ts,
60954359Sroberto	register struct format *format,
61054359Sroberto	register u_long why
61154359Sroberto	)
61254359Sroberto{
61354359Sroberto	parseio->parse_dtime.parse_stime = *ts;
61454359Sroberto}
61554359Sroberto
61654359Sroberto/*
617282408Scy * parse_pps_fnc_t pps_simple
61854359Sroberto *
61954359Sroberto * handle a pps time stamp
62054359Sroberto */
62154359Sroberto/*ARGSUSED*/
62254359Srobertou_long
62354359Srobertopps_simple(
62454359Sroberto	register parse_t *parseio,
62554359Sroberto	register int status,
62654359Sroberto	register timestamp_t *ptime
62754359Sroberto	)
62854359Sroberto{
62954359Sroberto	parseio->parse_dtime.parse_ptime  = *ptime;
63054359Sroberto	parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
631282408Scy
63254359Sroberto	return CVT_NONE;
63354359Sroberto}
63454359Sroberto
63554359Sroberto/*
636282408Scy * parse_pps_fnc_t pps_one
63754359Sroberto *
63854359Sroberto * handle a pps time stamp in ONE edge
63954359Sroberto */
64054359Sroberto/*ARGSUSED*/
64154359Srobertou_long
64254359Srobertopps_one(
64354359Sroberto	register parse_t *parseio,
64454359Sroberto	register int status,
64554359Sroberto	register timestamp_t *ptime
64654359Sroberto	)
64754359Sroberto{
64854359Sroberto	if (status)
64954359Sroberto		return pps_simple(parseio, status, ptime);
650282408Scy
65154359Sroberto	return CVT_NONE;
65254359Sroberto}
65354359Sroberto
65454359Sroberto/*
655282408Scy * parse_pps_fnc_t pps_zero
65654359Sroberto *
65754359Sroberto * handle a pps time stamp in ZERO edge
65854359Sroberto */
65954359Sroberto/*ARGSUSED*/
66054359Srobertou_long
66154359Srobertopps_zero(
66254359Sroberto	register parse_t *parseio,
66354359Sroberto	register int status,
66454359Sroberto	register timestamp_t *ptime
66554359Sroberto	)
66654359Sroberto{
66754359Sroberto	if (!status)
66854359Sroberto		return pps_simple(parseio, status, ptime);
669282408Scy
67054359Sroberto	return CVT_NONE;
67154359Sroberto}
67254359Sroberto
67354359Sroberto/*
67454359Sroberto * timepacket
67554359Sroberto *
67654359Sroberto * process a data packet
67754359Sroberto */
67854359Srobertostatic u_long
67954359Srobertotimepacket(
68054359Sroberto	register parse_t *parseio
68154359Sroberto	)
68254359Sroberto{
68354359Sroberto	register unsigned short format;
68454359Sroberto	register time_t t;
68554359Sroberto	u_long cvtrtc;		/* current conversion result */
68654359Sroberto	clocktime_t clock_time;
687282408Scy
68854359Sroberto	memset((char *)&clock_time, 0, sizeof clock_time);
68954359Sroberto	format = parseio->parse_lformat;
69054359Sroberto
69154359Sroberto	if (format == (unsigned short)~0)
69254359Sroberto		return CVT_NONE;
693282408Scy
69454359Sroberto	switch ((cvtrtc = clockformats[format]->convert ?
69554359Sroberto		 clockformats[format]->convert((unsigned char *)parseio->parse_ldata, parseio->parse_ldsize, (struct format *)(clockformats[format]->data), &clock_time, parseio->parse_pdata) :
69654359Sroberto		 CVT_NONE) & CVT_MASK)
69754359Sroberto	{
69854359Sroberto	case CVT_FAIL:
69954359Sroberto		parseio->parse_badformat++;
700285169Scy		return cvtrtc;
701282408Scy
70254359Sroberto	case CVT_NONE:
70354359Sroberto		/*
70454359Sroberto		 * too bad - pretend bad format
70554359Sroberto		 */
70654359Sroberto		parseio->parse_badformat++;
707285169Scy		return CVT_NONE;
708282408Scy
70954359Sroberto	case CVT_OK:
71054359Sroberto		break;
711282408Scy
71254359Sroberto	case CVT_SKIP:
71354359Sroberto		return CVT_NONE;
71454359Sroberto
71554359Sroberto	default:
71654359Sroberto		/* shouldn't happen */
71754359Sroberto#ifndef PARSEKERNEL
718280849Scy		msyslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"", clockformats[format]->name);
719282408Scy#endif
72054359Sroberto		return CVT_FAIL|cvtrtc;
72154359Sroberto	}
72254359Sroberto
72354359Sroberto	if ((t = parse_to_unixtime(&clock_time, &cvtrtc)) == -1)
72454359Sroberto	{
72554359Sroberto		return CVT_FAIL|cvtrtc;
72654359Sroberto	}
727282408Scy
72854359Sroberto	/*
72954359Sroberto	 * time stamp
73054359Sroberto	 */
73154359Sroberto#ifdef PARSEKERNEL
73254359Sroberto	parseio->parse_dtime.parse_time.tv.tv_sec  = t;
73354359Sroberto	parseio->parse_dtime.parse_time.tv.tv_usec = clock_time.usecond;
73454359Sroberto#else
735282408Scy	parseio->parse_dtime.parse_time.fp.l_ui = (uint32_t) (t + JAN_1970);
73654359Sroberto	TVUTOTSF(clock_time.usecond, parseio->parse_dtime.parse_time.fp.l_uf);
73754359Sroberto#endif
73854359Sroberto
73954359Sroberto	parseio->parse_dtime.parse_format       = format;
74054359Sroberto
74154359Sroberto	return updatetimeinfo(parseio, clock_time.flags);
74254359Sroberto}
74354359Sroberto
74454359Sroberto/*ARGSUSED*/
74554359Srobertoint
74654359Srobertoparse_timecode(
74754359Sroberto	parsectl_t *dct,
74854359Sroberto	parse_t    *parse
74954359Sroberto	)
75054359Sroberto{
75154359Sroberto	dct->parsegettc.parse_state  = parse->parse_lstate;
75254359Sroberto	dct->parsegettc.parse_format = parse->parse_lformat;
75354359Sroberto	/*
75454359Sroberto	 * move out current bad packet count
75554359Sroberto	 * user program is expected to sum these up
75654359Sroberto	 * this is not a problem, as "parse" module are
75754359Sroberto	 * exclusive open only
75854359Sroberto	 */
75954359Sroberto	dct->parsegettc.parse_badformat = parse->parse_badformat;
76054359Sroberto	parse->parse_badformat = 0;
761282408Scy
76254359Sroberto	if (parse->parse_ldsize <= PARSE_TCMAX)
76354359Sroberto	{
76454359Sroberto		dct->parsegettc.parse_count = parse->parse_ldsize;
76554359Sroberto		memcpy(dct->parsegettc.parse_buffer, parse->parse_ldata, dct->parsegettc.parse_count);
76654359Sroberto		return 1;
76754359Sroberto	}
76854359Sroberto	else
76954359Sroberto	{
77054359Sroberto		return 0;
77154359Sroberto	}
77254359Sroberto}
77354359Sroberto
774282408Scy
77554359Sroberto/*ARGSUSED*/
77654359Srobertoint
77754359Srobertoparse_setfmt(
77854359Sroberto	parsectl_t *dct,
77954359Sroberto	parse_t    *parse
78054359Sroberto	)
78154359Sroberto{
78254359Sroberto	if (dct->parseformat.parse_count <= PARSE_TCMAX)
78354359Sroberto	{
78454359Sroberto		if (dct->parseformat.parse_count)
78554359Sroberto		{
78654359Sroberto			register unsigned short i;
78754359Sroberto
78854359Sroberto			for (i = 0; i < nformats; i++)
78954359Sroberto			{
79054359Sroberto				if (!Strcmp(dct->parseformat.parse_buffer, clockformats[i]->name))
79154359Sroberto				{
79254359Sroberto					if (parse->parse_pdata)
79354359Sroberto						FREE(parse->parse_pdata, parse->parse_plen);
79454359Sroberto					parse->parse_pdata = 0;
795282408Scy
79654359Sroberto					parse->parse_plen = clockformats[i]->plen;
79754359Sroberto
79854359Sroberto					if (parse->parse_plen)
79954359Sroberto					{
80054359Sroberto						parse->parse_pdata = MALLOC(parse->parse_plen);
80154359Sroberto						if (!parse->parse_pdata)
80254359Sroberto						{
80354359Sroberto							parseprintf(DD_PARSE, ("set format failed: malloc for private data area failed\n"));
80454359Sroberto							return 0;
80554359Sroberto						}
80654359Sroberto						memset((char *)parse->parse_pdata, 0, parse->parse_plen);
80754359Sroberto					}
80854359Sroberto
80954359Sroberto					if (parse->parse_data)
81054359Sroberto						FREE(parse->parse_data, (unsigned)(parse->parse_dsize * 2 + 2));
81154359Sroberto					parse->parse_ldata = parse->parse_data = 0;
812282408Scy
81354359Sroberto					parse->parse_dsize = clockformats[i]->length;
814282408Scy
81554359Sroberto					if (parse->parse_dsize)
81654359Sroberto					{
81754359Sroberto						parse->parse_data = (char*)MALLOC((unsigned)(parse->parse_dsize * 2 + 2));
81854359Sroberto						if (!parse->parse_data)
81954359Sroberto						{
82054359Sroberto							if (parse->parse_pdata)
82154359Sroberto								FREE(parse->parse_pdata, parse->parse_plen);
82254359Sroberto							parse->parse_pdata = 0;
823282408Scy
82454359Sroberto							parseprintf(DD_PARSE, ("init failed: malloc for data area failed\n"));
82554359Sroberto							return 0;
82654359Sroberto						}
82754359Sroberto					}
82854359Sroberto
829282408Scy
83054359Sroberto					/*
83154359Sroberto					 * leave room for '\0'
83254359Sroberto					 */
83354359Sroberto					parse->parse_ldata     = parse->parse_data + parse->parse_dsize + 1;
834282408Scy
83554359Sroberto					parse->parse_lformat  = i;
836282408Scy
83754359Sroberto					return 1;
83854359Sroberto				}
83954359Sroberto			}
84054359Sroberto		}
84154359Sroberto	}
84254359Sroberto	return 0;
84354359Sroberto}
84454359Sroberto
84554359Sroberto/*ARGSUSED*/
84654359Srobertoint
84754359Srobertoparse_getfmt(
84854359Sroberto	parsectl_t *dct,
84954359Sroberto	parse_t    *parse
85054359Sroberto	)
85154359Sroberto{
85254359Sroberto	if (dct->parseformat.parse_format < nformats &&
85354359Sroberto	    Strlen(clockformats[dct->parseformat.parse_format]->name) <= PARSE_TCMAX)
85454359Sroberto	{
855282408Scy		dct->parseformat.parse_count = (unsigned short) (Strlen(clockformats[dct->parseformat.parse_format]->name) + 1);
85654359Sroberto		memcpy(dct->parseformat.parse_buffer, clockformats[dct->parseformat.parse_format]->name, dct->parseformat.parse_count);
85754359Sroberto		return 1;
85854359Sroberto	}
85954359Sroberto	else
86054359Sroberto	{
86154359Sroberto		return 0;
86254359Sroberto	}
86354359Sroberto}
86454359Sroberto
86554359Sroberto/*ARGSUSED*/
86654359Srobertoint
86754359Srobertoparse_setcs(
86854359Sroberto	parsectl_t *dct,
86954359Sroberto	parse_t    *parse
87054359Sroberto	)
87154359Sroberto{
87254359Sroberto	parse->parse_ioflags &= ~PARSE_IO_CSIZE;
873282408Scy	parse->parse_ioflags |= (int) (dct->parsesetcs.parse_cs & PARSE_IO_CSIZE);
87454359Sroberto	return 1;
87554359Sroberto}
87654359Sroberto
87754359Sroberto#else /* not (REFCLOCK && CLOCK_PARSE) */
87854359Srobertoint parse_bs;
87954359Sroberto#endif /* not (REFCLOCK && CLOCK_PARSE) */
88054359Sroberto
88154359Sroberto/*
88254359Sroberto * History:
88354359Sroberto *
88454359Sroberto * parse.c,v
885182007Sroberto * Revision 4.20  2005/08/06 17:39:40  kardel
886182007Sroberto * cleanup size handling wrt/ to buffer boundaries
887182007Sroberto *
888182007Sroberto * Revision 4.19  2005/04/16 17:32:10  kardel
889182007Sroberto * update copyright
890182007Sroberto *
891182007Sroberto * Revision 4.18  2004/11/14 16:11:05  kardel
892182007Sroberto * update Id tags
893182007Sroberto *
894182007Sroberto * Revision 4.17  2004/11/14 15:29:41  kardel
895182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style
896182007Sroberto *
89756746Sroberto * Revision 4.14  1999/11/28 09:13:52  kardel
89856746Sroberto * RECON_4_0_98F
89956746Sroberto *
90054359Sroberto * Revision 4.13  1999/02/28 11:50:20  kardel
90154359Sroberto * (timepacket): removed unecessary code
90254359Sroberto *
90354359Sroberto * Revision 4.12  1999/02/21 12:17:44  kardel
90454359Sroberto * 4.91f reconcilation
90554359Sroberto *
90654359Sroberto * Revision 4.11  1999/02/21 11:09:47  kardel
90754359Sroberto * unified debug output
90854359Sroberto *
90954359Sroberto * Revision 4.10  1998/12/20 23:45:30  kardel
91054359Sroberto * fix types and warnings
91154359Sroberto *
91254359Sroberto * Revision 4.9  1998/08/09 22:26:06  kardel
91354359Sroberto * Trimble TSIP support
91454359Sroberto *
91554359Sroberto * Revision 4.8  1998/06/14 21:09:39  kardel
91654359Sroberto * Sun acc cleanup
91754359Sroberto *
91854359Sroberto * Revision 4.7  1998/06/13 15:19:13  kardel
91954359Sroberto * fix mem*() to b*() function macro emulation
92054359Sroberto *
92154359Sroberto * Revision 4.6  1998/06/13 13:24:13  kardel
92254359Sroberto * printf fmt
92354359Sroberto *
92454359Sroberto * Revision 4.5  1998/06/13 13:01:10  kardel
92554359Sroberto * printf fmt
92654359Sroberto *
92754359Sroberto * Revision 4.4  1998/06/13 12:12:10  kardel
92854359Sroberto * bcopy/memcpy cleanup
92954359Sroberto * fix SVSV name clash
93054359Sroberto *
93154359Sroberto * Revision 4.3  1998/06/12 15:22:30  kardel
93254359Sroberto * fix prototypes
93354359Sroberto *
93454359Sroberto * Revision 4.2  1998/06/12 09:13:27  kardel
93554359Sroberto * conditional compile macros fixed
93654359Sroberto * printf prototype
93754359Sroberto *
93854359Sroberto * Revision 4.1  1998/05/24 09:39:55  kardel
93954359Sroberto * implementation of the new IO handling model
94054359Sroberto *
94154359Sroberto * Revision 4.0  1998/04/10 19:45:36  kardel
94254359Sroberto * Start 4.0 release version numbering
94354359Sroberto *
94454359Sroberto * from V3 3.46 log info deleted 1998/04/11 kardel
94554359Sroberto */
946