mem@sii.UUCP (Mark Mallett) (06/22/85)
<-> CMD003 TOPS20 style parsing Part 6 of 6 This is the 6th of 6 pieces of COMND, a TOPS-20 style parsing library for CP/M (and other) systems, edit level 003. Its contents are suitable for unpacking by the standard "sh" shell. Remove this header, and any trailer added by the news/mail system, and run the rest through the shell like this: sh part6 and you will get the following files: cmdpfd.c Date/Time function parsing. cmdpsd.c Date/Time function stub. cmdoss.cpm O/S specific routines for CP/M. date.cpm Date/Time O/S specific routines for CP/M 3.0 (CPM+). If you are unwilling to unpack it on a unix system, it should be fairly simple to write a program to unpack it somewhere else. **** End of Header, remove to here+1 **** echo "unpacking file cmdpfd.c" cat <<'EEOOFF' >cmdpfd.c /* cmdpfd.c COMND module; Date/time function parse. Copyright (C) 1985 Mark E. Mallett Permission is hereby granted to distribute this file indiscriminately. This file contains the code for the date/time parsing function. Edit history When Who What ------ --- -------------------------------- 84xxxx MEM Create file. Routines included: CFPdat Parse date and/or time */ #include "stdio.h" /* Standard system defs */ #include "comnd.h" /* COMND interface definitions */ #include "comndi.h" /* COMND internal definitions */ typedef /* Structure for "special" dates */ struct { int _mo; /* Month (1 - 12) */ int _da; /* Day of month (1 - 31) */ } SMD; /* External routines */ /* External data */ extern int CMDbel; /* Beep request flag */ /* Internal (public) routines */ /* Internal (public) data */ /* Local (static) data */ /* Tables for date and time parsing. */ static char *Mnmtbl[] = { /* Month names */ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL}; static char *Snmtbl[] = { /* Table of special names */ "April-Fools-Day", "Christmas", "Erics-Birthday", "Fourth-of-July", "Halloween", "New-Years-Day", "Valentines-day", NULL }; static SMD Sndtbl[] = { /* month/day for special names */ 4, 1, /* April fools */ 12, 25, /* Christmas */ 8, 19, /* Eric's birthday */ 7, 4, /* Fourth of July */ 10, 31, /* Halloween */ 1, 1, /* New Year's Day */ 2, 14, /* Valentine's day */ 0, 0}; /* end */ static char *Dowtbl[] = { /* Day-of-week table */ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL }; static char *Todtbl[] = { /* Time-of-day table */ "noon", NULL }; static CFB Timcfb = {_CMNUM, _CFHPP|_CFSDH, 0, 10, "Time in the form hh:mm:ss", 0}; static CFB Todcfb = {_CMKEY, _CFHPP, &Timcfb, &Todtbl, "Time of day, ", 0}; static CFB Plscfb = {_CMTOK, _CFHPP|_CFSDH, 0, "+", "+ for future offset from now", 0}; static CFB Mincfb = {_CMTOK, _CFHPP|_CFSDH, &Plscfb, "-", "- for past offset from now", 0}; static CFB Adncfb = {_CMNUM, _CFHPP|_CFSDH, &Mincfb, 10, "Decimal month number", 0}; static CFB Dowcfb = {_CMKEY, _CFHPP, &Adncfb, &Dowtbl, "Day of week, ", 0}; static CFB Snmcfb = {_CMKEY, _CFHPP, &Dowcfb, &Snmtbl, "Special date, ", 0}; static CFB Mnmcfb = {_CMKEY, _CFHPP, &Snmcfb, &Mnmtbl, "Month name, ", 0}; static CFB Clncfb = {_CMTOK, 0, 0, ":", 0, 0}; static CFB Cmycfb = {_CMTOK, _CFHPP|_CFSDH, 0, ",", "Comma and year", 0}; static CFB Domcfb = {_CMNUM, _CFHPP|_CFSDH, 0, 10, "Day of month", 0}; static CFB Yrcfb = {_CMNUM, _CFHPP|_CFSDH, 0, 10, "Year", 0}; /* *//* CFPdat (CSBptr, CFBptr, ccptr) Function parse for type=_CMDAT, date and/or time This function parses a date and/or time. It does this by calling COMND recursively, with special date/time parsing function blocks. Accepts : CSBptr Address of command state block CFBptr Address of command function block ccptr Address of CC table (N/A here) Returns : <value> Parse status, _CPxxx as defined in comndi.h. */ CFPdat (CSBptr, CFBptr, ccptr) CSB *CSBptr; /* Addr of command state block */ CFB *CFBptr; /* Addr of command function block */ WORD *ccptr; /* Addr of CC table */ { IND int i,j,t; /* Scratch */ IND int id,it; /* Internal date and time */ IND int *rslptr; /* Result pointer */ rslptr = CSBptr -> CSB_ABF; /* Get pointer to result buffer */ curdtm (&id, &it); /* Get today's date/time */ if (CFBptr -> CFB_FLG & _CFDTD) /* If date wanted */ { i = CFPdtd (CSBptr, CFBptr); /* Try for date */ if (!CFBptr -> CFB_FLG & _CFDTT) /* If time not wanted */ return (i); /* Just return the result */ switch (i) /* Go by parse result of date */ { case _CPABT: /* If abort... */ return (_CPABT); /* return abort code */ case _CPSUCC: /* Success(!) */ id = rslptr[0]; /* Remember date */ j = COMND (CSBptr, &Clncfb); /* Try for colon for time */ if (j == _CRNOP) /* If not parsed */ { rslptr[0] = id; /* Put date back */ rslptr[1] = it; /* Use current time */ return (_CPSUCC); /* Return ok */ } else if (j != _CROK) /* If not OK */ return (_CPABT); /* stop now */ break; /* Continue with getting time! */ case _CPAGN: /* Try again later.. */ case _CPGVH: /* Gave help */ case _CPNOP: /* Could not parse.. */ rslptr[0] = id; /* Store current date */ break; /* Quit and continue */ } } /* Try for time, if wanted */ if (!(CFBptr -> CFB_FLG & _CFDTT)) /* If time not wanted */ return (i); /* return result of date parse */ id = rslptr[0]; /* Remember date */ t = CFPdtt(CSBptr, CFBptr); /* Try to parse time */ rslptr[0] = id; /* Pass back date, if any */ if (!(CFBptr -> CFB_FLG & _CFDTD)) /* If we did not parse a date */ return (t); /* return result of time attempt. */ if (i == _CPGVH) /* If date gave help */ return (_CPGVH); /* then we HAVE to return that code */ return (t); /* Otherwise return what time said. */ } /* *//* CFBdtd (CSBptr, CFBptr) Parse date portion of date/time This function parses a date. It does this by calling COMND recursively. Accepts : CSBptr Address of command state block CFBptr Address of command function block Returns : <value> Parse status, _CPxxx as defined in comndi.h. */ CFPdtd (CSBptr, CFBptr) CSB *CSBptr; /* Addr of command state block */ CFB *CFBptr; /* Addr of command function block */ { IND CFB *CFBmat; /* Matching CFB address */ IND int m,d,y,id,it; /* Date values */ IND int *rslptr; /* Result pointer */ IND char **kptr; /* Keyword ptr ptr */ IND int i; /* Scratch */ IND int prem; /* Remembers parse point */ prem = CSBptr -> CSB_PRS; /* Remember the current parse point */ rslptr = CSBptr -> CSB_ABF; /* Point to result area */ i = COMNDr (CSBptr, &Mnmcfb, 1); /* Try parsing the date. */ if ((i != _CPSUCC) && (i != _CPCPE)) /* If not successful parse */ return (i); /* then return whatever it was */ CFBmat = CSBptr -> CSB_CFB; /* Get addr of matching CFB */ if (CFBmat == &Plscfb) /* Plus date/time */ { fprintf (stderr, "Relative date/time not supported\n"); return (_CPABT); } else if (CFBmat == &Mincfb) /* Minus date/time */ { fprintf (stderr, "Relative date/time not supported\n"); return (_CPABT); } else if ((CFBmat == &Mnmcfb) || (CFBmat == &Snmcfb)) /* Month or special date in year */ { kptr = (char **) (CSBptr -> CSB_RVL._ADR); /* Get the table entry address */ if (CFBmat == &Mnmcfb) { m = (kptr - &Mnmtbl[0]) +1; /* Get month number */ /* Get day of month */ i = COMNDr (CSBptr, &Domcfb, 2); /* Try for day of month */ if ((i != _CPSUCC) && (i != _CPCPE)) /* Check not success */ { CSBptr -> CSB_PRS = prem; /* Reset parse pointer */ return (i); /* return */ } d = CSBptr -> CSB_RVL._INT; /* Get day of month */ } else /* Special... */ { i = (kptr - &Snmtbl[0]); /* Get index */ m = Sndtbl[i]._mo; /* Get month */ d = Sndtbl[i]._da; /* and day */ } i = COMNDr (CSBptr, &Cmycfb, 2); /* Try for comma and year */ if ((i != _CPSUCC) && (i != _CPCPE)) /* Check not success */ { CSBptr -> CSB_PRS = prem; /* Reset parse pointer */ return (i); } i = COMNDr (CSBptr, &Yrcfb, 2); /* Now try for year */ if ((i != _CPSUCC) && (i != _CPCPE)) /* Check not success */ { CSBptr -> CSB_PRS = prem; /* Reset parse pointer */ return (i); } y = CSBptr -> CSB_RVL._INT; /* Get year */ i = cvedid (rslptr, &it, m, d, y, 0, 0); if (i != 0) { fprintf (stderr, "Bad component in date: %d\n", i); fprintf (stderr, "Inputs were %d/%d/%d\n", m, d, y); return (_CPNOP); /* Bad parse */ } return (_CPSUCC); /* Got it. */ } else return (_CPNOP); /* Nope. */ } /* *//* CFBdtt (CSBptr, CFBptr) Parse time portion of date/time This function parses a time. It does this by calling COMND recursively. Accepts : CSBptr Address of command state block CFBptr Address of command function block Returns : <value> Parse status, _CPxxx as defined in comndi.h. */ CFPdtt (CSBptr, CFBptr) CSB *CSBptr; /* Addr of command state block */ CFB *CFBptr; /* Addr of command function block */ { IND int i; /* Scratch */ i = COMNDr (CSBptr, &Todcfb, 2); /* Try parsing the time */ return (i); /* Return now. */ } EEOOFF echo "unpacking file cmdpsd.c" cat <<'EEOOFF' >cmdpsd.c /* cmdpsd.c COMND module; Stub for date/time function parse. Copyright (C) 1985 Mark E. Mallett Permission is hereby granted to distribute this file indiscriminately. This file is a stub for the date/time parsing function, and is to be included in the link when date/time functions are not used (in order to save memory on small machines like mine). Edit history When Who What ------ --- -------------------------------- 850527 MEM Create file. Routines included: CFPdat Parse date and/or time CMDpsd fake routine to drag in this module. */ #include "stdio.h" /* Standard system defs */ #include "comnd.h" /* COMND interface definitions */ #include "comndi.h" /* COMND internal definitions */ /* External routines */ /* External data */ /* Internal (public) routines */ /* Internal (public) data */ /* Local (static) data */ /* *//* CMDpsd() Parse stub for date/time If the COMND files are stored in an object library (for the linker), you can put this module first and call this routine directly in order to drag in this module and satisfy the references with the stub(s) in this routine. Or you can keep this module separate and link it in before referencing the library. */ CMDpsd() {} /* *//* CFPdat (CSBptr, CFBptr, ccptr) Function parse for type=_CMDAT, date and/or time This is a stub for the _CMDAT function processor. It will indicate an invalid function call. Accepts : CSBptr Address of command state block CFBptr Address of command function block ccptr Address of CC table (N/A here) Returns : <value> Parse status of _CPABT. */ CFPdat (CSBptr, CFBptr, ccptr) CSB *CSBptr; /* Addr of command state block */ CFB *CFBptr; /* Addr of command function block */ WORD *ccptr; /* Addr of CC table */ { CSBptr -> CSB_RCD = _CRIFC; /* Set invalid function code */ return (_CPABT); /* Abort, right now */ } EEOOFF echo "unpacking file cmdoss.cpm" cat <<'EEOOFF' >cmdoss.cpm /* cmdoss.cpm COMND module; OS-specific routines for CP/M-80 Copyright (C) 1985 Mark E. Mallett Permission is hereby granted to distribute this file indiscriminately. Edit history When Who What ------ --- -------------------------------- 84xxxx MEM Create file. Routines included are: CMDfob Flush terminal output buffer. CMDgtc Get character from terminal without echo CMDptc Output character to terminal (buffered) CMDpzs Put NUL-terminated string to terminal */ #include "stdio.h" /* Standard system defs */ #include "mem.h" /* Include my standard names */ /* External routines */ /* External data */ /* Internal (public) routines */ /* Internal (public) data */ /* Local (static) data */ BYTE Coline[201] = {0}; /* Output line */ int Colpos = {0}; /* Position in output line */ /* *//* CMDgtc() Get terminal input character, no echo. */ CMDgtc() { IND int c; while ((c = CPM(6,0xffff)&0xff) == 0) ; return (c&0x7f); } /* *//* CMDpzs (sptr) Output a zero-terminated string to the console. Inputs sptr Address of the zero-terminated string Outputs The string (buffered) out to the terminal. Notes CMDfob() can be called to flush the output. */ CMDpzs (sptr) BYTE *sptr; /* Address of string to output */ { while (*sptr != NUL) /* Until end.. */ CMDpoc (*sptr++); /* Output. */ } /* *//* CMDptc(c) Output c to the terminal, buffered. */ CMDptc(c) { Coline[Colpos++] = c; /* Store char */ if ((c == '\n') || (Colpos == 200)) /* If read to break */ CMDfob(); /* break */ } /* *//* CMDfob() Break console output. */ CMDfob() { if (Colpos) { write (fileno(stdout),Coline,Colpos); /* Write the line */ Colpos = 0; /* Reset pointer */ } } EEOOFF echo "unpacking file date.cpm" cat <<'EEOOFF' >date.cpm /* date.cpm Date/Time support for CP/M-80 v 3.0 Copyright (C) 1985 Mark E. Mallett Permission is hereby granted to distribute this file indiscriminately. Edit history When Who What ------ --- -------------------------------- 84xxxx MEM Create file. Included are curdtm Get current date/time cvedid Convert external to internal date cvided Convert internal to external date */ #include "stdio.h" #include "mem.h" /* Get my standard defs */ #include "cpm.h" /* Get CP/M call definitions */ /* Local definitions */ typedef /* date/time structure */ struct { int DAT_DAT; /* Days since Jan 1 1978 */ BYTE DAT_HRS; /* BCD hours */ BYTE DAT_MIN; /* BCD minutes */ } DAT; /* Date */ /* External variables */ /* External routines */ /* Locals */ static int mdtbl[] = {31,28,31,30,31,30,31,31,30,31,30,31}; /* Days in each month */ /* *//* curdtm (id, it) Get date/time from operating system Accepts : id Address of where to store the date in internal form it Address of where to store the time in internal form Returns : *id Date as an int. *it Time as an int. */ curdtm (id, it) int *id; /* Address of date variable */ int *it; /* Address of time variable */ { IND DAT date; /* Date value */ IND int i; /* Scratch */ CPM (_MRGDT, &date); /* Call system to get date */ *id = date.DAT_DAT; /* Get days since Jan 1 1978 */ i = (date.DAT_HRS>>4)&0x0F; i = i*10 + (date.DAT_HRS&0x0F); i = i*6 + ((date.DAT_MIN>>4)&0x0F); i = i*10 + (date.DAT_MIN&0x0F); *it = i; /* Return the time. */ } /* *//* cvedid (id, it, m, d, y, hh, mm) Convert external date/time to internal date/time Accepts : id Address of internal date variable (int) it Address of internal time variable (int) m Month number (1-12) d Day number (1-31) y Year number (1978-??) hh Hour (0 - 23) mm Minutes (0 - 59) Returns : <value> 0 if ok inputs -1 = bad year -2 = bad month -3 = bad day of month *id Internal date value *it Internal time value */ cvedid (id, it, m, d, y, hh, mm) int *id, *it; /* Addr of date and time variables */ int m, d, y, hh, mm; /* Date and time component values */ { IND int i,j; /* Scratch */ *it = hh*60+mm; /* Takes care of time */ if ((y < 1978) || (y > 2070)) return (-1); mdtbl[1] = 28; /* Setup February */ if (y%4 == 0) /* if leap year */ mdtbl[1] = 29; m--; /* Make month and day zero-based */ d--; if ((m < 0) || (m > 11)) /* Check out month */ return (-2); if ((d < 0) || (d >= mdtbl[m])) /* Check out day of month */ return (-3); i = 0; /* Calculate days */ for (j=0; j < m; j++) i += mdtbl[j]; i += d; i += (y-1978)*365; i += (y-1976)/4; *id = i+1; /* Return day */ return (0); /* Give good status */ } /* *//* cvided (id, it, m, d, y, hh, mm) Convert internal date/time values to external values Accepts : id Date in internal form it Time in internal form *m Where to put month number *d Where to put day number *y Where to put year number *hh Where to put hours *mm Where to put minutes Returns : *m Month number (1-12) *d Day number (1-31) *y Year number (1978-??) *hh Hour (0-23) *mm Minutes (0-59) */ cvided (id, it, m, d, y, hh, mm) int id, it; /* Internal date/time */ int *m, *d, *y, *hh, *mm; /* Where to put components */ { IND int i,j; /* Scratch */ IND int yr,ly,mo,day; /* Various values */ i = id-1; /* day 1 = Jan 1 1978 */ ly = (i+672)/1461; /* Number of leap days passed. */ yr = (i-ly)/365; /* Number of full years passed */ i = i-(yr*365)-((yr+1)/4); /* Number of day in this year */ yr = yr+1978; /* What year it is */ mdtbl[1] = 28; /* Presume not leap year */ if (yr%4 == 0) /* If is */ mdtbl[1] = 29; /* then set feb days */ for (j=0,mo=0; j <= i; mo++) /* Find month */ j = j+mdtbl[mo]; /* Add days */ j = j-mdtbl[--mo]; /* Subtract off last month */ day = (i-j)+1; /* Get real day. */ *y = yr; /* Return component values */ *m = mo+1; *d = day; *hh = it/60; *mm = it%60; } EEOOFF