home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 360_01 / uspell.c < prev    next >
Text File  |  1992-02-16  |  8KB  |  427 lines

  1. /*    uspell - UNIX spell checker
  2.  
  3.     based on spell.c by Kenji Hino
  4. */
  5.  
  6. #include <termio.h>
  7. #include <fcntl.h>
  8. #include <ctype.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/statfs.h>
  12.  
  13. #define MAXWORD        30    /* The maximum number of chars per word */
  14. #define MAXLINE        100    /* The maximum number of chars per line */
  15. #define GRANULE    16        /* index granularity            */
  16.  
  17. struct    stat    stats;
  18. struct    termio    termio;
  19.  
  20. struct    wpspcl    *wpspcl;
  21.  
  22. extern    int    errno;
  23.  
  24. unsigned    char    flag;    /* suffix flags                */
  25.  
  26. int    txtfil,            /* file descriptor for text file    */
  27.     dctfil,            /* file descriptor for dictionary    */
  28.     idxfil,            /* file descriptor for index file    */
  29.     nbad,            /* number of bad word entries allocated    */
  30.     lastbad,        /* next available bad word entry    */
  31.     cmpval;            /* result of last word compare        */
  32.     
  33. struct idx
  34.     {
  35.     unsigned char    *key;
  36.     long    addr;
  37.     };
  38.  
  39. struct    suffix
  40.     {
  41.     char    *value;
  42.     int    length;
  43.     };
  44.  
  45. struct    suffix    suffix[]=
  46.     {
  47.     {"ers",3},
  48.     {"ing",3},
  49.     {"ed",2},
  50.     {"er",2},
  51.     {"es",2},
  52.     {"ly",2},
  53.     {"d",1},
  54.     {"s",1},
  55.     0
  56.     };
  57.  
  58. struct    idx    *idx, *first, *last;
  59. struct    idx    *idxptr;
  60. struct    idx    *idxend;
  61. struct    idx    *lastidx;
  62. struct    idx    *badword;
  63.  
  64. char *malloc();
  65. char *filename;
  66.  
  67. main(argc,argv)
  68.     int argc;
  69.     char **argv;
  70.     {
  71.     long    addr;
  72.     int    x, savflg, i, dirsize;
  73.     unsigned    char    *direct, *dirend, *dirptr, *cp1;
  74.  
  75.     ioctl(0,TCGETA,&termio);
  76.     savflg=termio.c_oflag;
  77.     termio.c_oflag=OPOST+ONLCR+TAB3;
  78.     ioctl(0, TCSETA, &termio);
  79.     idxend=idx=(struct idx *) malloc((sizeof *idx)*(43000/GRANULE));
  80.     if ((idxfil = open("wpdict.idx", O_RDONLY)) == -1)
  81.         cant("wpdict.idx");
  82.  
  83.     fstat(idxfil,&stats);
  84.     dirsize=stats.st_size;
  85.     direct=(unsigned char *) malloc(dirsize);
  86.     dirend=direct+dirsize;
  87.     read(idxfil,direct,dirsize);
  88.     for (dirptr=direct; dirptr<dirend;)
  89.         {
  90.         for(cp1=dirptr; *cp1; cp1++);
  91.         cp1++;
  92.         addr=*cp1;
  93.         cp1++;
  94.         addr+=*cp1*256;
  95.         cp1++;
  96.         addr+=*cp1*65536;
  97.         cp1++;
  98.         idxend->key=dirptr;
  99.         idxend->addr=addr;
  100.         idxend++;
  101.         dirptr=cp1;
  102.         }
  103.  
  104.     lastidx=idxend;
  105.     lastidx--;
  106.     dctfil=open("wpdict.dat", O_RDONLY);
  107.     if (dctfil<0) cant("wpdict.dat");
  108.     argv++;
  109.     filename=*argv;
  110.     if ((txtfil = open(filename,O_RDONLY)) == -1)
  111.         cant(*argv);
  112.     else
  113.         {
  114.         dospel();
  115.         close(txtfil);
  116.         }
  117.  
  118.     termio.c_oflag=savflg;
  119.     ioctl(0,TCSETAW,&termio);    /* restore terminal settings */
  120.     }
  121.  
  122. dospel() /* do spell checking */
  123.     {
  124.     struct    idx    *idxpt2;
  125.     int    i, i2, j, start, end, size, iferr, spelled, suflen;
  126.     int    txtsize;
  127.     unsigned    char    word8[MAXWORD];
  128.     unsigned    char    word5[MAXWORD];
  129.     unsigned    char    word52[MAXWORD];
  130.     char    *txt, *txtptr, *txtend;
  131.     char    *cp1, *cp2, *cp3;
  132.     char    errbuf[MAXLINE];
  133.     char    c;
  134.  
  135.     fstat(txtfil,&stats);
  136.     txtsize=stats.st_size;
  137.     txt=malloc(txtsize);
  138.     txtend=txt+txtsize;
  139.     read(txtfil,txt,txtsize);
  140.     for (txtptr=txt; txtptr<txtend;)
  141.         {
  142.         for(cp1=txtptr, cp2=errbuf; *cp1!='\n'; cp1++, cp2++)
  143.             if (*cp1=='\t')
  144.                 *cp2='\t';
  145.             else
  146.                 *cp2=' ';
  147.  
  148.         *cp2++=*cp1++;
  149.         display_line(txtptr,cp1-txtptr);
  150.         iferr=-1;
  151.         start=end=0;
  152.         cp2=txtptr;
  153.         size=skipwhite(cp2);
  154.         cp2+=size;
  155.         while (cp2<cp1)
  156.             {
  157.             size=gtword(cp2);
  158.             sstor5(cp2,0,size,word5);
  159.             binsrc(word5);
  160.             if (!cmpval)
  161.                 spelled=1;
  162.             else
  163.                 spelled=srcfwd(word5);
  164.  
  165.             idxpt2=idxptr;
  166.             for (i=0, suflen=0; suffix[i].length && !spelled; i++)
  167.                 {
  168.                 if(size>suffix[i].length
  169.                     && strncmp(cp2+(size-suffix[i].length),
  170.                     suffix[i].value,
  171.                     suffix[i].length)==0)
  172.                     {
  173.                     suflen=suffix[i].length;
  174.                     sstor5(cp2,0,size-suflen,word52);
  175.                     idxptr=idxpt2;
  176.                     i2=srcbak(word52,1);
  177.                     if (i2 && flag&(1<<i)) spelled=1;
  178.                     }
  179.                 }
  180.  
  181.             if (!spelled
  182.                 && size>2
  183.                 && cp2[start+size-2]=='\''
  184.                 && cp2[start+size-1]=='s')
  185.                 {
  186.                 sstor5(cp2,0,size-2,word52);
  187.                 spelled=srcbak(word52,0);
  188.                 }
  189.  
  190.             if (!spelled)
  191.                 {
  192. /*                savbad(word5);*/
  193.                 iferr=1;
  194.                 cp3=errbuf+(cp2-txtptr);
  195.                 for(i=0; i<size; i++) *cp3++='*';
  196.                 }
  197.  
  198.             cp2+=size;
  199.             size=skipwhite(cp2);
  200.             cp2+=size;
  201.             }
  202.  
  203.         if (iferr==1) display_line(errbuf,cp1-txtptr);
  204.         txtptr=cp1;
  205.         }
  206.     }
  207.  
  208. skipwhite(cp1)
  209.     char    *cp1;
  210.     {
  211.     char    *cp2;
  212.  
  213.     for (cp2=cp1; !isalpha(*cp2) && *cp2!='\'' && *cp2!='\n'; cp2++);
  214.     if (*cp2=='\n') cp2++;
  215.     return(cp2-cp1);
  216.     }
  217.  
  218. gtword(cp1)
  219.     char    *cp1;
  220.     {
  221.     char    *cp2;
  222.  
  223.     for (cp2=cp1; isalpha(*cp2) || *cp2=='\''; cp2++);
  224.     return(cp2-cp1);
  225.     }
  226.  
  227. srcbak(word)
  228.     char    *word;
  229.     {
  230.     for(; r5cmp(word,idxptr->key)<0 && idxptr > idx; idxptr--);
  231.         if (idxptr == idx) return 0;
  232.     return(srcfwd(word));
  233.     }
  234.  
  235. int srcfwd(word)
  236.     char    *word;
  237.     {
  238.     struct    statfs    statfs;
  239.     static    int    gransize=MAXWORD*GRANULE;
  240.     static    int    blksiz;
  241.     int    cmp, dctsiz, dctblk, mapsiz, addr, startblk, endblk;
  242.     unsigned    char    buf[MAXWORD][GRANULE];
  243.     static    unsigned    char    *dict, *map;
  244.     unsigned    char    *cp1, *cp2;
  245.     unsigned    char    mask;
  246.  
  247.     if (!dict)
  248.         {
  249.         fstat(dctfil,&stats);
  250.         dctsiz=stats.st_size;
  251.         dict=(unsigned char *) malloc(dctsiz);
  252.         fstatfs(txtfil,&statfs,sizeof(statfs),0);
  253.         blksiz=statfs.f_bsize;
  254.         dctblk=(dctsiz/blksiz)+1;
  255.         mapsiz=(dctblk/8)+1;
  256.         map=(unsigned char *) calloc(1,mapsiz);
  257.         }
  258.  
  259.     addr=idxptr->addr;
  260.     startblk=addr/blksiz;
  261.     endblk=(addr+gransize)/blksiz;
  262.     cp1=map+(startblk/8);
  263.     mask=1<<(startblk%8);
  264.     if(!((*cp1)&mask))
  265.         {
  266.         lseek(dctfil,startblk*blksiz,0);
  267.         read(dctfil,dict+(startblk*blksiz),blksiz);
  268.         *cp1=(*cp1)|mask;
  269.         }
  270.  
  271.     if (startblk!=endblk)
  272.         {
  273.         cp1=map+(endblk/8);
  274.         mask=1<<(endblk%8);
  275.         if(!((*cp1)&mask))
  276.             {
  277.             lseek(dctfil,endblk*blksiz,0);
  278.             read(dctfil,dict+(endblk*blksiz),blksiz);
  279.             *cp1=(*cp1)|mask;
  280.             }
  281.         }
  282.  
  283.     for (cp1=dict+addr, cp2=dict+addr+gransize; cp1<cp2;)
  284.         {
  285.         if ((cmp=r5cmp(word,cp1))==0)
  286.             {
  287.             for(; *cp1; cp1++);
  288.             cp1++;
  289.             flag=*cp1;
  290.             return(1);
  291.             }
  292.         else if (cmp < 0)
  293.             {
  294.             return(0);
  295.             }
  296.  
  297.         for (; *cp1; cp1++);
  298.         cp1++;
  299.         cp1++;
  300.         }
  301.  
  302.     return(0);
  303.     }
  304.  
  305. int    binsrc(word)       /* do binary search */
  306.     char *word;
  307.     {
  308.     int    i;
  309.  
  310.     idxptr=idx;
  311.     cmpval=r5cmp(word,idx->key);
  312.     if (cmpval<=0) return;
  313.     idxptr=lastidx;
  314.     cmpval=r5cmp(word,lastidx->key);
  315.     if (cmpval>=0) return;
  316.     first=idx;
  317.     last=idxend;
  318.     while (last-first > 1)
  319.         {
  320.         idxptr=first+((last-first)/2);
  321. /*
  322.         idxptr=&idx[((((int) (first) - (int) (idx)) / sizeof(*idx))
  323.             + (((int) (last) - (int) (idx)) / sizeof(*idx))) /2];
  324. */
  325.         if ((cmpval=r5cmp(word,idxptr->key)) < 0)
  326.             last=idxptr;
  327.         else if (cmpval==0)
  328.             last=first=idxptr;
  329.         else if (cmpval>0)
  330.             first=idxptr;
  331.         }
  332.  
  333.     idxptr=first;
  334.     }
  335.  
  336. savbad(word)
  337.     char    *word;
  338.     {
  339.     unsigned    char    *str;
  340.  
  341.     if (!nbad)
  342.         {
  343.         nbad=256;
  344.         badword=(struct idx *) malloc((sizeof *badword)*nbad);
  345.         }
  346.     else if (lastbad==nbad)
  347.         {
  348.         nbad*=2;
  349.         badword=(struct idx *) realloc(badword,sizeof(*badword)*nbad);
  350.         }
  351.  
  352.     str=(unsigned char *) malloc(strlen(word)+1);
  353.     strcpy(str,word);
  354.     badword[lastbad++].key = str;
  355.     }
  356.  
  357. cant(name)
  358.     char    *name;
  359.     {
  360.  
  361.     write(1,"Can't open ",11);
  362.     write(1,name,strlen(name));
  363.     write(1,"\n",1);
  364.     exit(1);
  365.     }
  366.  
  367. errormes(message)
  368.     char    *message;
  369.     {
  370.     write(1,message,strlen(message));
  371.     write(1,"\n",1);
  372.     }
  373.  
  374. display_line(line,length)
  375.     char    *line;
  376.     int    length;
  377.     {
  378.     write(1,line,length);
  379.     }
  380.  
  381. r5cmp(cp1,cp2)
  382.     unsigned    char    *cp1, *cp2;
  383.     {
  384.     for (; *cp1 && *cp2 && *cp1==*cp2; cp1++, cp2++);
  385.     return(*cp1-*cp2);
  386.     }
  387.  
  388. sstor5(cp1,disp,len1,cp2)
  389.     register    char    *cp1, *cp2;    /* buffer addresses    */
  390.     int        disp;            /* field displacement    */
  391.     register    int    len1;        /* field length        */
  392.     {
  393.     int    pos, len2;
  394.     char    c;
  395.  
  396.     cp1+=disp;
  397.     for (pos=1, len2=0; *cp1 && len2<len1; cp1++, pos++, len2++)
  398.         {
  399.         c=*cp1;
  400.         if (c=='\'')
  401.             c=1;
  402.         else
  403.             c=(c&31)+1;
  404.  
  405.         if (pos==1)
  406.             {
  407.             *cp2=c<<3;
  408.             }
  409.         else if (pos==2)
  410.             {
  411.             *cp2=*cp2|(c>>2);
  412.             cp2++;
  413.             *cp2=c<<6;
  414.             }
  415.         else
  416.             {
  417.             *cp2=*cp2|c;
  418.             cp2++;
  419.             pos=0;
  420.             }
  421.         }
  422.  
  423.     if (pos!=1) cp2++;
  424.     *cp2=0;
  425.     }
  426.  
  427.