1 /*
2 
3   search.c - WordNet library of search code
4 
5 */
6 
7 #ifdef WINDOWS
8 #include <windows.h>
9 #include <windowsx.h>
10 #endif
11 #include <stdio.h>
12 #include <ctype.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <assert.h>
16 
17 #include "wn.h"
18 #ifdef WN1_6
19 #include "setutil.h"
20 #endif
21 
22 static char *Id = "$Id: search.c,v 1.161 2003/06/23 15:52:27 wn Exp $";
23 
24 /* For adjectives, indicates synset type */
25 
26 #define DONT_KNOW	0
27 #define DIRECT_ANT	1	/* direct antonyms (cluster head) */
28 #define INDIRECT_ANT	2	/* indrect antonyms (similar) */
29 #define PERTAINYM	3	/* no antonyms or similars (pertainyms) */
30 
31 /* Flags for printsynset() */
32 
33 #define ALLWORDS	0	/* print all words */
34 #define SKIP_ANTS	0	/* skip printing antonyms in printsynset() */
35 #define PRINT_ANTS	1	/* print antonyms in printsynset() */
36 #define SKIP_MARKER	0	/* skip printing adjective marker */
37 #define PRINT_MARKER	1	/* print adjective marker */
38 
39 /* Trace types used by printspaces() to determine print sytle */
40 
41 #define TRACEP		1	/* traceptrs */
42 #define TRACEC		2	/* tracecoords() */
43 #define TRACEI		3	/* traceinherit() */
44 
45 #define DEFON 1
46 #define DEFOFF 0
47 
48 /* Forward function declarations */
49 
50 static void WNOverview(char *, int);
51 #ifdef WN1_6
52 static void findsisters(IndexPtr), findtwins(IndexPtr), findcousins(IndexPtr);
53 static int read_cousintops(void);
54 static int groupexc(unsigned long, unsigned long);
55 #endif
56 static void findverbgroups(IndexPtr);
57 static void add_relatives(int, IndexPtr, int, int);
58 static void free_rellist(void);
59 static void printsynset(char *, SynsetPtr, char *, int, int, int, int);
60 static void printantsynset(SynsetPtr, char *, int, int);
61 static char *printant(int, SynsetPtr, int, char *, char *);
62 static void printbuffer(char *);
63 static void printsns(SynsetPtr, int);
64 static void printsense(SynsetPtr, int);
65 static void catword(char *, SynsetPtr, int, int, int);
66 static void printspaces(int, int);
67 static void printrelatives(IndexPtr, int);
68 static int HasHoloMero(IndexPtr, int);
69 static int HasPtr(SynsetPtr, int);
70 static int getsearchsense(SynsetPtr, int);
71 static int depthcheck(int, SynsetPtr);
72 static void interface_doevents();
73 static void getexample(char *, char *);
74 static int findexample(SynsetPtr);
75 
76 /* Static variables */
77 
78 static int prflag, sense, prlexid;
79 static int overflag = 0;	/* set when output buffer overflows */
80 static char searchbuffer[SEARCHBUF];
81 static int lastholomero;	/* keep track of last holo/meronym printed */
82 #define TMPBUFSIZE 1024*10
83 static char tmpbuf[TMPBUFSIZE];	/* general purpose printing buffer */
84 static char wdbuf[WORDBUF];	/* general purpose word buffer */
85 static char msgbuf[256];	/* buffer for constructing error messages */
86 static int adj_marker;
87 
88 extern long last_bin_search_offset;
89 
90 
91 /* Find word in index file and return parsed entry in data structure.
92    Input word must be exact match of string in database. */
93 
index_lookup(char * word,int dbase)94 IndexPtr index_lookup(char *word, int dbase)
95 {
96     IndexPtr idx = NULL;
97     FILE *fp;
98     char *line;
99 
100     if ((fp = indexfps[dbase]) == NULL) {
101 	sprintf(msgbuf, "WordNet library error: %s indexfile not open\n",
102 		partnames[dbase]);
103 	display_message(msgbuf);
104 	return(NULL);
105     }
106 
107     if ((line = bin_search(word, fp)) != NULL) {
108 	idx = parse_index( last_bin_search_offset, dbase, line);
109     }
110     return (idx);
111 }
112 
113 /* This function parses an entry from an index file into an Index data
114  * structure. It takes the byte offset and file number, and optionally the
115  * line. If the line is NULL, parse_index will get the line from the file.
116  * If the line is non-NULL, parse_index won't look at the file, but it still
117  * needs the dbase and offset parameters to be set, so it can store them in
118  * the Index struct.
119  */
120 
parse_index(long offset,int dbase,char * line)121 IndexPtr parse_index(long offset, int dbase, char *line) {
122 
123     IndexPtr idx = NULL;
124     char *ptrtok;
125     int j;
126 
127     if ( !line )
128       line = read_index( offset, indexfps[dbase] );
129 
130     idx = (IndexPtr)malloc(sizeof(Index));
131     assert(idx);
132 
133     /* set offset of entry in index file */
134     idx->idxoffset = offset;
135 
136     idx->wd='\0';
137     idx->pos='\0';
138     idx->off_cnt=0;
139     idx->tagged_cnt = 0;
140     idx->sense_cnt=0;
141     idx->offset='\0';
142     idx->ptruse_cnt=0;
143     idx->ptruse='\0';
144 
145     /* get the word */
146     ptrtok=strtok(line," \n");
147 
148     idx->wd = malloc(strlen(ptrtok) + 1);
149     assert(idx->wd);
150     strcpy(idx->wd, ptrtok);
151 
152     /* get the part of speech */
153     ptrtok=strtok(NULL," \n");
154     idx->pos = malloc(strlen(ptrtok) + 1);
155     assert(idx->pos);
156     strcpy(idx->pos, ptrtok);
157 
158     /* get the collins count */
159     ptrtok=strtok(NULL," \n");
160     idx->sense_cnt = atoi(ptrtok);
161 
162     /* get the number of pointers types */
163     ptrtok=strtok(NULL," \n");
164     idx->ptruse_cnt = atoi(ptrtok);
165 
166     if (idx->ptruse_cnt) {
167 	idx->ptruse = (int *) malloc(idx->ptruse_cnt * (sizeof(int)));
168 	assert(idx->ptruse);
169 
170 	/* get the pointers types */
171 	for(j=0;j < idx->ptruse_cnt; j++) {
172 	    ptrtok=strtok(NULL," \n");
173 	    idx->ptruse[j] = getptrtype(ptrtok);
174 	}
175     }
176 
177     /* get the number of offsets */
178     ptrtok=strtok(NULL," \n");
179     idx->off_cnt = atoi(ptrtok);
180 
181     /* get the number of senses that are tagged */
182     ptrtok=strtok(NULL," \n");
183     idx->tagged_cnt = atoi(ptrtok);
184 
185     /* make space for the offsets */
186     idx->offset = (long *) malloc(idx->off_cnt * (sizeof(long)));
187     assert(idx->offset);
188 
189     /* get the offsets */
190     for(j=0;j<idx->off_cnt;j++) {
191 	ptrtok=strtok(NULL," \n");
192 	idx->offset[j] = atol(ptrtok);
193     }
194     return(idx);
195 }
196 
197 /* 'smart' search of index file.  Find word in index file, trying different
198    techniques - replace hyphens with underscores, replace underscores with
199    hyphens, strip hyphens and underscores, strip periods. */
200 
getindex(char * searchstr,int dbase)201 IndexPtr getindex(char *searchstr, int dbase)
202 {
203     int i, j, k;
204     char c;
205     char strings[MAX_FORMS][WORDBUF]; /* vector of search strings */
206     static IndexPtr offsets[MAX_FORMS];
207     static int offset;
208 
209     /* This works like strrok(): if passed with a non-null string,
210        prepare vector of search strings and offsets.  If string
211        is null, look at current list of offsets and return next
212        one, or NULL if no more alternatives for this word. */
213 
214     if (searchstr != NULL) {
215 
216 	offset = 0;
217 	strtolower(searchstr);
218 	for (i = 0; i < MAX_FORMS; i++) {
219 	    strcpy(strings[i], searchstr);
220 	    offsets[i] = 0;
221 	}
222 
223 	strsubst(strings[1], '_', '-');
224 	strsubst(strings[2], '-', '_');
225 
226 	/* remove all spaces and hyphens from last search string, then
227 	   all periods */
228 	for (i = j = k = 0; (c = searchstr[i]) != '\0'; i++) {
229 	    if (c != '_' && c != '-')
230 		strings[3][j++] = c;
231 	    if (c != '.')
232 		strings[4][k++] = c;
233 	}
234 	strings[3][j] = '\0';
235 	strings[4][k] = '\0';
236 
237 	/* Get offset of first entry.  Then eliminate duplicates
238 	   and get offsets of unique strings. */
239 
240 	if (strings[0][0] != NULL)
241 	    offsets[0] = index_lookup(strings[0], dbase);
242 
243 	for (i = 1; i < MAX_FORMS; i++)
244 	    if ((strings[i][0]) != NULL && (strcmp(strings[0], strings[i])))
245 		offsets[i] = index_lookup(strings[i], dbase);
246     }
247 
248 
249     for (i = offset; i < MAX_FORMS; i++)
250 	if (offsets[i]) {
251 	    offset = i + 1;
252 	    return(offsets[i]);
253 	}
254 
255     return(NULL);
256 }
257 
258 /* Read synset from data file at byte offset passed and return parsed
259    entry in data structure. */
260 
read_synset(int dbase,long boffset,char * word)261 SynsetPtr read_synset(int dbase, long boffset, char *word)
262 {
263     FILE *fp;
264 
265     if((fp = datafps[dbase]) == NULL) {
266 	sprintf(msgbuf, "WordNet library error: %s datafile not open\n",
267 		partnames[dbase]);
268 	display_message(msgbuf);
269 	return(NULL);
270     }
271 
272     fseek(fp, boffset, 0);	/* position file to byte offset requested */
273 
274     return(parse_synset(fp, dbase, word)); /* parse synset and return */
275 }
276 
277 /* Read synset at current byte offset in file and return parsed entry
278    in data structure. */
279 
parse_synset(FILE * fp,int dbase,char * word)280 SynsetPtr parse_synset(FILE *fp, int dbase, char *word)
281 {
282     static char line[LINEBUF];
283     char tbuf[SMLINEBUF];
284     char *ptrtok;
285     char *tmpptr;
286     int foundpert = 0;
287     char wdnum[3];
288     int i;
289     SynsetPtr synptr;
290     long loc;			/* sanity check on file location */
291 
292     loc = ftell(fp);
293 
294     if ((tmpptr = fgets(line, LINEBUF, fp)) == NULL)
295 	return(NULL);
296 
297     synptr = (SynsetPtr)malloc(sizeof(Synset));
298     assert(synptr);
299 
300     synptr->hereiam = 0;
301     synptr->sstype = DONT_KNOW;
302     synptr->fnum = 0;
303     synptr->pos = '\0';
304     synptr->wcount = 0;
305     synptr->words = '\0';
306     synptr->whichword = 0;
307     synptr->ptrcount = 0;
308     synptr->ptrtyp = '\0';
309     synptr->ptroff = '\0';
310     synptr->ppos = '\0';
311     synptr->pto = '\0';
312     synptr->pfrm = '\0';
313     synptr->fcount = 0;
314     synptr->frmid = '\0';
315     synptr->frmto = '\0';
316     synptr->defn = '\0';
317     synptr->key = 0;
318     synptr->nextss = NULL;
319     synptr->nextform = NULL;
320     synptr->searchtype = -1;
321     synptr->ptrlist = NULL;
322     synptr->headword = NULL;
323     synptr->headsense = 0;
324 
325     ptrtok = line;
326 
327     /* looking at offset */
328     ptrtok = strtok(line," \n");
329     synptr->hereiam = atol(ptrtok);
330 
331     /* sanity check - make sure starting file offset matches first field */
332     if (synptr->hereiam != loc) {
333 	sprintf(msgbuf, "WordNet library error: no synset at location %d\n",
334 		loc);
335 	display_message(msgbuf);
336 	free(synptr);
337 	return(NULL);
338     }
339 
340     /* looking at FNUM */
341     ptrtok = strtok(NULL," \n");
342     synptr->fnum = atoi(ptrtok);
343 
344     /* looking at POS */
345     ptrtok = strtok(NULL, " \n");
346     synptr->pos = malloc(strlen(ptrtok) + 1);
347     assert(synptr->pos);
348     strcpy(synptr->pos, ptrtok);
349     if (getsstype(synptr->pos) == SATELLITE)
350 	synptr->sstype = INDIRECT_ANT;
351 
352     /* looking at numwords */
353     ptrtok = strtok(NULL, " \n");
354     synptr->wcount = strtol(ptrtok, NULL, 16);
355 
356     synptr->words = (char **)malloc(synptr->wcount  * sizeof(char *));
357     assert(synptr->words);
358     synptr->wnsns = (int *)malloc(synptr->wcount * sizeof(int));
359     assert(synptr->wnsns);
360     synptr->lexid = (int *)malloc(synptr->wcount * sizeof(int));
361     assert(synptr->lexid);
362 
363     for (i = 0; i < synptr->wcount; i++) {
364 	ptrtok = strtok(NULL, " \n");
365 	synptr->words[i] = malloc(strlen(ptrtok) + 1);
366 	assert(synptr->words[i]);
367 	strcpy(synptr->words[i], ptrtok);
368 
369 	/* is this the word we're looking for? */
370 
371 	if (word && !strcmp(word,strtolower(ptrtok)))
372 	    synptr->whichword = i+1;
373 
374 	ptrtok = strtok(NULL, " \n");
375 	sscanf(ptrtok, "%x", &synptr->lexid[i]);
376     }
377 
378     /* get the pointer count */
379     ptrtok = strtok(NULL," \n");
380     synptr->ptrcount = atoi(ptrtok);
381 
382     if (synptr->ptrcount) {
383 
384 	/* alloc storage for the pointers */
385 	synptr->ptrtyp = (int *)malloc(synptr->ptrcount * sizeof(int));
386 	assert(synptr->ptrtyp);
387 	synptr->ptroff = (long *)malloc(synptr->ptrcount * sizeof(long));
388 	assert(synptr->ptroff);
389 	synptr->ppos = (int *)malloc(synptr->ptrcount * sizeof(int));
390 	assert(synptr->ppos);
391 	synptr->pto = (int *)malloc(synptr->ptrcount * sizeof(int));
392 	assert(synptr->pto);
393 	synptr->pfrm = (int *)malloc(synptr->ptrcount * sizeof(int));
394 	assert(synptr->pfrm);
395 
396 	for(i = 0; i < synptr->ptrcount; i++) {
397 	    /* get the pointer type */
398 	    ptrtok = strtok(NULL," \n");
399 	    synptr->ptrtyp[i] = getptrtype(ptrtok);
400 	    /* For adjectives, set the synset type if it has a direct
401 	       antonym */
402 	    if (dbase == ADJ &&	synptr->sstype == DONT_KNOW) {
403 		if (synptr->ptrtyp[i] == ANTPTR)
404 		    synptr->sstype = DIRECT_ANT;
405 		else if (synptr->ptrtyp[i] == PERTPTR)
406 		    foundpert = 1;
407 	    }
408 
409 	    /* get the pointer offset */
410 	    ptrtok = strtok(NULL," \n");
411 	    synptr->ptroff[i] = atol(ptrtok);
412 
413 	    /* get the pointer part of speech */
414 	    ptrtok = strtok(NULL, " \n");
415 	    synptr->ppos[i] = getpos(ptrtok);
416 
417 	    /* get the lexp to/from restrictions */
418 	    ptrtok = strtok(NULL," \n");
419 
420 	    tmpptr = ptrtok;
421 	    strncpy(wdnum, tmpptr, 2);
422 	    wdnum[2] = '\0';
423 	    synptr->pfrm[i] = strtol(wdnum, (char **)NULL, 16);
424 
425 	    tmpptr += 2;
426 	    strncpy(wdnum, tmpptr, 2);
427 	    wdnum[2] = '\0';
428 	    synptr->pto[i] = strtol(wdnum, (char **)NULL, 16);
429 	}
430     }
431 
432     /* If synset type is still not set, see if it's a pertainym */
433 
434     if (dbase == ADJ && synptr->sstype == DONT_KNOW && foundpert == 1)
435 	synptr->sstype = PERTAINYM;
436 
437     /* retireve optional information from verb synset */
438     if(dbase == VERB) {
439 	ptrtok = strtok(NULL," \n");
440 	synptr->fcount = atoi(ptrtok);
441 
442 	/* allocate frame storage */
443 
444 	synptr->frmid = (int *)malloc(synptr->fcount * sizeof(int));
445 	assert(synptr->frmid);
446 	synptr->frmto = (int *)malloc(synptr->fcount * sizeof(int));
447 	assert(synptr->frmto);
448 
449 	for(i=0;i<synptr->fcount;i++) {
450 	    /* skip the frame pointer (+) */
451 	    ptrtok = strtok(NULL," \n");
452 
453 	    ptrtok = strtok(NULL," \n");
454 	    synptr->frmid[i] = atoi(ptrtok);
455 
456 	    ptrtok = strtok(NULL," \n");
457 	    synptr->frmto[i] = strtol(ptrtok, NULL, 16);
458 	}
459     }
460 
461     /* get the optional definition */
462 
463     ptrtok = strtok(NULL," \n");
464     if (ptrtok) {
465 	ptrtok = strtok(NULL," \n");
466 	sprintf(tbuf, "");
467 	while (ptrtok != NULL) {
468 	    strcat(tbuf,ptrtok);
469 	    ptrtok = strtok(NULL, " \n");
470 	    if(ptrtok)
471 		strcat(tbuf," ");
472 	}
473 	assert((1 + strlen(tbuf)) < sizeof(tbuf));
474 	synptr->defn = malloc(strlen(tbuf) + 4);
475 	assert(synptr->defn);
476 	sprintf(synptr->defn,"(%s)",tbuf);
477     }
478 
479     if (keyindexfp) { 		/* we have unique keys */
480 	sprintf(tmpbuf, "%c:%8.8d", partchars[dbase], synptr->hereiam);
481 	synptr->key = GetKeyForOffset(tmpbuf);
482     }
483 
484     /* Can't do earlier - calls indexlookup which messes up strtok calls */
485 
486     for (i = 0; i < synptr->wcount; i++)
487 	synptr->wnsns[i] = getsearchsense(synptr, i + 1);
488 
489     return(synptr);
490 }
491 
492 /* Free a synset linked list allocated by findtheinfo_ds() */
493 
free_syns(SynsetPtr synptr)494 void free_syns(SynsetPtr synptr)
495 {
496     SynsetPtr cursyn, nextsyn;
497 
498     if (synptr) {
499 	cursyn = synptr;
500 	while(cursyn) {
501 	    if (cursyn->nextform)
502 		free_syns(cursyn->nextform);
503 	    nextsyn = cursyn->nextss;
504 	    free_synset(cursyn);
505 	    cursyn = nextsyn;
506 	}
507     }
508 }
509 
510 /* Free a synset */
511 
free_synset(SynsetPtr synptr)512 void free_synset(SynsetPtr synptr)
513 {
514     int i;
515 
516     free(synptr->pos);
517     for (i = 0; i < synptr->wcount; i++){
518 	free(synptr->words[i]);
519     }
520     free(synptr->words);
521     free(synptr->wnsns);
522     free(synptr->lexid);
523     if (synptr->ptrcount) {
524 	free(synptr->ptrtyp);
525 	free(synptr->ptroff);
526 	free(synptr->ppos);
527 	free(synptr->pto);
528 	free(synptr->pfrm);
529     }
530     if (synptr->fcount) {
531 	free(synptr->frmid);
532 	free(synptr->frmto);
533     }
534     if (synptr->defn)
535 	free(synptr->defn);
536     if (synptr->headword)
537 	free(synptr->headword);
538     if (synptr->ptrlist)
539 	free_syns(synptr->ptrlist); /* changed from free_synset() */
540     free(synptr);
541 }
542 
543 /* Free an index structure */
544 
free_index(IndexPtr idx)545 void free_index(IndexPtr idx)
546 {
547     free(idx->wd);
548     free(idx->pos);
549     if (idx->ptruse)
550 	free(idx->ptruse);
551     free(idx->offset);
552     free(idx);
553 }
554 
555 /* Recursive search algorithm to trace a pointer tree */
556 
traceptrs(SynsetPtr synptr,int ptrtyp,int dbase,int depth)557 static void traceptrs(SynsetPtr synptr, int ptrtyp, int dbase, int depth)
558 {
559     int i;
560     int extraindent = 0;
561     SynsetPtr cursyn;
562     char prefix[40], tbuf[20];
563 
564     interface_doevents();
565     if (abortsearch)
566 	return;
567 
568     if (ptrtyp < 0) {
569 	ptrtyp = -ptrtyp;
570 	extraindent = 2;
571     }
572 
573     for (i = 0; i < synptr->ptrcount; i++) {
574 	if((synptr->ptrtyp[i] == ptrtyp) &&
575 	   ((synptr->pfrm[i] == 0) ||
576 	    (synptr->pfrm[i] == synptr->whichword))) {
577 
578 	    if(!prflag) {	/* print sense number and synset */
579 		printsns(synptr, sense + 1);
580 		prflag = 1;
581 	    }
582 	    printspaces(TRACEP, depth + extraindent);
583 
584 	    switch(ptrtyp) {
585 	    case PERTPTR:
586 		if (dbase == ADV)
587 		    sprintf(prefix, "Derived from %s ",
588 			    partnames[synptr->ppos[i]]);
589 		else
590 		    sprintf(prefix, "Pertains to %s ",
591 			    partnames[synptr->ppos[i]]);
592 		break;
593 	    case ANTPTR:
594 		if (dbase != ADJ)
595 		    sprintf(prefix, "Antonym of ");
596 		break;
597 	    case PPLPTR:
598 		sprintf(prefix, "Participle of verb ");
599 		break;
600 	    case HASMEMBERPTR:
601 		sprintf(prefix, "   HAS MEMBER: ");
602 		break;
603 	    case HASSTUFFPTR:
604 		sprintf(prefix, "   HAS SUBSTANCE: ");
605 		break;
606 	    case HASPARTPTR:
607 		sprintf(prefix, "   HAS PART: ");
608 		break;
609 	    case ISMEMBERPTR:
610 		sprintf(prefix, "   MEMBER OF: ");
611 		break;
612 	    case ISSTUFFPTR:
613 		sprintf(prefix, "   SUBSTANCE OF: ");
614 		break;
615 	    case ISPARTPTR:
616 		sprintf(prefix, "   PART OF: ");
617 		break;
618 	    default:
619 		sprintf(prefix, "=> ");
620 		break;
621 	    }
622 
623 	    /* Read synset pointed to */
624 	    cursyn=read_synset(synptr->ppos[i], synptr->ptroff[i], "");
625 
626 	    /* For Pertainyms and Participles pointing to a specific
627 	       sense, indicate the sense then retrieve the synset
628 	       pointed to and other info as determined by type.
629 	       Otherwise, just print the synset pointed to. */
630 
631 	    if ((ptrtyp == PERTPTR || ptrtyp == PPLPTR) &&
632 		synptr->pto[i] != 0) {
633 		sprintf(tbuf, " (Sense %d)\n",
634 			cursyn->wnsns[synptr->pto[i] - 1]);
635 		printsynset(prefix, cursyn, tbuf, DEFOFF, synptr->pto[i],
636 			    SKIP_ANTS, PRINT_MARKER);
637 		if (ptrtyp == PPLPTR) { /* adjective pointing to verb */
638 		    printsynset("      =>", cursyn, "\n",
639 				DEFON, ALLWORDS, PRINT_ANTS, PRINT_MARKER);
640 		    traceptrs(cursyn, HYPERPTR, getpos(cursyn->pos), 0);
641 		} else if (dbase == ADV) { /* adverb pointing to adjective */
642 		    printsynset("      =>", cursyn, "\n",DEFON, ALLWORDS,
643 				((getsstype(cursyn->pos) == SATELLITE)
644 				 ? SKIP_ANTS : PRINT_ANTS), PRINT_MARKER);
645 #ifdef FOOP
646  		    traceptrs(cursyn, HYPERPTR, getpos(cursyn->pos), 0);
647 #endif
648 		} else {	/* adjective pointing to noun */
649 		    printsynset("      =>", cursyn, "\n",
650 				DEFON, ALLWORDS, PRINT_ANTS, PRINT_MARKER);
651 		    traceptrs(cursyn, HYPERPTR, getpos(cursyn->pos), 0);
652 		}
653 	    } else if (ptrtyp == ANTPTR && dbase != ADJ && synptr->pto[i] != 0) {
654 		sprintf(tbuf, " (Sense %d)\n",
655 			cursyn->wnsns[synptr->pto[i] - 1]);
656 		printsynset(prefix, cursyn, tbuf, DEFOFF, synptr->pto[i],
657 			    SKIP_ANTS, PRINT_MARKER);
658 		printsynset("      =>", cursyn, "\n", DEFON, ALLWORDS,
659 			    PRINT_ANTS, PRINT_MARKER);
660 	    } else
661 		printsynset(prefix, cursyn, "\n", DEFON, ALLWORDS,
662 			    PRINT_ANTS, PRINT_MARKER);
663 
664 	    /* For HOLONYMS and MERONYMS, keep track of last one
665 	       printed in buffer so results can be truncated later. */
666 
667 	    if (ptrtyp >= ISMEMBERPTR && ptrtyp <= HASPARTPTR)
668 		lastholomero = strlen(searchbuffer);
669 
670 	    if(depth) {
671 		depth = depthcheck(depth, cursyn);
672 		traceptrs(cursyn, ptrtyp, getpos(cursyn->pos), (depth+1));
673 
674 		free_synset(cursyn);
675 	    } else
676 		free_synset(cursyn);
677 	}
678     }
679 }
680 
tracecoords(SynsetPtr synptr,int ptrtyp,int dbase,int depth)681 static void tracecoords(SynsetPtr synptr, int ptrtyp, int dbase, int depth)
682 {
683     int i;
684     SynsetPtr cursyn;
685 
686     interface_doevents();
687     if (abortsearch)
688 	return;
689 
690     for(i = 0; i < synptr->ptrcount; i++) {
691 	if((synptr->ptrtyp[i] == HYPERPTR) &&
692 	   ((synptr->pfrm[i] == 0) ||
693 	    (synptr->pfrm[i] == synptr->whichword))) {
694 
695 	    if(!prflag) {
696 		printsns(synptr, sense + 1);
697 		prflag = 1;
698 	    }
699 	    printspaces(TRACEC, depth);
700 
701 	    cursyn = read_synset(synptr->ppos[i], synptr->ptroff[i], "");
702 
703 	    printsynset("-> ", cursyn, "\n", DEFON, ALLWORDS,
704 			SKIP_ANTS, PRINT_MARKER);
705 
706 	    traceptrs(cursyn, ptrtyp, getpos(cursyn->pos), depth);
707 
708 	    if(depth) {
709 		depth = depthcheck(depth, cursyn);
710 		tracecoords(cursyn, ptrtyp, getpos(cursyn->pos), (depth+1));
711 		free_synset(cursyn);
712 	    } else
713 		free_synset(cursyn);
714 	}
715     }
716 }
717 
traceclassif(SynsetPtr synptr,int dbase,int search)718 static void traceclassif(SynsetPtr synptr, int dbase, int search)
719 {
720     int i, j, idx;
721     SynsetPtr cursyn;
722     long int prlist[1024];
723     char head[60];
724     int svwnsnsflag;
725 
726     interface_doevents();
727     if (abortsearch)
728 	return;
729 
730     idx = 0;
731 
732     for (i = 0; i < synptr->ptrcount; i++) {
733 	if (((synptr->ptrtyp[i] >= CLASSIF_START) &&
734 	     (synptr->ptrtyp[i] <= CLASSIF_END) && search == CLASSIFICATION) ||
735 
736 	    ((synptr->ptrtyp[i] >= CLASS_START) &&
737 	     (synptr->ptrtyp[i] <= CLASS_END) && search == CLASS) ) {
738 
739 	    if (!prflag) {
740 		printsns(synptr, sense + 1);
741 		prflag = 1;
742 	    }
743 
744 	    cursyn = read_synset(synptr->ppos[i], synptr->ptroff[i], "");
745 
746 	    for (j = 0; j < idx; j++) {
747 		if (synptr->ptroff[i] == prlist[j]) {
748 		    break;
749 		}
750 	    }
751 
752 	    if (j == idx) {
753 		prlist[idx++] = synptr->ptroff[i];
754 		printspaces(TRACEP, 0);
755 
756 		if (synptr->ptrtyp[i] == CLASSIF_CATEGORY)
757 		    strcpy(head, "CATEGORY->(");
758 		else if (synptr->ptrtyp[i] == CLASSIF_USAGE)
759 		    strcpy(head, "USAGE->(");
760 		else if (synptr->ptrtyp[i] == CLASSIF_REGIONAL)
761 		    strcpy(head, "REGION->(");
762 		else if (synptr->ptrtyp[i] == CLASS_CATEGORY)
763 		    strcpy(head, "CATEGORY_TERM->(");
764 		else if (synptr->ptrtyp[i] == CLASS_USAGE)
765 		    strcpy(head, "USAGE_TERM->(");
766 		else if (synptr->ptrtyp[i] == CLASS_REGIONAL)
767 		    strcpy(head, "REGION_TERM->(");
768 
769 		strcat(head, partnames[synptr->ppos[i]]);
770 		strcat(head, ") ");
771 
772 		svwnsnsflag = wnsnsflag;
773 		wnsnsflag = 1;
774 
775 		printsynset(head, cursyn, "\n", DEFOFF, ALLWORDS,
776 			    SKIP_ANTS, SKIP_MARKER);
777 
778 		wnsnsflag = svwnsnsflag;
779 	    }
780 
781 	    free_synset(cursyn);
782 	}
783     }
784 }
785 
tracenomins(SynsetPtr synptr,int dbase)786 static void tracenomins(SynsetPtr synptr, int dbase)
787 {
788     int i, j, idx;
789     SynsetPtr cursyn;
790     long int prlist[1024];
791     char prefix[40], tbuf[20];
792 
793     interface_doevents();
794     if (abortsearch)
795 	return;
796 
797     idx = 0;
798 
799     for (i = 0; i < synptr->ptrcount; i++) {
800 	if ((synptr->ptrtyp[i] == DERIVATION) &&
801 	    (synptr->pfrm[i] == synptr->whichword)) {
802 
803 	    if (!prflag) {
804 		printsns(synptr, sense + 1);
805 		prflag = 1;
806 	    }
807 
808 	    printspaces(TRACEP, 0);
809 
810 	    sprintf(prefix, "RELATED TO->(%s) ",
811 		    partnames[synptr->ppos[i]]);
812 
813 	    cursyn = read_synset(synptr->ppos[i], synptr->ptroff[i], "");
814 
815 	    sprintf(tbuf, "#%d\n",
816 		    cursyn->wnsns[synptr->pto[i] - 1]);
817 	    printsynset(prefix, cursyn, tbuf, DEFOFF, synptr->pto[i],
818 			SKIP_ANTS, SKIP_MARKER);
819 
820 	    /* only print synset once, even if more than one link */
821 
822 	    for (j = 0; j < idx; j++) {
823 #ifdef FOOP
824 		if (synptr->ptroff[i] == prlist[j]) {
825 		    break;
826 		}
827 #endif
828 	    }
829 
830 	    if (j == idx) {
831 		prlist[idx++] = synptr->ptroff[i];
832 		printspaces(TRACEP, 2);
833 		printsynset("=> ", cursyn, "\n", DEFON, ALLWORDS,
834 			    SKIP_ANTS, PRINT_MARKER);
835 	    }
836 
837 	    free_synset(cursyn);
838 	}
839     }
840 }
841 
842 /* Trace through the hypernym tree and print all MEMBER, STUFF
843    and PART info. */
844 
traceinherit(SynsetPtr synptr,int ptrbase,int dbase,int depth)845 static void traceinherit(SynsetPtr synptr, int ptrbase, int dbase, int depth)
846 {
847     int i;
848     SynsetPtr cursyn;
849 
850     interface_doevents();
851     if (abortsearch)
852 	return;
853 
854     for(i=0;i<synptr->ptrcount;i++) {
855 	if((synptr->ptrtyp[i] == HYPERPTR) &&
856 	   ((synptr->pfrm[i] == 0) ||
857 	    (synptr->pfrm[i] == synptr->whichword))) {
858 
859 	    if(!prflag) {
860 		printsns(synptr, sense + 1);
861 		prflag = 1;
862 	    }
863 	    printspaces(TRACEI, depth);
864 
865 	    cursyn = read_synset(synptr->ppos[i], synptr->ptroff[i], "");
866 
867 	    printsynset("=> ", cursyn, "\n", DEFON, ALLWORDS,
868 			SKIP_ANTS, PRINT_MARKER);
869 
870 	    traceptrs(cursyn, ptrbase, NOUN, depth);
871 	    traceptrs(cursyn, ptrbase + 1, NOUN, depth);
872 	    traceptrs(cursyn, ptrbase + 2, NOUN, depth);
873 
874 	    if(depth) {
875 		depth = depthcheck(depth, cursyn);
876 		traceinherit(cursyn, ptrbase, getpos(cursyn->pos), (depth+1));
877 		free_synset(cursyn);
878 	    } else
879 		free_synset(cursyn);
880 	}
881     }
882 
883     /* Truncate search buffer after last holo/meronym printed */
884     searchbuffer[lastholomero] = '\0';
885 }
886 
partsall(SynsetPtr synptr,int ptrtyp)887 static void partsall(SynsetPtr synptr, int ptrtyp)
888 {
889     int ptrbase;
890     int i, hasptr = 0;
891 
892     ptrbase = (ptrtyp == HMERONYM) ? HASMEMBERPTR : ISMEMBERPTR;
893 
894     /* First, print out the MEMBER, STUFF, PART info for this synset */
895 
896     for (i = 0; i < 3; i++) {
897 	if (HasPtr(synptr, ptrbase + i)) {
898 	    traceptrs(synptr, ptrbase + i, NOUN, 1);
899 	    hasptr++;
900 	}
901 	interface_doevents();
902 	if (abortsearch)
903 	    return;
904     }
905 
906     /* Print out MEMBER, STUFF, PART info for hypernyms on
907        HMERONYM search only */
908 
909 /*    if (hasptr && ptrtyp == HMERONYM) { */
910     if (ptrtyp == HMERONYM) {
911 	lastholomero = strlen(searchbuffer);
912 	traceinherit(synptr, ptrbase, NOUN, 1);
913     }
914 }
915 
traceadjant(SynsetPtr synptr)916 static void traceadjant(SynsetPtr synptr)
917 {
918     SynsetPtr newsynptr;
919     int i, j;
920     int anttype = DIRECT_ANT;
921     SynsetPtr simptr, antptr;
922     static char similar[] = "        => ";
923 
924     /* This search is only applicable for ADJ synsets which have
925        either direct or indirect antonyms (not valid for pertainyms). */
926 
927     if (synptr->sstype == DIRECT_ANT || synptr->sstype == INDIRECT_ANT) {
928 	printsns(synptr, sense + 1);
929 	printbuffer("\n");
930 
931 	/* if indirect, get cluster head */
932 
933 	if(synptr->sstype == INDIRECT_ANT) {
934 	    anttype = INDIRECT_ANT;
935 	    i = 0;
936 	    while (synptr->ptrtyp[i] != SIMPTR) i++;
937 	    newsynptr = read_synset(ADJ, synptr->ptroff[i], "");
938 	} else
939 	    newsynptr = synptr;
940 
941 	/* find antonyms - if direct, make sure that the antonym
942 	   ptr we're looking at is from this word */
943 
944 	for (i = 0; i < newsynptr->ptrcount; i++) {
945 
946 	    if (newsynptr->ptrtyp[i] == ANTPTR &&
947 		((anttype == DIRECT_ANT &&
948 		  newsynptr->pfrm[i] == newsynptr->whichword) ||
949 		 (anttype == INDIRECT_ANT))) {
950 
951 		/* read the antonym's synset and print it.  if a
952 		   direct antonym, print it's satellites. */
953 
954 		antptr = read_synset(ADJ, newsynptr->ptroff[i], "");
955 
956 		if (anttype == DIRECT_ANT) {
957 		    printsynset("", antptr, "\n", DEFON, ALLWORDS,
958 				PRINT_ANTS, PRINT_MARKER);
959 		    for(j = 0; j < antptr->ptrcount; j++) {
960 			if(antptr->ptrtyp[j] == SIMPTR) {
961 			    simptr = read_synset(ADJ, antptr->ptroff[j], "");
962 			    printsynset(similar, simptr, "\n", DEFON,
963 					ALLWORDS, SKIP_ANTS, PRINT_MARKER);
964 			    free_synset(simptr);
965 			}
966 		    }
967 		} else
968 		    printantsynset(antptr, "\n", anttype, DEFON);
969 
970 		free_synset(antptr);
971 	    }
972 	}
973 	if (newsynptr != synptr)
974 	    free_synset(newsynptr);
975     }
976 }
977 
978 
979 /* Fetch the given example sentence from the example file and print it out */
980 
getexample(char * offset,char * wd)981 void getexample(char *offset, char *wd)
982 {
983     char *line;
984     char sentbuf[512];
985 
986     if (vsentfilefp != NULL) {
987 	if (line = bin_search(offset, vsentfilefp)) {
988 	    while(*line != ' ')
989 		line++;
990 
991 	    printbuffer("          EX: ");
992 	    sprintf(sentbuf, line, wd);
993 	    printbuffer(sentbuf);
994 	}
995     }
996 }
997 
998 /* Find the example sentence references in the example sentence index file */
999 
findexample(SynsetPtr synptr)1000 int findexample(SynsetPtr synptr)
1001 {
1002     char tbuf[256], *temp, *offset;
1003     int wdnum;
1004     int found = 0;
1005 
1006     if (vidxfilefp != NULL) {
1007 	wdnum = synptr->whichword - 1;
1008 
1009 	sprintf(tbuf,"%s%%%-1.1d:%-2.2d:%-2.2d::",
1010 		synptr->words[wdnum],
1011 		getpos(synptr->pos),
1012 		synptr->fnum,
1013 		synptr->lexid[wdnum]);
1014 
1015 	if ((temp = bin_search(tbuf, vidxfilefp)) != NULL) {
1016 
1017 	    /* skip over sense key and get sentence numbers */
1018 
1019 	    temp += strlen(synptr->words[wdnum]) + 11;
1020 	    strcpy(tbuf, temp);
1021 
1022 	    offset = strtok(tbuf, " ,\n");
1023 
1024 	    while (offset) {
1025 		getexample(offset, synptr->words[wdnum]);
1026 		offset = strtok(NULL, ",\n");
1027 	    }
1028 	    found = 1;
1029 	}
1030     }
1031     return(found);
1032 }
1033 
printframe(SynsetPtr synptr,int prsynset)1034 static void printframe(SynsetPtr synptr, int prsynset)
1035 {
1036     int i;
1037 
1038     if (prsynset)
1039 	printsns(synptr, sense + 1);
1040 
1041     if (!findexample(synptr)) {
1042 	for(i = 0; i < synptr->fcount; i++) {
1043 	    if ((synptr->frmto[i] == synptr->whichword) ||
1044 		(synptr->frmto[i] == 0)) {
1045 		if (synptr->frmto[i] == synptr->whichword)
1046 		    printbuffer("          => ");
1047 		else
1048 		    printbuffer("          *> ");
1049 		printbuffer(frametext[synptr->frmid[i]]);
1050 		printbuffer("\n");
1051 	    }
1052 	}
1053     }
1054 }
1055 
printseealso(SynsetPtr synptr)1056 static void printseealso(SynsetPtr synptr)
1057 {
1058     SynsetPtr cursyn;
1059     int i, first = 1;
1060    int svwnsnsflag;
1061     static char firstline[] = "          Also See-> ";
1062     static char otherlines[] = "; ";
1063     char *prefix = firstline;
1064 
1065     /* Find all SEEALSO pointers from the searchword and print the
1066        word or synset pointed to. */
1067 
1068     for(i = 0; i < synptr->ptrcount; i++) {
1069 	if ((synptr->ptrtyp[i] == SEEALSOPTR) &&
1070 	    ((synptr->pfrm[i] == 0) ||
1071 	     (synptr->pfrm[i] == synptr->whichword))) {
1072 
1073 	    cursyn = read_synset(synptr->ppos[i], synptr->ptroff[i], "");
1074 
1075 	    svwnsnsflag = wnsnsflag;
1076 	    wnsnsflag = 1;
1077 	    printsynset(prefix, cursyn, "", DEFOFF,
1078 			synptr->pto[i] == 0 ? ALLWORDS : synptr->pto[i],
1079 			SKIP_ANTS, SKIP_MARKER);
1080 	    wnsnsflag = svwnsnsflag;
1081 
1082 	    free_synset(cursyn);
1083 
1084 	    if (first) {
1085 		prefix = otherlines;
1086 		first = 0;
1087 	    }
1088 	}
1089     }
1090     if (!first)
1091 	printbuffer("\n");
1092 }
1093 
freq_word(IndexPtr index)1094 static void freq_word(IndexPtr index)
1095 {
1096     int familiar=0;
1097     int cnt;
1098     static char *a_an[] = {
1099 	"", "a noun", "a verb", "an adjective", "an adverb" };
1100     static char *freqcats[] = {
1101 	"extremely rare","very rare","rare","uncommon","common",
1102 	"familiar","very familiar","extremely familiar"
1103     };
1104 
1105     if(index) {
1106 	cnt = index->sense_cnt;
1107 	if (cnt == 0) familiar = 0;
1108 	if (cnt == 1) familiar = 1;
1109 	if (cnt == 2) familiar = 2;
1110 	if (cnt >= 3 && cnt <= 4) familiar = 3;
1111 	if (cnt >= 5 && cnt <= 8) familiar = 4;
1112 	if (cnt >= 9 && cnt <= 16) familiar = 5;
1113 	if (cnt >= 17 && cnt <= 32) familiar = 6;
1114 	if (cnt > 32 ) familiar = 7;
1115 
1116 	sprintf(tmpbuf,
1117 		"\n%s used as %s is %s (polysemy count = %d)\n",
1118 		index->wd, a_an[getpos(index->pos)], freqcats[familiar], cnt);
1119 	printbuffer(tmpbuf);
1120     }
1121 }
1122 
wngrep(char * word_passed,int pos)1123 void wngrep (char *word_passed, int pos) {
1124    FILE *inputfile;
1125    char word[256];
1126    int wordlen, linelen, loc;
1127    char line[1024];
1128    int count = 0;
1129 
1130    inputfile = indexfps[pos];
1131    if (inputfile == NULL) {
1132       sprintf (msgbuf, "WordNet library error: Can't perform compounds "
1133          "search because %s index file is not open\n", partnames[pos]);
1134       display_message (msgbuf);
1135       return;
1136    }
1137    rewind(inputfile);
1138 
1139    strcpy (word, word_passed);
1140    ToLowerCase(word);		/* map to lower case for index file search */
1141    strsubst (word, ' ', '_');	/* replace spaces with underscores */
1142    wordlen = strlen (word);
1143 
1144    while (fgets (line, 1024, inputfile) != NULL) {
1145       for (linelen = 0; line[linelen] != ' '; linelen++) {}
1146       if (linelen < wordlen)
1147 	  continue;
1148       line[linelen] = '\0';
1149       strstr_init (line, word);
1150       while ((loc = strstr_getnext ()) != -1) {
1151          if (
1152             /* at the start of the line */
1153             (loc == 0) ||
1154             /* at the end of the line */
1155             ((linelen - wordlen) == loc) ||
1156             /* as a word in the middle of the line */
1157             (((line[loc - 1] == '-') || (line[loc - 1] == '_')) &&
1158             ((line[loc + wordlen] == '-') || (line[loc + wordlen] == '_')))
1159          ) {
1160             strsubst (line, '_', ' ');
1161             sprintf (tmpbuf, "%s\n", line);
1162             printbuffer (tmpbuf);
1163             break;
1164          }
1165       }
1166       if (count++ % 2000 == 0) {
1167          interface_doevents ();
1168          if (abortsearch) break;
1169       }
1170    }
1171 }
1172 
1173 /* Stucture to keep track of 'relative groups'.  All senses in a relative
1174    group are displayed together at end of search.  Transitivity is
1175    supported, so if either of a new set of related senses is already
1176    in a 'relative group', the other sense is added to that group as well. */
1177 
1178 struct relgrp {
1179     int senses[MAXSENSE];
1180     struct relgrp *next;
1181 };
1182 static struct relgrp *rellist;
1183 
1184 static struct relgrp *mkrellist(void);
1185 
1186 /* Simple hash function */
1187 #define HASHTABSIZE	1223	/* Prime number. Must be > 2*MAXTOPS */
1188 #define hash(n) ((n) % HASHTABSIZE)
1189 
1190 #ifdef WN1_6
1191 void trace_hyperptrs(SynsetPtr, void (*)(unsigned long, void *), void *, int);
1192 
1193 #define MAXTOPS 	300	/* Maximum number of lines in cousin.tops */
1194 
1195 static struct {
1196     int topnum;			/* Unique id assigned to this top node */
1197     Set_t rels;			/* set of top nodes this one is paired with */
1198     unsigned long offset;	/* Offset read from cousin.tops file */
1199 } cousintops[HASHTABSIZE];
1200 #endif
1201 
1202 /* Find relative groups for all senses of target word in given part
1203    of speech. */
1204 
relatives(IndexPtr idx,int dbase)1205 static void relatives(IndexPtr idx, int dbase)
1206 {
1207     rellist = NULL;
1208 
1209     switch(dbase) {
1210     case NOUN:
1211 #ifdef WN1_6
1212 /* Don't bother for nouns - doesn't work well */
1213 	findsisters(idx);
1214 	interface_doevents();
1215 	if (abortsearch)
1216 	    break;
1217 	findtwins(idx);
1218 	interface_doevents();
1219 	if (abortsearch)
1220 	    break;
1221 	findcousins(idx);
1222 	interface_doevents();
1223 	if (abortsearch)
1224 	    break;
1225 	printrelatives(idx, NOUN);
1226 #endif
1227 	break;
1228     case VERB:
1229 	findverbgroups(idx);
1230 	interface_doevents();
1231 	if (abortsearch)
1232 	    break;
1233 	printrelatives(idx, VERB);
1234 	break;
1235     default:
1236 	break;
1237     }
1238 
1239     free_rellist();
1240 }
1241 
1242 #ifdef WN1_6
1243 
1244 /* Look for 'twins' - synsets with 3 or more words in common. */
1245 
word_idx(char * wd,char * wdtable[],int nwords)1246 static int word_idx(char *wd, char *wdtable[], int nwords)
1247 {
1248      for ( ; --nwords >= 0 && strcmp(wd, wdtable[nwords]); )
1249 	  ;
1250      return nwords;
1251 }
1252 
add_word(char * wd,char * wdtable[],int nwords)1253 static int add_word(char *wd, char *wdtable[], int nwords)
1254 {
1255      wdtable[nwords] = strdup(wd);
1256      return nwords;
1257 }
1258 
1259 #define MAXWRDS 300
1260 
findtwins(IndexPtr idx)1261 static void findtwins(IndexPtr idx)
1262 {
1263      char *words[MAXWRDS];
1264      Set_t s[MAXSENSE], n;
1265      SynsetPtr synset;
1266      int i, j, nwords;
1267 
1268      assert(idx);
1269      nwords = 0;
1270      for (i = 0; i < idx->off_cnt; i++) {
1271 
1272 	  synset = read_synset(NOUN, idx->offset[i], "");
1273 
1274 	  s[i] = set_create(MAXWRDS);
1275 	  if (synset->wcount >=  3)
1276 	       for (j = 0; j < synset->wcount; j++) {
1277 		    char buf[256];
1278 		    int k;
1279 		    strtolower(strcpy(buf, synset->words[j]));
1280 		    k = word_idx(buf, words, nwords);
1281 		    if (k < 0) {
1282 			 k = add_word(buf, words, nwords);
1283 			 assert(nwords < MAXWRDS);
1284 			 nwords++;
1285 		    }
1286 		    set_addobj(s[i], k);
1287 	       }
1288 
1289 	  free_synset(synset);
1290      }
1291 
1292      n = set_create(MAXWRDS);
1293      for (i = 0; i < idx->off_cnt; i++)
1294 	  for (j = i + 1; j < idx->off_cnt; j++)
1295 	       if (set_intersection(n, s[i], s[j]),
1296 		   set_nelem(n) >= 3)
1297 		    add_relatives(NOUN, idx, j, i);
1298 
1299      set_destroy(n);
1300      for (i = 0; i < idx->off_cnt; i++)
1301 	  set_destroy(s[i]);
1302      for (i = 0; i < nwords; i++)
1303 	  free(words[i]);
1304 }
1305 
1306 /* Look for 'sisters' - senses of the search word with a common parent. */
1307 
findsisters(IndexPtr idx)1308 static void findsisters(IndexPtr idx)
1309 {
1310      int i, j, id = 0;
1311      SynsetPtr synset;
1312      Set_t syns[MAXSENSE], n;
1313      struct {int id; unsigned long off;} hypers[HASHTABSIZE] = {{0}};
1314 
1315      assert(idx);
1316 
1317      /*Read all synsets and list all hyperptrs.*/
1318 
1319      for (i = 0; i < idx->off_cnt; i++) {
1320 	  synset = read_synset(NOUN, idx->offset[i], idx->wd);
1321 	  assert(synset);
1322 	  syns[i] = set_create(4*MAXSENSE);
1323 	  assert(syns[i]);
1324 
1325 	  for (j = 0; j < synset->ptrcount; j++)
1326 	       if (synset->ptrtyp[j] == HYPERPTR) {
1327 		    int l = hash(synset->ptroff[j]);
1328 
1329 		    for ( ; hypers[l].off != synset->ptroff[j]; l++)
1330 			 if (hypers[l].off == 0) {
1331 			      hypers[l].off = synset->ptroff[j];
1332 			      hypers[l].id  =  id++;
1333 			      break;
1334 			 }
1335 			 else if (l == HASHTABSIZE - 1) l = -1;
1336 
1337 		    /*Found or inserted it.*/
1338 		    set_addobj(syns[i], hypers[l].id);
1339 	       }
1340 	  free_synset(synset);
1341      }
1342      n = set_create(4*MAXSENSE);
1343      assert(n);
1344 
1345      for (i = 0; i < idx->off_cnt; i++)
1346 	  for (j = i+1; j < idx->off_cnt; j++)
1347 	       if (set_intersection(n, syns[i], syns[j]),
1348 		   !set_isempty(n))
1349 		    add_relatives(NOUN, idx, i, j);
1350 
1351      set_destroy(n);
1352      for (i = 0; i < idx->off_cnt; i++)
1353 	  set_destroy(syns[i]);
1354 }
1355 
1356 /* Look for 'cousins' - two senses, each under a different predefined
1357    top node pair.  Top node offset pairs are stored in cousin.tops. */
1358 
1359 /* Return index of topnode if it exists */
1360 
find_topnode(unsigned long offset)1361 static int find_topnode(unsigned long offset)
1362 {
1363      int hashval = hash(offset), i;
1364 
1365      for (i = hashval; i < HASHTABSIZE; i++)
1366 	 if (cousintops[i].offset == offset)
1367 	     return(i);
1368      for (i = 0; i < hashval; i++)
1369 	 if (cousintops[i].offset == offset)
1370 	     return(i);
1371      return(-1);		/* not found */
1372  }
1373 
1374 /* Return an empty slot for <offset> to be placed in. */
1375 
new_topnode(unsigned long offset)1376 static int new_topnode(unsigned long offset)
1377 {
1378      int hashval = hash(offset), i;
1379 
1380      for (i = hashval; i < HASHTABSIZE; i++)
1381 	 if (!cousintops[i].rels)
1382 	     return(i);
1383      for (i = 0; i < hashval; i++)
1384 	 if (!cousintops[i].rels)
1385 	     return(i);
1386      return(-1);		/* table is full */
1387 }
1388 
add_topnode(int index,int id,Set_t s,unsigned long offset)1389 static void add_topnode(int index, int id, Set_t s, unsigned long offset)
1390 {
1391     if ((index >= 0) && (index < HASHTABSIZE)) {
1392 	cousintops[index].rels   = s;
1393 	cousintops[index].topnum = id;
1394 	cousintops[index].offset = offset;
1395     }
1396 }
1397 
clear_topnodes()1398 static void clear_topnodes()
1399 {
1400     int i;
1401 
1402     for (i = 0; i < HASHTABSIZE; i++)
1403 	cousintops[i].offset = 0;
1404 }
1405 
1406 /* Read cousin.tops file (one time only) and store in different form. */
1407 
read_cousintops(void)1408 static int read_cousintops(void)
1409 {
1410      static char done = 0;
1411      int id = 0;
1412      unsigned long top1, top2;
1413      int tidx1, tidx2;
1414 
1415      if (done) return(0);
1416 
1417      rewind(cousinfp);
1418      clear_topnodes();
1419 
1420      while (fscanf(cousinfp, "%ld %ld\n", &top1, &top2) != EOF) {
1421 	 if ((tidx1 = find_topnode(top1)) < 0)
1422 	     if ((tidx1 = new_topnode(top1)) != -1) {
1423 		 add_topnode(tidx1, id++, set_create(MAXTOPS), top1);
1424 	     } else {
1425 		 display_message("WordNet library error: cannot create topnode table for grouped sarches\n");
1426 		 return(-1);
1427 	     }
1428 
1429 	 if ((tidx2 = find_topnode(top2)) < 0)
1430 	     if ((tidx2 = new_topnode(top2)) != -1) {
1431 		 add_topnode(tidx2, id++, set_create(MAXTOPS), top2);
1432 	     } else {
1433 		 display_message("WordNet library error: cannot create topnode table for grouped sarches\n");
1434 		 return(-1);
1435 	     }
1436 
1437 	 set_addobj(cousintops[tidx1].rels,
1438 		    cousintops[tidx2].topnum);
1439 	 set_addobj(cousintops[tidx2].rels,
1440 		    cousintops[tidx1].topnum);
1441      }
1442      done = 1;
1443      return(0);
1444 }
1445 
1446 /* Record all top nodes found for synset. */
1447 
record_topnode(unsigned long hyperptr,void * sets)1448 static void record_topnode(unsigned long hyperptr, void *sets)
1449 {
1450      int i;
1451      assert(sets);
1452 
1453      if ((i = find_topnode(hyperptr)) >= 0) {
1454 	 set_addobj(((Set_t *)sets)[0], cousintops[i].topnum);
1455 	 set_union(((Set_t *)sets)[1], ((Set_t *)sets)[1], cousintops[i].rels);
1456      }
1457 }
1458 
findcousins(IndexPtr idx)1459 static void findcousins(IndexPtr idx)
1460 {
1461      int i, j, nsyns;
1462      SynsetPtr synset;
1463      Set_t n, syns_tops[MAXSENSE][2];
1464 
1465      assert(idx);
1466      if (read_cousintops() != 0)
1467 	 return;
1468 
1469      /* First read all the synsets */
1470 
1471      for (nsyns = 0; nsyns < idx->off_cnt; nsyns++) { /*why -1 in orig?*/
1472 	  synset = read_synset(NOUN, idx->offset[nsyns], "");
1473 	  syns_tops[nsyns][0] = set_create(MAXTOPS);
1474 	  syns_tops[nsyns][1] = set_create(MAXTOPS);
1475 
1476 	  record_topnode(idx->offset[nsyns], (void *)syns_tops[nsyns]);
1477 
1478 	  trace_hyperptrs(synset,
1479 			  record_topnode,
1480 			  syns_tops[nsyns], 1);
1481 	  free_synset(synset);
1482      }
1483 
1484      n = set_create(MAXTOPS);
1485      assert(n);
1486      for (i = 0; i < nsyns; i++)
1487 	  for (j = i + 1; j < nsyns; j++)
1488 	       if (set_intersection(n, syns_tops[i][0], syns_tops[j][1]),
1489 		   !set_isempty(n))
1490 		    add_relatives(NOUN, idx, i, j);
1491 
1492      for (i = 0; i < nsyns; i++) {
1493 	  set_destroy(syns_tops[i][0]);
1494 	  set_destroy(syns_tops[i][1]);
1495      }
1496      set_destroy(n);
1497 }
1498 /* Trace through HYPERPTRs up to MAXDEPTH, running `fn()' on each one. */
1499 
trace_hyperptrs(SynsetPtr synptr,void (* fn)(unsigned long hyperptr,void * cp),void * cp,int depth)1500 void trace_hyperptrs(SynsetPtr synptr,
1501 		     void (*fn)(unsigned long hyperptr, void *cp),
1502 		     void *cp, int depth)
1503 {
1504      SynsetPtr s;
1505      int i;
1506 
1507      if (depth >= MAXDEPTH)
1508 	  return;
1509      for (i = 0; i < synptr->ptrcount; i++)
1510 	  if (synptr->ptrtyp[i] == HYPERPTR) {
1511 	       fn(synptr->ptroff[i], cp);
1512 
1513 	       s = read_synset(synptr->ppos[i], synptr->ptroff[i], "");
1514 	       trace_hyperptrs(s, fn, cp, depth+1);
1515 	       free_synset(s);
1516 	  }
1517 }
1518 #endif
1519 
findverbgroups(IndexPtr idx)1520 static void findverbgroups(IndexPtr idx)
1521 {
1522      int i, j, k;
1523      SynsetPtr synset;
1524 
1525      assert(idx);
1526 
1527      /* Read all senses */
1528 
1529      for (i = 0; i < idx->off_cnt; i++) {
1530 
1531 	 synset = read_synset(VERB, idx->offset[i], idx->wd);
1532 
1533 	 /* Look for VERBGROUP ptr(s) for this sense.  If found,
1534 	    create group for senses, or add to existing group. */
1535 
1536 	 for (j = 0; j < synset->ptrcount; j++) {
1537 	       if (synset->ptrtyp[j] == VERBGROUP) {
1538 		   /* Need to find sense number for ptr offset */
1539 		   for (k = 0; k < idx->off_cnt; k++) {
1540 		       if (synset->ptroff[j] == idx->offset[k]) {
1541 			   add_relatives(VERB, idx, i, k);
1542 			   break;
1543 		       }
1544 		   }
1545 	       }
1546 	   }
1547 	 free_synset(synset);
1548      }
1549 }
1550 
add_relatives(int pos,IndexPtr idx,int rel1,int rel2)1551 static void add_relatives(int pos, IndexPtr idx, int rel1, int rel2)
1552 {
1553     int i;
1554     struct relgrp *rel, *last, *r;
1555 
1556 #ifdef WN1_6
1557     /* First make sure that senses are not on the excpetion list */
1558     if (pos == NOUN && groupexc(idx->offset[rel1], idx->offset[rel2]))
1559 	return;
1560 #endif
1561 
1562     /* If either of the new relatives are already in a relative group,
1563        then add the other to the existing group (transitivity).
1564        Otherwise create a new group and add these 2 senses to it. */
1565 
1566     for (rel = rellist; rel; rel = rel->next) {
1567 	if (rel->senses[rel1] == 1 || rel->senses[rel2] == 1) {
1568 	    rel->senses[rel1] = rel->senses[rel2] = 1;
1569 
1570 	    /* If part of another relative group, merge the groups */
1571 	    for (r = rellist; r; r = r->next) {
1572 		if (r != rel &&
1573 		    (r->senses[rel1] == 1 || r->senses[rel2] == 1)) {
1574 		    for (i = 0; i < MAXSENSE; i++)
1575 			rel->senses[i] |= r->senses[i];
1576 		}
1577 	    }
1578 	    return;
1579 	}
1580 	last = rel;
1581     }
1582     rel = mkrellist();
1583     rel->senses[rel1] = rel->senses[rel2] = 1;
1584     if (rellist == NULL)
1585 	rellist = rel;
1586     else
1587 	last->next = rel;
1588 }
1589 
1590 #ifdef WN1_6
groupexc(unsigned long off1,unsigned long off2)1591 static int groupexc(unsigned long off1, unsigned long off2)
1592 {
1593     char buf[9], *p, linebuf[1024];
1594 
1595     sprintf(buf, "%8.8lu", (off1 < off2 ? off1 : off2));
1596 
1597     if ((p = bin_search(buf, cousinexcfp)) != NULL) {
1598 	sprintf(buf, "%8.8lu", (off2 > off1 ? off2 : off1));
1599 	strcpy(linebuf, p + 9); /* don't copy key */
1600 	linebuf[strlen(linebuf) - 1] = '\0'; /* strip off newline */
1601 	p = strtok(linebuf, " ");
1602 	while (p && strcmp(p, buf))
1603 	    p = strtok(NULL, " ");
1604     }
1605     return(p ? 1 : 0);
1606 }
1607 #endif
1608 
mkrellist(void)1609 static struct relgrp *mkrellist(void)
1610 {
1611     struct relgrp *rel;
1612     int i;
1613 
1614     rel = (struct relgrp *) malloc(sizeof(struct relgrp));
1615     assert(rel);
1616     for (i = 0; i < MAXSENSE; i++)
1617 	rel->senses[i] = 0;
1618     rel->next = NULL;
1619     return(rel);
1620 }
1621 
free_rellist(void)1622 static void free_rellist(void)
1623 {
1624     struct relgrp *rel, *next;
1625 
1626     rel = rellist;
1627     while(rel) {
1628 	next = rel->next;
1629 	free(rel);
1630 	rel = next;
1631     }
1632 }
1633 
printrelatives(IndexPtr idx,int dbase)1634 static void printrelatives(IndexPtr idx, int dbase)
1635 {
1636     SynsetPtr synptr;
1637     struct relgrp *rel;
1638     int i, flag;
1639     int outsenses[MAXSENSE];
1640 
1641     for (i = 0; i < idx->off_cnt; i++)
1642 	outsenses[i] = 0;
1643     prflag = 1;
1644 
1645     for (rel = rellist; rel; rel = rel->next) {
1646 	flag = 0;
1647 	for (i = 0; i < idx->off_cnt; i++) {
1648 	    if (rel->senses[i] && !outsenses[i]) {
1649 		flag = 1;
1650 		synptr = read_synset(dbase, idx->offset[i], "");
1651 		printsns(synptr, i + 1);
1652 		traceptrs(synptr, HYPERPTR, dbase, 0);
1653 		outsenses[i] = 1;
1654 		free_synset(synptr);
1655 	    }
1656 	}
1657 	if (flag)
1658 	    printbuffer("--------------\n");
1659     }
1660 
1661     for (i = 0; i < idx->off_cnt; i++) {
1662 	if (!outsenses[i]) {
1663 	    synptr = read_synset(dbase, idx->offset[i], "");
1664 	    printsns(synptr, i + 1);
1665 	    traceptrs(synptr, HYPERPTR, dbase, 0);
1666 	    printbuffer("--------------\n");
1667 	    free_synset(synptr);
1668 	}
1669     }
1670 }
1671 
1672 /*
1673   Search code interfaces to WordNet database
1674 
1675   findtheinfo() - print search results and return ptr to output buffer
1676   findtheinfo_ds() - return search results in linked list data structrure
1677 */
1678 
findtheinfo(char * searchstr,int dbase,int ptrtyp,int whichsense)1679 char *findtheinfo(char *searchstr, int dbase, int ptrtyp, int whichsense)
1680 {
1681     SynsetPtr cursyn;
1682     IndexPtr idx = NULL;
1683     int depth = 0;
1684     int i, offsetcnt;
1685     char *bufstart;
1686     unsigned long offsets[MAXSENSE];
1687     int skipit;
1688 
1689     /* Initializations -
1690        clear output buffer, search results structure, flags */
1691 
1692     searchbuffer[0] = '\0';
1693 
1694     wnresults.numforms = wnresults.printcnt = 0;
1695     wnresults.searchbuf = searchbuffer;
1696     wnresults.searchds = NULL;
1697 
1698     abortsearch = overflag = 0;
1699     for (i = 0; i < MAXSENSE; i++)
1700 	offsets[i] = 0;
1701 
1702     switch (ptrtyp) {
1703     case OVERVIEW:
1704 	WNOverview(searchstr, dbase);
1705 	break;
1706     case FREQ:
1707 	while ((idx = getindex(searchstr, dbase)) != NULL) {
1708 	    searchstr = NULL;
1709 	    wnresults.SenseCount[wnresults.numforms] = idx->off_cnt;
1710 	    freq_word(idx);
1711 	    free_index(idx);
1712 	    wnresults.numforms++;
1713 	}
1714 	break;
1715     case WNGREP:
1716 	wngrep(searchstr, dbase);
1717 	break;
1718     case RELATIVES:
1719     case VERBGROUP:
1720 	while ((idx = getindex(searchstr, dbase)) != NULL) {
1721 	    searchstr = NULL;
1722 	    wnresults.SenseCount[wnresults.numforms] = idx->off_cnt;
1723 	    relatives(idx, dbase);
1724 	    free_index(idx);
1725 	    wnresults.numforms++;
1726 	}
1727 	break;
1728     default:
1729 
1730 	/* If negative search type, set flag for recursive search */
1731 	if (ptrtyp < 0) {
1732 	    ptrtyp = -ptrtyp;
1733 	    depth = 1;
1734 	}
1735 	bufstart = searchbuffer;
1736 	offsetcnt = 0;
1737 
1738 	/* look at all spellings of word */
1739 
1740 	while ((idx = getindex(searchstr, dbase)) != NULL) {
1741 
1742 	    searchstr = NULL;	/* clear out for next call to getindex() */
1743 	    wnresults.SenseCount[wnresults.numforms] = idx->off_cnt;
1744 	    wnresults.OutSenseCount[wnresults.numforms] = 0;
1745 
1746 	    /* Print extra sense msgs if looking at all senses */
1747 	    if (whichsense == ALLSENSES)
1748 		printbuffer(
1749 "                                                                         \n");
1750 
1751 	    /* Go through all of the searchword's senses in the
1752 	       database and perform the search requested. */
1753 
1754 	    for (sense = 0; sense < idx->off_cnt; sense++) {
1755 
1756 		if (whichsense == ALLSENSES || whichsense == sense + 1) {
1757 		    prflag = 0;
1758 
1759 		    /* Determine if this synset has already been done
1760 		       with a different spelling. If so, skip it. */
1761 		    for (i = 0, skipit = 0; i < offsetcnt && !skipit; i++) {
1762 			if (offsets[i] == idx->offset[sense])
1763 			    skipit = 1;
1764 		    }
1765 		    if (skipit != 1) {
1766 		    	offsets[offsetcnt++] = idx->offset[sense];
1767 		    	cursyn = read_synset(dbase, idx->offset[sense], idx->wd);
1768 		    	switch(ptrtyp) {
1769 		    	case ANTPTR:
1770 			    if(dbase == ADJ)
1771 			    	traceadjant(cursyn);
1772 			    else
1773 			    	traceptrs(cursyn, ANTPTR, dbase, depth);
1774 			    break;
1775 
1776 		    	case COORDS:
1777 			    tracecoords(cursyn, HYPOPTR, dbase, depth);
1778 			    break;
1779 
1780 		    	case FRAMES:
1781 			    printframe(cursyn, 1);
1782 			    break;
1783 
1784 		    	case MERONYM:
1785 			    traceptrs(cursyn, HASMEMBERPTR, dbase, depth);
1786 			    traceptrs(cursyn, HASSTUFFPTR, dbase, depth);
1787 			    traceptrs(cursyn, HASPARTPTR, dbase, depth);
1788 			    break;
1789 
1790 		    	case HOLONYM:
1791 			    traceptrs(cursyn, ISMEMBERPTR, dbase, depth);
1792 			    traceptrs(cursyn, ISSTUFFPTR, dbase, depth);
1793 			    traceptrs(cursyn, ISPARTPTR, dbase, depth);
1794 			    break;
1795 
1796 		    	case HMERONYM:
1797 			    partsall(cursyn, HMERONYM);
1798 			    break;
1799 
1800 		    	case HHOLONYM:
1801 			    partsall(cursyn, HHOLONYM);
1802 			    break;
1803 
1804 		    	case SEEALSOPTR:
1805 			    printseealso(cursyn);
1806 			    break;
1807 
1808 #ifdef FOOP
1809 			case PPLPTR:
1810 			    traceptrs(cursyn, ptrtyp, dbase, depth);
1811 			    traceptrs(cursyn, PPLPTR, dbase, depth);
1812 			    break;
1813 #endif
1814 
1815 		    	case SIMPTR:
1816 		    	case SYNS:
1817 		    	case HYPERPTR:
1818 			    printsns(cursyn, sense + 1);
1819 			    prflag = 1;
1820 
1821 			    traceptrs(cursyn, ptrtyp, dbase, depth);
1822 
1823 			    if (dbase == ADJ) {
1824 			    	traceptrs(cursyn, PERTPTR, dbase, depth);
1825 			    	traceptrs(cursyn, PPLPTR, dbase, depth);
1826 			    } else if (dbase == ADV) {
1827 			    	traceptrs(cursyn, PERTPTR, dbase, depth);
1828 			    }
1829 
1830 			    if (saflag)	/* print SEE ALSO pointers */
1831 			    	printseealso(cursyn);
1832 
1833 			    if (dbase == VERB && frflag)
1834 			    	printframe(cursyn, 0);
1835 			    break;
1836 
1837 			case DERIVATION:
1838 			    tracenomins(cursyn, dbase);
1839 			    break;
1840 
1841 			case CLASSIFICATION:
1842 			case CLASS:
1843 			    traceclassif(cursyn, dbase, ptrtyp);
1844 			    break;
1845 
1846 		    	default:
1847 			    traceptrs(cursyn, ptrtyp, dbase, depth);
1848 			    break;
1849 
1850 		    	} /* end switch */
1851 
1852 		    	free_synset(cursyn);
1853 
1854 		    } /* end if (skipit) */
1855 
1856 		} /* end if (whichsense) */
1857 
1858 		if (skipit != 1) {
1859 		    interface_doevents();
1860 		    if ((whichsense == sense + 1) || abortsearch || overflag)
1861 		    	break;	/* break out of loop - we're done */
1862 		}
1863 
1864 	    } /* end for (sense) */
1865 
1866 	    /* Done with an index entry - patch in number of senses output */
1867 
1868 	    if (whichsense == ALLSENSES) {
1869 		i = wnresults.OutSenseCount[wnresults.numforms];
1870 		if (i == idx->off_cnt && i == 1)
1871 		    sprintf(tmpbuf, "\n1 sense of %s", idx->wd);
1872 		else if (i == idx->off_cnt)
1873 		    sprintf(tmpbuf, "\n%d senses of %s", i, idx->wd);
1874 		else if (i > 0)	/* printed some senses */
1875 		    sprintf(tmpbuf, "\n%d of %d senses of %s",
1876 			    i, idx->off_cnt, idx->wd);
1877 
1878 		/* Find starting offset in searchbuffer for this index
1879 		   entry and patch string in.  Then update bufstart
1880 		   to end of searchbuffer for start of next index entry. */
1881 
1882 		if (i > 0) {
1883 		    if (wnresults.numforms > 0) {
1884 			bufstart[0] = '\n';
1885 			bufstart++;
1886 		    }
1887 		    strncpy(bufstart, tmpbuf, strlen(tmpbuf));
1888 		    bufstart = searchbuffer + strlen(searchbuffer);
1889 		}
1890 	    }
1891 
1892 	    free_index(idx);
1893 
1894 	    interface_doevents();
1895 	    if (overflag || abortsearch)
1896 		break;		/* break out of while (idx) loop */
1897 
1898 	    wnresults.numforms++;
1899 
1900 	} /* end while (idx) */
1901 
1902     } /* end switch */
1903 
1904     interface_doevents();
1905     if (abortsearch)
1906 	printbuffer("\nSearch Interrupted...\n");
1907     else if (overflag)
1908 	sprintf(searchbuffer,
1909 		"Search too large.  Narrow search and try again...\n");
1910 
1911     /* replace underscores with spaces before returning */
1912 
1913     return(strsubst(searchbuffer, '_', ' '));
1914 }
1915 
findtheinfo_ds(char * searchstr,int dbase,int ptrtyp,int whichsense)1916 SynsetPtr findtheinfo_ds(char *searchstr, int dbase, int ptrtyp, int whichsense)
1917 {
1918     IndexPtr idx;
1919     SynsetPtr cursyn;
1920     SynsetPtr synlist = NULL, lastsyn = NULL;
1921     int depth = 0;
1922     int newsense = 0;
1923 
1924     wnresults.numforms = 0;
1925     wnresults.printcnt = 0;
1926 
1927     while ((idx = getindex(searchstr, dbase)) != NULL) {
1928 
1929 	searchstr = NULL;	/* clear out for next call */
1930 	newsense = 1;
1931 
1932 	if(ptrtyp < 0) {
1933 	    ptrtyp = -ptrtyp;
1934 	    depth = 1;
1935 	}
1936 
1937 	wnresults.SenseCount[wnresults.numforms] = idx->off_cnt;
1938 	wnresults.OutSenseCount[wnresults.numforms] = 0;
1939 	wnresults.searchbuf = NULL;
1940 	wnresults.searchds = NULL;
1941 
1942 	/* Go through all of the searchword's senses in the
1943 	   database and perform the search requested. */
1944 
1945 	for(sense = 0; sense < idx->off_cnt; sense++) {
1946 	    if (whichsense == ALLSENSES || whichsense == sense + 1) {
1947 		cursyn = read_synset(dbase, idx->offset[sense], idx->wd);
1948 		if (lastsyn) {
1949 		    if (newsense)
1950 			lastsyn->nextform = cursyn;
1951 		    else
1952 			lastsyn->nextss = cursyn;
1953 		}
1954 		if (!synlist)
1955 		    synlist = cursyn;
1956 		newsense = 0;
1957 
1958 		cursyn->searchtype = ptrtyp;
1959 		cursyn->ptrlist = traceptrs_ds(cursyn, ptrtyp,
1960 					       getpos(cursyn->pos),
1961 					       depth);
1962 
1963 		lastsyn = cursyn;
1964 
1965 		if (whichsense == sense + 1)
1966 		    break;
1967 	    }
1968 	}
1969 	free_index(idx);
1970 	wnresults.numforms++;
1971 
1972 	if (ptrtyp == COORDS) {	/* clean up by removing hypernym */
1973 	    lastsyn = synlist->ptrlist;
1974 	    synlist->ptrlist = lastsyn->ptrlist;
1975 	    free_synset(lastsyn);
1976 	}
1977     }
1978     wnresults.searchds = synlist;
1979     return(synlist);
1980 }
1981 
1982 /* Recursive search algorithm to trace a pointer tree and return results
1983   in linked list of data structures. */
1984 
traceptrs_ds(SynsetPtr synptr,int ptrtyp,int dbase,int depth)1985 SynsetPtr traceptrs_ds(SynsetPtr synptr, int ptrtyp, int dbase, int depth)
1986 {
1987     int i;
1988     SynsetPtr cursyn, synlist = NULL, lastsyn = NULL;
1989     int tstptrtyp, docoords;
1990 
1991     /* If synset is a satellite, find the head word of its
1992        head synset and the head word's sense number. */
1993 
1994     if (getsstype(synptr->pos) == SATELLITE) {
1995 	for (i = 0; i < synptr->ptrcount; i++)
1996 	    if (synptr->ptrtyp[i] == SIMPTR) {
1997 		cursyn = read_synset(synptr->ppos[i],
1998 				      synptr->ptroff[i],
1999 				      "");
2000 		synptr->headword = malloc(strlen(cursyn->words[0]) + 1);
2001 		assert(synptr->headword);
2002 		strcpy(synptr->headword, cursyn->words[0]);
2003 		synptr->headsense = cursyn->lexid[0];
2004 		free_synset(cursyn);
2005 		break;
2006 	    }
2007     }
2008 
2009     if (ptrtyp == COORDS) {
2010 	tstptrtyp = HYPERPTR;
2011 	docoords = 1;
2012     } else {
2013 	tstptrtyp = ptrtyp;
2014 	docoords = 0;
2015     }
2016 
2017     for (i = 0; i < synptr->ptrcount; i++) {
2018 	if((synptr->ptrtyp[i] == tstptrtyp) &&
2019 	   ((synptr->pfrm[i] == 0) ||
2020 	    (synptr->pfrm[i] == synptr->whichword))) {
2021 
2022 	    cursyn=read_synset(synptr->ppos[i], synptr->ptroff[i], "");
2023 	    cursyn->searchtype = ptrtyp;
2024 
2025 	    if (lastsyn)
2026 		lastsyn->nextss = cursyn;
2027 	    if (!synlist)
2028 		synlist = cursyn;
2029 	    lastsyn = cursyn;
2030 
2031 	    if(depth) {
2032 		depth = depthcheck(depth, cursyn);
2033 		cursyn->ptrlist = traceptrs_ds(cursyn, ptrtyp,
2034 					       getpos(cursyn->pos),
2035 					       (depth+1));
2036 	    } else if (docoords) {
2037 		cursyn->ptrlist = traceptrs_ds(cursyn, HYPOPTR, NOUN, 0);
2038 	    }
2039 	}
2040     }
2041     return(synlist);
2042 }
2043 
WNOverview(char * searchstr,int pos)2044 static void WNOverview(char *searchstr, int pos)
2045 {
2046     SynsetPtr cursyn;
2047     IndexPtr idx = NULL;
2048     char *cpstring = searchstr, *bufstart;
2049     int sense, i, offsetcnt;
2050     int svdflag, skipit;
2051     unsigned long offsets[MAXSENSE];
2052 
2053     cpstring = searchstr;
2054     bufstart = searchbuffer;
2055     for (i = 0; i < MAXSENSE; i++)
2056 	offsets[i] = 0;
2057     offsetcnt = 0;
2058 
2059     while ((idx = getindex(cpstring, pos)) != NULL) {
2060 
2061 	cpstring = NULL;	/* clear for next call to getindex() */
2062 	wnresults.SenseCount[wnresults.numforms++] = idx->off_cnt;
2063 	wnresults.OutSenseCount[wnresults.numforms] = 0;
2064 
2065 	printbuffer(
2066 "                                                                                                   \n");
2067 
2068 	/* Print synset for each sense.  If requested, precede
2069 	   synset with synset offset and/or lexical file information.*/
2070 
2071 	for (sense = 0; sense < idx->off_cnt; sense++) {
2072 
2073 	    for (i = 0, skipit = 0; i < offsetcnt && !skipit; i++)
2074 		if (offsets[i] == idx->offset[sense])
2075 		    skipit = 1;
2076 
2077 	    if (!skipit) {
2078 		offsets[offsetcnt++] = idx->offset[sense];
2079 		cursyn = read_synset(pos, idx->offset[sense], idx->wd);
2080 		if (idx->tagged_cnt != -1 &&
2081 		    ((sense + 1) <= idx->tagged_cnt)) {
2082 		  sprintf(tmpbuf, "%d. (%d) ",
2083 			  sense + 1, GetTagcnt(idx, sense + 1));
2084 		} else {
2085 		  sprintf(tmpbuf, "%d. ", sense + 1);
2086 		}
2087 
2088 		svdflag = dflag;
2089 		dflag = 1;
2090 		printsynset(tmpbuf, cursyn, "\n", DEFON, ALLWORDS,
2091 			    SKIP_ANTS, SKIP_MARKER);
2092 		dflag = svdflag;
2093 		wnresults.OutSenseCount[wnresults.numforms]++;
2094 		wnresults.printcnt++;
2095 
2096 		free_synset(cursyn);
2097 	    }
2098 	}
2099 
2100 	/* Print sense summary message */
2101 
2102 	i = wnresults.OutSenseCount[wnresults.numforms];
2103 
2104 	if (i > 0) {
2105 	    if (i == 1)
2106 		sprintf(tmpbuf, "\nThe %s %s has 1 sense",
2107 			partnames[pos], idx->wd);
2108 	    else
2109 		sprintf(tmpbuf, "\nThe %s %s has %d senses",
2110 			partnames[pos], idx->wd, i);
2111 	    if (idx->tagged_cnt > 0)
2112 		sprintf(tmpbuf + strlen(tmpbuf),
2113 			" (first %d from tagged texts)\n", idx->tagged_cnt);
2114 	    else if (idx->tagged_cnt == 0)
2115 		sprintf(tmpbuf + strlen(tmpbuf),
2116 			" (no senses from tagged texts)\n");
2117 
2118 	    strncpy(bufstart, tmpbuf, strlen(tmpbuf));
2119 	    bufstart = searchbuffer + strlen(searchbuffer);
2120 	} else
2121 	    bufstart[0] = '\0';
2122 
2123 	wnresults.numforms++;
2124 	free_index(idx);
2125     }
2126 }
2127 
2128 /* Do requested search on synset passed, returning output in buffer. */
2129 
do_trace(SynsetPtr synptr,int ptrtyp,int dbase,int depth)2130 char *do_trace(SynsetPtr synptr, int ptrtyp, int dbase, int depth)
2131 {
2132     searchbuffer[0] = '\0';	/* clear output buffer */
2133     traceptrs(synptr, ptrtyp, dbase, depth);
2134     return(searchbuffer);
2135 }
2136 
2137 /* Set bit for each search type that is valid for the search word
2138    passed and return bit mask. */
2139 
is_defined(char * searchstr,int dbase)2140 unsigned int is_defined(char *searchstr, int dbase)
2141 {
2142     IndexPtr index;
2143     int i;
2144     unsigned long retval = 0;
2145 
2146     wnresults.numforms = wnresults.printcnt = 0;
2147     wnresults.searchbuf = NULL;
2148     wnresults.searchds = NULL;
2149 
2150     while ((index = getindex(searchstr, dbase)) != NULL) {
2151 	searchstr = NULL;	/* clear out for next getindex() call */
2152 
2153 	wnresults.SenseCount[wnresults.numforms] = index->off_cnt;
2154 
2155 	/* set bits that must be true for all words */
2156 
2157 	retval |= bit(SIMPTR) | bit(FREQ) | bit(SYNS)|
2158 	    bit(WNGREP) | bit(OVERVIEW);
2159 
2160 	/* go through list of pointer characters and set appropriate bits */
2161 
2162 	for(i = 0; i < index->ptruse_cnt; i++) {
2163 
2164 	    if (index->ptruse[i] <= LASTTYPE) {
2165 		retval |= bit(index->ptruse[i]);
2166 	    }
2167 
2168 #ifdef FOOP
2169 
2170 	    if (index->ptruse[i] >= CLASSIF_START &&
2171 		 index->ptruse[i] <= CLASSIF_END) {
2172 		retval |= bit(CLASSIFICATION);
2173 	    }
2174 
2175 
2176 	    if (index->ptruse[i] >= CLASS_START &&
2177 		 index->ptruse[i] <= CLASS_END) {
2178 		retval |= bit(CLASS);
2179 	    }
2180 #endif
2181 
2182 	    if (index->ptruse[i] >= ISMEMBERPTR &&
2183 	       index->ptruse[i] <= ISPARTPTR)
2184 		retval |= bit(HOLONYM);
2185 	    else if (index->ptruse[i] >= HASMEMBERPTR &&
2186 		    index->ptruse[i] <= HASPARTPTR)
2187 		retval |= bit(MERONYM);
2188 
2189 	    if (index->ptruse[i] == SIMPTR) {
2190 		retval |= bit(ANTPTR);
2191 	    }
2192 	}
2193 
2194 	if (dbase == NOUN) {
2195 #ifdef WN1_6
2196 	    retval |= bit(RELATIVES);
2197 #endif
2198 	    /* check for inherited holonyms and meronyms */
2199 
2200 	    if (HasHoloMero(index, HMERONYM))
2201 		retval |= bit(HMERONYM);
2202 	    if (HasHoloMero(index, HHOLONYM))
2203 		retval |= bit(HHOLONYM);
2204 
2205 	    /* if synset has hypernyms, enable coordinate search */
2206 
2207 	    if (retval & bit(HYPERPTR))
2208 		retval |= bit(COORDS);
2209 	} else if (dbase == VERB) {
2210 
2211 	    /* if synset has hypernyms, enable coordinate search */
2212 	    if (retval & bit(HYPERPTR))
2213 		retval |= bit(COORDS);
2214 
2215 	    /* enable grouping of related synsets and verb frames */
2216 
2217 	    retval |= bit(RELATIVES) | bit(FRAMES);
2218 	}
2219 
2220 	free_index(index);
2221 	wnresults.numforms++;
2222     }
2223     return(retval);
2224 }
2225 
2226 /* Determine if any of the synsets that this word is in have inherited
2227    meronyms or holonyms. */
2228 
HasHoloMero(IndexPtr index,int ptrtyp)2229 static int HasHoloMero(IndexPtr index, int ptrtyp)
2230 {
2231     int i, j;
2232     SynsetPtr synset, psynset;
2233     int found=0;
2234     int ptrbase;
2235 
2236     ptrbase = (ptrtyp == HMERONYM) ? HASMEMBERPTR : ISMEMBERPTR;
2237 
2238     for(i = 0; i < index->off_cnt; i++) {
2239 	synset = read_synset(NOUN, index->offset[i], "");
2240 	for (j = 0; j < synset->ptrcount; j++) {
2241 	    if (synset->ptrtyp[j] == HYPERPTR) {
2242 		psynset = read_synset(NOUN, synset->ptroff[j], "");
2243 		found += HasPtr(psynset, ptrbase);
2244 		found += HasPtr(psynset, ptrbase + 1);
2245 		found += HasPtr(psynset, ptrbase + 2);
2246 
2247 		free_synset(psynset);
2248 	    }
2249 	}
2250 	free_synset(synset);
2251     }
2252     return(found);
2253 }
2254 
HasPtr(SynsetPtr synptr,int ptrtyp)2255 static int HasPtr(SynsetPtr synptr, int ptrtyp)
2256 {
2257     int i;
2258 
2259     for(i = 0; i < synptr->ptrcount; i++) {
2260         if(synptr->ptrtyp[i] == ptrtyp) {
2261 	    return(1);
2262 	}
2263     }
2264     return(0);
2265 }
2266 
2267 /* Set bit for each POS that search word is in.  0 returned if
2268    word is not in WordNet. */
2269 
in_wn(char * word,int pos)2270 unsigned int in_wn(char *word, int pos)
2271 {
2272     int i;
2273     unsigned int retval = 0;
2274 
2275     if (pos == ALL_POS) {
2276 	for (i = 1; i < NUMPARTS + 1; i++)
2277 	    if (indexfps[i] != NULL && bin_search(word, indexfps[i]) != NULL)
2278 		retval |= bit(i);
2279     } else if (indexfps[pos] != NULL && bin_search(word,indexfps[pos]) != NULL)
2280 	    retval |= bit(pos);
2281     return(retval);
2282 }
2283 
depthcheck(int depth,SynsetPtr synptr)2284 static int depthcheck(int depth, SynsetPtr synptr)
2285 {
2286     if(depth >= MAXDEPTH) {
2287 	sprintf(msgbuf,
2288 		"WordNet library error: Error Cycle detected\n   %s\n",
2289 		synptr->words[0]);
2290 	display_message(msgbuf);
2291 	depth = -1;		/* reset to get one more trace then quit */
2292     }
2293     return(depth);
2294 }
2295 
2296 /* Strip off () enclosed comments from a word */
2297 
deadjify(char * word)2298 static char *deadjify(char *word)
2299 {
2300     char *y;
2301 
2302     adj_marker = UNKNOWN_MARKER; /* default if not adj or unknown */
2303 
2304     y=word;
2305     while(*y) {
2306 	if(*y == '(') {
2307 	    if (!strncmp(y, "(a)", 3))
2308 		adj_marker = ATTRIBUTIVE;
2309 	    else if (!strncmp(y, "(ip)", 4))
2310 		adj_marker = IMMED_POSTNOMINAL;
2311 	    else if (!strncmp(y, "(p)", 3))
2312 		adj_marker = PREDICATIVE;
2313 	    *y='\0';
2314 	} else
2315 	    y++;
2316     }
2317     return(word);
2318 }
2319 
getsearchsense(SynsetPtr synptr,int whichword)2320 static int getsearchsense(SynsetPtr synptr, int whichword)
2321 {
2322     IndexPtr idx;
2323     int i;
2324 
2325     strsubst(strcpy(wdbuf, synptr->words[whichword - 1]), ' ', '_');
2326     strtolower(wdbuf);
2327 
2328     if (idx = index_lookup(wdbuf, getpos(synptr->pos))) {
2329 	for (i = 0; i < idx->off_cnt; i++)
2330 	    if (idx->offset[i] == synptr->hereiam) {
2331 		free_index(idx);
2332 		return(i + 1);
2333 	    }
2334 	free_index(idx);
2335     }
2336     return(0);
2337 }
2338 
printsynset(char * head,SynsetPtr synptr,char * tail,int definition,int wdnum,int antflag,int markerflag)2339 static void printsynset(char *head, SynsetPtr synptr, char *tail, int definition, int wdnum, int antflag, int markerflag)
2340 {
2341     int i, wdcnt;
2342     char tbuf[SMLINEBUF];
2343 
2344     tbuf[0] = '\0';		/* clear working buffer */
2345 
2346     strcat(tbuf, head);		/* print head */
2347 
2348     /* Precede synset with additional information as indiecated
2349        by flags */
2350 
2351     if (offsetflag)		/* print synset offset */
2352 	sprintf(tbuf + strlen(tbuf),"{%8.8d} ", synptr->hereiam);
2353     if (fileinfoflag) {		/* print lexicographer file information */
2354 	sprintf(tbuf + strlen(tbuf), "<%s> ", lexfiles[synptr->fnum]);
2355 	prlexid = 1;		/* print lexicographer id after word */
2356     } else
2357 	prlexid = 0;
2358 
2359     if (wdnum)			/* print only specific word asked for */
2360 	catword(tbuf, synptr, wdnum - 1, markerflag, antflag);
2361     else			/* print all words in synset */
2362 	for(i = 0, wdcnt = synptr->wcount; i < wdcnt; i++) {
2363 	    catword(tbuf, synptr, i, markerflag, antflag);
2364 	    if (i < wdcnt - 1)
2365 		strcat(tbuf, ", ");
2366 	}
2367 
2368     if(definition && dflag && synptr->defn) {
2369 	strcat(tbuf," -- ");
2370 	strcat(tbuf,synptr->defn);
2371     }
2372 
2373     strcat(tbuf,tail);
2374     printbuffer(tbuf);
2375 }
2376 
printantsynset(SynsetPtr synptr,char * tail,int anttype,int definition)2377 static void printantsynset(SynsetPtr synptr, char *tail, int anttype, int definition)
2378 {
2379     int i, wdcnt;
2380     char tbuf[SMLINEBUF];
2381     char *str;
2382     int first = 1;
2383 
2384     tbuf[0] = '\0';
2385 
2386     if (offsetflag)
2387 	sprintf(tbuf,"{%8.8d} ", synptr->hereiam);
2388     if (fileinfoflag) {
2389 	sprintf(tbuf + strlen(tbuf),"<%s> ", lexfiles[synptr->fnum]);
2390 	prlexid = 1;
2391     } else
2392 	prlexid = 0;
2393 
2394     /* print anotnyms from cluster head (of indirect ant) */
2395 
2396     strcat(tbuf, "INDIRECT (VIA ");
2397     for(i = 0, wdcnt = synptr->wcount; i < wdcnt; i++) {
2398 	if (first) {
2399 	    str = printant(ADJ, synptr, i + 1, "%s", ", ");
2400 	    first = 0;
2401 	} else
2402 	    str = printant(ADJ, synptr, i + 1, ", %s", ", ");
2403 	if (*str)
2404 	    strcat(tbuf, str);
2405     }
2406     strcat(tbuf, ") -> ");
2407 
2408     /* now print synonyms from cluster head (of indirect ant) */
2409 
2410     for (i = 0, wdcnt = synptr->wcount; i < wdcnt; i++) {
2411 	catword(tbuf, synptr, i, SKIP_MARKER, SKIP_ANTS);
2412 	if (i < wdcnt - 1)
2413 	    strcat(tbuf, ", ");
2414     }
2415 
2416     if(dflag && synptr->defn && definition) {
2417 	strcat(tbuf," -- ");
2418 	strcat(tbuf,synptr->defn);
2419     }
2420 
2421     strcat(tbuf,tail);
2422     printbuffer(tbuf);
2423 }
2424 
catword(char * buf,SynsetPtr synptr,int wdnum,int adjmarker,int antflag)2425 static void catword(char *buf, SynsetPtr synptr, int wdnum, int adjmarker, int antflag)
2426 {
2427     static char vs[] = " (vs. %s)";
2428     static char *markers[] = {
2429 	"",			/* UNKNOWN_MARKER */
2430 	"(predicate)",		/* PREDICATIVE */
2431 	"(prenominal)",		/* ATTRIBUTIVE */
2432 	"(postnominal)",	/* IMMED_POSTNOMINAL */
2433     };
2434 
2435     /* Copy the word (since deadjify() changes original string),
2436        deadjify() the copy and append to buffer */
2437 
2438     strcpy(wdbuf, synptr->words[wdnum]);
2439     strcat(buf, deadjify(wdbuf));
2440 
2441     /* Print additional lexicographer information and WordNet sense
2442        number as indicated by flags */
2443 
2444     if (prlexid && (synptr->lexid[wdnum] != 0))
2445 	sprintf(buf + strlen(buf), "%d", synptr->lexid[wdnum]);
2446     if (wnsnsflag)
2447 	sprintf(buf + strlen(buf), "#%d", synptr->wnsns[wdnum]);
2448 
2449     /* For adjectives, append adjective marker if present, and
2450        print antonym if flag is passed */
2451 
2452     if (getpos(synptr->pos) == ADJ) {
2453 	if (adjmarker == PRINT_MARKER)
2454 	    strcat(buf, markers[adj_marker]);
2455 	if (antflag == PRINT_ANTS)
2456 	    strcat(buf, printant(ADJ, synptr, wdnum + 1, vs, ""));
2457     }
2458 }
2459 
printant(int dbase,SynsetPtr synptr,int wdnum,char * template,char * tail)2460 static char *printant(int dbase, SynsetPtr synptr, int wdnum, char *template, char *tail)
2461 {
2462     int i, j, wdoff;
2463     SynsetPtr psynptr;
2464     char tbuf[WORDBUF];
2465     static char retbuf[SMLINEBUF];
2466     int first = 1;
2467 
2468     retbuf[0] = '\0';
2469 
2470     /* Go through all the pointers looking for anotnyms from the word
2471        indicated by wdnum.  When found, print all the antonym's
2472        antonym pointers which point back to wdnum. */
2473 
2474     for (i = 0; i < synptr->ptrcount; i++) {
2475 	if (synptr->ptrtyp[i] == ANTPTR && synptr->pfrm[i] == wdnum) {
2476 
2477 	    psynptr = read_synset(dbase, synptr->ptroff[i], "");
2478 
2479 	    for (j = 0; j < psynptr->ptrcount; j++) {
2480 		if (psynptr->ptrtyp[j] == ANTPTR &&
2481 		    psynptr->pto[j] == wdnum &&
2482 		    psynptr->ptroff[j] == synptr->hereiam) {
2483 
2484 		    wdoff = (psynptr->pfrm[j] ? (psynptr->pfrm[j] - 1) : 0);
2485 
2486 		    /* Construct buffer containing formatted antonym,
2487 		       then add it onto end of return buffer */
2488 
2489 		    strcpy(wdbuf, psynptr->words[wdoff]);
2490 		    strcpy(tbuf, deadjify(wdbuf));
2491 
2492 		    /* Print additional lexicographer information and
2493 		       WordNet sense number as indicated by flags */
2494 
2495 		    if (prlexid && (psynptr->lexid[wdoff] != 0))
2496 			sprintf(tbuf + strlen(tbuf), "%d",
2497 				psynptr->lexid[wdoff]);
2498 		    if (wnsnsflag)
2499 			sprintf(tbuf + strlen(tbuf), "#%d",
2500 				psynptr->wnsns[wdoff]);
2501 		    if (!first)
2502 			strcat(retbuf, tail);
2503 		    else
2504 			first = 0;
2505 		    sprintf(retbuf + strlen(retbuf), template, tbuf);
2506 		}
2507 	    }
2508 	    free_synset(psynptr);
2509 	}
2510     }
2511     return(retbuf);
2512 }
2513 
printbuffer(char * string)2514 static void printbuffer(char *string)
2515 {
2516     if (overflag)
2517 	return;
2518     if (strlen(searchbuffer) + strlen(string) >= SEARCHBUF)
2519         overflag = 1;
2520     else
2521 	strcat(searchbuffer, string);
2522 }
2523 
printsns(SynsetPtr synptr,int sense)2524 static void printsns(SynsetPtr synptr, int sense)
2525 {
2526     printsense(synptr, sense);
2527     printsynset("", synptr, "\n", DEFON, ALLWORDS, PRINT_ANTS, PRINT_MARKER);
2528 }
2529 
printsense(SynsetPtr synptr,int sense)2530 static void printsense(SynsetPtr synptr, int sense)
2531 {
2532     char tbuf[256];
2533 
2534     /* Append lexicographer filename after Sense # if flag is set. */
2535 
2536     if (fnflag)
2537 	sprintf(tbuf,"\nSense %d in file \"%s\"\n",
2538 		sense, lexfiles[synptr->fnum]);
2539     else
2540 	sprintf(tbuf,"\nSense %d\n", sense);
2541 
2542     printbuffer(tbuf);
2543 
2544     /* update counters */
2545     wnresults.OutSenseCount[wnresults.numforms]++;
2546     wnresults.printcnt++;
2547 }
2548 
printspaces(int trace,int depth)2549 static void printspaces(int trace, int depth)
2550 {
2551     int j;
2552 
2553     for (j = 0; j < depth; j++)
2554 	printbuffer("    ");
2555 
2556     switch(trace) {
2557     case TRACEP:		/* traceptrs(), tracenomins() */
2558 	if (depth)
2559 	    printbuffer("   ");
2560 	else
2561 	    printbuffer("       ");
2562 	break;
2563 
2564     case TRACEC:		/* tracecoords() */
2565 	if (!depth)
2566 	    printbuffer("    ");
2567 	break;
2568 
2569     case TRACEI:			/* traceinherit() */
2570 	if (!depth)
2571 	    printbuffer("\n    ");
2572 	break;
2573     }
2574 }
2575 
2576 /* Dummy function to force Tcl/Tk to look at event queue to see of
2577    the user wants to stop the search. */
2578 
interface_doevents(void)2579 static void interface_doevents (void) {
2580    if (interface_doevents_func != NULL) interface_doevents_func ();
2581 }
2582 
2583 /*
2584   Revision log: (since version 1.5)
2585 
2586   $Log: search.c,v $
2587   Revision 1.161  2003/06/23 15:52:27  wn
2588   cleaned up format of nomin output
2589 
2590   Revision 1.160  2003/06/05 15:29:45  wn
2591   added pos and sense number for domains
2592 
2593   Revision 1.159  2003/04/15 13:54:16  wn
2594   *** empty log message ***
2595 
2596   Revision 1.158  2003/03/20 19:31:36  wn
2597   removed NOMIN_START/NOMIN_END range and replaced with DERIVATION
2598 
2599   Revision 1.157  2003/02/06 19:01:36  wn
2600   added code to print out word pointed to in derivational links.
2601 
2602   Revision 1.156  2003/02/06 18:03:30  wn
2603   work on classifications
2604 
2605   Revision 1.155  2002/10/29 15:46:27  wn
2606   added CLASSIFICATION code
2607 
2608   Revision 1.154  2002/09/16 15:43:01  wn
2609   allow "grep" string to be in upper case
2610 
2611   Revision 1.153  2002/09/16 15:39:16  wn
2612   *** empty log message ***
2613 
2614   Revision 1.152  2002/03/22 19:39:15  wn
2615   fill in key field in SynsetPtr if key file found
2616 
2617   Revision 1.151  2002/03/07 18:47:52  wn
2618   updates for 1.7.1
2619 
2620   Revision 1.150  2001/12/04 17:48:21  wn
2621   added test to tracenomins to only print nominalizations of serach
2622   word and not all words in synset
2623 
2624   Revision 1.149  2001/11/27 19:53:24  wn
2625   removed check for version on verb example sentence stuff. only
2626   needed for 1.5
2627 
2628   Revision 1.148  2001/11/06 18:51:04  wn
2629   fixed bug in getindex when passed "."
2630   added code to skip classification
2631 
2632   Revision 1.147  2001/10/11 18:00:56  wn
2633   fixed bug in free_syns - wasn't freeing synset pointed to by nextform
2634 
2635   Revision 1.146  2001/07/27 14:32:41  wn
2636   fixed order of adjective markers
2637 
2638   Revision 1.145  2001/06/19 15:01:22  wn
2639   commed out include for setutil.h
2640 
2641   Revision 1.144  2001/05/30 16:24:17  wn
2642   changed is_defined to return unsigned int
2643 
2644   Revision 1.143  2001/03/30 17:13:00  wn
2645   fixed is_defined - wasn't setting coords for verbs
2646 
2647   Revision 1.142  2001/03/29 16:18:03  wn
2648   added newline before output from FREQ search
2649 
2650   Revision 1.141  2001/03/29 16:11:39  wn
2651   added code to tractptrs to print direct antonyms nicer
2652 
2653   Revision 1.140  2001/03/27 18:47:41  wn
2654   removed tcflag
2655 
2656   Revision 1.139  2001/03/27 16:47:44  wn
2657   updated is_defined for holonyms and meronyms
2658 
2659   Revision 1.138  2000/08/14 16:04:24  wn
2660   changed 'get_index' to call sub to do work
2661   added code for nominalizations
2662 
2663   Revision 1.137  1998/08/11 18:07:11  wn
2664   minor fixes: free synptr space before rreturning if error; remove
2665   useless statement in free_syns
2666 
2667  * Revision 1.136  1998/08/07  17:51:32  wn
2668  * added COORDS to traceptrs_ds and findtheinfo_ds
2669  * fixed getsearchsense code to only happen in parse_synset
2670  *
2671  * Revision 1.135  1998/08/07  13:04:24  wn
2672  * *** empty log message ***
2673  *
2674  * Revision 1.134  1997/11/07  16:27:36  wn
2675  * cleanup calls to traceptrs
2676  *
2677  * Revision 1.133  1997/10/16  17:13:08  wn
2678  * fixed bug in add_topnode when index == 0
2679  *
2680  * Revision 1.132  1997/09/05  15:33:18  wn
2681  * change printframes to only print generic frames if specific example not found
2682  *
2683  * Revision 1.131  1997/09/02  16:31:18  wn
2684  * changed includes
2685  *
2686  * Revision 1.130  1997/09/02  14:43:23  wn
2687  * added code to test wnrelease in parse_synset and WNOverview
2688  *
2689  * Revision 1.129  1997/08/29  20:45:25  wn
2690  * added location sanity check on parse_synset
2691  *
2692  * Revision 1.128  1997/08/29  18:35:03  wn
2693  * a bunch of additional cleanups; added code to traceptrs_ds to
2694  * tore wordnet sense number for each word; added wnresults structure;
2695  * terminate holo/mero search at highest level having holo/mero
2696  *
2697  * Revision 1.127  1997/08/28  17:26:46  wn
2698  * Changed "n senses from tagged data" to "n senses from tagged texts"
2699  * in the overview.
2700  *
2701  * Revision 1.126  1997/08/27  13:26:07  wn
2702  * trivial change in wngrep (initialized count to zero)
2703  *
2704  * Revision 1.125  1997/08/26  21:13:14  wn
2705  * Grep now runs quickly because it doesn't call the doevents callback
2706  * after each line of the search.
2707  *
2708  * Revision 1.124  1997/08/26  20:11:23  wn
2709  * massive cleanups to print functions
2710  *
2711  * Revision 1.123  1997/08/26  15:04:18  wn
2712  * I think I got it this time; replaced goto skipit with int skipit flag
2713  * to make compiling easier on the Mac.
2714  *
2715  * Revision 1.122  1997/08/26  14:43:40  wn
2716  * In an effort to avoid compilation errors on the
2717  * Mac caused by the use of a "goto", I had tried to replace it with
2718  * an if block, but had done so improperly.  This is the restored version
2719  * from before.  Next check-in will have it properly replaced with flags.
2720  *
2721  * Revision 1.121  1997/08/25  15:54:21  wn
2722  * *** empty log message ***
2723  *
2724  * Revision 1.120  1997/08/22  21:06:02  wn
2725  * added code to use wnsnsflag to print wn sense number after each word
2726  *
2727  * Revision 1.119  1997/08/22  20:52:09  wn
2728  * cleaned up findtheinfo and other fns a bit
2729  *
2730  * Revision 1.118  1997/08/21  20:59:20  wn
2731  * grep now uses strstr instead of regexp searches.  the old version is
2732  * still there but commented out.
2733  *
2734  * Revision 1.117  1997/08/21  18:41:30  wn
2735  * now eliminates duplicates on search returns, but not yet in overview
2736  *
2737   Revision 1.116  1997/08/13 17:23:45  wn
2738   fixed mac defines
2739 
2740  * Revision 1.115  1997/08/08  20:56:33  wn
2741  * now uses built-in grep
2742  *
2743  * Revision 1.114  1997/08/08  19:15:41  wn
2744  * added code to read attest_cnt field in index file.
2745  * made searchbuffer fixed size
2746  * added WNOverview (OVERVIEW) search
2747  * added offsetflag to print synset offset before synset
2748  *
2749  * Revision 1.113  1997/08/05  14:20:29  wn
2750  * changed printbuffer to not realloc space, removed calls to stopsearch()
2751  *
2752  * Revision 1.112  1997/07/25  17:30:03  wn
2753  * various cleanups for release 1.6
2754  *
2755   Revision 1.111  1997/07/11 20:20:04  wn
2756   Added interface_doevents code for making searches interruptable in single-threaded environments.
2757 
2758  * Revision 1.110  1997/07/10  19:01:57  wn
2759  * changed evca stuff
2760  *
2761   Revision 1.109  1997/04/22 19:59:08  wn
2762   allow pertainyms to have antonyms
2763 
2764  * Revision 1.108  1996/09/17  20:05:01  wn
2765  * cleaned up EVCA code
2766  *
2767  * Revision 1.107  1996/08/16  18:34:13  wn
2768  * fixed minor bug in findcousins
2769  *
2770  * Revision 1.106  1996/07/17  14:02:17  wn
2771  * Added Kohl's verb example sentences. See getexample() and findExample().
2772  *
2773  * Revision 1.105  1996/06/14  18:49:49  wn
2774  * upped size of tmpbuf
2775  *
2776  * Revision 1.104  1996/02/08  16:42:30  wn
2777  * added some newlines to separate output and clear out tmpbuf
2778  * so invalid searches return empty string
2779  *
2780  * Revision 1.103  1995/11/30  14:54:53  wn
2781  * added grouped search for verbs
2782  *
2783  * Revision 1.102  1995/07/19  13:17:38  bagyenda
2784  * *** empty log message ***
2785  *
2786  * Revision 1.101  1995/07/18  19:15:30  wn
2787  * *** empty log message ***
2788  *
2789  * Revision 1.100  1995/07/18  18:56:24  bagyenda
2790  * New implementation of grouped searches --Paul.
2791  *
2792  * Revision 1.99  1995/06/30  19:21:23  wn
2793  * added code to findtheinfo_ds to link additional word forms
2794  * onto synset chain
2795  *
2796  * Revision 1.98  1995/06/12  18:33:51  wn
2797  * Minor change to getindex() -- Paul.
2798  *
2799  * Revision 1.97  1995/06/09  14:46:42  wn
2800  * *** empty log message ***
2801  *
2802  * Revision 1.96  1995/06/09  14:32:49  wn
2803  * changed code for PPLPTR and PERTPTR to print synsets pointed to
2804  *
2805  * Revision 1.95  1995/06/01  15:50:34  wn
2806  * cleanup of code dealing with various hyphenations
2807  *
2808  */
2809