home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / TEXT / UTILITY / TEABD100.ZIP / TEABUILD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-12  |  8.2 KB  |  335 lines

  1. /*
  2.  * TEA database builder
  3.  *
  4.  * Version 0.90
  5.  *
  6.  * Usage: TEABUILD <ascii_input_file>
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12. #include <stdlib.h>
  13.  
  14. typedef int Boolean;
  15. #define False           (0)
  16. #define True            (!False)
  17.  
  18. #define LENMIN          1
  19. #define LENMAX          40
  20.  
  21. #define BUFMAX          1024
  22.  
  23. #define OFFSETMAX       0x7
  24.  
  25. #define CODE_APOSTROPHE '{'
  26. #define CODE_CAP        '|'
  27. #define CODE_HYPHEN     '}'
  28. #define CODE_SPACE      '~'
  29.  
  30. #define OUTPUT_PREFIX   "words"
  31.  
  32. /*
  33.  * Cache of the encode state for all the different entry lengths required.
  34.  * The program can work with fewer file handles than the number of output
  35.  * files it is writing, if necessary.
  36.  */
  37. typedef struct  _encodeState {
  38.     struct _encodeState *next;
  39.     struct _encodeState *prev;
  40.     FILE                *fp;
  41.     Boolean             created;
  42.     char                frame[LENMAX+1];
  43.     int                 offset;
  44. } EncodeState;
  45.  
  46. EncodeState encodeStateCache[LENMAX];
  47. struct _encodeState *encodeStateCacheHead;
  48.  
  49. static void output(fp, code, offset)
  50. FILE *fp;
  51. int code;
  52. int offset;
  53. {
  54.     /*
  55.      * Output a single encoded character or modifier
  56.      */
  57.  
  58.     if (fputc(offset | ((code - 'a') << 3), fp) == EOF)
  59.     {
  60.         fprintf(stderr, "Error writing output file\n");
  61.         exit(1);
  62.     }
  63. }
  64.  
  65. static void openall()
  66. {
  67.     /*
  68.      * Initialise all the encode state structures
  69.      */
  70.     EncodeState *esp;
  71.  
  72.     encodeStateCacheHead = NULL;
  73.  
  74.     for (esp = encodeStateCache; esp < (encodeStateCache+LENMAX); esp++)
  75.     {
  76.         esp->next = NULL;
  77.         esp->prev = NULL;
  78.         esp->fp = NULL;
  79.         esp->created = False;
  80.         memset(esp->frame, '\0', sizeof(esp->frame));
  81.         esp->offset = 0;
  82.     }
  83. }
  84.  
  85. static EncodeState *encache(len)
  86. int len;
  87. {
  88.     /*
  89.      * Ensure the output file associated with entries of length 'len'
  90.      * is open and return a pointer to its encode state.
  91.      */
  92.     EncodeState *esp = &encodeStateCache[len-1], *espOld;
  93.     char *type;
  94.     char outputname[BUFMAX];
  95.  
  96.     if (esp->fp == NULL)
  97.     {
  98.         /* file must be (re-)opened */
  99.  
  100.         /* get output file name */
  101.         sprintf(outputname, "%s.%d", OUTPUT_PREFIX, len);
  102.  
  103.         /* get output file open mode */
  104.         type = esp->created ? "ab" : "wb";
  105.         esp->created = True;
  106.  
  107.         /* try opening the file; on error, close the file handle
  108.            for the least recently used entry length and try again */
  109.         while ((esp->fp = fopen(outputname, type)) == NULL)
  110.         {
  111.             if (encodeStateCacheHead == NULL)
  112.             {
  113.                 fprintf(stderr, "Couldn't open \"%s\"\n", outputname);
  114.                 exit(1);
  115.             }
  116.  
  117.             espOld = encodeStateCacheHead->prev;
  118.             fclose(espOld->fp);
  119.  
  120.             if (espOld == encodeStateCacheHead)
  121.             {
  122.                 /* only entry in cache */
  123.                 encodeStateCacheHead = NULL;
  124.                 espOld->next = NULL;
  125.                 espOld->prev = NULL;
  126.                 esp->fp = NULL;
  127.             }
  128.             else
  129.             {
  130.                 /* other entries in cache */
  131.                 espOld->prev->next = espOld->next;
  132.                 espOld->next->prev = espOld->prev;
  133.                 espOld->next = NULL;
  134.                 espOld->prev = NULL;
  135.                 espOld->fp = NULL;
  136.             }
  137.         }
  138.  
  139.         /* add the entry to the front of the cache */
  140.         if (encodeStateCacheHead == NULL)
  141.         {
  142.             esp->next = esp;
  143.             esp->prev = esp;
  144.         }
  145.         else
  146.         {
  147.             esp->next = encodeStateCacheHead;
  148.             esp->prev = encodeStateCacheHead->prev;
  149.         }
  150.         encodeStateCacheHead = esp;
  151.  
  152.         esp->next->prev = esp;
  153.         esp->prev->next = esp;
  154.     }
  155.     else if (esp != encodeStateCacheHead)
  156.     {
  157.         /* remove entry from current position */
  158.         esp->prev->next = esp->next;
  159.         esp->next->prev = esp->prev;
  160.  
  161.         /* add entry at front of cache */
  162.         esp->next = encodeStateCacheHead;
  163.         esp->prev = encodeStateCacheHead->prev;
  164.         encodeStateCacheHead = esp;
  165.  
  166.         esp->next->prev = esp;
  167.         esp->prev->next = esp;
  168.     }
  169.  
  170.     return(esp);
  171. }
  172.  
  173. static void closeall()
  174. {
  175.     /*
  176.      * Flush the encode states through. A special case must be dealt
  177.      * with where the alphabetic characters of the last word are identical
  178.      * to those of the penultimate word and the last word has no
  179.      * "modifiers" (space, hyphen, apostrophe, shift). In this case,
  180.      * a "redundant" character must be output to ensure the last word
  181.      * is unambigously represented in the output file.
  182.      */
  183.     EncodeState *esp;
  184.     int i;
  185.  
  186.     for (i = 0; i < LENMAX; i++)
  187.     {
  188.         if (    encodeStateCache[i].created
  189.              && encodeStateCache[i].offset > i)
  190.         {
  191.             /* last entry must be flushed through */
  192.             esp = encache(i+1);
  193.             output(esp->fp, esp->frame[0], 0);
  194.         }
  195.     }
  196.  
  197.     /* close any open files */
  198.     if ((esp = encodeStateCacheHead) != NULL)
  199.     {
  200.         do
  201.         {
  202.             fclose(esp->fp);
  203.             esp = esp->next;
  204.         } while (esp != encodeStateCacheHead);
  205.     }
  206. }
  207.  
  208. static void encode(entry)
  209. char *entry;
  210. {
  211.     /*
  212.      * Add a single entry to the appropriate output file
  213.      */
  214.     char word[BUFMAX], *wp;
  215.     int cursor, wordlength;
  216.     EncodeState *esp;
  217.  
  218.     /* convert the word into lower case + modifiers */
  219.     wp = word;
  220.     wordlength = 0;
  221.     for ( ; *entry != '\0'; entry++)
  222.     {
  223.         if (*entry == ' ')
  224.         {
  225.             *wp++ = CODE_SPACE;
  226.         }
  227.         else if (*entry == '\'')
  228.         {
  229.             *wp++ = CODE_APOSTROPHE;
  230.         }
  231.         else if (*entry == '-')
  232.         {
  233.             *wp++ = CODE_HYPHEN;
  234.         }
  235.         else if (isalpha(*entry))
  236.         {
  237.             if (isupper(*entry))
  238.             {
  239.                 *wp++ = CODE_CAP;
  240.                 *wp++ = tolower(*entry);
  241.             }
  242.             else
  243.             {
  244.                 *wp++ = *entry;
  245.             }
  246.             wordlength++;
  247.         }
  248.     }
  249.     *wp = '\0';
  250.  
  251.     if (wordlength <= LENMAX)
  252.     {
  253.         /* ensure the handle to the output file is available */
  254.         esp = encache(wordlength);
  255.  
  256.         cursor = 0;
  257.         for (wp = word; *wp != '\0'; wp++)
  258.         {
  259.             /* check if a modifier needs to be output */
  260.             if (*wp >= CODE_APOSTROPHE)
  261.             {
  262.                 if (cursor < wordlength)
  263.                 {
  264.                     output(esp->fp, *wp, esp->offset);
  265.                     esp->offset = 0;
  266.                 }
  267.             }
  268.             /* check if a letter need to be output */
  269.             else if (    (*wp != esp->frame[cursor])
  270.                       || (esp->offset == OFFSETMAX) )
  271.             {
  272.                 output(esp->fp, *wp, esp->offset);
  273.                 esp->offset = 0;
  274.  
  275.                 esp->frame[cursor++] = *wp;
  276.             }
  277.             else
  278.             {
  279.                 esp->offset++;
  280.                 cursor++;
  281.             }
  282.         }
  283.     }
  284.     else
  285.     {
  286.         fprintf(stderr, "Skipping long entry\n");
  287.     }
  288. }
  289.  
  290. main(argc, argv)
  291. int argc;
  292. char *argv[];
  293. {
  294.     char linebuf[BUFMAX], *lbp;
  295.     FILE *ifp;
  296.  
  297.     /* check usage */
  298.     if (argc != 2)
  299.     {
  300.         fprintf(stderr, "Usage: TEABUILD <ascii_input_file>\n");
  301.         exit(1);
  302.     }
  303.  
  304.     /* open ASCII input file */
  305.     if ((ifp = fopen(argv[1], "r")) == NULL)
  306.     {
  307.         fprintf(stderr, "Couldn't open \"%s\" for input\n", argv[1]);
  308.         exit(1);
  309.     }
  310.  
  311.     /* initialise the encode state cache */
  312.     openall();
  313.  
  314.     /* do a single pass of the input file, presenting each line
  315.        as an entry to be encoded */
  316.     while (fgets(linebuf, sizeof(linebuf), ifp) != NULL)
  317.     {
  318.         if ((lbp = strchr(linebuf, '\n')) == NULL)
  319.         {
  320.             fprintf(stderr, "Skipping long entry\n");
  321.         }
  322.         else
  323.         {
  324.             /* delete the newline */
  325.             *lbp = '\0';
  326.             encode(linebuf);
  327.         }
  328.     }
  329.  
  330.     /* flush the encode state cache */
  331.     closeall();
  332.  
  333.     return(0);
  334. }
  335.