xref: /freebsd/contrib/ntp/libparse/parse.c (revision 8d20be1e22095c27faf8fe8b2f0d089739cc742e)
1 /*
2  * /src/NTP/ntp4-dev/libparse/parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A
3  *
4  * parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A
5  *
6  * Parser module for reference clock
7  *
8  * PARSEKERNEL define switches between two personalities of the module
9  * if PARSEKERNEL is defined this module can be used
10  * as kernel module. In this case the time stamps will be
11  * a struct timeval.
12  * when PARSEKERNEL is not defined NTP time stamps will be used.
13  *
14  * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
15  * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. Neither the name of the author nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  */
42 
43 #ifdef HAVE_CONFIG_H
44 # include <config.h>
45 #endif
46 
47 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
48 
49 #if	!(defined(lint) || defined(__GNUC__))
50 static char rcsid[] = "parse.c,v 4.20 2005/08/06 17:39:40 kardel RELEASE_20050806_A";
51 #endif
52 
53 #include "ntp_fp.h"
54 #include "ntp_unixtime.h"
55 #include "ntp_calendar.h"
56 #include "ntp_stdlib.h"
57 #include "ntp_machine.h"
58 #include "ntp.h"		/* (get Y2KFixes definitions) 	Y2KFixes */
59 
60 #include "parse.h"
61 
62 #ifndef PARSESTREAM
63 # include <stdio.h>
64 #else
65 # include "sys/parsestreams.h"
66 #endif
67 
68 extern clockformat_t *clockformats[];
69 extern unsigned short nformats;
70 
71 static u_long timepacket P((parse_t *));
72 
73 /*
74  * strings support usually not in kernel - duplicated, but what the heck
75  */
76 static int
77 Strlen(
78 	register const char *s
79 	)
80 {
81 	register int c;
82 
83 	c = 0;
84 	if (s)
85 	{
86 		while (*s++)
87 		{
88 			c++;
89 		}
90 	}
91 	return c;
92 }
93 
94 static int
95 Strcmp(
96 	register const char *s,
97 	register const char *t
98 	)
99 {
100 	register int c = 0;
101 
102 	if (!s || !t || (s == t))
103 	{
104 		return 0;
105 	}
106 
107 	while (!(c = *s++ - *t++) && *s && *t)
108 	    /* empty loop */;
109 
110 	return c;
111 }
112 
113 int
114 parse_timedout(
115 	       parse_t *parseio,
116 	       timestamp_t *tstamp,
117 	       struct timeval *del
118 	       )
119 {
120 	struct timeval delta;
121 
122 #ifdef PARSEKERNEL
123 	delta.tv_sec = tstamp->tv.tv_sec - parseio->parse_lastchar.tv.tv_sec;
124 	delta.tv_usec = tstamp->tv.tv_usec - parseio->parse_lastchar.tv.tv_usec;
125 	if (delta.tv_usec < 0)
126 	{
127 		delta.tv_sec  -= 1;
128 		delta.tv_usec += 1000000;
129 	}
130 #else
131 	extern long tstouslo[];
132 	extern long tstousmid[];
133 	extern long tstoushi[];
134 
135 	l_fp delt;
136 
137 	delt = tstamp->fp;
138 	L_SUB(&delt, &parseio->parse_lastchar.fp);
139 	TSTOTV(&delt, &delta);
140 #endif
141 
142 	if (timercmp(&delta, del, >))
143 	{
144 		parseprintf(DD_PARSE, ("parse: timedout: TRUE\n"));
145 		return 1;
146 	}
147 	else
148 	{
149 		parseprintf(DD_PARSE, ("parse: timedout: FALSE\n"));
150 		return 0;
151 	}
152 }
153 
154 /*ARGSUSED*/
155 int
156 parse_ioinit(
157 	register parse_t *parseio
158 	)
159 {
160 	parseprintf(DD_PARSE, ("parse_iostart\n"));
161 
162 	parseio->parse_plen = 0;
163 	parseio->parse_pdata = (void *)0;
164 
165 	parseio->parse_data = 0;
166 	parseio->parse_ldata = 0;
167 	parseio->parse_dsize = 0;
168 
169 	parseio->parse_badformat = 0;
170 	parseio->parse_ioflags   = PARSE_IO_CS7;	/* usual unix default */
171 	parseio->parse_index     = 0;
172 	parseio->parse_ldsize    = 0;
173 
174 	return 1;
175 }
176 
177 /*ARGSUSED*/
178 void
179 parse_ioend(
180 	register parse_t *parseio
181 	)
182 {
183 	parseprintf(DD_PARSE, ("parse_ioend\n"));
184 
185 	if (parseio->parse_pdata)
186 	    FREE(parseio->parse_pdata, parseio->parse_plen);
187 
188 	if (parseio->parse_data)
189 	    FREE(parseio->parse_data, (unsigned)(parseio->parse_dsize * 2 + 2));
190 }
191 
192 unsigned int
193 parse_restart(
194 	      parse_t *parseio,
195 	      unsigned int ch
196 	      )
197 {
198 	unsigned int updated = PARSE_INP_SKIP;
199 
200 	/*
201 	 * re-start packet - timeout - overflow - start symbol
202 	 */
203 
204 	if (parseio->parse_index)
205 	{
206 		/*
207 		 * filled buffer - thus not end character found
208 		 * do processing now
209 		 */
210 		parseio->parse_data[parseio->parse_index] = '\0';
211 		memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
212 		parseio->parse_ldsize = parseio->parse_index;
213 		updated = PARSE_INP_TIME;
214 	}
215 
216 	parseio->parse_index = 1;
217 	parseio->parse_data[0] = ch;
218 	parseprintf(DD_PARSE, ("parse: parse_restart: buffer start (updated = %x)\n", updated));
219 	return updated;
220 }
221 
222 unsigned int
223 parse_addchar(
224 	      parse_t *parseio,
225 	      unsigned int ch
226 	      )
227 {
228 	/*
229 	 * add to buffer
230 	 */
231 	if (parseio->parse_index < parseio->parse_dsize)
232 	{
233 		/*
234 		 * collect into buffer
235 		 */
236 		parseprintf(DD_PARSE, ("parse: parse_addchar: buffer[%d] = 0x%x\n", parseio->parse_index, ch));
237 		parseio->parse_data[parseio->parse_index++] = ch;
238 		return PARSE_INP_SKIP;
239 	}
240 	else
241 		/*
242 		 * buffer overflow - attempt to make the best of it
243 		 */
244 		return parse_restart(parseio, ch);
245 }
246 
247 unsigned int
248 parse_end(
249 	  parse_t *parseio
250 	  )
251 {
252 	/*
253 	 * message complete processing
254 	 */
255 	parseio->parse_data[parseio->parse_index] = '\0';
256 	memcpy(parseio->parse_ldata, parseio->parse_data, (unsigned)(parseio->parse_index+1));
257 	parseio->parse_ldsize = parseio->parse_index;
258 	parseio->parse_index = 0;
259 	parseprintf(DD_PARSE, ("parse: parse_end: buffer end\n"));
260 	return PARSE_INP_TIME;
261 }
262 
263 /*ARGSUSED*/
264 int
265 parse_ioread(
266 	register parse_t *parseio,
267 	register unsigned int ch,
268 	register timestamp_t *tstamp
269 	)
270 {
271 	register unsigned updated = CVT_NONE;
272 	/*
273 	 * within STREAMS CSx (x < 8) chars still have the upper bits set
274 	 * so we normalize the characters by masking unecessary bits off.
275 	 */
276 	switch (parseio->parse_ioflags & PARSE_IO_CSIZE)
277 	{
278 	    case PARSE_IO_CS5:
279 		ch &= 0x1F;
280 		break;
281 
282 	    case PARSE_IO_CS6:
283 		ch &= 0x3F;
284 		break;
285 
286 	    case PARSE_IO_CS7:
287 		ch &= 0x7F;
288 		break;
289 
290 	    case PARSE_IO_CS8:
291 		ch &= 0xFF;
292 		break;
293 	}
294 
295 	parseprintf(DD_PARSE, ("parse_ioread(0x%lx, char=0x%x, ..., ...)\n", (unsigned long)parseio, ch & 0xFF));
296 
297 	if (!clockformats[parseio->parse_lformat]->convert)
298 	{
299 		parseprintf(DD_PARSE, ("parse_ioread: input dropped.\n"));
300 		return CVT_NONE;
301 	}
302 
303 	if (clockformats[parseio->parse_lformat]->input)
304 	{
305 		unsigned long input_status;
306 
307 		input_status = clockformats[parseio->parse_lformat]->input(parseio, ch, tstamp);
308 
309 		if (input_status & PARSE_INP_SYNTH)
310 		{
311 			updated = CVT_OK;
312 		}
313 
314 		if (input_status & PARSE_INP_TIME)	/* time sample is available */
315 		{
316 			updated = timepacket(parseio);
317 		}
318 
319 		if (input_status & PARSE_INP_DATA) /* got additional data */
320 		{
321 			updated |= CVT_ADDITIONAL;
322 		}
323 	}
324 
325 
326 	/*
327 	 * remember last character time
328 	 */
329 	parseio->parse_lastchar = *tstamp;
330 
331 #ifdef DEBUG
332 	if ((updated & CVT_MASK) != CVT_NONE)
333 	{
334 		parseprintf(DD_PARSE, ("parse_ioread: time sample accumulated (status=0x%x)\n", updated));
335 	}
336 #endif
337 
338 	parseio->parse_dtime.parse_status = updated;
339 
340 	return (((updated & CVT_MASK) != CVT_NONE) ||
341 		((updated & CVT_ADDITIONAL) != 0));
342 }
343 
344 /*
345  * parse_iopps
346  *
347  * take status line indication and derive synchronisation information
348  * from it.
349  * It can also be used to decode a serial serial data format (such as the
350  * ONE, ZERO, MINUTE sync data stream from DCF77)
351  */
352 /*ARGSUSED*/
353 int
354 parse_iopps(
355 	register parse_t *parseio,
356 	register int status,
357 	register timestamp_t *ptime
358 	)
359 {
360 	register unsigned updated = CVT_NONE;
361 
362 	/*
363 	 * PPS pulse information will only be delivered to ONE clock format
364 	 * this is either the last successful conversion module with a ppssync
365 	 * routine, or a fixed format with a ppssync routine
366 	 */
367 	parseprintf(DD_PARSE, ("parse_iopps: STATUS %s\n", (status == SYNC_ONE) ? "ONE" : "ZERO"));
368 
369 	if (clockformats[parseio->parse_lformat]->syncpps)
370 	{
371 		updated = clockformats[parseio->parse_lformat]->syncpps(parseio, status == SYNC_ONE, ptime);
372 		parseprintf(DD_PARSE, ("parse_iopps: updated = 0x%x\n", updated));
373 	}
374 
375 	return (updated & CVT_MASK) != CVT_NONE;
376 }
377 
378 /*
379  * parse_iodone
380  *
381  * clean up internal status for new round
382  */
383 /*ARGSUSED*/
384 void
385 parse_iodone(
386 	register parse_t *parseio
387 	)
388 {
389 	/*
390 	 * we need to clean up certain flags for the next round
391 	 */
392 	parseprintf(DD_PARSE, ("parse_iodone: DONE\n"));
393 	parseio->parse_dtime.parse_state = 0; /* no problems with ISRs */
394 }
395 
396 /*---------- conversion implementation --------------------*/
397 
398 /*
399  * convert a struct clock to UTC since Jan, 1st 1970 0:00 (the UNIX EPOCH)
400  */
401 #define days_per_year(x)	((x) % 4 ? 365 : ((x % 400) ? ((x % 100) ? 366 : 365) : 366))
402 
403 time_t
404 parse_to_unixtime(
405 	register clocktime_t   *clock_time,
406 	register u_long *cvtrtc
407 	)
408 {
409 #define SETRTC(_X_)	{ if (cvtrtc) *cvtrtc = (_X_); }
410 	static int days_of_month[] =
411 	{
412 		0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
413 	};
414 	register int i;
415 	time_t t;
416 
417 	if (clock_time->utctime)
418 	    return clock_time->utctime;	/* if the conversion routine gets it right away - why not */
419 
420 	if ( clock_time->year < YEAR_PIVOT )			/* Y2KFixes [ */
421 	    clock_time->year += 100;	/* convert 20xx%100 to 20xx-1900 */
422 	if ( clock_time->year < YEAR_BREAK )	/* expand to full four-digits */
423 	    clock_time->year += 1900;
424 
425 	if (clock_time->year < 1970 )				/* Y2KFixes ] */
426 	{
427 		SETRTC(CVT_FAIL|CVT_BADDATE);
428 		return -1;
429 	}
430 
431 	/*
432 	 * sorry, slow section here - but it's not time critical anyway
433 	 */
434 	t = julian0(clock_time->year) - julian0(1970);		/* Y2kFixes */
435   				/* month */
436 	if (clock_time->month <= 0 || clock_time->month > 12)
437 	{
438 		SETRTC(CVT_FAIL|CVT_BADDATE);
439 		return -1;		/* bad month */
440 	}
441 
442 #if 0								/* Y2KFixes */
443 				/* adjust leap year */
444 	if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
445 	    t--;
446 #else								/* Y2KFixes [ */
447 	if ( clock_time->month >= 3  &&  isleap_4(clock_time->year) )
448 	    t++;		/* add one more if within leap year */
449 #endif								/* Y2KFixes ] */
450 
451 	for (i = 1; i < clock_time->month; i++)
452 	{
453 		t += days_of_month[i];
454 	}
455 				/* day */
456 	if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ?
457 			       clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month]))
458 	{
459 		SETRTC(CVT_FAIL|CVT_BADDATE);
460 		return -1;		/* bad day */
461 	}
462 
463 	t += clock_time->day - 1;
464 				/* hour */
465 	if (clock_time->hour < 0 || clock_time->hour >= 24)
466 	{
467 		SETRTC(CVT_FAIL|CVT_BADTIME);
468 		return -1;		/* bad hour */
469 	}
470 
471 	t = TIMES24(t) + clock_time->hour;
472 
473   				/* min */
474 	if (clock_time->minute < 0 || clock_time->minute > 59)
475 	{
476 		SETRTC(CVT_FAIL|CVT_BADTIME);
477 		return -1;		/* bad min */
478 	}
479 
480 	t = TIMES60(t) + clock_time->minute;
481 				/* sec */
482 
483 	if (clock_time->second < 0 || clock_time->second > 60)	/* allow for LEAPs */
484 	{
485 		SETRTC(CVT_FAIL|CVT_BADTIME);
486 		return -1;		/* bad sec */
487 	}
488 
489 	t  = TIMES60(t) + clock_time->second;
490 
491 	t += clock_time->utcoffset;	/* warp to UTC */
492 
493 				/* done */
494 
495 	clock_time->utctime = t;		/* documentray only */
496 
497 	return t;
498 }
499 
500 /*--------------- format conversion -----------------------------------*/
501 
502 int
503 Stoi(
504 	const unsigned char *s,
505 	long *zp,
506 	int cnt
507 	)
508 {
509 	char unsigned const *b = s;
510 	int f,z,v;
511 	char unsigned c;
512 
513 	f=z=v=0;
514 
515 	while(*s == ' ')
516 	    s++;
517 
518 	if (*s == '-')
519 	{
520 		s++;
521 		v = 1;
522 	}
523 	else
524 	    if (*s == '+')
525 		s++;
526 
527 	for(;;)
528 	{
529 		c = *s++;
530 		if (c == '\0' || c < '0' || c > '9' || (cnt && ((s-b) > cnt)))
531 		{
532 			if (f == 0)
533 			{
534 				return(-1);
535 			}
536 			if (v)
537 			    z = -z;
538 			*zp = z;
539 			return(0);
540 		}
541 		z = (z << 3) + (z << 1) + ( c - '0' );
542 		f=1;
543 	}
544 }
545 
546 int
547 Strok(
548 	const unsigned char *s,
549 	const unsigned char *m
550 	)
551 {
552 	if (!s || !m)
553 	    return 0;
554 
555 	while(*s && *m)
556 	{
557 		if ((*m == ' ') ? 1 : (*s == *m))
558 		{
559 			s++;
560 			m++;
561 		}
562 		else
563 		{
564 			return 0;
565 		}
566 	}
567 	return !*m;
568 }
569 
570 u_long
571 updatetimeinfo(
572 	       register parse_t *parseio,
573 	       register u_long   flags
574 	       )
575 {
576 #ifdef PARSEKERNEL
577 	{
578 		int s = splhigh();
579 #endif
580 
581 		parseio->parse_lstate          = parseio->parse_dtime.parse_state | flags | PARSEB_TIMECODE;
582 
583 		parseio->parse_dtime.parse_state = parseio->parse_lstate;
584 
585 #ifdef PARSEKERNEL
586 		(void)splx((unsigned int)s);
587 	}
588 #endif
589 
590 
591 #ifdef PARSEKERNEL
592 	parseprintf(DD_PARSE, ("updatetimeinfo status=0x%x, time=%x\n", parseio->parse_dtime.parse_state,
593 			       parseio->parse_dtime.parse_time.tv.tv_sec));
594 #else
595 	parseprintf(DD_PARSE, ("updatetimeinfo status=0x%lx, time=%x\n", (long)parseio->parse_dtime.parse_state,
596 	                       parseio->parse_dtime.parse_time.fp.l_ui));
597 #endif
598 
599 	return CVT_OK;		/* everything fine and dandy... */
600 }
601 
602 
603 /*
604  * syn_simple
605  *
606  * handle a sync time stamp
607  */
608 /*ARGSUSED*/
609 void
610 syn_simple(
611 	register parse_t *parseio,
612 	register timestamp_t *ts,
613 	register struct format *format,
614 	register u_long why
615 	)
616 {
617 	parseio->parse_dtime.parse_stime = *ts;
618 }
619 
620 /*
621  * pps_simple
622  *
623  * handle a pps time stamp
624  */
625 /*ARGSUSED*/
626 u_long
627 pps_simple(
628 	register parse_t *parseio,
629 	register int status,
630 	register timestamp_t *ptime
631 	)
632 {
633 	parseio->parse_dtime.parse_ptime  = *ptime;
634 	parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
635 
636 	return CVT_NONE;
637 }
638 
639 /*
640  * pps_one
641  *
642  * handle a pps time stamp in ONE edge
643  */
644 /*ARGSUSED*/
645 u_long
646 pps_one(
647 	register parse_t *parseio,
648 	register int status,
649 	register timestamp_t *ptime
650 	)
651 {
652 	if (status)
653 		return pps_simple(parseio, status, ptime);
654 
655 	return CVT_NONE;
656 }
657 
658 /*
659  * pps_zero
660  *
661  * handle a pps time stamp in ZERO edge
662  */
663 /*ARGSUSED*/
664 u_long
665 pps_zero(
666 	register parse_t *parseio,
667 	register int status,
668 	register timestamp_t *ptime
669 	)
670 {
671 	if (!status)
672 		return pps_simple(parseio, status, ptime);
673 
674 	return CVT_NONE;
675 }
676 
677 /*
678  * timepacket
679  *
680  * process a data packet
681  */
682 static u_long
683 timepacket(
684 	register parse_t *parseio
685 	)
686 {
687 	register unsigned short format;
688 	register time_t t;
689 	u_long cvtrtc;		/* current conversion result */
690 	clocktime_t clock_time;
691 
692 	memset((char *)&clock_time, 0, sizeof clock_time);
693 	format = parseio->parse_lformat;
694 
695 	if (format == (unsigned short)~0)
696 		return CVT_NONE;
697 
698 	switch ((cvtrtc = clockformats[format]->convert ?
699 		 clockformats[format]->convert((unsigned char *)parseio->parse_ldata, parseio->parse_ldsize, (struct format *)(clockformats[format]->data), &clock_time, parseio->parse_pdata) :
700 		 CVT_NONE) & CVT_MASK)
701 	{
702 	case CVT_FAIL:
703 		parseio->parse_badformat++;
704 		break;
705 
706 	case CVT_NONE:
707 		/*
708 		 * too bad - pretend bad format
709 		 */
710 		parseio->parse_badformat++;
711 		break;
712 
713 	case CVT_OK:
714 		break;
715 
716 	case CVT_SKIP:
717 		return CVT_NONE;
718 
719 	default:
720 		/* shouldn't happen */
721 #ifndef PARSEKERNEL
722 		msyslog(LOG_WARNING, "parse: INTERNAL error: bad return code of convert routine \"%s\"\n", clockformats[format]->name);
723 #endif
724 		return CVT_FAIL|cvtrtc;
725 	}
726 
727 	if ((t = parse_to_unixtime(&clock_time, &cvtrtc)) == -1)
728 	{
729 		return CVT_FAIL|cvtrtc;
730 	}
731 
732 	/*
733 	 * time stamp
734 	 */
735 #ifdef PARSEKERNEL
736 	parseio->parse_dtime.parse_time.tv.tv_sec  = t;
737 	parseio->parse_dtime.parse_time.tv.tv_usec = clock_time.usecond;
738 #else
739 	parseio->parse_dtime.parse_time.fp.l_ui = t + JAN_1970;
740 	TVUTOTSF(clock_time.usecond, parseio->parse_dtime.parse_time.fp.l_uf);
741 #endif
742 
743 	parseio->parse_dtime.parse_format       = format;
744 
745 	return updatetimeinfo(parseio, clock_time.flags);
746 }
747 
748 /*ARGSUSED*/
749 int
750 parse_timecode(
751 	parsectl_t *dct,
752 	parse_t    *parse
753 	)
754 {
755 	dct->parsegettc.parse_state  = parse->parse_lstate;
756 	dct->parsegettc.parse_format = parse->parse_lformat;
757 	/*
758 	 * move out current bad packet count
759 	 * user program is expected to sum these up
760 	 * this is not a problem, as "parse" module are
761 	 * exclusive open only
762 	 */
763 	dct->parsegettc.parse_badformat = parse->parse_badformat;
764 	parse->parse_badformat = 0;
765 
766 	if (parse->parse_ldsize <= PARSE_TCMAX)
767 	{
768 		dct->parsegettc.parse_count = parse->parse_ldsize;
769 		memcpy(dct->parsegettc.parse_buffer, parse->parse_ldata, dct->parsegettc.parse_count);
770 		return 1;
771 	}
772 	else
773 	{
774 		return 0;
775 	}
776 }
777 
778 
779 /*ARGSUSED*/
780 int
781 parse_setfmt(
782 	parsectl_t *dct,
783 	parse_t    *parse
784 	)
785 {
786 	if (dct->parseformat.parse_count <= PARSE_TCMAX)
787 	{
788 		if (dct->parseformat.parse_count)
789 		{
790 			register unsigned short i;
791 
792 			for (i = 0; i < nformats; i++)
793 			{
794 				if (!Strcmp(dct->parseformat.parse_buffer, clockformats[i]->name))
795 				{
796 					if (parse->parse_pdata)
797 						FREE(parse->parse_pdata, parse->parse_plen);
798 					parse->parse_pdata = 0;
799 
800 					parse->parse_plen = clockformats[i]->plen;
801 
802 					if (parse->parse_plen)
803 					{
804 						parse->parse_pdata = MALLOC(parse->parse_plen);
805 						if (!parse->parse_pdata)
806 						{
807 							parseprintf(DD_PARSE, ("set format failed: malloc for private data area failed\n"));
808 							return 0;
809 						}
810 						memset((char *)parse->parse_pdata, 0, parse->parse_plen);
811 					}
812 
813 					if (parse->parse_data)
814 						FREE(parse->parse_data, (unsigned)(parse->parse_dsize * 2 + 2));
815 					parse->parse_ldata = parse->parse_data = 0;
816 
817 					parse->parse_dsize = clockformats[i]->length;
818 
819 					if (parse->parse_dsize)
820 					{
821 						parse->parse_data = (char*)MALLOC((unsigned)(parse->parse_dsize * 2 + 2));
822 						if (!parse->parse_data)
823 						{
824 							if (parse->parse_pdata)
825 								FREE(parse->parse_pdata, parse->parse_plen);
826 							parse->parse_pdata = 0;
827 
828 							parseprintf(DD_PARSE, ("init failed: malloc for data area failed\n"));
829 							return 0;
830 						}
831 					}
832 
833 
834 					/*
835 					 * leave room for '\0'
836 					 */
837 					parse->parse_ldata     = parse->parse_data + parse->parse_dsize + 1;
838 
839 					parse->parse_lformat  = i;
840 
841 					return 1;
842 				}
843 			}
844 		}
845 	}
846 	return 0;
847 }
848 
849 /*ARGSUSED*/
850 int
851 parse_getfmt(
852 	parsectl_t *dct,
853 	parse_t    *parse
854 	)
855 {
856 	if (dct->parseformat.parse_format < nformats &&
857 	    Strlen(clockformats[dct->parseformat.parse_format]->name) <= PARSE_TCMAX)
858 	{
859 		dct->parseformat.parse_count = Strlen(clockformats[dct->parseformat.parse_format]->name)+1;
860 		memcpy(dct->parseformat.parse_buffer, clockformats[dct->parseformat.parse_format]->name, dct->parseformat.parse_count);
861 		return 1;
862 	}
863 	else
864 	{
865 		return 0;
866 	}
867 }
868 
869 /*ARGSUSED*/
870 int
871 parse_setcs(
872 	parsectl_t *dct,
873 	parse_t    *parse
874 	)
875 {
876 	parse->parse_ioflags &= ~PARSE_IO_CSIZE;
877 	parse->parse_ioflags |= dct->parsesetcs.parse_cs & PARSE_IO_CSIZE;
878 	return 1;
879 }
880 
881 #else /* not (REFCLOCK && CLOCK_PARSE) */
882 int parse_bs;
883 #endif /* not (REFCLOCK && CLOCK_PARSE) */
884 
885 /*
886  * History:
887  *
888  * parse.c,v
889  * Revision 4.20  2005/08/06 17:39:40  kardel
890  * cleanup size handling wrt/ to buffer boundaries
891  *
892  * Revision 4.19  2005/04/16 17:32:10  kardel
893  * update copyright
894  *
895  * Revision 4.18  2004/11/14 16:11:05  kardel
896  * update Id tags
897  *
898  * Revision 4.17  2004/11/14 15:29:41  kardel
899  * support PPSAPI, upgrade Copyright to Berkeley style
900  *
901  * Revision 4.14  1999/11/28 09:13:52  kardel
902  * RECON_4_0_98F
903  *
904  * Revision 4.13  1999/02/28 11:50:20  kardel
905  * (timepacket): removed unecessary code
906  *
907  * Revision 4.12  1999/02/21 12:17:44  kardel
908  * 4.91f reconcilation
909  *
910  * Revision 4.11  1999/02/21 11:09:47  kardel
911  * unified debug output
912  *
913  * Revision 4.10  1998/12/20 23:45:30  kardel
914  * fix types and warnings
915  *
916  * Revision 4.9  1998/08/09 22:26:06  kardel
917  * Trimble TSIP support
918  *
919  * Revision 4.8  1998/06/14 21:09:39  kardel
920  * Sun acc cleanup
921  *
922  * Revision 4.7  1998/06/13 15:19:13  kardel
923  * fix mem*() to b*() function macro emulation
924  *
925  * Revision 4.6  1998/06/13 13:24:13  kardel
926  * printf fmt
927  *
928  * Revision 4.5  1998/06/13 13:01:10  kardel
929  * printf fmt
930  *
931  * Revision 4.4  1998/06/13 12:12:10  kardel
932  * bcopy/memcpy cleanup
933  * fix SVSV name clash
934  *
935  * Revision 4.3  1998/06/12 15:22:30  kardel
936  * fix prototypes
937  *
938  * Revision 4.2  1998/06/12 09:13:27  kardel
939  * conditional compile macros fixed
940  * printf prototype
941  *
942  * Revision 4.1  1998/05/24 09:39:55  kardel
943  * implementation of the new IO handling model
944  *
945  * Revision 4.0  1998/04/10 19:45:36  kardel
946  * Start 4.0 release version numbering
947  *
948  * from V3 3.46 log info deleted 1998/04/11 kardel
949  */
950