home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / quot210s.zip / src / sig.c < prev    next >
C/C++ Source or Header  |  1998-10-27  |  15KB  |  510 lines

  1. /*
  2.  * sig.c
  3.  *
  4.  * The Quoteriser's random signature generator.
  5.  *
  6.  *      Created: 8th December 1997
  7.  * Version 1.00: 21st December 1997
  8.  * Version 1.01: 6th June 1998
  9.  * Version 1.10: 27th October 1998
  10.  *
  11.  * (C) 1997-1998 Nicholas Paul Sheppard
  12.  *
  13.  * This file is distributed under the GNU General Public License. See the
  14.  * file copying.txt for details.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <errno.h>
  21. #include <ctype.h>
  22. #include <time.h>
  23. #include "quotes.h"
  24. #include "authors.h"
  25. #include "html.h"
  26. #include "general.h"
  27. #include "typeset.h"
  28.  
  29.  
  30. /* limits */
  31. #define SIG_MAX_CELLS    80
  32.  
  33.  
  34. /* output format flags */
  35. #define QSIG_FLAUTHOR    0x00000001    /* print author's name */
  36. #define QSIG_FLSOURCE    0x00000002    /* print quote source */
  37. #define QSIG_FLFALLBACK    0x00000004    /* enable fall-back to other format */
  38.  
  39. /* internal function prototypes */
  40. void    SigGenerate(QUOTEDB *, AUTHORDB *, char *, int, int, FILE *);
  41. char    *SigGenerateRow(QUOTEDB *, AUTHORDB *, char *, int, int, FILE *);
  42. int    SigQuoteTag(char *);
  43. char    *SigRandomQuote(QUOTEDB *, AUTHORDB *, int, int);
  44.  
  45.  
  46. int main(int argc, char **argv)
  47. {
  48.     FILE        *fTemplate;    /* template (input) file */
  49.     FILE        *fSig;        /* signature (output) file */
  50.     char        *pszQuoteDB;    /* name of quote database */
  51.     char        *pszAuthorDB;    /* name of author database */
  52.     char        *pszTemplate;    /* name of template file */
  53.     QUOTEDB        qdb;        /* quote database */
  54.     AUTHORDB    adb;        /* author database */
  55.     int        iAuthor;    /* author output option */
  56.     int        iSource;    /* source output option */
  57.     int        iLineLimit;    /* output line limit */
  58.     int        flMode;        /* output format flags */
  59.     int        i;        /* counter */
  60.  
  61.     /* set defaults */
  62.     iAuthor = -1;
  63.     iSource = -1;
  64.     iLineLimit = 0;
  65.  
  66.     /* parse command line */
  67.     i = 1;
  68.     while ((i < argc) && ((argv[i][0] == '-'))) {
  69.         if (argv[i][1] == 'a') {
  70.             if (argv[i][2] == '-') {
  71.                 iAuthor = 0;
  72.             } else if (argv[i][2] == 's') {
  73.                 iAuthor = 1;
  74.                 iSource = (iSource == -1)? 0 : iSource;
  75.             } else if (argv[i][2] == '+') {
  76.                 iAuthor = 2;
  77.             } else {
  78.                 fprintf(stderr, "Unrecognised option %s.\n", argv[i]);
  79.             }
  80.         } else if (argv[i][1] == 'l') {
  81.             iLineLimit = atoi(argv[i] + 2);
  82.         } else if (argv[i][1] == 's') {
  83.             if (argv[i][2] == '-') {
  84.                 iSource = 0;
  85.             } else if (argv[i][2] == 'a') {
  86.                 iSource = 1;
  87.                 iAuthor = (iAuthor == -1)? 0 : iAuthor;
  88.             } else if (argv[i][2] == '+') {
  89.                 iSource = 2;
  90.             } else {
  91.                 fprintf(stderr, "Unrecognised option %s.\n", argv[i]);
  92.             }
  93.         } else if (argv[i][1] == '?') {
  94.             i = argc;
  95.         } else if (argv[i][1] == '-') {
  96.             i++;
  97.             break;
  98.         } else {
  99.             fprintf(stderr, "Unrecognised option %s.\n", argv[i]);
  100.         }
  101.         i++;
  102.     }
  103.     iAuthor = (iAuthor == -1)? 2 : iAuthor;
  104.     iSource = (iSource == -1)? 2 : iSource;
  105.  
  106.  
  107.     if (i >= argc) {
  108.         /* print help screen */
  109.         printf("The Quoteriser: Random Signature Generator 1.10\n");
  110.         printf("(C) 1997-1998 Nicholas Paul Sheppard. This program is distributed\n");
  111.         printf("under the GNU General Public License and comes with NO WARRANTY\n");
  112.         printf("WHATSOEVER. See the file copying.txt for details.\n\n");
  113.         printf("Usage: sig [options] <template> {<signature>}\n\n");
  114.         printf("  where: <template>  is the name of the template (input) file\n");
  115.         printf("         <signature> is the name of the signature (output) files\n\n");
  116.         printf("Valid options:\n");
  117.         printf("  -?   print this message\n");
  118.         printf("  -a-  don't print author\n");
  119.         printf("  -as  print author if available, otherwise source\n");
  120.         printf("  -a+  print author (default)\n");
  121.         printf("  -lN  print warning if output has more than N lines\n");
  122.         printf("  -s-  don't print quote source\n");
  123.         printf("  -sa  print source if available, otherwise author\n");
  124.         printf("  -s+  print source (default)\n");
  125.         printf("  --   no more arguments on the command line\n\n");
  126.         printf("Environment: QUOTER_QDB - quote database (must be set)\n");
  127.         printf("             QUOTER_ADB - author database (optional)\n");
  128.         return (0);
  129.     }
  130.  
  131.     /* determine the output format flags */
  132.     flMode = 0;
  133.     if ((iAuthor == 2) || (iAuthor == 1))
  134.         flMode |= QSIG_FLAUTHOR;
  135.     if ((iSource == 2) || (iSource == 1))
  136.         flMode |= QSIG_FLSOURCE;
  137.     if ((iAuthor == 1) || (iSource == 1))
  138.         flMode |= QSIG_FLFALLBACK;
  139.     if ((flMode & QSIG_FLAUTHOR) && (flMode & QSIG_FLSOURCE))
  140.         flMode &= ~QSIG_FLFALLBACK;
  141.  
  142.     /* open quote database */
  143.     if ((pszQuoteDB = getenv("QUOTER_QDB")) == NULL) {
  144.         fprintf(stderr, "The QUOTER_QDB environment variable is not set.\n");
  145.         return (1);
  146.     }
  147.     if (!QuoteOpenDB(pszQuoteDB, &qdb, S_IREAD)) {
  148.         fprintf(stderr, "sig: unable to open %s for reading.\n", pszQuoteDB);
  149.         return (1);
  150.     }
  151.  
  152.     /* open author database (if necessary) */
  153.     if (!(flMode & (QSIG_FLAUTHOR | QSIG_FLFALLBACK)) || ((pszAuthorDB = getenv("QUOTER_ADB")) == NULL)) {
  154.         AuthorNullifyDB(&adb);
  155.     } else if (!AuthorOpenDB(pszAuthorDB, &adb, S_IREAD)) {
  156.         fprintf(stderr, "sig: unable to open %s for reading.\n", pszAuthorDB);
  157.         return (1);
  158.     }
  159.  
  160.     /* open template file */
  161.     if ((fTemplate = fopen(argv[i], "r")) == NULL) {
  162.         fprintf(stderr, "sig: %s: %s", argv[i], strerror(errno));
  163.         return (1);
  164.     }
  165.  
  166.     /* open signature file */
  167.     if ((i + 1) >= argc) {
  168.         /* no signature file specified; use stdout */
  169.         fSig = stdout;
  170.     } else {
  171.         if ((fSig = fopen(argv[i + 1], "w")) == NULL) {
  172.             fprintf(stderr, "sig: %s: %s", argv[i + 1], strerror(errno));
  173.             return (1);
  174.         }
  175.     }
  176.  
  177.     /* read template into memory */
  178.     if ((pszTemplate = strfromf(fTemplate)) == NULL) {
  179.         fprintf(stderr, "sig: memory allocation failure.\n");
  180.         return (1);
  181.     }
  182.  
  183.     /* do it */
  184.     srand(time(NULL));
  185.     i++;
  186.     if (i >= argc) {
  187.         /* no signature file specified; use stdout */
  188.         SigGenerate(&qdb, &adb, pszTemplate, flMode, iLineLimit, stdout);
  189.     } else for (; i < argc; i++) {
  190.         if ((fSig = fopen(argv[i], "w")) == NULL) {
  191.             fprintf(stderr, "sig: %s: %s", argv[i], strerror(errno));
  192.         } else {
  193.             SigGenerate(&qdb, &adb, pszTemplate, flMode, iLineLimit, fSig);
  194.             fclose(fSig);
  195.         }
  196.     }
  197.  
  198.     /* close files */
  199.     QuoteCloseDB(&qdb);
  200.     if (adb.dbfInfo != NULL)
  201.         AuthorCloseDB(&adb);
  202.     fclose(fTemplate);
  203.  
  204.     /* free memory */
  205.     free(pszTemplate);
  206.  
  207.     return (0);
  208. }
  209.  
  210.  
  211. void SigGenerate(QUOTEDB *pqdb, AUTHORDB *padb, char *pszTemplate, int flMode, int iLineLimit, FILE *f)
  212. /*
  213.  * Generate a signature file, inserting random quotes where indicated by the
  214.  * template string.
  215.  *
  216.  * QUOTEDB *pqdb    - quote database to obtain quotes from
  217.  * AUTHORDB *padb    - author database to contain authors from (may be empty)
  218.  * char *pszTemplate    - template string - will be altered
  219.  * int flMode        - output format flags
  220.  * int iLineLimit    - output limit before printing a warning (0 for none)
  221.  * FILE *f        - output file
  222.  */
  223. {
  224.     char    *pszCurrent;        /* cursor */
  225.     char    *pszNext;        /* look-ahead */
  226.     char    szTag[HTML_MAX_TAG];    /* HTML tag */
  227.     int    i;            /* counter */
  228.  
  229.     pszCurrent = pszTemplate;
  230.     while (pszCurrent[0] != '\0') {
  231.  
  232.         /* search for next tag */
  233.         while ((pszCurrent[0] != '\0') && (pszCurrent[0] != '<'))
  234.             pszCurrent++;
  235.  
  236.         /* hopefully, it's a <TR> tag */
  237.         if (pszCurrent[0] == '<') {
  238.             i = HTMLGetNextChunk(pszCurrent, szTag, &pszNext);
  239.             pszCurrent = pszNext;
  240.             if ((i == HTML_TAG_MID) || (i == HTML_TAG_END)) {
  241.                 if (HTMLParseTag(szTag) == HTML_TABLE_ROW) {
  242.                     /* format the row */
  243.                     pszNext = SigGenerateRow(pqdb, padb, pszCurrent, flMode, iLineLimit, f);
  244.                     pszCurrent = pszNext;
  245.                 }
  246.             }
  247.         }
  248.     }
  249. }
  250.  
  251.  
  252. char *SigGenerateRow(QUOTEDB *pqdb, AUTHORDB *padb, char *pszTemplate, int flMode, int iLineLimit, FILE *f)
  253. /*
  254.  * Typeset one row of cells.
  255.  *
  256.  * QUOTEDB *pqdb    - quote database to obtain quotes from
  257.  * AUTHORDB *padb    - author database to contain authors from (may be empty)
  258.  * char *pszTemplate    - template string
  259.  * int flMode        - output format flags
  260.  * int iLineLimit    - output limit before printing a warning (0 for none)
  261.  * FILE *f        - output file
  262.  *
  263.  * Returns        - pointer to the position in pszTemplate from which to carry on
  264.  */
  265. {
  266.     char        *apszCells[SIG_MAX_CELLS];    /* cell contents */
  267.     char        szTag[HTML_MAX_TAG];        /* HTML tag */
  268.     char        *pszBuffer;            /* copy of pszTemplate */
  269.     char        *pszCurrent;            /* cursor */
  270.     char        *pszNext;            /* look-ahead */
  271.     int        aiWidth[SIG_MAX_CELLS];        /* cell widths */
  272.     int        iCount;                /* number of cells */
  273.     int        i;                /* counter */
  274.     HTML_TDATTR    tda;                /* attribute from TD elements */
  275.     int        iLines;                /* number of lines in output */
  276.     int        bDone;                /* loop invariant */
  277.     int        bMove;                /* update pszCurrent? */
  278.     int        abAllocated[SIG_MAX_CELLS];    /* did we allocate cells? */
  279.  
  280.     /* start with a copy of the template string */
  281.     if ((pszBuffer = (char *)malloc(strlen(pszTemplate) + 1)) == NULL) {
  282.         fprintf(stderr, "sig: memory allocation failure.\n");
  283.         exit(1);
  284.     }
  285.     strcpy(pszBuffer, pszTemplate);
  286.  
  287.     /* divide the input string up into cells */
  288.     pszCurrent = pszBuffer;
  289.     iCount = 0;
  290.     bDone = 0;
  291.     memset(abAllocated, 0, SIG_MAX_CELLS * sizeof(int));
  292.     do {
  293.         /* search for next tag */
  294.         while ((pszCurrent[0] != '\0') && (pszCurrent[0] != '<'))
  295.             pszCurrent++;
  296.  
  297.         if (pszCurrent[0] == '<') {
  298.             bMove = 1;
  299.             switch (HTMLGetNextChunk(pszCurrent, szTag, &pszNext)) {
  300.                 case HTML_TAG_MID:
  301.                 case HTML_TAG_END:
  302.                     switch (HTMLParseTag(szTag)) {
  303.                         case HTML_TABLE_ROW:
  304.                             bDone = 1;
  305.                             bMove = 0;
  306.                             break;
  307.  
  308.                         case HTML_TABLE_DATA:
  309.                             HTMLAttrTD(szTag, &tda);
  310.                             apszCells[iCount] = pszNext;
  311.                             aiWidth[iCount] = tda.iColSpan;
  312.                             if (++iCount > SIG_MAX_CELLS)
  313.                                 bDone = 1;
  314.                             break;
  315.  
  316.                         case HTML_UNKNOWN:
  317.                             /* hopefully, a <quote> tag */
  318.                             if ((aiWidth[iCount] = SigQuoteTag(szTag)) > 0) {
  319.                                 apszCells[iCount] = SigRandomQuote(pqdb, padb, aiWidth[iCount], flMode);
  320.                                 abAllocated[iCount] = 1;
  321.                                 if (++iCount > SIG_MAX_CELLS)
  322.                                     bDone = 1;
  323.                             }
  324.                             break;
  325.                     }
  326.                     break;
  327.  
  328.                 case HTML_END:
  329.                     bDone = 1;
  330.                     break;
  331.             }
  332.             *(pszCurrent - 1) = '\0';
  333.             if (bMove)
  334.                 pszCurrent = pszNext;
  335.         } else
  336.             bDone = 1;
  337.     } while (!bDone);
  338.  
  339.     /* write the row cells out to the file */
  340.     if (iCount > 0) {
  341.         if ((iLines = strboxf(f, apszCells, aiWidth, iCount)) == -1) {
  342.             fprintf(stderr, "sig: memory allocation failure.\n");
  343.             exit(1);
  344.         } else if ((iLineLimit > 0) && (iLines > iLineLimit)) {
  345.             fprintf(stderr, "sig: warning: output has %d lines.\n", iLines);
  346.         }
  347.     }
  348.  
  349.     /* de-allocate any memory we allocated */
  350.     free(pszBuffer);
  351.     for (i = 0; i < iCount; i++)
  352.         if (abAllocated[i])
  353.             free(apszCells[i]);
  354.  
  355.     return (pszCurrent);
  356. }
  357.  
  358.  
  359. int SigQuoteTag(char *pszTag)
  360. /*
  361.  * Read information from a <quote> tag. This is *not* a real HTML tag;
  362.  * this is used for Quoteriser purposes only.
  363.  *
  364.  * char *pszTag        - the tag
  365.  *
  366.  * Returns        - the value of the COLSPAN attribute
  367.  *              0 if there is a problem
  368.  */
  369. {
  370.     char    *pch;            /* cursor */
  371.     char    szString[HTML_MAX_TAG];    /* working buffer */
  372.     char    szAttr[8];        /* attribute name */
  373.     int    i;            /* counter */
  374.  
  375.     /* find tag identifier */
  376.     pch = pszTag + 1;
  377.     while (isspace(*pch))
  378.         pch++;
  379.  
  380.     /* check that this *is* a quote tag */
  381.     i = 0;
  382.     while (!isspace(*pch) && ((*pch) != '>')) {
  383.         szString[i++] = (*pch);
  384.         pch++;
  385.     }
  386.     szString[i] = '\0';
  387.     if (strcmpci(szString, "QUOTE") != 0)
  388.         /* not a <quote> tag */
  389.         return (0);
  390.  
  391.     /* look for COLSPAN attribute */
  392.     i = 0;
  393.     pch = HTMLAttrFirst(pszTag, szAttr, sizeof(szAttr), szString, sizeof(szString));
  394.     while (pch != NULL) {
  395.         if (strcmpci(szAttr, "COLSPAN") == 0)
  396.             i = atoi(szString);
  397.         pch = HTMLAttrNext(pch, szAttr, sizeof(szAttr), szString, sizeof(szString));
  398.     }
  399.  
  400.     return (i);
  401. }
  402.  
  403.  
  404. char *SigRandomQuote(QUOTEDB *pqdb, AUTHORDB *padb, int iWidth, int flMode)
  405. /*
  406.  * Choose and typeset a random quote. Memory for the quote will be
  407.  * allocated.
  408.  *
  409.  * QUOTEDB *pqdb    - quote database to get quote from
  410.  * AUTHORDB *padb    - author database to get author from
  411.  * int flMode        - output format flags
  412.  * int iWidth        - width to typeset quote in
  413.  *
  414.  * Returns    - a pointer to the quote
  415.  *          NULL if there is a problem
  416.  */
  417. {
  418.     QUOTESEARCH    qs;            /* for searching the database */
  419.     QUOTEINFO    *pqi;            /* quote to print */
  420.     AUTHORINFO    *pai;            /* author to print */
  421.     int        iQuote;            /* number of quote to choose */
  422.     int        bPrintAuthor;        /* print author's name? */
  423.     int        bPrintSource;        /* print quote source? */
  424.     char        *pszText;        /* quote text */
  425.     char        *apszTypeset[3];    /* strings to typeset */
  426.     char        szString[210];        /* working buffer */
  427.     int        i;            /* counter */
  428.     char        *pszRet;        /* return value */
  429.     static int    iCount = -1;        /* number of quotes in the database */
  430.  
  431.     if (iCount == -1) {
  432.            /* count the number of quotes in the database */
  433.         iCount = 0;
  434.         if (QuoteFullSearchInit(pqdb, &qs)) {
  435.             iCount++;
  436.             while (QuoteFullSearchNext(&qs))
  437.                 iCount++;
  438.         }
  439.         QuoteFullSearchEnd(&qs);
  440.     }
  441.  
  442.     if (iCount == 0) {
  443.         /* empty database */
  444.         return (NULL);
  445.     }
  446.  
  447.     /* choose a random quote */
  448.     if (iCount > 1) {
  449.         iQuote = rand() % iCount;
  450.     } else
  451.         iQuote = 0;
  452.     for (QuoteFullSearchInit(pqdb, &qs), i = 0; i < iQuote; QuoteFullSearchNext(&qs), i++);
  453.     QuoteFullSearchEnd(&qs);
  454.  
  455.     /* initialise the typeset array to be empty */
  456.     for (i = 0; i < 3; i++)
  457.         apszTypeset[i] = NULL;
  458.  
  459.     /* decide on what to print */
  460.     bPrintAuthor = 0;
  461.     bPrintSource = 0;
  462.     if (!QuoteGetQuote(pqdb, qs.szLastCode, &pqi, &pszText)) {
  463.         fprintf(stderr, "sig: memory allocation failure\n");
  464.         exit(1);
  465.     }
  466.     if (flMode & QSIG_FLAUTHOR) {
  467.         if (padb->dbfInfo != NULL)
  468.             if (AuthorGetAuthor(padb, pqi->szAuthorCode, &pai, NULL))
  469.                 bPrintAuthor = 1;
  470.         if (!bPrintAuthor && (flMode & QSIG_FLFALLBACK))
  471.                 bPrintSource = strlen(pqi->szSource) > 0;
  472.     }
  473.     if (flMode & QSIG_FLSOURCE) {
  474.         bPrintSource = strlen(pqi->szSource) > 0;
  475.         if (!bPrintSource && (flMode & QSIG_FLFALLBACK))
  476.             if (padb->dbfInfo != NULL)
  477.                 if (AuthorGetAuthor(padb, pqi->szAuthorCode, &pai, NULL))
  478.                     bPrintAuthor = 1;
  479.     }
  480.     if (pszText != NULL)
  481.         apszTypeset[0] = pszText;
  482.  
  483.     /* typeset the quote */
  484.     if (bPrintAuthor || bPrintSource)  {
  485.         strcpy(szString, "<p>- ");
  486.         if (bPrintAuthor) {
  487.             strcat(szString, pai->szGivenName);
  488.             if ((strlen(pai->szSurname) > 0) && (strlen(pai->szGivenName) > 0))
  489.                 strcat(szString, " ");
  490.             strcat(szString, pai->szSurname);
  491.         }
  492.         if (bPrintAuthor && bPrintSource)
  493.             strcat(szString, ", ");
  494.         if (bPrintSource) {
  495.             strcat(szString, "<i>");
  496.             strcat(szString, pqi->szSource);
  497.             strcat(szString, "</i>");
  498.         }
  499.         apszTypeset[1] = szString;
  500.     }
  501.     pszRet = TypesetASCII(apszTypeset, iWidth);
  502.  
  503.     /* de-allocate memory */
  504.     QuoteFreeQuote(&pqi, &pszText);
  505.     if (bPrintAuthor)
  506.         AuthorFreeAuthor(&pai, NULL);
  507.  
  508.     return (pszRet);
  509. }
  510.