[net.sources] CMD003 Part 6 of 6

mem@sii.UUCP (Mark Mallett) (06/08/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