home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / AZTEC-C / QUOTE.ARK / QUOTE.C < prev    next >
Text File  |  1986-06-19  |  15KB  |  728 lines

  1. /* quote (c) copyright 1985 Mark E. Mallett
  2.  
  3.     Quote program
  4.  
  5.  
  6. Permission is granted to distribute this program indiscriminately.  Please
  7. leave all credits in place.  If you change it, please try to live with the
  8. coding style.
  9.  
  10.     -- Edit history --
  11.  
  12. 850329    MEM    Original version
  13.  
  14. 850423    MEM    Add the -s option
  15.  
  16. 850427    MEM    Add the -r option
  17.  
  18. */
  19.  
  20. /* Configuration: */
  21.  
  22. #define    ISCPM                /* Define this if CP/M system */
  23. #define    Z80                /* Define this if Z80 CPU */
  24.  
  25.  
  26. #include "stdio.h"
  27.  
  28. #ifdef ISCPM
  29. #include "cpm.h"
  30. #endif
  31.  
  32.  
  33. /* Local definitions */
  34.  
  35. #define    _VMAJ    1            /* Major version number */
  36. #define    _VMIN    1            /* Minor version number */
  37.  
  38. #define    isalpha(c) (isupper(c) || islower(c))
  39.  
  40. #define    IND    static        /* For variables with no allocation
  41.                     dependancies (don't have to be
  42.                     on the stack).  "static" works best
  43.                     on Z-80, which is not stack-oriented.
  44.                     For stack machines, remove the word
  45.                     "static". */
  46.  
  47. #define    TRUE    1
  48. #define    FALSE    0
  49. #define NUL    '\000'
  50.  
  51.  
  52. #ifdef ISCPM
  53. typedef                    /* date/time structure */
  54.   struct
  55.     {
  56.     int        DAT_DAT;        /* Days since Jan 1 1978 */
  57.     char    DAT_HRS;        /* BCD hours */
  58.     char    DAT_MIN;        /* BCD minutes */
  59.     }
  60.   DAT;                    /* Date */
  61. #endif
  62.  
  63. /* External variables */
  64.  
  65.  
  66.  
  67. /* External routines */
  68.  
  69.  
  70. extern    long    ftell();        /* Tell file position */
  71.  
  72.  
  73. /* Internal variables (public) */
  74.  
  75.  
  76. /* Internal routines */
  77.  
  78.     char    *newstr();
  79.  
  80. /* Local variables */
  81.  
  82. static    char    *Alist = {NULL};    /* Acceptance/rejection list */
  83. static    int    Cnsflg = {FALSE};    /* Copyright suppression flag */
  84. static    int    Creflg = {FALSE};    /* Create-index mode */
  85. static    char    *Exline = {NULL};    /* Address of command line on exit */
  86. static    FILE    *Ifp = {NULL};        /* File var for index file */
  87. static    char    *Inxfnm = {NULL};    /* Points to index filename */
  88. static    int    Qcnt = {0};        /* Number of quotes */
  89. static    FILE    *Qfp = {NULL};        /* File var for quotefile */
  90. static    char    *Quofnm = {NULL};    /* Points to quote filename */
  91. static    int    Rejflg = TRUE;        /* TRUE if Alist is rejection list */
  92. static    int    Rptfac = {1};        /* Repeat factor */
  93. static    int    Rseed;            /* Random number seed */
  94.  
  95.  
  96. /* Local (forward) routine defs */
  97.  
  98. /*
  99.  
  100. *//* main
  101.  
  102.         The main routine
  103.  
  104. */
  105.  
  106. main (argc, argv)
  107.  
  108. int        argc;
  109. char        **argv;
  110.  
  111. {
  112. IND    int        c;        /* Character var */
  113. IND    int        i;        /* Scratch */
  114. IND    int        n;        /* NEXT index after arg */
  115. IND    char        *aptr;        /* ptr to arg, if any */
  116.     char        cmdlin[100];    /* to keep command line in */
  117.  
  118. for (i = 1; i < argc; i++)        /* Look at command line arguments */
  119.     {
  120.     if (argv[i][0] != '-')        /* Be tough */
  121.     {
  122.     printf ("Illegal argument %s\n", argv[i]);
  123.     exiter(0);
  124.     }
  125.  
  126.     c = argv[i][1];            /* Look at option char */
  127.     c = tolower(c);
  128.     aptr = NULL;            /* Init pot. arg pointer */
  129.     if (argv[i][2] != NUL)        /* If anything after option char */
  130.     {
  131.     aptr = &argv[i][2];        /*  then that is it */
  132.     n = i;                /* Value of next i */
  133.     }
  134.     else
  135.     if (i < argc)            /* Only if there is one */
  136.         {
  137.         n = i+1;            /* Arg is next one */
  138.         aptr = argv[n];        /* Point to it */
  139.         }
  140.  
  141.     switch (c)                /* Branch on char */
  142.     {
  143.     case 'c':            /* Create-index mode */
  144.         Creflg = TRUE;        /* Set mode flag */
  145.         break;
  146.  
  147.  
  148. #ifdef ISCPM
  149.     case 'e':            /* Command to use on exit */
  150.         strcpy (cmdlin, aptr);    /* Init command... */
  151.         for (i = n+1; i < argc; i++)
  152.         {
  153.         strcat (cmdlin, " ");    /* Add separator */
  154.         strcat (cmdlin, argv[i]);
  155.         }
  156.         Exline = newstr (cmdlin);    /* Remember exit line */
  157.         break;
  158. #endif
  159.  
  160.  
  161.     case 'i':            /* Index file name */
  162.         if (Inxfnm != NULL)        /* Already got? */
  163.         {
  164.         printf ("Duplicate -i seen\n");
  165.         exiter();
  166.         }
  167.         Inxfnm = aptr;        /* Remember index filename */
  168.         i = n;            /* Remember next arg position */
  169.         break;
  170.  
  171.  
  172.     case 'n':            /* "not" */
  173.         Rejflg = TRUE;        /* Set "not" flag */
  174.         Alist = aptr;        /* remember rejection list */
  175.         i = n;
  176.         break;
  177.  
  178.     case 'o':            /* "only" */
  179.         Rejflg = FALSE;        /* Alist is acceptance */
  180.         Alist = aptr;        /* remember acceptance list */
  181.         i = n;
  182.         break;
  183.  
  184.  
  185.     case 'q':            /* Quotefile name */
  186.         if (Quofnm != NULL)        /* Already got? */
  187.         {
  188.         printf ("Duplicate -q seen\n");
  189.         exiter();
  190.         }
  191.         Quofnm = aptr;        /* Remember quote filename */
  192.         i = n;            /* Point to next arg */
  193.         break;
  194.  
  195.  
  196.     case 'r':            /* Repeat factor... */
  197.         Rptfac = atoi(aptr);    /* Get the number */
  198.         if (Rptfac < 1)        /* Let's be reasonable */
  199.         {
  200.         printf ("Invalid repeat factor %d... dummy!!\n", Rptfac);
  201.         exiter();
  202.         }
  203.         i = n;            /* Switch to right arg */
  204.         break;
  205.  
  206.     case 's':            /* Suppress copyright? */
  207.         Cnsflg = TRUE;
  208.         break;
  209.  
  210.  
  211.     default:            /* Something else */
  212.         printf ("Ignoring illegal option %s\n", argv[i]);
  213.     }
  214.  
  215.     }
  216.  
  217.  
  218. /* Supposed to do this for protection, so... */
  219.  
  220. if (!Cnsflg)                /* If not suppressing it */
  221.     printf ("QUOTE vsn %d.%d; (C) 1985 Mark E. Mallett.\n",_VMAJ,_VMIN);
  222.  
  223. if (Creflg)                /* Making index? */
  224.     {
  225.     makinx();                /* Make index */
  226.     exiter();
  227.     }
  228.  
  229. pquote();                /* Print quote */
  230. exiter();
  231. }
  232. /*
  233.  
  234. *//* pquote()
  235.  
  236.     Print quote from scratch
  237.  
  238.  
  239. Accepts :
  240.  
  241.  
  242. Returns :
  243.  
  244.  
  245. */
  246.  
  247. pquote ()
  248.  
  249. {
  250. IND    int    c;            /* Character */
  251. IND    int    i;            /* Scratch */
  252. IND    int    qnum;            /* Quote number selected */
  253. IND    long    qibase;            /* fpos of first index */
  254. IND    long    qiloc;            /* fpos of desired index */
  255. IND    long    qfloc;            /* Location of quote */
  256.     char    fname[50];        /* Holds file name from inx file */
  257.     char    qfline[150];        /* Quotefile line */
  258.  
  259.  
  260. if (Inxfnm == NULL)            /* Checkout index filename */
  261.     Inxfnm = "QUOTE.INX";        /*  use default */
  262. if ((Ifp = fopen(Inxfnm, "r")) == NULL)    /* Try to open index file */
  263.     {
  264.     printf ("Can not open index file %s\n", Inxfnm);
  265.     return;
  266.     }
  267.  
  268. fgets (fname, 50, Ifp);            /* Read name of quote file */
  269. for (i = 0; i < 50; i++)
  270.     if ((fname[i] == '\n') || (fname[i] == NUL))
  271.     break;
  272. fname[i] = NUL;
  273.  
  274. if (Quofnm == NULL)            /* Now make association by default */
  275.     Quofnm = newstr(fname);
  276.  
  277. if ((Qfp = fopen(Quofnm, "r")) == NULL)    /* Try to open quote filename */
  278.     {
  279.     printf ("Can not open quote file %s\n", Quofnm);
  280.     fclose (Ifp);
  281.     return;
  282.     }
  283.  
  284. fread (&Qcnt, sizeof(int), 1, Ifp);    /* Get # of quotes */
  285. if (Qcnt <= 0)                /* Trap bad value */
  286.     {
  287.     printf ("No quotes indexed.\n");
  288.     return;
  289.     }
  290.  
  291. qibase = ftell (Ifp);            /* Start of quote index */
  292.  
  293. while (Rptfac--)            /* Print correct number of quotes */
  294.     {
  295.     qnum = irand(Qcnt);            /* Generate random quote number */
  296.     qiloc = qibase + (qnum*sizeof(long)); /* Where index is for this quote */
  297.     fseek (Ifp, qiloc, 0);        /* Find this index */
  298.     fread (&qfloc, sizeof(long), 1, Ifp); /* Get quote-file location */
  299.     fseek (Qfp, qfloc, 0);        /* Position there */
  300.     printf ("\n");            /* Give separation */
  301.  
  302.     while (fgets (qfline, 150, Qfp) == qfline)
  303.     {
  304.     if (qfline[0] == '>')        /* If end of quote */
  305.         break;
  306.     for (i = 0; i < 150; i++)    /* Make line pretty */
  307.         {
  308.         c = qfline[i];
  309.         if ((c == '\n') || (c == NUL))
  310.         break;
  311.         }
  312.     qfline[i] = NUL;
  313.     printf ("%s\n", qfline);
  314.     }
  315.  
  316.     printf ("\n");            /* Separate */
  317.     }
  318.  
  319.  
  320. fclose (Ifp);
  321. fclose (Qfp);
  322. }
  323. /*
  324.  
  325. *//* makinx()
  326.  
  327.     Make index file using information gathered elsewhere (i.e. from
  328. the command line).
  329.  
  330.  
  331. Accepts :
  332.  
  333.     Inxfnm:        Addr of name of index file name
  334.     Quofnm:        Addr of name of quote filename
  335.  
  336.  
  337. Returns :
  338.  
  339.  
  340. */
  341.  
  342. makinx()
  343.  
  344. {
  345. IND    long    qcmark;            /* Where to write quote-count */
  346. IND    long    qfpos;            /* Quote-file positional marker */
  347. IND    int    c;            /* Character */
  348. IND    int    i;            /* Scratch */
  349. IND    int    blank;            /* Blank-line flag */
  350. IND    int    dotcnt;            /* dot count. . . */
  351. IND    int    rejcnt;            /* Reject count */
  352.     char    qfline[150];        /* Quotefile line */
  353.  
  354.  
  355. if (Quofnm == NULL)            /* See if quote filename given */
  356.     Quofnm = "QUOTE.TXT";        /*  use default */
  357. if (Inxfnm == NULL)            /* Ditto for index filename */
  358.     Inxfnm = "QUOTE.INX";
  359.  
  360. if ((Qfp = fopen(Quofnm, "r")) == NULL)    /* Open up date file */
  361.     {
  362.     printf ("Can not open file %s for input.\n", Quofnm);
  363.     exiter();
  364.     }
  365.  
  366. if ((Ifp = fopen(Inxfnm, "w")) == NULL)    /* Open up index file */
  367.     {
  368.     printf ("Can not open file %s for output.\n", Inxfnm);
  369.     fclose (Qfp);
  370.     exiter();
  371.     }
  372.  
  373. fprintf (Ifp, "%s\n", Quofnm);        /* Make quote file association in
  374.                        index file. */
  375.  
  376. Qcnt = 0;                /* Init quote counter */
  377. rejcnt = 0;                /* Init reject count */
  378. qcmark = ftell(Ifp);            /* This is where the count is */
  379. fwrite (&Qcnt, sizeof(int), 1, Ifp);    /* Write the quote count */
  380.  
  381. printf ("Constructing quote index.");
  382. dotcnt = 12;
  383. while (fgets (qfline, 150, Qfp) == qfline)
  384.     {                    /* Scan the quotes file */
  385.     if (qfline[0] == '!')        /* Allow comments inbetween quotes */
  386.     continue;
  387.     for (i = 0; i < 150; i++)        /* make it nul-terminated */
  388.     {
  389.     c = qfline[i];            /* Get char */
  390.     if ((c == '\n') || (c == NUL))
  391.         break;
  392.     }
  393.     qfline[i] = NUL;
  394.  
  395.     blank = TRUE;            /* Presume blank line */
  396.     for (i = 0; i < 150; i++)
  397.     {
  398.     c = qfline[i];
  399.     if (c == NUL)
  400.         break;
  401.     if ((c != ' ') && (c != '    '))
  402.         {                /* Space or tab */
  403.         blank = FALSE;
  404.         break;
  405.         }
  406.     }
  407.     if (blank)                /* If blank line */
  408.     continue;            /*  ignore it */
  409.  
  410. /* Found start of quote */
  411.  
  412.     if (++dotcnt <= 39)
  413.     printf (" .");
  414.     else
  415.     {
  416.     printf ("\n.");
  417.     dotcnt = 0;
  418.     }
  419.  
  420.     if (qacc(qfline))            /* If it is acceptable */
  421.     {
  422.     qfpos = ftell(Qfp);        /* Find queuefile posn */
  423.     fwrite (&qfpos, sizeof(long), 1, Ifp);
  424.     Qcnt++;                /* Write marker and bump count */
  425.     }
  426.     else                /* Not acceptable */
  427.     rejcnt++;            /*  bump reject count */
  428.  
  429.     while (fgets(qfline, 150, Qfp) == qfline)
  430.     {                /* Skip to end of quote */
  431.     if (qfline[0] == '>')        /* End marker.. */
  432.         break;
  433.     }
  434.     }
  435.  
  436. /* Done with quote file */
  437.  
  438. fseek (Ifp, qcmark, 0);            /* Go to the count marker */
  439. fwrite (&Qcnt, sizeof(int), 1, Ifp);    /* Re-write the counter */
  440.  
  441. printf ("\nIndex constructed; %d quote", Qcnt);
  442. if (Qcnt != 1)
  443.     printf ("s");
  444. printf (" included");
  445. if (rejcnt != 0)
  446.     {
  447.     printf ("; %d quote", rejcnt);
  448.     if (rejcnt != 1)
  449.     printf ("s");
  450.     printf (" rejected");
  451.     }
  452. printf (".\n");
  453.  
  454. fclose (Ifp);                /* Index file is done. . . */
  455. fclose (Qfp);
  456. }
  457. /*
  458.  
  459. *//* qacc (idline)
  460.  
  461.     Determine acceptance of quote based on its identification line
  462.  
  463.  
  464. Accepts :
  465.  
  466.     idline        identification line of the quote, consisting of
  467.             keywords describing the quote.
  468.  
  469.  
  470. Returns :
  471.  
  472.     <value>        TRUE if acceptable
  473.             FALSE if not
  474.  
  475.  
  476. */
  477.  
  478. qacc (idline)
  479.  
  480. char        *idline;        /* Identification line */
  481.  
  482. {
  483. IND    char    *idptr, *alptr;        /* Pointers */
  484.     char    idname[50], alname[50];    /* Holds names */
  485.  
  486. if (Alist == NULL)            /* If no accept/reject list */
  487.     return (TRUE);            /*  then we always succeed */
  488.  
  489. idptr = idline;                /* Setup pointer to list */
  490.  
  491. while (TRUE)                /* Do this for length of id line */
  492.     {
  493.     idptr = xname(idptr, &idname);    /* Extract name */
  494.     if (idname[0] == NUL)        /* If no more names */
  495.     break;                /*  then be done. */
  496.     alptr = Alist;            /* Check each name in acc/rej list */
  497.     while (TRUE)
  498.     {
  499.     alptr = xname (alptr, &alname);    /* Extract name */
  500.     if (alname[0] == NUL)        /* If no more names */
  501.         break;            /*  be done. */
  502.     if (nccmp(idname, alname) == 0)    /* If names match */
  503.         return (!Rejflg);        /*  then return negative of the
  504.                          sense of rejection */
  505.     }
  506.     }
  507.  
  508. /* Here no names matched; return whatever sense of rejection we're in. */
  509.  
  510. return (Rejflg);
  511. }
  512. /*
  513.  
  514. *//* xname (ptr, name)
  515.  
  516.     Extracts a name from a string.
  517.  
  518.  
  519. Accepts :
  520.  
  521.     ptr        Address of the string
  522.     name        Address of the name buffer
  523.  
  524. Returns :
  525.  
  526.     <value>        Address of pointer to rest of string
  527.     name        Filled with name.
  528.  
  529.  
  530. Note:
  531.  
  532.     A "name" is considered to be a collection of alphanumeric
  533. characters.
  534.  
  535. */
  536.  
  537. char *xname (ptr, name)
  538.  
  539. char        *ptr;
  540. char        *name;
  541.  
  542. {
  543. IND    int    c;            /* Character */
  544.  
  545. while ((c = *ptr++) != NUL)        /* Skip to first alphanumeric */
  546.     if (isalpha(c) || isdigit(c))
  547.     break;
  548.  
  549. while (isalpha(c) || isdigit(c))    /* Save string of alphanumerics */
  550.     {
  551.     *name++ = c;            /* Store char */
  552.     c = *ptr++;                /* Fetch next one. */
  553.     }
  554.  
  555. *name = NUL;                /* Tie off the name */
  556. if (c == NUL)                /* If end of string */
  557.     ptr--;                /*  don't skip past it. */
  558. return (ptr);                /* Done. */
  559. }
  560. /*
  561.  
  562. *//* exiter()
  563.  
  564.     Exits to the system, with proper command line.
  565.  
  566. */
  567.  
  568. exiter()
  569.  
  570. {
  571. #ifdef ISCPM
  572. if (Exline != NULL)
  573.     {
  574.     strcpy (0x80, Exline);
  575.     CPM (0x2F, 0xFF);
  576.     }
  577. #endif
  578. exit(0);
  579. }
  580. /*
  581.  
  582. *//* nccmp(s1,s2)
  583.  
  584.     Compare strings without case sensitivity
  585.  
  586. Accepts :
  587.  
  588.     s1        Addr of first string
  589.     s2        Addr of second string
  590.  
  591. Returns :
  592.  
  593.     <value>        -1 if s1 < s2
  594.              0 if s1 = s2
  595.              1 if s1 > s2
  596.  
  597. */
  598.  
  599. nccmp (s1,s2)
  600.  
  601. char        *s1;            /* String 1 */
  602. char        *s2;            /* String 2 */
  603.  
  604. {
  605. IND    int    c1,c2;            /* Chars */
  606.  
  607. while (TRUE)
  608.     {
  609.     c1 = *s1++;
  610.     c1 = toupper(c1);
  611.     c2 = *s2++;
  612.     c2 = toupper(c2);
  613.     if (c1 < c2)
  614.     return (-1);
  615.     if (c1 > c2)
  616.     return (1);
  617.     if (c1 == NUL)
  618.     return(0);
  619.     }
  620. }
  621. /*
  622.  
  623. *//* newstr (str)
  624.  
  625.     Makes a copy of a string
  626.  
  627.  
  628. Accepts :
  629.  
  630.     str        Addr of string to copy
  631.  
  632.  
  633. Returns :
  634.  
  635.     <value>        Address of copy
  636.  
  637.  
  638. */
  639.  
  640. char *newstr (str)
  641.  
  642. char        *str;            /* String to copy */
  643.  
  644. {
  645. IND    char    *sptr;            /* Points to new string */
  646.  
  647. sptr = calloc (1, strlen(str)+1);    /* Make space for new string */
  648. strcpy (sptr, str);            /* Copy it */
  649. return (sptr);                /* Return it */
  650. }
  651. /*
  652.  
  653. *//* irand (max)
  654.  
  655.     Return random number from 0 to max-1
  656.  
  657.  
  658. Accepts :
  659.  
  660.     max        Maximum value
  661.  
  662.  
  663. Returns :
  664.  
  665.     <value>        random number from 0 to max-1 inclusive
  666.  
  667.  
  668. Notes:
  669.  
  670.     Conditional code for specific operating systems must be
  671. written here.
  672.  
  673. */
  674.  
  675. irand (max)
  676.  
  677. int        max;            /* Top end */
  678.  
  679. {
  680.     int    rslt;            /* Resultant value */
  681.  
  682. #ifdef Z80                /* If z80 */
  683. rslt += (getrr() >> 2);            /* Add r-register to whatever
  684.                        garbage rslt is inited to */
  685. #endif
  686.  
  687. #ifdef ISCPM
  688.     {
  689.     DAT    date;                /* Date structure */
  690.     int    it, id, x;            /* time, date, x */
  691.  
  692.     CPM (_MRGDT, &date);        /* Call system to get date */
  693.     id = date.DAT_DAT;            /* Get days since Jan 1 1978 */
  694.     x = (date.DAT_HRS>>4)&0x0F;
  695.     x = x*10 + (date.DAT_HRS&0x0F);
  696.     x = x*6 + ((date.DAT_MIN>>4)&0x0F);
  697.     it = x*10 + (date.DAT_MIN&0x0F);
  698.     rslt += (it+id);            /* Get some wierd result */
  699.     }
  700. #endif
  701.  
  702. Rseed += Rseed*13+rslt;
  703. if (Rseed < 0)
  704.     Rseed = -Rseed;
  705.  
  706. return (Rseed%max);            /* What the heck */
  707. }
  708. #ifdef Z80
  709. /*
  710.  
  711. *//* getrr()
  712.  
  713.     Returns the value of the Z80's refresh register
  714.  
  715.  
  716. */
  717.  
  718. #asm
  719.     public    getrr_
  720. getrr_:
  721.     DB    0EDH,05FH    ;LD A,R
  722.     MVI    H,0        ;Put into HL
  723.     MOV    L,A
  724.     RET
  725. #endasm
  726. esh register
  727.  
  728.