]> git.lyx.org Git - lyx.git/blob - src/support/mythes/mythes.cxx
add checks for empty word list to avoid crashes later in MyThes::binsearch()
[lyx.git] / src / support / mythes / mythes.cxx
1 #include "license.readme"
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <errno.h>
6
7 #include "mythes.hxx"
8
9 // some basic utility routines
10
11
12 // string duplication routine
13 char * mythesstrdup(const char * p)
14 {
15    
16   int sl = strlen(p) + 1;
17   char * d = (char *)malloc(sl);
18   if (d) {
19     memcpy(d,p,sl);
20     return d;
21   }
22   return NULL;
23 }
24
25
26 // return index of char in string
27 int mystr_indexOfChar(const char * d, int c)
28 {
29   const char * p = strchr(d,c);
30   if (p) return (int)(p-d);
31   return -1;
32 }
33
34
35 // remove cross-platform text line end characters
36 void mytheschomp(char * s)
37 {
38   int k = strlen(s);
39   if ((k > 0) && ((*(s+k-1)=='\r') || (*(s+k-1)=='\n'))) *(s+k-1) = '\0';
40   if ((k > 1) && (*(s+k-2) == '\r')) *(s+k-2) = '\0';
41 }
42
43
44
45 MyThes::MyThes(const char* idxpath, const char * datpath)
46 {
47     nw = 0;
48     encoding = NULL;
49     list = NULL;
50     offst = NULL;
51
52     if (thInitialize(idxpath, datpath) != 1) {
53         fprintf(stderr,"Error - can't open %s or %s\n",idxpath, datpath);
54         fflush(stderr);
55         if (encoding) free((void*)encoding);
56         if (list)  free((void*)list);
57         if (offst) free((void*)offst);
58         // did not initialize properly - throw exception?
59     }
60 }
61
62
63 MyThes::~MyThes()
64 {
65     if (thCleanup() != 1) {
66         /* did not cleanup properly - throw exception? */
67     }
68     if (encoding) free((void*)encoding);
69     encoding = NULL;
70     list = NULL;
71     offst = NULL;
72 }
73
74
75 int MyThes::thInitialize(const char* idxpath, const char* datpath)
76 {
77
78     // open the index file
79     FILE * pifile = fopen(idxpath,"r");
80     if (!pifile) {
81         pifile = NULL;
82         return 0;
83     } 
84
85     // parse in encoding and index size */    
86     char * wrd;
87     wrd = (char *)calloc(1, MAX_WD_LEN);
88     int len = readLine(pifile,wrd,MAX_WD_LEN);
89     encoding = mythesstrdup(wrd);
90     len = readLine(pifile,wrd,MAX_WD_LEN);
91     int idxsz = atoi(wrd); 
92     
93
94     // now allocate list, offst for the given size
95     list = (char**)   calloc(idxsz,sizeof(char*));
96     offst = (unsigned int*) calloc(idxsz,sizeof(unsigned int));
97
98     if ( (!(list)) || (!(offst)) ) {
99        fprintf(stderr,"Error - bad memory allocation\n");
100        fflush(stderr);
101        return 0;
102     }
103
104     // now parse the remaining lines of the index
105     len = readLine(pifile,wrd,MAX_WD_LEN);
106     while (len > 0)
107     { 
108         int np = mystr_indexOfChar(wrd,'|');
109         if (nw < idxsz) {
110            if (np >= 0) {          
111               *(wrd+np) = '\0';
112               list[nw] = (char *)calloc(1,(np+1));
113               memcpy((list[nw]),wrd,np);
114               offst[nw] = atoi(wrd+np+1);
115               nw++;
116            }
117         }
118         len = readLine(pifile,wrd,MAX_WD_LEN);
119     }
120
121     free((void *)wrd);
122     fclose(pifile);
123     pifile=NULL;
124
125     /* next open the data file */
126     pdfile = fopen(datpath,"r");
127     if (!pdfile) {
128         pdfile = NULL;
129         return 0;
130     } 
131         
132     return 1;        
133 }
134
135
136 int MyThes::thCleanup()
137 {
138     /* first close the data file */
139     if (pdfile) {
140         fclose(pdfile);
141         pdfile=NULL;
142     }
143
144     /* now free up all the allocated strings on the list */
145     for (int i=0; i < nw; i++) 
146     {
147         if (list[i]) {
148             free(list[i]);
149             list[i] = 0;
150         }
151     }
152
153     if (list)  free((void*)list);
154     if (offst) free((void*)offst);
155
156     nw = 0;
157     return 1;
158 }
159
160
161
162 // lookup text in index and count of meanings and a list of meaning entries
163 // with each entry having a synonym count and pointer to an 
164 // array of char * (i.e the synonyms)
165 // 
166 // note: calling routine should call CleanUpAfterLookup with the original
167 // meaning point and count to properly deallocate memory
168
169 int MyThes::Lookup(const char * pText, int len, mentry** pme)
170
171
172     *pme = NULL;
173
174     // handle the case of missing file or file related errors
175     if (! pdfile) return 0;
176
177     // handle the case if empty word list
178     if (nw <= 0) return 0;
179
180     long offset = 0;
181
182     /* copy search word and make sure null terminated */
183     char * wrd = (char *) calloc(1,(len+1));
184     memcpy(wrd,pText,len);
185   
186     /* find it in the list */
187     int idx = binsearch(wrd,list,nw);
188     free(wrd);  
189     if (idx < 0) return 0;
190
191     // now seek to the offset
192     offset = (long) offst[idx];
193     int rc = fseek(pdfile,offset,SEEK_SET);
194     if (rc) {
195        return 0;
196     }
197
198     // grab the count of the number of meanings
199     // and allocate a list of meaning entries
200     char * buf = NULL;
201     buf  = (char *) malloc( MAX_LN_LEN );
202     if (!buf) return 0;
203     readLine(pdfile, buf, (MAX_LN_LEN-1));
204     int np = mystr_indexOfChar(buf,'|');
205     if (np < 0) {
206          free(buf);
207          return 0;
208     }          
209     int nmeanings = atoi(buf+np+1);
210     *pme = (mentry*) malloc( nmeanings * sizeof(mentry) );
211     if (!(*pme)) {
212         free(buf);
213         return 0;
214     }
215
216     // now read in each meaning and parse it to get defn, count and synonym lists
217     mentry* pm = *(pme);
218     char dfn[MAX_WD_LEN];
219
220     for (int j = 0; j < nmeanings; j++) {
221         readLine(pdfile, buf, (MAX_LN_LEN-1));
222
223         pm->count = 0;
224         pm->psyns = NULL;
225         pm->defn = NULL;
226
227         // store away the part of speech for later use
228         char * p = buf;
229         char * pos = NULL;
230         np = mystr_indexOfChar(p,'|');
231         if (np >= 0) {
232            *(buf+np) = '\0';
233            pos = mythesstrdup(p);
234            p = p + np + 1;
235         } else {
236           pos = mythesstrdup("");
237         }
238         
239         // count the number of fields in the remaining line
240         int nf = 1;
241         char * d = p;
242         np = mystr_indexOfChar(d,'|');        
243         while ( np >= 0 ) {
244           nf++;
245           d = d + np + 1;
246           np = mystr_indexOfChar(d,'|');          
247         }
248         pm->count = nf;
249         pm->psyns = (char **) malloc(nf*sizeof(char*)); 
250         
251         // fill in the synonym list
252         d = p;
253         for (int j = 0; j < nf; j++) {
254             np = mystr_indexOfChar(d,'|');
255             if (np > 0) {
256               *(d+np) = '\0';
257               pm->psyns[j] = mythesstrdup(d);
258               d = d + np + 1;
259             } else {
260               pm->psyns[j] = mythesstrdup(d);
261             }            
262         }
263
264         // add pos to first synonym to create the definition
265         int k = strlen(pos);
266         int m = strlen(pm->psyns[0]);
267         if ((k+m) < (MAX_WD_LEN - 1)) {
268              strncpy(dfn,pos,k);
269              *(dfn+k) = ' ';
270              strncpy((dfn+k+1),(pm->psyns[0]),m+1);
271              pm->defn = mythesstrdup(dfn);
272         } else {
273              pm->defn = mythesstrdup(pm->psyns[0]);
274         }
275         free(pos);
276         pm++;
277
278     }
279     free(buf);
280    
281     return nmeanings;
282
283
284
285
286 void MyThes::CleanUpAfterLookup(mentry ** pme, int nmeanings)
287
288
289     if (nmeanings == 0) return;
290     if ((*pme) == NULL) return;
291
292     mentry * pm = *pme;
293        
294     for (int i = 0; i < nmeanings; i++) {
295        int count = pm->count;
296        for (int j = 0; j < count; j++) {
297           if (pm->psyns[j]) free(pm->psyns[j]);
298           pm->psyns[j] = NULL;
299        }
300        if (pm->psyns) free(pm->psyns);
301        pm->psyns = NULL;
302        if (pm->defn) free(pm->defn);
303        pm->defn = NULL;
304        pm->count = 0;
305        pm++;
306     }
307     pm = *pme;
308     free(pm);
309     *pme = NULL;
310     return;
311 }
312
313
314 // read a line of text from a text file stripping
315 // off the line terminator and replacing it with
316 // a null string terminator.
317 // returns:  -1 on error or the number of characters in
318 //             in the returning string
319
320 // A maximum of nc characters will be returned
321
322 int MyThes::readLine(FILE * pf, char * buf, int nc)
323 {
324     
325   if (fgets(buf,nc,pf)) {
326     mytheschomp(buf);
327     return strlen(buf);
328   }
329   return -1;
330 }
331
332
333  
334 //  performs a binary search on null terminated character
335 //  strings
336 //
337 //  returns: -1 on not found
338 //           index of wrd in the list[]
339
340 int MyThes::binsearch(char * sw, char* list[], int nlst) 
341 {
342     int lp, up, mp, j, indx;
343     if (0==nlst) return -1;
344     lp = 0;
345     up = nlst-1;
346     indx = -1;
347     if (strcmp(sw,list[lp]) < 0) return -1;
348     if (strcmp(sw,list[up]) > 0) return -1;
349     while (indx < 0 ) {
350         mp = (int)((lp+up) >> 1);
351         j = strcmp(sw,list[mp]);
352         if ( j > 0) {
353             lp = mp + 1;
354         } else if (j < 0 ) {
355             up = mp - 1;
356         } else {
357             indx = mp;
358         }
359         if (lp > up) return -1;      
360     }
361     return indx;
362 }
363
364 char * MyThes::get_th_encoding()
365 {
366   if (encoding) return encoding;
367   return NULL;
368 }
369