/* minder Reminder service 1985 Mark E. Mallett */ #include "minder.h" #include "comnd.h" #include "setjmp.h" #include "cpm.h" char ovlccp = {0}; /* Don't overlay CCP (CP/M) */ /* Local definitions */ /* External routines */ /* External data */ extern int Chgflg; /* Changes-made flag */ extern int Curdat; /* Current date */ extern int Curtim; /* Current time */ extern EVT *Evthdr; /* Heads the EVT list */ extern CFB Inicfb; /* CFB for initialization */ extern int Osdate; /* O/S supports date/time */ extern CSB Topcsb; /* top-level command state block */ extern jmp_buf Topenv; /* setjmp environment buffer */ extern char *Usrnam; /* Name of invoking user */ /* Local routines */ extern int addcmd(); /* the ADD command */ extern int exicmd(); /* the EXIT command */ extern int hlpcmd(); /* the HELP command */ extern int hlpcms(); /* Routine for help:command */ extern int hlpful(); /* Routine for help:full */ extern int liscmd(); /* the LIST command */ extern int modcmd(); /* the MODIFY command */ extern int quicmd(); /* the QUIT command */ extern int remcmd(); /* the REMOVE command */ extern int rptcmd(); /* the REPORT command */ extern int shwcmd(); /* the SHOW command */ /* Local data */ static int Datflg = {FALSE}; /* -d option given */ static int Rptmod = {FALSE}; /* If invoked in report mode */ /* Command keyword and dispatch tables */ BYTE *Cmktbl[] = { /* Command keywords.. */ "ADD", /* Add event */ "EXIT", /* Exit this program */ "HELP", /* Give help */ "LIST", /* List events */ "MODIFY", /* Modify an event */ "QUIT", /* Quit without saving changes */ "REMOVE", /* Remove an event */ "REPORT", /* Report active events */ "SHOW", /* Show an event's definition */ NULL /* Ends with a null pointer */ }; int (*Cmddsp[])() = { addcmd, /* ADD */ exicmd, /* EXIT */ hlpcmd, /* HELP */ liscmd, /* LIST */ modcmd, /* MODIFY */ quicmd, /* QUIT */ remcmd, /* REMOVE */ rptcmd, /* REPORT */ shwcmd, /* SHOW */ 0 /* Ends with a zero for convenience */ }; /* HELP keyword and dispatch tables */ BYTE *Hlptbl[] = { "COMMAND", "FULL", NULL }; int (*Hlpdsp[])() = { hlpcms, hlpful, 0 }; /* COMND blocks */ CFB Cmkcfb = {_CMKEY, _CFHPP, 0, &Cmktbl, "Command, ", 0}; static CFB Hkwcfb = {_CMKEY, _CFDPP, &Cmkcfb, &Hlptbl, 0, "FULL"}; /* *//* main The main routine */ main (argc, argv) int argc; char **argv; { IND int mo, da, yr; /* Month, day, year */ IND int c; /* Character var */ IND int i; /* Scratch */ IND int n; /* NEXT index after arg */ IND BYTE *aptr; /* ptr to arg, if any */ IND BYTE **kptr; /* Points to kwd table entry */ IND WORD cpmver; /* CPM version number */ /* Supposed to do this for protection, so... */ printf ("MINDER vsn *1*; (C) 1985 Mark E. Mallett.\n"); for (i = 1; i < argc; i++) /* Look at command line arguments */ { if (argv[i][0] != '-') /* Be tough */ { printf ("Illegal argument %s\n", argv[i]); exit(0); } c = argv[i][1]; /* Look at option char */ c = tolower(c); aptr = NULL; /* Init pot. arg pointer */ if (argv[i][2] != NUL) /* If anything after option char */ { aptr = &argv[i][2]; /* then that is it */ n = i; /* Value of next i */ } else if (i < argc) /* Only if there is one */ { n = i+1; /* Arg is next one */ aptr = argv[n]; /* Point to it */ } switch (c) /* Branch on char */ { case 'd': /* Date supplied */ if (Datflg) /* Already got one? */ printf ("Duplicate -d option.\n"); else { yr = 1900 + d2(aptr); /* Get yr */ mo = d2(&aptr[2]); /* Month */ da = d2(&aptr[4]); /* Day */ cvedid (&Curdat, &Curtim, mo, da, yr, 0, 0); Datflg = TRUE; } i = n; break; case 'r': /* Report mode */ Rptmod = TRUE; /* Set the flag */ break; case 'u': /* Username */ if (Usrnam != NULL) /* If more than one.. */ { printf ("Duplicate username given\n"); exit(); } Usrnam = newstr(aptr); /* Remember user name */ i = n; /* Skip to next argument */ break; default: /* Something else */ printf ("Ignoring illegal option %s\n", argv[i]); } } cpmver = CPM (_MRCPV, 0); /* Get CP/M version */ if ((cpmver & 0xff00) != 0) /* Not CP/M ? */ printf ("Warning... This is not a CP/M system.\n"); Osdate = (cpmver >= 0x30); /* Date fn in CPM+ */ if (!Osdate) /* If os date/time not supported */ if (!Datflg) /* We have to have date option */ { printf ("Since this is not a CPM+ system, the current date must be\n"); printf ("supplied on the command line, in the form:\n"); printf (" A> minder -d yymmdd\n"); exit(0); } loaddb(); /* Load the database */ if (Rptmod) /* Invoked in report mode? */ { report(); /* Call report module */ if (Chgflg) /* Any changes? */ savedb(); /* Save db */ exit(); /* Be done */ } printf ("Type ? for help at any time.\n"); /* Enter command loop */ while (TRUE) /* Forever */ { if (COMND (&Topcsb, &Inicfb) != _CROK) /* eh? */ { printf ("Fatal error initializing COMND\n"); exit(); } setjmp (Topenv); /* Mark here for reparse */ if (COMNDi (&Topcsb, &Cmkcfb) != _CROK) /* Collect keyword */ continue; kptr = (char **) (Topcsb.CSB_RVL._ADR); i = kptr - (&Cmktbl[0]); /* Get keyword index */ (*Cmddsp[i])(); /* Process command */ } } /* *//* d2 (ptr) Returns value of 2-digit ASCII decimal string @ ptr This is used for command line parsing of the date. */ int d2 (ptr) char *ptr; { IND int v; /* Value */ v = (*ptr++) - '0'; /* First digit */ v = (v*10) + (*ptr - '0'); /* Value */ return (v); } /* *//* addcmd () Processes the ADD command. Accepts : Returns : */ addcmd () { IND EVT *EVTptr; /* Pointer to event block */ char evname[50]; /* Event name */ if (!noise (&Topcsb, "event named")) /* Give guide words */ return; if (!getuqs (&Topcsb, "event name", evname)) return; if (!confrm (&Topcsb)) /* Confirm the command */ return; if (findev(evname) != NULL) /* Make sure not duplicate */ { printf ("Event %s already exists. Please use another name.\n", evname); } else { EVTptr = calloc (1, sizeof(EVT)); /* Allocate event block */ EVTptr -> EVT_NAM = newstr (evname); /* Get event name */ if (Usrnam != NULL) /* If we're identified */ { EVTptr -> EVT_FRM = newstr(Usrnam); EVTptr -> EVT_FOR = newstr(Usrnam); } evdef (EVTptr); /* Go define it */ addev (EVTptr); /* Add this event */ printf ("Event %s added.\n", EVTptr -> EVT_NAM); } } /* *//* exicmd () Processes the EXIT command. Accepts : Returns : */ exicmd () { if (!noise (&Topcsb, "and save changes")) /* Give guide words */ return; if (!confrm (&Topcsb)) /* Confirm the command */ return; if (Chgflg) /* If any changes made */ savedb(); /* Save the database */ exit(0); } /* *//* hlpcmd() the HELP command (taken from lbbhlp.c) */ hlpcmd() { int i; /* Command index */ char **kptr; /* Keyword ptr ptr */ if (!noise (&Topcsb, "on subject")) /* Give guidance */ return; if (COMNDi (&Topcsb, &Hkwcfb) != _CROK) /* Get keyword */ return; kptr = (char **) Topcsb.CSB_RVL._ADR; /* Get returned pointer */ if (Topcsb.CSB_CFB == &Cmkcfb) /* If matched command keyword */ { i = kptr - &Cmktbl[0]; /* Get index */ return (hlpcms(i)); /* Process the thing */ } i = kptr - &Hlptbl[0]; /* Get index */ (*Hlpdsp[i])(-1); /* Process it */ } /* *//* hlpcms HELP COMMAND */ hlpcms(inx) int inx; { IND int i; /* Scratch */ IND char **kptr; /* Ptr to kwd ptr */ if ((i = inx) == -1) /* If not command keyword */ { if (!noise (&Topcsb, "named")) /* Guide again */ return; if (COMNDi (&Topcsb, &Cmkcfb) != _CROK) /* Collect keyword */ return; kptr = (char **) (Topcsb.CSB_RVL._ADR); i = kptr - (&Cmktbl[0]); /* Get keyword index */ } if (!confrm(&Topcsb)) /* Get confirmation */ return; givhlp (Cmktbl[i]); /* Give help for this command */ } /* *//* hlpful HELP FULL */ hlpful() { if (!confrm(&Topcsb)) /* Get confirmation */ return; givhlp ("*FULL*"); /* Give the full help */ } /* *//* givhlp (key) Extract keyed help from help file Accepts : key String to match in help key Returns : Notes : The help file MINDER.HLP is simple in organization; it contains a number of sections of text each beginning with /key and ending with a line beginning with slash (/) */ givhlp (key) char *key; { IND int c; /* Character */ char line[101]; /* Line buffer */ IND int i; /* Scratch */ IND int intext; /* Flag in text or not */ IND FILE *fp; /* for Help file */ if ((fp = fopen("MINDER.HLP", "r")) == NULL) { printf ("Help file is not available!\n"); return; } printf ("Please wait while I look this up . . .\n"); intext = FALSE; /* Not in keyed text yet */ while (TRUE) { i = 0; /* Init line index */ while ((c = getfc (fp)) != EOF) if (c == '\n') break; else if (i < 100) line[i++] = c; if ((i == 0) && (c == EOF)) break; line[i] = NUL; if (line[0] == '/') /* Special marker ? */ { if (intext) /* If in text */ break; /* ends with next slash line */ else /* Not intext, look at key */ if (strcmp (&line[1], key) == 0) { intext = TRUE; printf ("\n"); } } else if (intext) /* In text ? */ { printf ("%s\n", line); /* Print the line */ } } if (!intext) /* If didn't find anything */ { printf ("Help for %s is not available.\n", key); } fclose (fp); } /* *//* liscmd () Processes the LIST command. Accepts : Returns : */ liscmd () { IND EVT *EVTptr; /* Event block pointer */ IND int m,d,y,hh,mm; /* Date/time components */ IND int okflg; /* OK to list flag */ if (!noise (&Topcsb, "events")) /* Give guide words */ return; if (!confrm (&Topcsb)) /* Confirm the command */ return; EVTptr = Evthdr; /* Start at beginning */ while (EVTptr) { okflg = chkfor(EVTptr); /* Check it's ok to see.. */ if (Usrnam) /* that includes from us */ if (EVTptr -> EVT_FRM) if (nccmp (EVTptr -> EVT_FRM, Usrnam) == 0) okflg = TRUE; if (okflg) /* Make sure for us.. */ { cvided (EVTptr -> EVT_DTD, EVTptr -> EVT_DTM, &m, &d, &y, &hh, &mm); printf ("%c %02d/%02d/%04d %02d:%02d %-15s %s\n", chkfor(EVTptr)?'>':'<', m, d, y, hh, mm, EVTptr -> EVT_NAM, EVTptr -> EVT_MSG); } EVTptr = EVTptr -> EVT_FLK; } } /* *//* modcmd () Processes the MODIFY command. Accepts : Returns : */ modcmd () { IND EVT *EVTptr; /* Pointer to event block */ if (!noise (&Topcsb, "event named")) /* Give guide words */ return; if ((EVTptr = getenm (&Topcsb)) == NULL) /* Get event name */ return; if (!confrm (&Topcsb)) /* Confirm the command */ return; remev (EVTptr); /* Unlink this event */ evdef (EVTptr); /* Modify it */ addev (EVTptr); /* Put the event back in */ } /* *//* quicmd () Processes the QUIT command. Accepts : Returns : */ quicmd () { if (!noise (&Topcsb, "without saving changes")) /* Give guide words */ return; if (!confrm (&Topcsb)) /* Confirm the command */ return; exit(0); } /* *//* remcmd () Processes the REMOVE command. Accepts : Returns : */ remcmd () { IND EVT *EVTptr; /* Event pointer */ if (!noise (&Topcsb, "event named")) /* Give guide words */ return; if ((EVTptr = getenm (&Topcsb)) == NULL) /* Get event name */ return; if (!confrm (&Topcsb)) /* Confirm the command */ return; remev (EVTptr); /* Unlink this event */ } /* *//* rptcmd () Processes the REPORT command. Accepts : Returns : */ rptcmd () { if (!noise (&Topcsb, "active events")) /* Give guide words */ return; if (!confrm (&Topcsb)) /* Confirm the command */ return; report(); /* Call the reporter. */ } /* *//* shwcmd () Processes the SHOW command. Accepts : Returns : */ shwcmd () { IND EVT *EVTptr; /* Pointer to event block */ if (!noise (&Topcsb, "event named")) /* Give guide words */ return; if ((EVTptr = getenm (&Topcsb)) == NULL) /* Get event name */ return; if (!confrm (&Topcsb)) /* Confirm the command */ return; evshw(EVTptr); /* Show it */ }