home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / philspell-1.0 / part01 / main.c next >
C/C++ Source or Header  |  1993-05-01  |  8KB  |  264 lines

  1. /*
  2.  *
  3.  * main.c for "philspell"
  4.  *
  5.  * This file is Copyright (c) 1992 Phillip "Edward" Nunez.  Phillip grants
  6.  * you full permission to copy and distribute this code provided you do not
  7.  * interfere with any of the copyrights (c)s installed therein.
  8.  *
  9.  * Phillip grants permission to extract portions of this code for use in
  10.  * other code provided you give full credit to him in all documentation
  11.  * pertaining to your program, preserve copyrights in files from which code
  12.  * is extracted, and put his name in your program's output.
  13.  *
  14.  *
  15.  * This header automatically generated by the UNIX program philcopyright,
  16.  * Copyright (c) 1991 Phillip "Edward" Nunez.  For information regarding
  17.  * philcopyright, mail phillip@soda.berkeley.edu.
  18.  *
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23.  
  24. #include "skiplist.h"
  25.  
  26. static char philSCCSid[] = "@(#)main.c          1.0     Phillip `Edward' Nunez";
  27.  
  28. #define DEFAULT_FILENAME "/usr/dict/words"
  29. #define SKIPMAX 16
  30.  
  31. static char  scratchbuf[BUFSIZ];
  32. static char *philsProgramName;
  33.  
  34. static char *philExists = "Phillip \"Edward\" Nunez";
  35.  
  36. typedef skipnode philSkipNode;
  37. typedef skipnode philSkipList;
  38.  
  39. char *suffixes[] = {
  40.     "ive", /**/ "ion", "tion", "en", /**/ "ions", "ications", "ens", /**/
  41.     "th", "ieth", /**/ "ly", /**/ "ing", /**/ "ings", /**/ "ed", /**/
  42.     "est", /**/ "er", /**/ "ers", /**/ "ers", /**/ "s", "es", "ies", /**/
  43.     "ness", "iness", /****/ "ment", "al", "ally", "able", "speak"
  44. };
  45. unsigned int *suffix_lens;
  46.  
  47. char *prefixes[] = {
  48.     "non", "anti", "un", "in", "re", "en", "ex", "im", "de", "phil"
  49. };
  50. unsigned int *prefix_lens;
  51.  
  52. char *muties[] = {
  53.     "able", "tion", "sion", "tion", "ing", "ily", "ed", "ier", "ly", "tions",
  54.     "tions", "ies", "ied"
  55. };
  56. char *mutie_results[] = {
  57.     "e",    "te",   "de",   "t",    "e",   "y",   "e",  "y",   "le", "tion",
  58.     "te",   "y",    "y"
  59. };
  60. unsigned int *mutie_lens;
  61.  
  62. /*
  63.  * Someone actually had the nerve to tell me today that the "right" way to
  64.  * impelment all the lists of prefixes and suffixes and stuff was to use
  65.  * a backward-indexed trie with type/data records stored at the nodes.  I
  66.  * think that's really dumb because who wants to spell all their words
  67.  * backwards?
  68.  * 
  69.  * She said this part of the program was really pathetic because it was O(n).
  70.  * But I like O(N)-- N for Nunez!  That starts with N and that's next to O and
  71.  * that's next to P and that stands for "Pool" and that rhymes with "Cool!"
  72.  *
  73.  *                                                         -Phillip
  74.  */
  75.  
  76. #define NUMSUFFIXES (sizeof(suffixes) / sizeof(char *))
  77. #define NUMPREFIXES (sizeof(prefixes) / sizeof(char *))
  78. #define NUMMUTIES   (sizeof(muties)   / sizeof(char *))
  79.  
  80. unsigned int funny = 0;
  81.  
  82. void philPerror(char *s) {
  83.     fprintf(stderr, "Error in Phillip's program \"%s\":\n>\t%s\n",
  84.                 philsProgramName, s);
  85. }
  86.  
  87. char *philLowerizeAndStrdup(char *t) {
  88.     unsigned int len = strlen(t);
  89.     char *start, *s;
  90.  
  91.     start = s = (char *)malloc(len + 1);
  92.  
  93.     do *s++ = (isupper(*t) ? tolower(*t) : *t);
  94.         while (*t++);
  95.  
  96.     return start;
  97. }
  98.  
  99. philSkipNode philLookupNoPrefix(char *word, philSkipList list) {
  100.     philSkipNode n;
  101.     unsigned int i, l, m;
  102.     char newtrybuf[BUFSIZ];
  103.  
  104.     n = skip_lookup(word, list, SKIPMAX, NULL);
  105.  
  106.     if (!n) {
  107.         i = 0;
  108.     l = strlen(word);
  109.     while (!n && (i < NUMSUFFIXES)) {
  110.         if (l > (m = suffix_lens[i])) {
  111.             if (strcasecmp(word + (l - m), suffixes[i]) == 0) {
  112.             strncpy(newtrybuf, word, l - m);
  113.             newtrybuf[l - m] = '\0';
  114.             if (funny) printf("\nTrying suffix '%s':  %s -> %s\n",
  115.                           suffixes[i], word, newtrybuf);
  116.             n = skip_lookup(newtrybuf, list, SKIPMAX, NULL);
  117.         }
  118.         }
  119.         i++;
  120.     }
  121.         if (!n) {
  122.         i = 0;
  123.         while (!n && (i < NUMMUTIES)) {
  124.             if (l > (m = mutie_lens[i])) {
  125.             if (strcasecmp(word + (l - m), muties[i]) == 0) {
  126.                 strncpy(newtrybuf, word, l - m);
  127.                 strcpy(newtrybuf + l - m, mutie_results[i]);
  128.             if (funny) printf("\nTrying mutie '%s/%s': %s -> %s\n",
  129.                       muties[i], mutie_results[i],
  130.                       word, newtrybuf);
  131.             n = skip_lookup(newtrybuf, list, SKIPMAX, NULL);
  132.             }
  133.         }
  134.         i++;
  135.         }
  136.     }
  137.     }
  138.     return n;
  139. }
  140.  
  141. void philSpellCheckWord(char *word, philSkipList list) {
  142.     philSkipNode n;
  143.     unsigned int i, l, m;
  144.     char newtrybuf[BUFSIZ];
  145.  
  146.     n = skip_lookup(word, list, SKIPMAX, NULL);
  147.  
  148.     if (!n) {
  149.         i = 0;
  150.     l = strlen(word);
  151.     while (!n && (i < NUMPREFIXES)) {
  152.         if (l > (m = prefix_lens[i])) {
  153.             if (strncasecmp(word, prefixes[i], m) == 0) {
  154.             strcpy(newtrybuf, word + m);
  155.             if (funny) printf("\nTrying prefix '%s':  %s -> %s\n",
  156.                       prefixes[i], word, newtrybuf);
  157.             n = philLookupNoPrefix(newtrybuf, list);
  158.         }
  159.         }
  160.         i++;
  161.     }
  162.     if (!n) n = philLookupNoPrefix(word, list);
  163.     }
  164.     fprintf(stdout, "%s%s", word, n ? "" : " (sic)");
  165. }
  166.  
  167. void philSpellCheck(philSkipList list) {
  168.     char *res;
  169.     char wordbuf[BUFSIZ], *s;
  170.  
  171.     while (res = gets(scratchbuf)) {
  172.     while (*res) {
  173.         while (*res && !isalpha(*res)) fputc(*res++, stdout);
  174.         s = wordbuf;
  175.         while (isalpha(*res)) *s++ = *res++;
  176.         *s = '\0';
  177.         if (*wordbuf) philSpellCheckWord(wordbuf, list);
  178.     }
  179.     fputc('\n', stdout);
  180.     }
  181. }
  182.  
  183. void philLoadAndGo(FILE *f) {
  184.     philSkipList s = skip_create(SKIPMAX);
  185.     unsigned int i;
  186.  
  187.     suffix_lens = (unsigned int *)malloc(NUMSUFFIXES * sizeof(char *));
  188.     i = 0;
  189.     while (i < NUMSUFFIXES) (suffix_lens[i] = strlen(suffixes[i])), i++;
  190.  
  191.     prefix_lens = (unsigned int *)malloc(NUMPREFIXES * sizeof(char *));
  192.     i = 0;
  193.     while (i < NUMPREFIXES) (prefix_lens[i] = strlen(prefixes[i])), i++;
  194.  
  195.     mutie_lens = (unsigned int *)malloc(NUMMUTIES * sizeof(char *));
  196.     i = 0;
  197.     while (i < NUMMUTIES) (mutie_lens[i] = strlen(muties[i])), i++;
  198.  
  199.     while (fgets(scratchbuf, BUFSIZ, f)) {
  200.         scratchbuf[strlen(scratchbuf) - 1] = '\0';
  201.         skip_add(philLowerizeAndStrdup(scratchbuf), philExists, s, SKIPMAX);
  202.     }
  203.  
  204.     fclose(f);
  205.  
  206.     philSpellCheck(s);
  207. }
  208.  
  209. static char *filename = DEFAULT_FILENAME;
  210.  
  211. void philParseCLA(int argc, char *argv[]) {
  212.     unsigned int n = 1;
  213.     char *s;
  214.  
  215.     while (n < argc) {
  216.         s = argv[n];
  217.     if (*s++ != '-') {
  218.         sprintf(scratchbuf, "Argument #%d doesn't start with a dash.", n);
  219.         philPerror(scratchbuf);
  220.     } else if (*s == 'v') funny = 1;
  221.       else if (*s == 'f') {
  222.           n++;
  223.           if (n == argc) philPerror("Missing filename for option f.");
  224.           else filename = argv[n];
  225.       } else {
  226.           sprintf(scratchbuf, "Unknown option: %s.", s);
  227.           philPerror(scratchbuf);
  228.       }
  229.     n++;
  230.     }
  231. }
  232.  
  233. void philMain(int argc, char *argv[]) {
  234.     FILE *f;
  235.  
  236.     philsProgramName = argv[0];
  237.  
  238.     philParseCLA(argc, argv);
  239.  
  240.     f = fopen(filename, "r");
  241.     if (f == NULL) {
  242.         sprintf(scratchbuf, "Unable to open file \"%s\".", filename);
  243.         philPerror(scratchbuf);
  244.     exit(1);
  245.     }
  246.  
  247.     philLoadAndGo(f);
  248.     exit(0);
  249. }
  250.  
  251.  
  252. void main(int argc, char *argv[]) {
  253.                                         /*        
  254.                                          *  This is just a hook to make the
  255.                                          *  program work even on compilers not
  256.                                          *  smart enough to make philMain()
  257.                                          *  the entry procedure instead of
  258.                      *  main(), when philMain() exists.
  259.                                          *  [gcc requires this, for example.]
  260.                                          *
  261.                                          */
  262.     philMain(argc, argv);
  263. }
  264.