Back to index

courier  0.68.2
ispell.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2006 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 /*
00008 */
00009 #include      "ispell.h"
00010 #include      <stdio.h>
00011 #include      <stdlib.h>
00012 #if    HAVE_CONFIG_H
00013 #include      <config.h>
00014 #endif
00015 
00016 #if    HAVE_UNISTD_H
00017 #include      <unistd.h>
00018 #endif
00019 
00020 #include      <sys/types.h>
00021 #if    HAVE_SYS_WAIT_H
00022 #include      <sys/wait.h>
00023 #endif
00024 
00025 #include      <signal.h>
00026 #include      <string.h>
00027 
00028 static pid_t ispell_pid;
00029 static RETSIGTYPE (*prevsighandler)(int);
00030 
00031 #ifndef       ISPELL
00032 #define       ISPELL "/usr/bin/ispell"
00033 #endif
00034 
00035 static void wait4pid()
00036 {
00037 int    waitstat;
00038 
00039        if (prevsighandler == SIG_DFL)
00040               while ( wait(&waitstat) != ispell_pid)
00041                      ;
00042 }
00043 
00044 static int fork_ispell(const char *ispellline, const char *dict,
00045                             struct ispell *isp)
00046 {
00047 int    fdbuf[2], fdbuf2[2];
00048 size_t l;
00049 int    waitstat;
00050 int    c;
00051 FILE   *ispell_resp;
00052 size_t ispell_resp_buf_size=0;
00053 const char *args[6];
00054 int    argn;
00055 
00056        isp->ispell_buf=0;
00057 
00058        prevsighandler=signal(SIGCHLD, SIG_DFL);
00059        signal(SIGCHLD, prevsighandler);
00060 
00061        if (pipe(fdbuf) < 0)
00062        {
00063               perror("pipe");
00064               return (-1);
00065        }
00066 
00067        switch (ispell_pid=fork())  {
00068        case -1:
00069               perror("fork");
00070               close(fdbuf[0]);
00071               close(fdbuf[1]);
00072               return (-1);
00073        case 0:
00074               if (pipe(fdbuf2) < 0) {
00075                      perror("pipe");
00076                      _exit(-1);
00077               }
00078 
00079               /*
00080               ** First child will fork and run the real ispell, and write to
00081               ** it on stdin.
00082               */
00083 
00084               switch (ispell_pid=fork())  {
00085               case -1:
00086                      perror("fork");
00087                      _exit(-1);
00088               case 0:
00089                      dup2(fdbuf2[0], 0);
00090                      dup2(fdbuf[1], 1);
00091                      close(fdbuf[0]);
00092                      close(fdbuf[1]);
00093                      close(fdbuf2[0]);
00094                      close(fdbuf2[1]);
00095                      argn=0;
00096                      args[argn++]="ispell";
00097                      args[argn++]="-a";
00098                      if (dict)
00099                      {
00100                             args[argn++]="-d";
00101                             args[argn++]=dict;
00102                      }
00103                      args[argn]=0;
00104                      execv(ISPELL, (char **)args);
00105                      perror("fork_ispell: execv " ISPELL);
00106                      _exit(1);
00107               }
00108               close(fdbuf[0]);
00109               close(fdbuf[1]);
00110               close(fdbuf2[0]);
00111               signal(SIGCHLD, SIG_DFL);
00112               l=strlen(ispellline);
00113               while (l)
00114               {
00115               int    n=write(fdbuf2[1], ispellline, l);
00116 
00117                      if (n <= 0)
00118                      {
00119                             perror("fork_ispell: write");
00120                             _exit(1);
00121                      }
00122                      ispellline += n;
00123                      l -= n;
00124               }
00125               if (write(fdbuf2[1], "\n", 1) != 1)
00126               {
00127                      perror("fork_ispell: write");
00128                      _exit(1);
00129               }
00130               close(fdbuf2[1]);
00131               while ( wait(&waitstat) != ispell_pid)
00132                      ;
00133               _exit(0);
00134        }
00135 
00136        close(fdbuf[1]);
00137        ispell_resp=fdopen(fdbuf[0], "r");
00138        if (!ispell_resp)
00139        {
00140               perror("fork_ispell: fdopen");
00141               close(fdbuf[0]);
00142               wait4pid();
00143               return (-1);
00144        }
00145 
00146        l=0;
00147 
00148        for (;;)
00149        {
00150               if (l >= ispell_resp_buf_size)
00151               {
00152               char   *newbuf;
00153               size_t l=ispell_resp_buf_size + BUFSIZ;
00154                      newbuf=isp->ispell_buf ? realloc(isp->ispell_buf, l)
00155                                    :malloc(l);
00156                      if (!newbuf)
00157                      {
00158                             perror("fork_ispell: malloc/realloc");
00159                             if (isp->ispell_buf) free(isp->ispell_buf);
00160                             isp->ispell_buf=0;
00161                             wait4pid();
00162                             fclose(ispell_resp);
00163                             return (-1);
00164                      }
00165                      isp->ispell_buf=newbuf;
00166                      ispell_resp_buf_size=l;
00167               }
00168 
00169               if ( (c=getc(ispell_resp)) == EOF )
00170                      break;
00171 
00172               isp->ispell_buf[l++]=c;
00173        }
00174 
00175        isp->ispell_buf[l]=0;
00176        fclose(ispell_resp);
00177        wait4pid();
00178        return (0);
00179 }
00180 
00181 struct ispell *ispell_run(const char *dict, const char *line)
00182 {
00183 char   *p, *q;
00184 struct ispell *isp;
00185 struct ispell_misspelled **islistptr, *ip;
00186 int    c;
00187 int    nmisses;
00188 struct ispell_suggestion **sp;
00189 
00190        if ((isp=(struct ispell *)malloc(sizeof(struct ispell))) == 0)
00191        {
00192               perror("malloc");
00193               return (0);
00194        }
00195        isp->ispell_buf=0;
00196        isp->first_misspelled=0;
00197        islistptr=&isp->first_misspelled;
00198 
00199        if (fork_ispell(line, dict, isp))
00200        {
00201               ispell_free(isp);
00202               fprintf(stderr, "ERR: ispell_run: fork_ispell failed\n");
00203               return (0);
00204        }
00205 
00206        if ((p=strchr(isp->ispell_buf, '\n')) == 0)
00207        {
00208               fprintf(stderr, "ERR: ispell_run: incomplete result from ispell\n");
00209               ispell_free(isp);
00210               return (0);
00211        }
00212        ++p;
00213        q=0;
00214        islistptr= &isp->first_misspelled;
00215        for ( ; p && *p != '\n'; p=q)
00216        {
00217               if ((q=strchr(p, '\n')) != 0)
00218                      *q++=0;
00219 
00220               if ( *p != '&' && *p != '?' && *p != '#') continue;
00221 
00222               if ( (ip=*islistptr=(struct ispell_misspelled *)
00223                      malloc(sizeof(struct ispell_misspelled))) == 0)
00224               {
00225                      perror("malloc");
00226                      ispell_free(isp);
00227                      return (0);
00228               }
00229 
00230               ip->next=0;
00231               islistptr= &ip->next;
00232 
00233               c=*p++;
00234               while (*p == ' ')    ++p;
00235               ip->misspelled_word=p;
00236               while (*p && *p != ' ')     ++p;
00237               if (*p)       *p++=0;
00238 
00239               nmisses=0;
00240               while (*p == ' ')    ++p;
00241               if (c == '&' || c == '?')
00242               {
00243                      while (*p >= '0' && *p <= '9')
00244                             nmisses=nmisses * 10 + *p++ - '0';
00245                      while (*p == ' ')    ++p;
00246               }
00247 
00248               ip->word_pos=0;
00249               while (*p >= '0' && *p <= '9')
00250                      ip->word_pos=ip->word_pos * 10 + *p++ - '0';
00251               ip->first_suggestion=0;
00252               if (nmisses == 0 || *p != ':')     continue;
00253               ++p;
00254               sp= &ip->first_suggestion;
00255               while (nmisses)
00256               {
00257                      if ( (*sp=(struct ispell_suggestion *)
00258                             malloc(sizeof(struct ispell_suggestion)))
00259                             == 0)
00260                      {
00261                             perror("malloc");
00262                             ispell_free(isp);
00263                             return (0);
00264                      }
00265                      (*sp)->suggested_word=strtok(p, ", ");
00266                      p=0;
00267                      (*sp)->next=0;
00268                      sp= &(*sp)->next;
00269                      --nmisses;
00270               }
00271        }
00272        return (isp);
00273 }
00274 
00275 void ispell_free(struct ispell *isp)
00276 {
00277 struct ispell_misspelled *msp;
00278 
00279        while ((msp=isp->first_misspelled) != 0)
00280        {
00281        struct ispell_suggestion *sgp;
00282 
00283               isp->first_misspelled=msp->next;
00284 
00285               while ((sgp=msp->first_suggestion) != 0)
00286               {
00287                      msp->first_suggestion=sgp->next;
00288                      free(sgp);
00289               }
00290 
00291               free(msp);
00292        }
00293 
00294        if (isp->ispell_buf) free(isp->ispell_buf);
00295        free(isp);
00296 }