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