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

搜索引擎

开发平台:

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. **  long 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. ** ** ** PATCHED 5/13/96, CJC
  20. **
  21. ** Added code to countwords and countwordstr to disreguard the last char
  22. ** if requiered by the config.h
  23. ** G. Hill  3/12/97  ghill@library.berkeley.edu
  24. **
  25. ** Changed addentry, countwords, countwordstr, parsecomment, printindex
  26. ** added createMetaEntryList, getMeta, parseMetaData
  27. ** to support METADATA
  28. ** G. Hill 3/18/97 ghill@library.berkeley.edu
  29. **
  30. ** Changed removestops to support printing of stop words
  31. ** G. Hill 4/7/97
  32. **
  33. ** Changed countwords, countwrdstr, and parseMetaData to disreguard the
  34. ** first char if required by the config.h
  35. ** G.Hill 10/16/97  ghill@library.berkeley.edu
  36. **
  37. ** Added stripIgnoreLastChars and isIgnoreLastChar routines which iteratively
  38. ** remove all ignore characters from the end of each word.
  39. ** P. Bergner  10/5/97  bergner@lcse.umn.edu
  40. **
  41. ** Added stripIgnoreFirstChars and isIgnoreFirstChar to make stripping of
  42. ** the ignore first chars iterative.
  43. ** G. Hill 11/19/97 ghill@library.berkeley.edu
  44. **
  45. ** Added possibility of use of quotes and brackets in meta CONTENT countwords, parsemetadata
  46. ** G. Hill 1/14/98
  47. **
  48. ** Added regex for replace rule G.Hill 1/98
  49. */
  50. #include "swish.h"
  51. #include "index.h"
  52. #include "hash.h"
  53. #include "mem.h"
  54. #include "string.h"
  55. #include "check.h"
  56. #include "search.h"
  57. #include "docprop.h"
  58. #include "stemmer.h"
  59. /* Stores file names in alphabetical order so they can be
  60. ** indexed alphabetically. No big whoop.
  61. */
  62. struct sortentry *addsortentry(e, filename, title)
  63. struct sortentry *e;
  64. char *filename;
  65. char *title;
  66. {
  67. if (e == NULL) {
  68. e = (struct sortentry *) emalloc(sizeof(struct sortentry));
  69. e->filename = (char *) mystrdup(filename);
  70. e->title = (char *) mystrdup(title);
  71. e->left = e->right = NULL;
  72. }
  73. else {
  74. if (strcmp(e->filename, filename) > 0)
  75. e->left = (struct sortentry *)
  76. addsortentry(e->left, filename, title);
  77. else
  78. e->right = (struct sortentry *)
  79. addsortentry(e->right, filename, title);
  80. }
  81. return e;
  82. }
  83. /* Adds a word to the master index tree.
  84. */
  85. struct entry *addentry(e, word, filenum, emphasized, structure, metaName)
  86. struct entry *e;
  87. char *word;
  88. int filenum;
  89. int emphasized;
  90. int structure;
  91. int metaName;
  92. {
  93. int isbigger;
  94. struct location *tp, *oldtp;
  95. if (e == NULL) {
  96. e = (struct entry *) emalloc(sizeof(struct entry));
  97. e->word = (char *) mystrdup(word);
  98. e->tfrequency = 1;
  99. e->locationlist = (struct location *)
  100. emalloc(sizeof(struct location));
  101. e->locationlist->filenum = filenum;
  102. e->locationlist->frequency = 1;
  103. e->locationlist->emphasized = emphasized;
  104. e->locationlist->structure = structure;
  105. e->locationlist->metaName = metaName;
  106. e->locationlist->next = NULL;
  107. e->left = e->right = NULL;
  108. totalwords++;
  109. }
  110. else {
  111. isbigger = wordcompare(e->word, word);
  112. if (isbigger == 0) {
  113. tp = e->locationlist;
  114. while (tp != NULL) {
  115. if (tp->filenum == filenum && tp->metaName == metaName) 
  116. break;
  117. oldtp = tp;
  118. tp = tp->next;
  119. }
  120. if (tp == NULL) {
  121. tp = (struct location *) emalloc(sizeof(struct
  122. location));
  123. tp->filenum = filenum;
  124. tp->frequency = 1;
  125. tp->emphasized = emphasized;
  126. tp->structure = structure;
  127. tp->metaName = metaName;
  128. tp->next = NULL;
  129. oldtp->next = tp;
  130. if (!emphasized)
  131. e->tfrequency = e->tfrequency + 1;
  132. }
  133. else {
  134. if ((tp->filenum == filenum) && (tp->metaName == metaName)) 
  135. {
  136. tp->frequency++;
  137. if (emphasized)
  138. tp->emphasized++;
  139. tp->structure |= structure;
  140. }
  141. }
  142. }
  143. else if (isbigger > 0)
  144. {
  145. e->left = (struct entry *)
  146. addentry(e->left, word, filenum, emphasized, structure, metaName);
  147. }
  148. else
  149. {
  150. e->right = (struct entry *)
  151. addentry(e->right, word, filenum, emphasized, structure, metaName);
  152. }
  153. }
  154. return e;
  155. }
  156. /* Adds a file to the master list of files and file numbers.
  157. */
  158. struct file *addtofilelist(filep, filename, title, size, newFileEntry)
  159. struct file *filep;
  160. char *filename;
  161. char *title;
  162. int size;
  163. struct file ** newFileEntry;
  164. {
  165. struct file *newnode;
  166. static struct file *filelistp = NULL;
  167. newnode = (struct file *) emalloc(sizeof(struct file));
  168. if (newFileEntry != NULL)
  169. {
  170. *newFileEntry = newnode; /* pass object pointer up to caller */
  171. }
  172. newnode->filename = (char *) mystrdup(filename);
  173. newnode->title = (char *) mystrdup(title);
  174. newnode->size = size;
  175. newnode->next = NULL;
  176. #ifdef SUPPORT_DOC_PROPERTIES
  177. newnode->docProperties = NULL;
  178. #endif
  179. if (filep == NULL)
  180. filep = newnode;
  181. else if (filelistp != NULL)
  182. filelistp->next = newnode;
  183. filelistp = newnode;
  184. return filep;
  185. }
  186. /* Just goes through the master list of files and
  187. ** counts 'em.
  188. */
  189. int getfilecount(filep)
  190. struct file *filep;
  191. {
  192. int i;
  193. for (i = 0; filep != NULL; filep = filep->next)
  194. i++;
  195. return i;
  196. }
  197. /* Returns the nicely formatted date.
  198. */
  199. char *getthedate()
  200. {
  201. static char date[MAXSTRLEN];
  202. time_t time;
  203. time = (time_t) getthetime();
  204. /* strftime(date, MAXSTRLEN, "%x %X", (struct tm *) localtime(&time));*/
  205. strftime(date, MAXSTRLEN, "%d/%m/%y %H:%M:%S %Z",
  206. (struct tm *) localtime(&time)); 
  207. return date;
  208. }
  209. /* Indexes all the words in a file and adds the appropriate information
  210. ** to the appropriate structures.
  211. */
  212. int countwords(vp, filename, title, indextitleonly)
  213. void *vp;
  214. char *filename;
  215. char *title;
  216. int indextitleonly;
  217. {
  218. int c, i, j, inword, ftotalwords, emphasized, structure;
  219. int metaName;
  220. static int filenum;
  221. char word[MAXWORDLEN], tag[MAXSTRLEN];
  222. struct file *thisFileEntry = NULL;
  223. ftotalwords = 0;
  224. if (indextitleonly) {
  225. filelist = addtofilelist(filelist, filename, title, vsize(vp), NULL);
  226. filenum++;
  227. if (!(filenum % 128))
  228. filenum++;
  229. addtofwordtotals(filenum, 100);
  230. return (countwordstr(title, filenum, 0));
  231. }
  232. filelist = addtofilelist(filelist, filename, title, vsize(vp), &thisFileEntry);
  233. filenum++;
  234. if (!(filenum % 128))
  235. filenum++;
  236. c = 1;
  237. i = j = 0;
  238. inword = 0;
  239. emphasized = 0;
  240. structure = 1;
  241. metaName = 1;
  242. while (c != EOF && (c = vgetc(vp)) != EOF) 
  243. {
  244. if (!inword) {
  245. if (iswordchar((char)c)) {
  246. i = 0;
  247. word[i++] = c;
  248. if (i == MAXWORDLEN)
  249. i--;
  250. inword = 1;
  251. }
  252. }
  253. else if (inword) 
  254. {
  255. if (!iswordchar((char)c)) 
  256. {
  257. word[i++] = '';
  258. if (i == MAXWORDLEN)
  259. word[--i] = '';
  260. /* Move this stuff after entities are converted
  261. for (i = 0; word[i]; i++)
  262. word[i] = tolower(word[i]);
  263. i = 0;
  264. */
  265. if (isokword(word))
  266. {
  267. strcpy(word, (char *) convertentities(word));
  268. }
  269. /* Ok, can now go to lowercase, the whole problem
  270. was with entities Á would become á
  271. */
  272. for (i = 0; word[i]; i++)
  273. word[i] = tolower(word[i]);
  274. i = 0;
  275. /* Get rid of the last char's */
  276. stripIgnoreLastChars(word);
  277. /* Get rid of the first char */
  278. stripIgnoreFirstChars(word);
  279. if (applyStemmingRules)
  280. {
  281. /* apply stemming algorithm to the word to index */
  282. Stem(word);
  283. }
  284. /* Sorry, have to do isokword() twice to filter out converted strings! */
  285. if (hasokchars(word) && isokword(word)) 
  286. {
  287. #ifdef DEBUG
  288. printf(" %s %dn", word, structure);
  289. #endif
  290. entrylist = (struct entry *)
  291. addentry(entrylist, word, filenum, emphasized,  structure, metaName);
  292. ftotalwords++;
  293. }
  294. inword = 0;
  295. }
  296. else {
  297. word[i++] = c;
  298. if (i == MAXWORDLEN)
  299. i--;
  300. }
  301. }
  302. if (c == '<' && !INDEXTAGS) {
  303. j = 0;
  304. while ((c = vgetc(vp)) != EOF) {
  305. tag[j++] = c;
  306. if (j == MAXSTRLEN)
  307. j--;
  308. if (c == '>' && notEscaped(tag,j) ) {
  309. if (j)
  310. tag[--j] = '';
  311. else
  312. tag[j] = '';
  313. #ifdef DEBUG
  314. printf("t: %sn", tag);
  315. #endif
  316. structure = getstructure(tag,
  317. structure);
  318. #ifdef DEBUG
  319. printf("s: %dn", structure);
  320. #endif
  321. if ((tag[0]=='!') && 
  322. lstrstr(tag,"META") && 
  323. (lstrstr(tag,"START") ||
  324. lstrstr(tag,"END") ) ) 
  325. {
  326. if (lstrstr(tag, "START")) 
  327. {
  328. metaName=getMeta(tag, NULL);
  329. /* If there is not a legal metaName
  330. ** the program quits into getMeta
  331. */
  332. }
  333. else if (lstrstr(tag, "END") ) 
  334. {
  335. metaName = 1;
  336. }
  337. }
  338. else if ( (tag[0] != '!') &&
  339. (lstrstr(tag, "META")) &&
  340. (lstrstr(tag,"NAME")) &&
  341. (lstrstr(tag,"CONTENT")) )
  342. {
  343. ftotalwords += parseMetaData(tag, filenum, structure, thisFileEntry);
  344. }
  345. else if ( (tag[0] == '!') && indexComments)
  346. {
  347. ftotalwords += parsecomment(tag, filenum, structure,1);
  348. }
  349. if ((structure & IN_HEADER) ||
  350. (structure & IN_TITLE))
  351. emphasized = 5;
  352. else
  353. emphasized = 0;
  354. break;
  355. }
  356. }
  357. }
  358. }
  359. addtofwordtotals(filenum, ftotalwords);
  360. return ftotalwords;
  361. }
  362. /* Indexes the words in a string, such as a file name or an
  363. ** HTML title.
  364. */
  365. int countwordstr(s, filenum, emphasized)
  366. char *s;
  367. int filenum;
  368. int emphasized;
  369. {
  370. int i, j, inword, wordcount;
  371. char c, word[MAXWORDLEN], tmpstr[MAXFILELEN];
  372. sprintf(tmpstr, "%s ", s);
  373. for (j = inword = wordcount = 0; (c = tmpstr[j]) != ''; j++) {
  374. if (!inword) {
  375. if (iswordchar(c)) {
  376. i = 0;
  377. word[i++] = c;
  378. if (i == MAXWORDLEN)
  379. i--;
  380. inword = 1;
  381. }
  382. }
  383. else {
  384. if (!iswordchar(c)) {
  385. wordcount++;
  386. word[i] = '';
  387. /* Same as above, move after convertentities
  388. for (i = 0; word[i]; i++)
  389. word[i] = tolower(word[i]);
  390. */
  391. if (isokword(word))
  392. strcpy(word, (char *)
  393. convertentities(word));
  394. /* Ok to go lower now */
  395. for (i = 0; word[i]; i++)
  396. word[i] = tolower(word[i]);
  397. /* Get rid of specified last char's */
  398. stripIgnoreLastChars (word);
  399. /* Get rid of the first char */
  400. stripIgnoreFirstChars(word);
  401. if (hasokchars(word) && isokword(word))
  402. entrylist = (struct entry *)
  403. addentry(entrylist, word,
  404. filenum, emphasized, IN_FILE, 1);
  405. inword = 0;
  406. }
  407. else {
  408. word[i++] = c;
  409. if (i == MAXWORDLEN)
  410. i--;
  411. }
  412. }
  413. }
  414. return wordcount;
  415. }
  416. /* This returns the value corresponding to the HTML structures
  417. ** a word is in.
  418. */
  419. int getstructure(tag, structure)
  420. char *tag;
  421. int structure;
  422. {
  423.         int len;
  424.         char oldChar = 0;
  425.         char* endOfTag = NULL;
  426.         char* pos;
  427. pos = tag;
  428.         while (*pos)
  429.   {
  430.                 if (isspace(*pos))
  431.   {
  432.                         endOfTag = pos; /* remember where we are... */
  433.                         oldChar = *pos; /* ...and what we saw */
  434.                         *pos = '';    /* truncate string, for now */
  435.       }
  436. else 
  437.   pos++;
  438.       }
  439.         if (ourstricmp(tag, "/title") == 0)
  440.                 structure &= ~IN_TITLE;
  441.         else if (ourstricmp(tag, "title") == 0)
  442.                 structure |= IN_TITLE;
  443.         else if (ourstricmp(tag, "/head") == 0)
  444.                 structure &= ~IN_HEAD;
  445.         else if (ourstricmp(tag, "head") == 0)
  446.                 structure |= IN_HEAD;
  447.         else if (ourstricmp(tag, "/body") == 0)
  448.                 structure &= ~IN_BODY;
  449.         else if (ourstricmp(tag, "body") == 0)
  450.                 structure |= IN_BODY;
  451.         else if (tag[0] == '/' && tolower(tag[1]) == 'h' && isdigit(tag[2]))
  452.                 structure &= ~IN_HEADER;
  453.         else if (tolower(tag[0]) == 'h' && isdigit(tag[1]))
  454.                 structure |= IN_HEADER;
  455.         else if ((ourstricmp(tag, "/em") == 0) || 
  456.  (ourstricmp(tag, "/strong") == 0))
  457.                 structure &= ~IN_EMPHASIZED;
  458.         else if ((ourstricmp(tag, "em") == 0) ||
  459.  (ourstricmp(tag, "strong") == 0))
  460.                 structure |= IN_EMPHASIZED;
  461.         else if ((ourstricmp(tag, "b") == 0) || (ourstricmp(tag, "i") == 0))
  462.                 structure |= IN_EMPHASIZED;
  463.         else if ((ourstricmp(tag, "/b") == 0) || 
  464.  (ourstricmp(tag, "/i") == 0))
  465.                 structure &= ~IN_EMPHASIZED;
  466.         if (endOfTag != NULL)
  467.   {
  468.                 *endOfTag = oldChar;
  469.       }
  470.         return structure;
  471. }
  472. /* Parses the words in a comment.
  473. */
  474. int parsecomment(tag, filenum, structure, metaName)
  475. char *tag;
  476. int filenum;
  477. int structure;
  478. int metaName;
  479. {
  480. int i, j, inword, wordcount, emphasized;
  481. char c, word[MAXWORDLEN];
  482. if (EMPHASIZECOMMENTS)
  483. emphasized = 5;
  484. else
  485. emphasized = 0;
  486. structure |= IN_COMMENTS;
  487. for (j = 1, inword = wordcount = 0; (c = tag[j]) != ''; j++) {
  488. if (!inword) {
  489. if (iswordchar(c)) {
  490. i = 0;
  491. word[i++] = c;
  492. if (i == MAXWORDLEN)
  493. i--;
  494. inword = 1;
  495. }
  496. }
  497. else {
  498. if (!iswordchar(c)) {
  499. wordcount++;
  500. word[i] = '';
  501. for (i = 0; word[i]; i++)
  502. word[i] = tolower(word[i]);
  503. if (isokword(word))
  504. strcpy(word, (char *)
  505. convertentities(word));
  506. if (hasokchars(word) && isokword(word))
  507. {
  508. if (applyStemmingRules)
  509. {
  510. /* apply stemming algorithm to the word to index */
  511. Stem(word);
  512. }
  513. entrylist = (struct entry *)
  514. addentry(entrylist, word, filenum, emphasized, structure, metaName);
  515. }
  516. inword = 0;
  517. }
  518. else {
  519. word[i++] = c;
  520. if (i == MAXWORDLEN)
  521. i--;
  522. }
  523. }
  524. }
  525. return wordcount;
  526. }
  527. /* Removes words that occur in over _plimit_ percent of the files and
  528. ** that occur in over _flimit_ files (marks them as stopwords, that is).
  529. */
  530. int removestops(ep, totalfiles, plimit, flimit)
  531. struct entry *ep;
  532. int totalfiles;
  533. int plimit;
  534. int flimit;
  535. {
  536. int percent, wordfilecount, stopwords;
  537. struct location *lp;
  538. stopwords = 0;
  539. if (ep != NULL) {
  540. stopwords += removestops(ep->left, totalfiles, plimit, flimit);
  541. lp = ep->locationlist;
  542. wordfilecount = 0;
  543. while (lp != NULL) {
  544. wordfilecount++;
  545. lp = lp->next;
  546. }
  547. percent = (int) (((float) wordfilecount / (float) totalfiles) * 100.0f);
  548. if (percent >= plimit && wordfilecount >= flimit) {
  549. addStopList(ep->word);
  550. addstophash(ep->word);
  551. stopwords++;
  552. }
  553. stopwords += removestops(ep->right,totalfiles, plimit, flimit);
  554. }
  555. return stopwords;
  556. }
  557. /* This is somewhat similar to the rank calculation algorithm
  558. ** from WAIS (I think). Any suggestions for improvements?
  559. ** Note that ranks can't be smaller than 1, emphasized words
  560. ** (words in titles, headers) have ranks multiplied by at least 5
  561. ** (just a guess), and ranks divisible by 128 are bumped up by one
  562. ** (to make the compression scheme with with '' as a line delimiter
  563. ** work). Fudging with the ranks doesn't seem to make much difference.
  564. */
  565. int getrank(freq, tfreq, words, emphasized)
  566. int freq;
  567. int tfreq;
  568. int words;
  569. int emphasized;
  570. {
  571. double d, e, f;
  572. int tmprank;
  573. if (freq < 5)
  574. freq = 5;
  575. d = 1.0 / (double) tfreq;
  576. e = (log((double) freq) + 10.0) * d;
  577. if (!ignoreTotalWordCountWhenRanking)
  578. {
  579. e /= words;
  580. }
  581. else
  582. {
  583. /* scale the rank down a bit. a larger has the effect of
  584.    making small differences in work frequency wash out */ 
  585. e /= 100;
  586. }
  587. f = e * 10000.0;
  588. /*sprintf(rankstr, "%f", f);
  589. tmprank = atoi(rankstr);*/
  590. tmprank = (int) f;
  591. if (tmprank <= 0)
  592. tmprank = 1;
  593. if (emphasized)
  594. tmprank *= emphasized;
  595. if (!(tmprank % 128))
  596. tmprank++;
  597. return tmprank;
  598. }
  599. /* Prints the index information at the head of index files.
  600. */
  601. void printheader(fp, filename, totalwords, totalfiles, merged)
  602. FILE *fp;
  603. char *filename;
  604. int totalwords;
  605. int totalfiles;
  606. int merged;
  607. {
  608. char *c;
  609. c = (char *) strrchr(filename, '/');
  610. fprintf(fp, "%sn", INDEXHEADER);
  611. fprintf(fp, "%sn", INDEXVERSION);
  612. fprintf(fp, "# %sn", (merged) ? "MERGED INDEX" : "");
  613. fprintf(fp, "# Name: %sn", (indexn[0] == '') ? "(no name)" :
  614. indexn);
  615. fprintf(fp, "# Saved as: %sn", 
  616. (c == NULL && c + 1 != '') ? filename : c + 1);
  617. fprintf(fp, "# Counts: ");
  618. if (totalwords)
  619. fprintf(fp, "%d words%s", totalwords, (totalfiles) ? ", " : "");
  620. if (totalfiles)
  621. fprintf(fp, "%d files", totalfiles);
  622. fprintf(fp, "n");
  623. fprintf(fp, "# Indexed on: %sn", getthedate());
  624. fprintf(fp, "# Description: %sn", (indexd[0] == '') ?
  625. "(no description)" : indexd);
  626. fprintf(fp, "# Pointer: %sn", (indexp[0] == '') ?
  627. "(no pointer)" : indexp);
  628. fprintf(fp, "# Maintained by: %sn", (indexa[0] == '') ?
  629. "(no maintainer)" : indexa);
  630. #ifdef SUPPORT_DOC_PROPERTIES
  631. fprintf(fp, "# DocumentProperties: %sn", "Enabled");
  632. #endif
  633. fprintf(fp, "%s %dn", STEMMINGHEADER, applyStemmingRules);
  634. }
  635. char* getFileNameByFileNum(int filenum)
  636. {
  637. /* for diagnostics only */
  638. struct file *filep = filelist;
  639. while ((filep != NULL) && --filenum)
  640. {
  641. filep = filep->next;
  642. }
  643. if (filep != NULL)
  644. return filep->filename;
  645. else
  646. return "";
  647. }
  648. /* Print the index entries that hold the word, rank, and other information.
  649. */
  650. void printindex(ep, fp)
  651. struct entry *ep;
  652. FILE *fp;
  653. {
  654. int i, rank;
  655. struct location *lp;
  656. if (ep != NULL) {
  657. printindex(ep->left, fp);
  658. if (!isstopword(ep->word)) {
  659. for (i = 0; indexchars[i] != ''; i++)
  660. if ((ep->word)[0] == indexchars[i] &&
  661. !offsets[i])
  662. offsets[i] = ftell(fp);
  663. fprintf(fp, "%s:", ep->word);
  664. lp = ep->locationlist;
  665. while (lp != NULL) {
  666. int totalWords;
  667. totalWords = gettotalwords(lp->filenum);
  668. rank = getrank(lp->frequency, ep->tfrequency,
  669. totalWords, lp->emphasized);
  670. if (verbose == 4)
  671. {
  672. printf("%st%st%dt%dt%dt%dt%dt%dt%dn",
  673. getFileNameByFileNum(lp->filenum), 
  674. ep->word, 
  675. lp->emphasized, 
  676. rank, 
  677. lp->frequency, 
  678. ep->tfrequency, 
  679. totalWords,
  680. lp->structure,
  681. lp->metaName);
  682. }
  683. compress(lp->filenum, fp);
  684. compress(rank, fp);
  685. compress(lp->structure, fp);
  686. compress(lp->metaName, fp);
  687. lp = lp->next;
  688. }
  689. fputc(0, fp);
  690. }
  691. printindex(ep->right, fp);
  692. }
  693. }
  694. /* Prints the list of stopwords into the index file.
  695. */
  696. void printstopwords(fp)
  697. FILE *fp;
  698. {
  699. int hashval;
  700. struct swline *sp;
  701. offsets[STOPWORDPOS] = ftell(fp);
  702. for (hashval = 0; hashval < HASHSIZE; hashval++) {
  703. sp = hashstoplist[hashval];
  704. while (sp != NULL) {
  705. fprintf(fp, "%s ", sp->line);
  706. sp = sp->next;
  707. }
  708. }
  709. fprintf(fp, "n");
  710. }
  711. void writeFileEntry(filep, fp)
  712.      struct file *filep;
  713.      FILE *fp;
  714. {
  715. fprintf(fp, "%s "%s" %dn", 
  716. ruleparse(filep->filename),
  717. filep->title, filep->size);
  718. #ifdef SUPPORT_DOC_PROPERTIES
  719. storeDocProperties(filep->docProperties, fp);
  720. freeDocProperties(&filep->docProperties);
  721. #endif
  722. }
  723. void readFileEntry(fp, line, docProperties)
  724.      FILE* fp;
  725.      char* line;
  726.      struct docPropertyEntry **docProperties;
  727. {
  728. fgets(line, MAXSTRLEN, fp);
  729. if (docProperties != NULL)
  730. *docProperties = NULL;
  731. #ifdef SUPPORT_DOC_PROPERTIES
  732. /* read (or skip over) the document properties section  */
  733. fetchDocProperties(docProperties, fp);
  734. #endif
  735. }
  736. /* Prints the list of files, titles, and sizes into the index file.
  737. */
  738. void printfilelist(filep, fp)
  739. struct file *filep;
  740. FILE *fp;
  741. {
  742. int i;
  743. i = 0;
  744. offsets[FILELISTPOS] = ftell(fp);
  745. while (filep != NULL) 
  746. {
  747. int filenum = i++;
  748. addtofilehashlist(filenum, ftell(fp));
  749. writeFileEntry(filep, fp);
  750. filep = filep->next;
  751. }
  752. }
  753. /* Prints the list of metaNames into the file index
  754. */
  755. void printMetaNames(fp)
  756. FILE *fp;
  757. {
  758. struct metaEntry* entry;
  759. char docPropStyle[20];
  760. offsets[METANAMEPOS] = ftell(fp);
  761. for (entry = metaEntryList; entry; entry = entry->next)
  762.     {
  763. docPropStyle[0] = '';
  764. #ifdef SUPPORT_DOC_PROPERTIES
  765. if (entry->isDocProperty)
  766. {
  767. /* write the meta name style:
  768.  * <name>"0   -> normal meta name [default, so does not have to be written]
  769.  * <name>"1   -> doc property name
  770.  * <name>"2   -> both
  771.  */
  772. sprintf(docPropStyle, ""%d", (entry->isOnlyDocProperty) ? 1 : 2);
  773. }
  774. #endif
  775. fprintf(fp, "%s%s ", entry->metaName, docPropStyle);
  776.     }
  777. fprintf(fp, "n");
  778. }
  779. /* Prints the list of file offsets into the index file.
  780.  */
  781. void printfileoffsets(fp)
  782. FILE *fp;
  783. {
  784. int i;
  785. offsets[FILEOFFSETPOS] = ftell(fp);
  786. for (i = 0; getfilenum(i) != 0; i++)
  787. fprintf(fp, "%016li", getfilenum(i));
  788. fprintf(fp,"n");
  789. }
  790. /* Takes a number and prints it to a file using the simple
  791. ** accordion scheme of storing numbers.
  792. */
  793. void compress(num, fp)
  794. int num;
  795. FILE *fp;
  796. {
  797. int i, r;
  798. static char s[8];
  799. i = 0;
  800. while (num) {
  801. r = num % 128;
  802. num /= 128;
  803. s[i++] = r;
  804. }
  805. while (i-- >= 0)
  806. fputc(s[i] | (i ? 128 : 0), fp);
  807. }
  808. /* Prints out the decompressed values in an index file.*/
  809. void decompress(fp)
  810. FILE *fp;
  811. {
  812. int c, x, inword, fieldnum;
  813. long pos;
  814. char line[MAXSTRLEN], header[MAXHEADCHARS + 1];
  815. readoffsets(fp);
  816. if (verbose == 4)
  817. {
  818. readfileoffsets(fp);
  819. }
  820. fseek(fp, 0, 0);
  821. inword = 1;
  822. fieldnum = 0;
  823. while (1) {
  824. c = fgetc(fp);
  825. ungetc(c, fp);
  826. if (c == '#') {
  827. fgets(line, MAXSTRLEN, fp);
  828. printf("%s", line);
  829. continue;
  830. }
  831. else {
  832. fgets(header, MAXHEADCHARS + 1, fp);
  833. printf("%s", header);
  834. break;
  835. }
  836. }
  837. while ((c = fgetc(fp)) != EOF) 
  838. {
  839. if (c == ':' && inword) {
  840. inword = 0;
  841. putchar(c);
  842. }
  843. if (inword)
  844. putchar(c);
  845. else {
  846. x = 0;
  847. do {
  848. c = fgetc(fp);
  849. pos = ftell(fp);
  850. if (pos == offsets[STOPWORDPOS]) {
  851. putchar('n');
  852. while (fgets(line, MAXSTRLEN, fp) != NULL)
  853. {
  854. printf("%s", line);
  855. }
  856. return;
  857. }
  858. if (c == 0) {
  859. putchar('n');
  860. inword = 1;
  861. break;
  862. }
  863. x *= 128;
  864. x += c & 127;
  865. } while (c & 128);
  866. if (x)
  867. {
  868. if (verbose == 4)
  869.   {
  870.     if (fieldnum == 0)
  871.       {
  872. char* filename;
  873. char* junk;
  874. pos = ftell(fp);
  875. filename = lookupfile(x, fp, NULL);
  876. junk = strchr(filename, '"');
  877. *(junk-1) = '';
  878. printf(" %s", filename);
  879. fseek(fp, pos, 0);
  880.       }
  881.     else if (fieldnum == 1)
  882.       {
  883. printf(" %d", x);
  884.       }
  885.     else if (fieldnum == 2)
  886.       {
  887.       }
  888.     else if (fieldnum == 3)
  889.       {
  890.       }
  891.   }
  892. else
  893.   {
  894. printf(" %d", x);
  895.   }
  896. fieldnum++;
  897. if (fieldnum == 4)
  898.   fieldnum = 0;
  899. }
  900. }
  901. }
  902. }
  903. /* Parses lines according to the ReplaceRules directives.
  904. */
  905. char *ruleparse(line)
  906. char *line;
  907. {
  908. char rule[MAXSTRLEN];
  909. static char tmpline[MAXSTRLEN], newtmpline[MAXSTRLEN];
  910. static char line1[MAXSTRLEN], line2[MAXSTRLEN];
  911. struct swline *tmplist;
  912. if (replacelist == NULL)
  913. return line;
  914. tmplist = replacelist;
  915. strcpy(tmpline, line);
  916. while (1) 
  917. {
  918. if (tmplist == NULL)
  919. return tmpline;
  920. strcpy(rule, tmplist->line);
  921. tmplist = tmplist->next;
  922. if (tmplist == NULL)
  923. return tmpline;
  924. if (rule == NULL) {
  925. replacelist = tmplist;
  926. return tmpline;
  927. }
  928. else {
  929. if (lstrstr(rule, "replace")) {
  930. strcpy(line1, tmplist->line);
  931. tmplist = tmplist->next;
  932. if (tmplist)
  933. {
  934. strcpy(line2, tmplist->line);
  935. tmplist = tmplist->next;
  936. }
  937. else
  938. {
  939. /* Handle case where 2nd part of replace rule
  940. ** is an empty string. Config-file parsing
  941. ** idiosyncrasies cause a replace of "x" to ""
  942. ** to incompletely represent the rule.
  943. */
  944. line2[0] = '';
  945. }
  946. strcpy(newtmpline, (char *) matchAndChange(tmpline,
  947. line1, line2));
  948. }
  949. else if (lstrstr(rule, "append")) {
  950. sprintf(newtmpline, "%s%s", tmpline,
  951. tmplist->line);
  952. tmplist = tmplist->next;
  953. }
  954. else if (lstrstr(rule, "prepend")) {
  955. sprintf(newtmpline, "%s%s", tmplist->line,
  956. tmpline);
  957. tmplist = tmplist->next;
  958. }
  959. else if (lstrstr(rule,"remove")) {
  960. strcpy(newtmpline, (char *)matchAndChange(tmpline,tmplist->line,""));
  961. }
  962. strcpy(tmpline, newtmpline);
  963. }
  964. }
  965. }
  966. /* Get the MetaData index when the whole tag is passed */
  967. int getMeta(tag, docPropName)
  968. char* tag;
  969. int* docPropName;
  970. {
  971. char* temp;
  972. char word[MAXWORDLEN];
  973. int i;
  974. struct metaEntry* list;
  975. if (docPropName != NULL)
  976. {
  977. *docPropName = 0;
  978. }
  979. i = 0;
  980. temp = (char*) lstrstr((char*)tag,(char*) "NAME");
  981. if (temp == NULL)
  982. return 1;
  983. temp += strlen("NAME");
  984. /* Get to the '=' sign disreguarding blanks */
  985. while (temp != NULL) {
  986. if (strncmp(temp, "=",1))
  987. temp++;
  988. else {
  989. temp++;
  990. break;
  991. }
  992. }
  993. /* Get to the beginning of the word disreguarding blanks and quotes */
  994. while (temp != NULL) {
  995. if (!strncmp(temp," ",1) || !strncmp(temp,""",1) )
  996. temp++;
  997. else
  998. break;
  999. }
  1000. /* Copy the word and convert to lowercase */
  1001. while (temp !=NULL && strncmp(temp," ",1) 
  1002. && strncmp(temp,""",1) && i<= MAXWORDLEN ) {
  1003. word[i] = *temp++;
  1004. word[i] = tolower(word[i]);
  1005. i++;
  1006. }
  1007. if (i == MAXWORDLEN)
  1008. word[--i] = '';
  1009. else
  1010. word[i] = '';
  1011. for (list = metaEntryList; list != NULL; list = list->next)
  1012. {
  1013. if (!strcmp(list->metaName, word) )
  1014. {
  1015. #ifdef SUPPORT_DOC_PROPERTIES
  1016. if ((docPropName != NULL) && (list->isDocProperty))
  1017. {
  1018. *docPropName = list->index;
  1019. }
  1020. if (list->isOnlyDocProperty)
  1021. {
  1022. /* property is not for indexing, so return generic metaName value */
  1023. return 1;
  1024. }
  1025. #endif
  1026. return list->index;
  1027. }
  1028. }
  1029. /* If it is ok not to have the name listed, just index as no-name */
  1030. if (OKNOMETA) {
  1031. /*    printf ("nwarning: metaName %s does not exiest in the user config file", word); */
  1032. return 1;
  1033. }
  1034. else {
  1035. printf ("nerr: INDEXING FAILUREn");
  1036. printf ("err: The metaName %s does not exist in the user config filen", word);
  1037. exit(0);
  1038. }
  1039. }
  1040. /* Parses the Meta tag */
  1041. int parseMetaData(tag, filenum, structure, thisFileEntry)
  1042. char* tag;
  1043. int filenum;
  1044. int structure;
  1045. struct file* thisFileEntry;
  1046. {
  1047. int metaName, j, i, inword, wordcount, emphasized, jstart;
  1048. char* temp;
  1049. char c, word[MAXWORDLEN];
  1050. int docPropName = 0;
  1051. wordcount = 0;
  1052. temp = NULL;
  1053. metaName= getMeta(tag, &docPropName);
  1054. temp = (char*) lstrstr((char*) tag,(char*) "CONTENT");
  1055. /* if there is no  CONTENT is another tag so just ignore the whole thing
  1056. * the check is done here istead of before because META tags do not have
  1057. * a fixed length that can be checked
  1058. */
  1059. if (temp != NULL)
  1060.     {
  1061. temp += strlen("CONTENT");
  1062. /* Get to the " sign disreguarding blanks */
  1063. while (temp != NULL) {
  1064. if (strncmp(temp, """,1))
  1065. temp++;
  1066. else {
  1067. temp++;
  1068. break;
  1069. }
  1070. }
  1071. jstart = strlen(tag) - strlen(temp);
  1072. if (EMPHASIZECOMMENTS)
  1073. emphasized = 5;
  1074. else
  1075. emphasized = 0;
  1076. #ifdef SUPPORT_DOC_PROPERTIES
  1077. if (docPropName)
  1078. {
  1079. temp = strchr(tag + jstart, '"'); /* first quote after start of CONTENT */
  1080. if (temp != NULL)
  1081. {
  1082. *temp = ''; /* terminate CONTENT, temporarily */
  1083. addDocProperty(&thisFileEntry->docProperties, docPropName, tag+jstart);
  1084. *temp = '"'; /* restore string */
  1085. }
  1086. }
  1087. #endif
  1088. for (j = jstart, inword = wordcount = 0;(c = tag[j]) != ''; j++) {
  1089. if (!inword) {
  1090. if (iswordchar(c)) {
  1091. i = 0;
  1092. word[i++] = c;
  1093. if (i == MAXWORDLEN)
  1094. i--;
  1095. inword = 1;
  1096. }
  1097. }
  1098. else {
  1099. if (!iswordchar(c)) {
  1100. wordcount++;
  1101. word[i] = '';
  1102. for (i = 0; word[i]; i++)
  1103. word[i] = tolower(word[i]);
  1104. if (isokword(word))
  1105. strcpy(word, (char *)
  1106. convertentities(word));
  1107. /* Get rid of the last specified char's */
  1108. stripIgnoreLastChars(word);
  1109. /* Get rid of the first char */
  1110. stripIgnoreFirstChars(word);
  1111. if (applyStemmingRules)
  1112. {
  1113. /* apply stemming algorithm to the word to index */
  1114. Stem(word);
  1115. }
  1116. if (hasokchars(word) && isokword(word))
  1117. entrylist = (struct entry *)
  1118. addentry(entrylist, word,
  1119. filenum, emphasized, 
  1120. structure, metaName);
  1121. inword = 0;
  1122. if (c == '"' && tag[j-1] != '\')
  1123. break;
  1124. }
  1125. else {
  1126. word[i++] = c;
  1127. if (i == MAXWORDLEN)
  1128. i--;
  1129. }
  1130. }
  1131. }
  1132.     }
  1133. return wordcount;
  1134. }
  1135. /*  These 2 routines fix the problem when a word ends with mutiple
  1136. **  IGNORELASTCHAR's (eg, qwerty'. ).  The old code correctly deleted
  1137. **  the ".", but didn't check if the new last character ("'") is also
  1138. **  an ignore character.
  1139. */
  1140. void stripIgnoreLastChars(char *word)
  1141. {
  1142. int i;
  1143. /* Get rid of specified last char's */
  1144. for (i=0; word[i] != ''; i++)
  1145. ;
  1146. /* Iteratively strip off the last character if it's an ignore character */
  1147. while ( isIgnoreLastChar(word[--i]) )
  1148. word[i] = '';
  1149. }
  1150. int isIgnoreLastChar(char c)
  1151. {
  1152. int i;
  1153. /*  Returns TRUE if the character is a member of ignorelastchar,
  1154. **  FALSE otherwise.
  1155. */
  1156. for (i=0; ignorelastchar[i] != ''; i++)
  1157. {
  1158. if (c == ignorelastchar[i])
  1159. return 1;
  1160. }
  1161. return 0;
  1162. }
  1163. void stripIgnoreFirstChars(char *word)
  1164. {
  1165. int j, k;
  1166. int i = 0;
  1167. /* Keep going until a char not to ignore is found */
  1168. while ( isIgnoreFirstChar(word[i]) )
  1169. i++;
  1170. /* If all the char's are valid, just return */
  1171. if (0 == i)
  1172. return;
  1173. else
  1174.     {
  1175. for ( k=i, j=0; word[k] != ''; j++,k++)
  1176. {
  1177. word[j] = word[k];
  1178. }
  1179. /* Add the NULL */
  1180. word[j] = '';
  1181.     }
  1182. }
  1183. int isIgnoreFirstChar(char c)
  1184. {
  1185. int i;
  1186. for (i=0; ignorefirstchar[i] != ''; i++)
  1187. if (c == ignorefirstchar[i])
  1188. return 1;
  1189. return 0;
  1190. }
  1191. int notEscaped( char *tag, int j)
  1192. {
  1193. if ( j > 1)
  1194.     { 
  1195. if ( tag[j - 2] !=  '\')
  1196. { return 1;}
  1197. else
  1198. { return 0; }
  1199.     }
  1200. else
  1201.     { return 1; }
  1202. }