search.c
上传用户:qin5330
上传日期:2007-01-05
资源大小:114k
文件大小:28k
源码类别:

搜索引擎

开发平台:

Perl

  1. /*
  2. ** Copyright (C) 1995, 1996, 1997, 1998 Hewlett-Packard Company
  3. ** Originally by Kevin Hughes, kev@kevcom.com, 3/11/94
  4. **
  5. ** This program and library is free software; you can redistribute it and/or
  6. ** modify it under the terms of the GNU (Library) General Public License
  7. ** as published by the Free Software Foundation; either version 2
  8. ** of the License, or any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU (Library) General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU (Library) General Public License
  16. ** along with this program; if not, write to the Free Software
  17. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. **-----------------------------------------------------------------
  19. ** Changes in expandstar and parseterm to fix the wildcard * problem.
  20. ** G. Hill, ghill@library.berkeley.edu  3/11/97
  21. **
  22. ** Changes in notresultlist, parseterm, and fixnot to fix the NOT problem
  23. ** G. Hill, ghill@library.berkeley.edu 3/13/97
  24. **
  25. ** Changes in search, parseterm, fixnot, operate, getfileinfo
  26. ** to support METADATA
  27. ** G. Hill 3/18/97 ghill@library.berkeley.edu
  28. **
  29. ** Change in search to allow for search with a list including
  30. ** also some empty indexes.
  31. ** G. Hill after a suggestion by J. Winstead 12/18/97
  32. **
  33. ** Created countResults for number of hits in search
  34. ** G. Hill 12/18/97
  35. */
  36. #include "swish.h"
  37. #include "search.h"
  38. #include "file.h"
  39. #include "list.h"
  40. #include "string.h"
  41. #include "merge.h"
  42. #include "hash.h"
  43. #include "mem.h"
  44. #include "docprop.h"
  45. #include "stemmer.h"
  46. /* The main search function.
  47. ** Parentheses are stripped out, things made lowercase,
  48. ** extra blanks removed, etc.
  49. */
  50. void search(words, indexlist, structure)
  51. char *words;
  52. struct swline *indexlist;
  53. int structure;
  54. {
  55. int i, j, metaName, indexYes, totalResults;
  56. float num;
  57. char word[MAXWORDLEN];
  58. struct result *resultlist;
  59. struct sortresult *sortresultlist;
  60. struct swline *tmplist;
  61. FILE *fp;
  62. #ifdef DEBUG
  63. struct swline *newp2;
  64. #endif
  65. #if IGNORE_STOPWORDS_IN_QUERY
  66.     struct swline *pointer1, *pointer2;
  67. #endif
  68. searchwordlist = NULL;
  69. metaName = 1;
  70. indexYes = 0;
  71. for (i = j = 0; words[i] != '' && words[i] != 'n'; i++) 
  72. {
  73. if (isspace(words[i]) || words[i] == '(' || words[i] == ')' || words[i] == '=') 
  74. {
  75. if (words[i] == '=')
  76. {
  77. if (j != 0)
  78. {
  79. if (words[i-1] != '\')
  80. word[j] = '';
  81. searchwordlist = (struct swline *) addswline(searchwordlist, 
  82. (char *) convertentities(word));
  83. j = 0;
  84. searchwordlist = (struct swline *) addswline(searchwordlist, "=");
  85. }
  86. else
  87. {
  88. /* Needs to erase the '' */
  89. j--;
  90. word[j] = tolower(words[i]);
  91. j++;
  92. }
  93. }
  94. else
  95. {
  96. searchwordlist = (struct swline *) addswline(searchwordlist, "=");
  97. }
  98. }
  99. else
  100. {
  101. if (j) 
  102. {
  103. word[j] = '';
  104. searchwordlist = (struct swline *) addswline(searchwordlist, 
  105. (char *) convertentities(word));
  106. j = 0;
  107. }
  108. if (words[i] == '(') 
  109. {
  110. searchwordlist = (struct swline *) addswline(searchwordlist, "(");
  111. }
  112. if (words[i] == ')') 
  113. {
  114. searchwordlist = (struct swline *)
  115. addswline(searchwordlist, ")");
  116. }
  117. }
  118. }
  119. else 
  120. {
  121. word[j] = tolower(words[i]);
  122. j++;
  123. }
  124. }
  125. if (j) 
  126. {
  127. word[j] = '';
  128. searchwordlist = (struct swline *) addswline(searchwordlist, 
  129. (char *) convertentities(word));
  130. }
  131. printf("%sn", INDEXHEADER);
  132. if (words[0] == '') 
  133. {
  134. printf("err: no search words specifiedn.n");
  135. exit(0);
  136. }
  137. while (indexlist != NULL) {
  138. commonerror = bigrank = 0;
  139. if ((fp = openIndexFileForRead(indexlist->line)) == NULL) {
  140. printf("# Name: unknown indexn");
  141. printf("err: could not open index filen.n");
  142. exit(0);
  143. }
  144. if (!isokindexheader(fp)) {
  145. printf("err: the index file format is unknownn.n");
  146. exit(0);
  147. }
  148. /* Was stemming applied to the index? If so, we want
  149. * to apply stemming to the search terms as well */
  150. applyStemmingRules = wasStemmingAppliedToIndex(fp);
  151. getheader(fp);
  152. if (!getindexfilenum(fp)) {
  153. indexlist = indexlist->next;
  154. continue;
  155. }
  156. else
  157. { indexYes = 1; /*There is a non-empty index */ }
  158. readoffsets(fp);
  159. readstopwords(fp);
  160. readfileoffsets(fp);
  161. readMetaNames(fp);
  162. #if IGNORE_STOPWORDS_IN_QUERY
  163. /* Added JM 1/10/98. */
  164. pointer1 = searchwordlist;
  165. pointer2 = searchwordlist->next;
  166. while (pointer1 != NULL &&
  167. isstopword(pointer1->line) && !isrule(pointer1->line)) {
  168. searchwordlist = pointer2;
  169. free(pointer1);
  170. pointer1 = pointer2;
  171. pointer2 = pointer2 ? pointer2->next : NULL;
  172. }
  173. if (pointer1 == NULL)
  174. {
  175. /* This query contained only stopwords! */
  176. printf("err: all search words too common to be usefuln.n");
  177. exit(0);
  178. }
  179. while (pointer2 != NULL) {
  180. if (isstopword(pointer2->line) &&  !isrule(pointer2->line)) {
  181. pointer1->next = pointer2->next;
  182. free(pointer2);
  183. }
  184. else {
  185. pointer1 = pointer1->next;
  186. }
  187. pointer2 = pointer2->next;
  188. }
  189. #endif
  190. printf("# Search words:");
  191. tmplist = searchwordlist;
  192. while (tmplist != NULL) {
  193. printf(" %s", tmplist->line);
  194. tmplist = tmplist->next;
  195. }
  196. putchar('n');
  197. resultlist = NULL;
  198. tmplist = searchwordlist;
  199. tmplist = (struct swline *) fixnot(tmplist);
  200. searchwordlist = (struct swline *) expandstar(tmplist, fp);
  201. #ifdef DEBUG
  202. newp2 = searchwordlist;
  203. while (newp2 != NULL) {
  204. printf("%s ", newp2->line);
  205. newp2 = newp2->next;
  206. }
  207. putchar('n');
  208. #endif
  209. #ifdef SUPPORT_DOC_PROPERTIES
  210. initSearchResultProperties();
  211. #endif
  212. resultlist = (struct result *) parseterm(fp, 0, metaName);
  213. sortresultlist = NULL;
  214. while (resultlist != NULL) 
  215. {
  216. if (resultlist->structure & structure)
  217. {
  218. long propPos;
  219. char* fileInfo = lookupfile(resultlist->filenum, fp, &propPos);
  220. sortresultlist = (struct sortresult *)
  221. addsortresult(sortresultlist, resultlist->rank,
  222. fileInfo,
  223. propPos,
  224. resultlist->filenum);
  225. }
  226. resultlist = resultlist->next;
  227. }
  228. if (sortresultlist == NULL) {
  229. if (commonerror)
  230. printf("err: a word is too commonn");
  231. else
  232. printf("err: no resultsn");
  233. }
  234. else {
  235. if (bigrank)
  236. num = 1000.0f / (float) bigrank;
  237. else
  238. num = 1000.0f;
  239. totalResults = countResults(sortresultlist);
  240. printf("# Number of hits: %dn",totalResults);
  241. printsortedresults(sortresultlist, num, fp);
  242. }
  243. /* keep file open during printsortedresults() so that 
  244. * doc properties can be retrieved */
  245. fclose(fp);
  246. searchwordlist = tmplist;
  247. indexlist = indexlist->next;
  248. }
  249. if (!indexYes)
  250. {
  251. printf("err: the index file(s) is emptyn.n");
  252. exit(0);
  253. }
  254. printf(".n");
  255. }
  256. /* This puts parentheses in the right places around not structures
  257. ** so the parser can do its thing correctly.
  258. ** It does it both for 'not' and '='; the '=' is used for the METADATA (GH)
  259. */
  260. struct swline *fixnot(sp)
  261. struct swline *sp;
  262. {
  263. int openparen, hasnot;
  264. int openMeta, hasMeta;
  265. struct swline *tmpp, *newp;
  266. #ifdef DEBUG
  267. struct swline *newp2;
  268. #endif
  269. tmpp = sp;
  270. newp = NULL;
  271. openparen = 0;
  272. openMeta = 0;
  273. hasMeta = 0;
  274. hasnot = 0;
  275. while (tmpp != NULL) {
  276. if ( ((tmpp->line)[0] == '(') && hasnot)
  277. openparen++;
  278. else if ( ((tmpp->line)[0] == '(') && hasMeta)
  279. openMeta++;
  280. else if ( ((tmpp->line)[0] == ')') && hasnot)
  281. openparen--;
  282. else if ( ((tmpp->line)[0] == ')') && hasMeta)
  283. openMeta--;
  284. if (isMetaName(tmpp->next)) {
  285. /* If it is a metaName add the name and = and skip to next */
  286. hasMeta = 1;
  287. newp = (struct swline *) addswline(newp, "(");
  288. newp = (struct swline *) addswline(newp, tmpp->line);
  289. newp = (struct swline *) addswline(newp, "=");
  290. tmpp = tmpp->next;
  291. tmpp = tmpp->next;
  292. continue;
  293. }
  294. if (!strcmp(tmpp->line, "not") ) {
  295. hasnot = 1;
  296. newp = (struct swline *) addswline(newp, "(");
  297. }
  298. else if (hasnot && !openparen) {
  299. hasnot = 0;
  300. newp = (struct swline *) addswline(newp, tmpp->line);
  301. newp = (struct swline *) addswline(newp, ")");
  302. tmpp = tmpp->next;
  303. continue;
  304. }
  305. else if (hasMeta && !openMeta) {
  306. hasMeta = 0;
  307. newp = (struct swline *) addswline(newp, tmpp->line);
  308. newp = (struct swline *) addswline(newp, ")");
  309. tmpp = tmpp->next;
  310. continue;
  311. }
  312. newp = (struct swline *) addswline(newp, tmpp->line);
  313. if (!strcmp(tmpp->line, "=") ) {
  314. hasMeta = 1;
  315. newp = (struct swline *) addswline(newp, "(");
  316. }
  317. tmpp = tmpp->next;
  318. }
  319. #ifdef DEBUG
  320. newp2 = newp;
  321. while (newp2 != NULL) {
  322. printf("%s ", newp2->line);
  323. newp2 = newp2->next;
  324. }
  325. putchar('n');
  326. #endif
  327. return newp;
  328. }
  329. /* Expands words with asterisks as wildcards into a series of
  330. ** "or" searches. Terms like "quick*" are expanded into
  331. ** "quicktime or quickly", etc.
  332. */
  333. struct swline *expandstar(sp, fp)
  334. struct swline *sp;
  335. FILE *fp;
  336. {
  337. int i, firsttime, gotstar;
  338. char foundword[MAXWORDLEN], searchword[MAXWORDLEN];
  339. struct swline *newp;
  340. newp = NULL;
  341. while (sp != NULL) {
  342. strcpy(searchword, sp->line);
  343. if (searchword[0] != '*' && strchr(searchword, '*')) {
  344. for (i = gotstar = 0; searchword[i]; i++)
  345. if (gotstar)
  346. searchword[i] = '';
  347. else if (searchword[i] == '*') {
  348. searchword[i] = '';
  349. gotstar = 1;
  350. }
  351. firsttime = 0;
  352. do {
  353. strcpy(foundword, getmatchword(searchword,
  354. fp, firsttime));
  355. if (strcmp(foundword, NOWORD)) {
  356. /* Add "(" if it is the first time */
  357. if (firsttime == 0) 
  358. newp = (struct swline *)
  359. addswline(newp, "(");
  360. if (firsttime)
  361. newp = (struct swline *)
  362. addswline(newp, "or");
  363. newp = (struct swline *)
  364. addswline(newp, foundword);
  365. }
  366. else {
  367. if (!firsttime)
  368. newp = (struct swline *)
  369. addswline(newp, NOWORD);
  370. else  /*Add ")" if last of many */
  371. newp = (struct swline *)
  372. addswline(newp, ")");
  373. break;
  374. }
  375. firsttime++;
  376. } while (strcmp(foundword, NOWORD));
  377. }
  378. else {
  379. newp = (struct swline *) addswline(newp,
  380. searchword);
  381. }
  382. sp = sp->next;
  383. }
  384. return newp;
  385. }
  386. /* If firsttime is 1, returns the first match to a beginnng of a word.
  387. ** Else if it's 0, returns the next match, until nothing is found,
  388. ** in which case NULL is returned.
  389. */
  390. char *getmatchword(word, fp, firsttime)
  391. char *word;
  392. FILE *fp;
  393. int firsttime;
  394. {
  395. int i, c, found;
  396. char *d;
  397. static char fileword[MAXWORDLEN];
  398. if (!firsttime) {
  399. for (i = found = 0; indexchars[i] != ''; i++)
  400. if (word[0] == indexchars[i]) {
  401. fseek(fp, offsets[i], 0);
  402. found = 1;
  403. }
  404. if (!found)
  405. return NOWORD;
  406. }
  407. if (offsets[STOPWORDPOS] == ftell(fp))
  408. return NOWORD;
  409. for (i = 0; (c = fgetc(fp)) != 0; ) {
  410. if (c == ':') {
  411. fileword[i] = '';
  412. i = 0;
  413. while ((c = fgetc(fp)) != 0)
  414. ;
  415. if (fileword[0] != word[0])
  416. return NOWORD;
  417. d = (char *) strstr(fileword, word);
  418. if (d != NULL && d == &fileword[0])
  419. return fileword;
  420. else {
  421. if (offsets[STOPWORDPOS] == ftell(fp))
  422. return NOWORD;
  423. }
  424. }
  425. else
  426. fileword[i++] = c;
  427. }
  428. return NOWORD;
  429. }
  430. /* Reads and prints the header of an index file.
  431. */
  432. void getheader(fp)
  433. FILE *fp;
  434. {
  435. int c;
  436. char line[MAXSTRLEN];
  437. fgets(line, MAXSTRLEN, fp);
  438. while (1) {
  439. c = fgetc(fp);
  440. ungetc(c, fp);
  441. if (c == '#') {
  442. fgets(line, MAXSTRLEN, fp);
  443. printf("%s", line);
  444. continue;
  445. }
  446. else
  447. break;
  448. }
  449. fseek(fp, 0, 0);
  450. }
  451. /* Reads the offsets in the index file so word lookup is faster.
  452. */
  453. void readoffsets(fp)
  454. FILE *fp;
  455. {
  456. int c, i, k;
  457. long j, num;
  458. for (i = 0; i < MAXCHARS; i++)
  459. offsets[i] = 0;
  460. fseek(fp, 0, 0);
  461. while (1) {
  462. c = fgetc(fp);
  463. if (c == '#') {
  464. do {
  465. c = fgetc(fp);
  466. } while (c && c != 'n');
  467. continue;
  468. }
  469. else
  470. break;
  471. }
  472. j = 0;
  473. while (c != EOF && c != 'n') {
  474. k = MAXLONGLEN;
  475. for (num = 0; c && isdigit(c) && k--; ) {
  476. num = (num * 10) + (c - '0');
  477. c = fgetc(fp);
  478. }
  479. offsets[j++] = num;
  480. }
  481. }
  482. /* Reads the stopwords in the index file.
  483. */
  484. void readstopwords(fp)
  485. FILE *fp;
  486. {
  487. int i, c;
  488. char word[MAXWORDLEN];
  489. fseek(fp, offsets[STOPWORDPOS], 0);
  490. for (i = 0; (c = fgetc(fp)) != 'n' && c != EOF; )
  491. if (!isspace(c))
  492. word[i++] = c;
  493. else {
  494. word[i] = '';
  495. addstophash(word);
  496. i = 0;
  497. }
  498. }
  499. /* Reads the metaNames from the index
  500. */
  501. void readMetaNames(fp)
  502. FILE *fp;
  503. {
  504. int i, c;
  505. char word[MAXWORDLEN];
  506. fseek(fp, offsets[METANAMEPOS], 0);
  507. for (i = 0; (c = fgetc(fp)) != 'n' && c != EOF; )
  508. {
  509. if (!isspace(c))
  510. {
  511. word[i++] = c;
  512. }
  513. else 
  514. {
  515. int docPropStyle = 0;
  516. char* docPropStyleTmp;
  517. word[i] = '';
  518. /* parse the meta name style:
  519.  * <name>"0   -> normal meta name [default]
  520.  * <name>"1   -> doc property name
  521.  * <name>"2   -> both
  522.  */
  523. docPropStyleTmp = strrchr(word, '"');
  524. if (docPropStyleTmp != NULL)
  525. {
  526. *docPropStyleTmp++ = ''; /* remove (and move past) quote */
  527. docPropStyle = atoi(docPropStyleTmp);
  528. }
  529. /* add the meta tag, possible twice */
  530. if ((docPropStyle == 0) || (docPropStyle == 2))
  531. addMetaEntry(&metaEntryList, word, 0); /* as metaName */
  532. if ((docPropStyle == 1) || (docPropStyle == 2))
  533. addMetaEntry(&metaEntryList, word, 1); /* as docProp */
  534. i = 0;
  535. }
  536. }
  537. }
  538. /* Reads the file offset table in the index file.
  539. */
  540. void readfileoffsets(fp)
  541. FILE *fp;
  542. {
  543. int j, k, c;
  544. long num;
  545. j = 0;
  546. fseek(fp, offsets[FILEOFFSETPOS], 0);
  547. c = fgetc(fp);
  548. while (c != EOF && c != 'n') {
  549. k = MAXLONGLEN;
  550. for (num = 0; c != EOF && isdigit(c) && k--; ) {
  551. num = (num * 10) + (c - '0');
  552. c = fgetc(fp);
  553. }
  554. addtofilehashlist(j++, num);
  555. }
  556. }
  557. /* The recursive parsing function.
  558. ** This was a headache to make but ended up being surprisingly easy. :)
  559. ** parseone tells the function to only operate on one word or term.
  560. */
  561. struct result *parseterm(fp, parseone, metaName)
  562. FILE *fp;
  563. int parseone;
  564. int metaName;
  565. {
  566. int rulenum;
  567. char word[MAXWORDLEN];
  568. struct result *rp, *newrp;
  569. /*
  570.  * The andLevel is used to help keep the ranking function honest
  571.  * when it ANDs the results of the latest search term with
  572.  * the results so far (rp).  The idea is that if you AND three
  573.  * words together you ultimately want to resulting rank to
  574.  * be the average of all three individual work ranks. By keeping
  575.  * a running total of the number of terms already ANDed, the
  576.  * next AND operation can properly scale the average-rank-so-far
  577.  * and recompute the new average properly (see andresultlists()).
  578.  * This implementation is a little weak in that it will not average
  579.  * across terms that are in parenthesis. (It treats an () expression
  580.  * as one term, and weights it as "one".)
  581.  */
  582. int andLevel = 0; /* number of terms ANDed so far */
  583. rp = NULL;
  584. rulenum = OR_RULE;
  585. while (searchwordlist != NULL) {
  586. strcpy(word, searchwordlist->line);
  587. if (rulenum == NO_RULE)
  588. rulenum = DEFAULT_RULE;
  589. if (isunaryrule(word)) {
  590. searchwordlist = searchwordlist->next;
  591. rp = (struct result *) parseterm(fp, 1, metaName);
  592. rp = (struct result *) notresultlist(rp, fp);
  593. /* Wild goose chase */
  594. rulenum = NO_RULE;
  595. continue;
  596. }
  597. else if (isbooleanrule(word)) {
  598. rulenum = getrulenum(word);
  599. searchwordlist = searchwordlist->next;
  600. continue;
  601. }
  602. if (rulenum != AND_RULE)
  603. andLevel = 0; /* reset */
  604. else if (rulenum == AND_RULE)
  605. andLevel++;
  606. if (word[0] == '(') {
  607. searchwordlist = searchwordlist->next;
  608. newrp = (struct result *) parseterm(fp, 0, metaName);
  609. if (rulenum == AND_RULE)
  610. rp = (struct result *)
  611. andresultlists(rp, newrp, andLevel);
  612. else if (rulenum == OR_RULE)
  613. rp = (struct result *)
  614. orresultlists(rp, newrp);
  615. if (searchwordlist == NULL)
  616. break;
  617. rulenum = NO_RULE;
  618. continue;
  619. }
  620. else if (word[0] == ')') {
  621. searchwordlist = searchwordlist->next;
  622. break;
  623. }
  624. /* Check if the next word is '=' */
  625. if ( isMetaName(searchwordlist->next) ) {
  626. metaName = getMetaName(word);
  627. if (metaName == 1){
  628. printf ("err: The metaName %s doesn't exist in  user configfilen", word);
  629. exit(0);
  630. }
  631. /* Skip both the metaName end the '=' */
  632. searchwordlist = searchwordlist->next->next;
  633. newrp = (struct result *) parseterm(fp, 1, metaName);
  634. if (rulenum == AND_RULE)
  635. rp = (struct result *) andresultlists(rp, newrp, andLevel);
  636. else if (rulenum == OR_RULE)
  637. rp = (struct result *) orresultlists(rp, newrp);
  638. if (searchwordlist == NULL)
  639. break;
  640. rulenum = NO_RULE;
  641. metaName = 1;
  642. continue;
  643. }
  644. rp = (struct result *) operate(rp, rulenum, word, 
  645.        fp, metaName,
  646.    andLevel);
  647. if (parseone) {
  648. searchwordlist = searchwordlist->next;
  649. break;
  650. }
  651. rulenum = NO_RULE;
  652. searchwordlist = searchwordlist->next;
  653. }
  654. return rp;
  655. }
  656. /* Looks up a word in the index file -
  657. ** it calls getfileinfo(), which does the real searching.
  658. */
  659. struct result *operate(rp, rulenum, word, fp, metaName, andLevel)
  660. struct result *rp;
  661. int rulenum;
  662. char *word;
  663. FILE *fp;
  664. int metaName;
  665. int andLevel;
  666. {
  667. int i, found;
  668. struct result *newrp, *returnrp;
  669. if (applyStemmingRules)
  670. {
  671. /* apply stemming algorithm to the search term */
  672. Stem(word);
  673. }
  674. if (isstopword(word) && !isrule(word)) 
  675. {
  676. if (rulenum == OR_RULE && rp != NULL)
  677. return rp;
  678. else
  679. commonerror = 1;
  680. }
  681. for (i = found = 0; indexchars[i] != ''; i++)
  682. {
  683. if (word[0] == indexchars[i]) 
  684. {
  685. fseek(fp, offsets[i], 0);
  686. found = 1;
  687. }
  688. }
  689. if (!found) 
  690. {
  691. if (rulenum == AND_RULE)
  692. return NULL;
  693. else if (rulenum == OR_RULE)
  694. return rp;
  695. }
  696. newrp = (struct result *) getfileinfo(word, fp, metaName);
  697. if (rulenum == AND_RULE)
  698. returnrp = (struct result *) andresultlists(rp, newrp, andLevel);
  699. else if (rulenum == OR_RULE)
  700. returnrp = (struct result *) orresultlists(rp, newrp);
  701. else if (rulenum == NOT_RULE)
  702. returnrp = (struct result *) notresultlist(newrp, fp);
  703. return returnrp;
  704. }
  705. /* Looks up a file name in the index file.
  706. */
  707. char *lookupfile(filenum, fp, propPos)
  708.      int filenum;
  709.      FILE *fp;
  710.      long *propPos;
  711. {
  712. static char line[MAXSTRLEN];
  713. fseek(fp, getfilenum(decodefilenum(filenum) - 1), 0);
  714. fgets(line, MAXSTRLEN, fp);
  715. #ifdef SUPPORT_DOC_PROPERTIES
  716. if (propPos != NULL)
  717. *propPos = ftell(fp);
  718. #endif
  719. return line;
  720. }
  721. /* Finds a word and returns its corresponding file and rank information list.
  722. ** If not found, NULL is returned.
  723. */
  724. struct result *getfileinfo(word, fp, metaName)
  725. char *word;
  726. FILE *fp;
  727. int metaName;
  728. {
  729. int i, c, x, countnum, rank, filenum, structure;
  730. char fileword[MAXWORDLEN];
  731. struct result *rp;
  732. int res;
  733. rp = NULL;
  734. for (i = 0; (c = fgetc(fp)) != 0; ) {
  735. if (c == ':') {
  736. fileword[i] = '';
  737. i = 0;
  738. res = strcmp(word,fileword);
  739. if (!res)
  740. break;
  741. else if (res > 0){
  742. while ((c = fgetc(fp)) != 0)
  743. ;
  744. if (offsets[STOPWORDPOS] == ftell(fp))
  745. return NULL;
  746. continue;
  747. }
  748. else if (res < 0)
  749. return NULL;
  750. }
  751. else
  752. fileword[i++] = c;
  753. }
  754. if (c == 0)
  755. return NULL;
  756. countnum = 1;
  757. ungetc(c, fp);
  758. while ((c = fgetc(fp)) != 0) 
  759. {
  760. x = 0;
  761. do {
  762. c = fgetc(fp);
  763. if (c == 0)
  764. return rp;
  765. x *= 128;
  766. x += c & 127;
  767. } while (c & 128);
  768. if (x) 
  769. {
  770. if (countnum == 1) {
  771. filenum = x;
  772. countnum++;
  773. }
  774. else if (countnum == 2) {
  775. rank = x;
  776. countnum++;
  777. }
  778. else if (countnum == 3) {
  779. structure = x;
  780. countnum++;
  781. }
  782. else if (countnum == 4) {
  783. if ( x == metaName )
  784. {
  785. rp = (struct result *) addtoresultlist(rp, filenum, rank, structure);
  786. if (verbose == 4)
  787. {
  788. /* dump diagnostic info */
  789. char* pos;
  790. char* fileinfo;
  791. long curFilePos;
  792. curFilePos = ftell(fp); /* save */
  793. fileinfo = lookupfile(filenum, fp, NULL);
  794. pos = strchr(fileinfo, '"'); /* after file name */
  795. if (pos)
  796. *(pos-1) = ''; /* truncate */
  797. printf("# diagt%st%st%dn",
  798. fileinfo, 
  799. word, 
  800. rank);
  801. if (pos)
  802. *(pos-1) = ' '; /* restore */
  803. fseek(fp, curFilePos, 0); /* restore */
  804. }
  805. }
  806. countnum = 1;
  807. }
  808. }
  809. }
  810. return rp;
  811. }
  812. /* Is a word a rule?
  813. */
  814. int isrule(word)
  815. char *word;
  816. {
  817. if (!strcmp(word, "and") || !strcmp(word, "or") || !strcmp(word, "not"))
  818. return 1;
  819. else
  820. return 0;
  821. }
  822. /* Is a word a boolean rule?
  823. */
  824. int isbooleanrule(word)
  825. char *word;
  826. {
  827. if (!strcmp(word, "and") || !strcmp(word, "or"))
  828. return 1;
  829. else
  830. return 0;
  831. }
  832. /* Is a word a unary rule?
  833. */
  834. int isunaryrule(word)
  835. char *word;
  836. {
  837. if (!strcmp(word, "not"))
  838. return 1;
  839. else
  840. return 0;
  841. }
  842. /* Return the number for a rule.
  843. */
  844. int getrulenum(word)
  845. char *word;
  846. {
  847. if (!strcmp(word, "and"))
  848. return AND_RULE;
  849. else if (!strcmp(word, "or"))
  850. return OR_RULE;
  851. else if (!strcmp(word, "not"))
  852. return NOT_RULE;
  853. return NO_RULE;
  854. }
  855. /* Takes two lists of results from searches and ANDs them together.
  856. */
  857. struct result *andresultlists(r1, r2, andLevel)
  858.      struct result *r1;
  859.      struct result *r2;
  860.      int andLevel;
  861. {
  862. static struct result *tmpnode, *newnode;
  863. if (r1 == NULL || r2 == NULL)
  864. return NULL;
  865. newnode = NULL;
  866. if (andLevel < 1)
  867. andLevel = 1;
  868. while (r1 != NULL) {
  869. tmpnode = r2;
  870. while (tmpnode != NULL) {
  871. if (r1->filenum == tmpnode->filenum)
  872. {
  873. /*
  874.  * Computing the new rank is interesting because
  875.  * we want to weight each of the words that was
  876.  * previously ANDed equally along with the new word.
  877.  * We compute a running average using andLevel and
  878.  * simply scale up the old average (in r1->rank)
  879.  * and recompute a new, equally weighted average.
  880.  */
  881. int newRank;
  882. /*newRank = (r1->rank + tmpnode->rank) / 2;*/
  883. newRank = ((r1->rank * andLevel) + tmpnode->rank) / (andLevel+1);
  884. newnode = (struct result *)
  885. addtoresultlist(newnode, 
  886. r1->filenum,
  887. newRank,
  888. r1->structure & tmpnode->structure);
  889. }
  890. tmpnode = tmpnode->next;
  891. }
  892. r1 = r1->next;
  893. }
  894. return newnode;
  895. }
  896. /* Takes two lists of results from searches and ORs them together.
  897. */
  898. struct result *orresultlists(r1, r2)
  899. struct result *r1;
  900. struct result *r2;
  901. {
  902. int i;
  903. struct result *rp;
  904. static struct result *newnode;
  905. newnode = NULL;
  906. if (r1 == NULL)
  907. return r2;
  908. else if (r2 == NULL)
  909. return r1;
  910. initresulthashlist();
  911. while (r1 != NULL) {
  912. mergeresulthashlist(r1->filenum, r1->rank, r1->structure);
  913. r1 = r1->next;
  914. }
  915. while (r2 != NULL) {
  916. mergeresulthashlist(r2->filenum, r2->rank, r2->structure);
  917. r2 = r2->next;
  918. }
  919. for (i = 0; i < HASHSIZE; i++) {
  920. rp = resulthashlist[i];
  921. while (rp != NULL) {
  922. newnode = (struct result *) addtoresultlist(newnode,
  923. rp->filenum, rp->rank, rp->structure);
  924. rp = rp->next;
  925. }
  926. }
  927. return newnode;
  928. }
  929. /* This performs the NOT unary operation on a result list.
  930. ** NOTed files are marked with a default rank of 1000.
  931. **
  932. ** Basically it returns all the files that have not been
  933. ** marked (GH)
  934. */
  935. struct result *notresultlist(rp, fp)
  936. struct result *rp;
  937. FILE *fp;
  938. {
  939. int i, filenums;
  940. struct result *newp;
  941. newp = NULL;
  942. initmarkentrylist();
  943. while (rp != NULL) {
  944. marknum(rp->filenum);
  945. rp = rp->next;
  946. }
  947. filenums = getindexfilenum(fp);
  948. for (i = 1; i <= filenums; i++) {
  949. if (!ismarked(i))
  950. newp = (struct result *) addtoresultlist(newp, i, 1000, IN_ALL);
  951. }
  952. return newp;
  953. }
  954. /* Adds a file number and rank to a list of results.
  955. */
  956. struct result *addtoresultlist(rp, filenum, rank, structure)
  957. struct result *rp;
  958. int filenum;
  959. int rank;
  960. int structure;
  961. {
  962. struct result *newnode;
  963. static struct result *head;
  964. newnode = (struct result *) emalloc(sizeof(struct result));
  965. newnode->filenum = filenum;
  966. newnode->rank = rank;
  967. newnode->structure = structure;
  968. newnode->next = NULL;
  969. if (rp == NULL)
  970. rp = newnode;
  971. else
  972. head->next = newnode;
  973. head = newnode;
  974. return rp;
  975. }
  976. /* Adds the results of a search, sorts them by rank.
  977. */
  978. struct sortresult *addsortresult(sp, rank, fileinfo, propPos, filenum)
  979.      struct sortresult *sp;
  980.      int rank;
  981.      char *fileinfo;
  982.      long propPos;
  983.      int filenum;
  984. {
  985. if (rank > bigrank)
  986. bigrank = rank;
  987. if (sp == NULL) {
  988. char* endOfLinePos;
  989. sp = (struct sortresult *) emalloc(sizeof(struct sortresult));
  990. sp->rank = rank;
  991. sp->fileinfo = (char *) mystrdup(fileinfo);
  992. sp->left = sp->right = NULL;
  993. /* formatting search results is easier without the newline */
  994. endOfLinePos = strchr(sp->fileinfo, 'n');
  995. if (endOfLinePos)
  996. *endOfLinePos = '';
  997. #ifdef SUPPORT_DOC_PROPERTIES
  998. sp->propPos = propPos; /* allows later lookup of doc properties */
  999. #endif
  1000. }
  1001. else {
  1002. if (sp->rank < rank)
  1003. sp->left = (struct sortresult *) addsortresult(sp->left, rank, fileinfo, propPos, filenum);
  1004. else
  1005. sp->right = (struct sortresult *) addsortresult(sp->right, rank, fileinfo, propPos, filenum);
  1006. }
  1007. return sp;
  1008. }
  1009. /* Counts the number of files that are the result
  1010.    of a search
  1011. */
  1012. int countResults(sp)
  1013. struct sortresult *sp;
  1014. {
  1015. int tot;
  1016. if (sp == NULL)
  1017. return 0;
  1018. else
  1019.     {
  1020. tot = countResults(sp->right) + countResults(sp->left) + 1;
  1021.     }
  1022. return tot;
  1023. }
  1024. /* Prints the final results of a search.
  1025. */
  1026. void printsortedresults(sp, num, fp)
  1027.      struct sortresult *sp;
  1028.      double num;
  1029.      FILE* fp;
  1030. {
  1031. int rank;
  1032. if (sp != NULL) 
  1033. {
  1034. printsortedresults(sp->left, num, fp);
  1035. rank = (int) ((float) sp->rank * num);
  1036. if (rank >= 999)
  1037. rank = 1000;
  1038. if (maxhits) 
  1039. {
  1040. if (useCustomOutputDelimiter)
  1041. {
  1042. /* parse fileinfo into filename and title */
  1043. char* filename;
  1044. char* title;
  1045. char* endOfTitle = NULL;
  1046. char* fileSize;
  1047. filename = sp->fileinfo;
  1048. title = strchr(filename, '"');
  1049. if (title == NULL)
  1050. {
  1051. title = "";
  1052. fileSize = "0";
  1053. }
  1054. else
  1055. {
  1056. *(title-1) = ''; /* remove space between filename and title */
  1057. title++; /* past double quote */
  1058. endOfTitle = strchr(title, '"'); /* end of title */
  1059. if (endOfTitle)
  1060. {
  1061. *endOfTitle = '';
  1062. fileSize = endOfTitle+1;
  1063. while (*fileSize == ' ')
  1064. fileSize++;
  1065. }
  1066. else
  1067. {
  1068. fileSize = "0";
  1069. }
  1070. }
  1071. printf("%d%s%s%s%s%s%s", 
  1072. (rank <= 0) ? 1 : rank, 
  1073. customOutputDelimiter,
  1074. filename,
  1075. customOutputDelimiter,
  1076. title,
  1077. customOutputDelimiter,
  1078. fileSize);
  1079. if (*title)
  1080. {
  1081. /* restore fileinfo... */
  1082. *(--title) = ' '; /* restore space */
  1083. if (endOfTitle)
  1084. *endOfTitle = '"';
  1085. }
  1086. }
  1087. else
  1088. {
  1089. printf("%d %s", (rank <= 0) ? 1 : rank, sp->fileinfo);
  1090. }
  1091. #ifdef SUPPORT_DOC_PROPERTIES
  1092. printSearchResultProperties(sp->propPos, fp);
  1093. #endif
  1094. printf("n");
  1095. if (maxhits > 0) 
  1096. {
  1097. maxhits--;
  1098. }
  1099. }
  1100. printsortedresults(sp->right, num, fp);
  1101. }
  1102. }
  1103. /* Reads a compressed line. This is just here for testing, etc.
  1104. */
  1105. void getrawindexline(fp)
  1106. FILE *fp;
  1107. {
  1108. int c, inword;
  1109. inword = 1;
  1110. while ((c = fgetc(fp)) != EOF) {
  1111. if (c == ':' && inword)
  1112. inword = 0;
  1113. if (!inword) {
  1114. do {
  1115. c = fgetc(fp);
  1116. if (c == 0)
  1117. return;
  1118. } while (c & 128);
  1119. }
  1120. }
  1121. }
  1122. /* Does an index file have a readable format?
  1123. */
  1124. int isokindexheader(fp)
  1125. FILE *fp;
  1126. {
  1127. char line[MAXSTRLEN];
  1128. fseek(fp, 0, 0);
  1129. fgets(line, MAXSTRLEN, fp);
  1130. if (line[strlen(line) - 1] == 'n')
  1131. line[strlen(line) - 1] = '';
  1132. if (strcmp(line, INDEXHEADER)) {
  1133. fseek(fp, 0, 0);
  1134. return 0;
  1135. }
  1136. fseek(fp, 0, 0);
  1137. return 1;
  1138. }
  1139. int wasStemmingAppliedToIndex(fp)
  1140.      FILE *fp;
  1141. {
  1142. /* Check the header for the magic line "# Stemming Applied:"
  1143.  * and see if stemming was applied.
  1144.  * Return 1 if it was, 0 otherwise
  1145.  */
  1146. char line[MAXSTRLEN];
  1147. int stemmingDone = 0; /* assume no stemming */
  1148. int hdrLen;
  1149. hdrLen = strlen(STEMMINGHEADER);
  1150. fseek(fp, 0, 0);
  1151. fgets(line, MAXSTRLEN, fp);
  1152. while (line[0] == '#')
  1153. {
  1154. if (strncmp(line, STEMMINGHEADER, hdrLen) == 0)
  1155. {
  1156. /* found the line. what does it say? */
  1157. stemmingDone = atoi(line+hdrLen);
  1158. break;
  1159. }
  1160. fgets(line, MAXSTRLEN, fp);
  1161. }
  1162. fseek(fp, 0, 0);
  1163. return stemmingDone;
  1164. }
  1165. /* Returns the value associated with the metaName if it exists
  1166. */
  1167. int getMetaName(word)
  1168. char * word;
  1169. {
  1170. struct metaEntry* temp;
  1171. for (temp = metaEntryList; temp != NULL; temp = temp->next) 
  1172. if (!strcmp(temp->metaName, word))
  1173. return temp->index;
  1174. return 1;
  1175. }
  1176. /* Checks if the next word is "="
  1177. */
  1178. int isMetaName (searchWord)
  1179. struct swline* searchWord;
  1180. {
  1181. if (searchWord == NULL)
  1182. return 0;
  1183. if (!strcmp(searchWord->line, "=") )
  1184. return 1;
  1185. return 0;
  1186. }
  1187.