oekwic.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * COMPONENT_NAME: austext
  25. *
  26. * FUNCTIONS: findstr_workproc
  27. * kwic_workproc
  28. * make_one_kwic
  29. * oe_ditto2kwic
  30. * oe_findstr_hitl
  31. * restore_findstr_hitl
  32. *
  33. * ORIGINS: 27
  34. *
  35. * IBM CONFIDENTIAL -- (IBM Confidential Restricted when
  36. * combined with the aggregated modules for this product)
  37. * OBJECT CODE ONLY SOURCE MATERIALS
  38. *
  39. * (C) COPYRIGHT International Business Machines Corp. 1992,1995
  40. * All Rights Reserved
  41. * US Government Users Restricted Rights - Use, duplication or
  42. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  43. */
  44. /******************************* OEKWIC.C ********************************
  45. * $XConsortium: oekwic.c /main/4 1996/05/07 13:42:36 drk $
  46. * April 1992.
  47. * Opera Engine (OE) functions that create KeyWord In Context (KWIC)
  48. * abstracts to replace database abstract when requested by user.
  49. * KWIC abstract is a string extracted
  50. * from the cleartext where the first hitword appears.
  51. * Also includes find-string functions which use similar logic.
  52. * Also includes a few generic OE utilities.
  53. *
  54. * $Log$
  55. * Revision 1.6 1995/09/05 19:02:02 miker
  56. * Made usrblk universal global. Deleted refs to socblk.
  57. * Other minor name and function changes for DtSearch.
  58. *
  59. */
  60. #include "SearchE.h"
  61. #include <ctype.h>
  62. #include <time.h>
  63. /******#define DEBUG_KWIC*********/
  64. /********#define DEBUG_FINDSTR_ITER***********/
  65. /******#define DEBUG_FINDSTR********/
  66. #define PROGNAME "OEKWIC"
  67. #define START_KWIC_ITERATIONS 10
  68. #define START_FINDSTR_ITERATIONS 10
  69. #define MIN_KWIC_ITERATIONS 2
  70. #define MIN_FINDSTR_ITERATIONS 2
  71. #define MIN_KWIC_BUFSZ 20
  72. static int found_one_substring = FALSE;
  73. /************************************************/
  74. /* */
  75. /* make_one_kwic */
  76. /* */
  77. /************************************************/
  78. /* Builds abstract for record in usrblk.cleartext to
  79. * KWIC string where first word/substring in
  80. * usrblk.hitwords array is in center of abstract string.
  81. * Returns new abstract in passed buffer (in a ditto list).
  82. * General format of new abstract is: "...text <<word>> text...".
  83. */
  84. static void make_one_kwic (char *abstract)
  85. {
  86. char c;
  87. int i;
  88. long from; /* offset from beginning of cleartext */
  89. int abstrsz;
  90. char *to, *lastto;
  91. abstrsz = usrblk.dblk->dbrec.or_abstrsz;
  92. if (usrblk.kwiclen > 0 && usrblk.kwiclen < abstrsz)
  93. abstrsz = usrblk.kwiclen;
  94. to = abstract;
  95. lastto = to + abstrsz - 2;
  96. /* No hitwords to abstract */
  97. if (usrblk.hitwcount <= 0L)
  98. return;
  99. /* Find beginning of 'from' string */
  100. from = usrblk.hitwords[0].offset -
  101. ((abstrsz - usrblk.hitwords[0].length - 14) >> 1L);
  102. if (from < 0L) from = 0L;
  103. /* If abstract doesnt begin at start of cleartext, print ellipsis */
  104. if (from != 0L) for (i=3; i>0; i--)
  105. *to++ = '.';
  106. /* Move text up to the start of the word.
  107. * Replace cntrl chars with single space.
  108. */
  109. while (from < usrblk.hitwords[0].offset)
  110. {
  111. c = usrblk.cleartext [from++];
  112. *to++ = (iscntrl(c))? ' ' : c;
  113. }
  114. /* Move the word itself, hilited with angle brackets */
  115. for (i=2; i>0; i--)
  116. *to++ = '<';
  117. for (i=0; i<usrblk.hitwords[0].length; i++)
  118. *to++ = usrblk.cleartext [from++];
  119. for (i=2; i>0; i--)
  120. *to++ = '>';
  121. /* Move text beyond the word until end of input or end of abstract buffer */
  122. while (from < usrblk.clearlen && to < lastto - 4)
  123. {
  124. c = usrblk.cleartext [from++];
  125. *to++ = (iscntrl(c))? ' ' : c;
  126. }
  127. /* If not end of input, print another ellipsis */
  128. if (from < usrblk.clearlen) for (i=3; i>0; i--) *to++ = '.';
  129. *to = '\0';
  130. #ifdef DEBUG_KWIC
  131. printf("%s\n", abstract);
  132. #endif
  133. return;
  134. } /* make_one_kwic() */
  135. /************************************************/
  136. /* */
  137. /* oe_ditto2kwic */
  138. /* */
  139. /************************************************/
  140. /* Converts all abstracts in dittolist to KWIC strings */
  141. void oe_ditto2kwic (void)
  142. {
  143. void kwic_workproc (void);
  144. int search_type = usrblk.search_type;
  145. /* First validate the input fields in usrblk */
  146. if (usrblk.dittocount <= 0L || usrblk.stemcount <= 0)
  147. {
  148. usrblk.retncode = OE_BAD_QUERY;
  149. return;
  150. }
  151. /* Set up various global variables for calls to oe_stems_to_hitwords().
  152. * Only an exact words search (search_type == 'W') does not require
  153. * stemming. Statistical, semantic and exact stems searches
  154. * do require stemming.
  155. */
  156. OE_kind_of_stems = (search_type == 'W') ? WORD_KIND : STEM_KIND;
  157. /* Initialize where user loop status maintained between workproc calls */
  158. saveusr.dittolist = usrblk.dittolist;
  159. saveusr.iterations = START_KWIC_ITERATIONS;
  160. /* Call the work procedure that traverses the entire dittolist.
  161. * If NO_ITERATE is specified, it will run to completion.
  162. * Otherwise it will run just its first set of iterations,
  163. * move its own address into usrblk.workproc, then return.
  164. * Until workproc/mainloop is done, the static variable 'saveusr.dittolist'
  165. * will always indicate where the last execution of the loop ended.
  166. */
  167. usrblk.flags &= ~USR_STOPSRCH; /* init stop button to OFF */
  168. kwic_workproc(); /* work proc will set retncode */
  169. return;
  170. } /* oe_ditto2kwic() */
  171. /************************************************/
  172. /* */
  173. /* kwic_workproc */
  174. /* */
  175. /************************************************/
  176. /* called repeatedly to convert abstracts in dittolist to KWIC strings */
  177. void kwic_workproc (void)
  178. {
  179. int iter;
  180. int entire_list_done;
  181. time_t start_time;
  182. double time_dif;
  183. DtSrResult *dit;
  184. LLIST *bloblist;
  185. char sprintbuf[256];
  186. /* test whether user has pushed STOP button since last call */
  187. if (usrblk.flags & USR_STOPSRCH)
  188. {
  189. usrblk.retncode = OE_USER_STOP;
  190. return;
  191. }
  192. #ifdef DEBUG_KWIC
  193. printf ("\nSTART ITERATIONS = %d\n", saveusr.iterations);
  194. #endif
  195. /* initialize the loop */
  196. dit = saveusr.dittolist;
  197. entire_list_done = FALSE;
  198. time (&start_time);
  199. /* Traverse entire dittolist. Unblob each record,
  200. * create a hitword list, then use it to convert abstract.
  201. */
  202. for (iter = saveusr.iterations; iter > 0; )
  203. {
  204. /* Set usrblk.dblk ptr to correct database for curr ditto node */
  205. if (dbn_to_dblk (dit->dbn))
  206. saveusr.vistano = usrblk.dblk->vistano;
  207. else
  208. {
  209. usrblk.retncode = OE_NOTAVAIL;
  210. return;
  211. }
  212. /* If this record's database has too small an
  213. * abstract buffer, just skip the conversion.
  214. */
  215. if (usrblk.dblk->dbrec.or_abstrsz < MIN_KWIC_BUFSZ)
  216. goto NEXT_DIT;
  217. /* Skip any records which do not have blobs. */
  218. if (usrblk.dblk->dbrec.or_dbaccess != ORA_BLOB)
  219. goto NEXT_DIT;
  220. if ((bloblist = ve_getblobs (dit->dba, saveusr.vistano)) == NULL)
  221. {
  222. sprintf (sprintbuf, PROGNAME"149 "
  223. "Corrupted database address on hitlist. "
  224. "Erroneous record: '%s' in database '%s'.",
  225. dit->reckey, usrblk.dblk->label);
  226. DtSearchAddMessage (sprintbuf);
  227. usrblk.retncode = OE_NOTAVAIL;
  228. return;
  229. }
  230. usrblk.retncode = oe_unblob (bloblist, FALSE);
  231. if (usrblk.retncode != OE_OK)
  232. {
  233. sprintf (sprintbuf, PROGNAME"213 "
  234. "Erroneous record: '%s' in database '%s'.",
  235. dit->reckey, usrblk.dblk->label);
  236. DtSearchAddMessage (sprintbuf);
  237. return;
  238. }
  239. if (!oe_stems_to_hitwords (1))
  240. return;
  241. make_one_kwic (dit->abstractp);
  242. /* Increment ditto pointer. Check for end of dittolist. */
  243. NEXT_DIT:
  244. if ((dit = dit->link) == NULL)
  245. {
  246. entire_list_done = TRUE;
  247. break;
  248. }
  249. /* Decrement iteration counter unless user said not to */
  250. if (!(usrblk.flags & USR_NO_ITERATE))
  251. iter--;
  252. } /* end iteration loop */
  253. if (usrblk.debug & (USRDBG_SRCHCMPL | USRDBG_HITLIST))
  254. print_dittolist (saveusr.dittolist, PROGNAME"888");
  255. /* End of current set of iterations.
  256. * If main loop is not completed,
  257. * adjust number of iterations to about 1 second,
  258. * save current status, and return to caller.
  259. */
  260. if (!entire_list_done)
  261. {
  262. time_dif = difftime (time(NULL), start_time);
  263. if (time_dif < 1.)
  264. saveusr.iterations = (float) saveusr.iterations * 1.5;
  265. else if (time_dif > 1.)
  266. saveusr.iterations = (double) saveusr.iterations / time_dif;
  267. if (saveusr.iterations < MIN_KWIC_ITERATIONS)
  268. saveusr.iterations = MIN_KWIC_ITERATIONS;
  269. #ifdef DEBUG_KWIC
  270. printf ("\nEND ITERATIONS = %d, time_dif = %lf\n",
  271. saveusr.iterations, time_dif);
  272. #endif
  273. saveusr.dittolist = dit; /* temp save curr loc in usrblk.dittolist */
  274. usrblk.workproc = kwic_workproc;
  275. usrblk.retncode = OE_SEARCHING;
  276. return;
  277. } /* endif where we are still searching */
  278. /* Unless user specified no_iterate, calling program should always
  279. * reset workproc to NULL. Dummy_workproc just appends an
  280. * error message to notify programmer of his problem.
  281. */
  282. if (!(usrblk.flags & USR_NO_ITERATE))
  283. usrblk.workproc = dummy_workproc;
  284. usrblk.retncode = OE_OK;
  285. return;
  286. } /* kwic_workproc() */
  287. /************************************************/
  288. /* */
  289. /* oe_findstr_hitl */
  290. /* */
  291. /************************************************/
  292. /* Reduces dittolist to the subset of records that
  293. * contain string in query, and converts their
  294. * abstracts to a KWIC-like string.
  295. */
  296. void oe_findstr_hitl (void)
  297. {
  298. void findstr_workproc (void);
  299. char *ptr, *ptr2;
  300. char msgbuf [256];
  301. /* Validate input fields */
  302. if (usrblk.query == NULL || usrblk.query[0] == '\0')
  303. {
  304. usrblk.retncode = OE_BAD_QUERY;
  305. return;
  306. }
  307. if (strlen(usrblk.query) >= DtSrMAXWIDTH_HWORD)
  308. {
  309. sprintf (msgbuf, PROGNAME"516 "
  310. "No more than %d characters are allowed in the search string.",
  311. DtSrMAXWIDTH_HWORD - 1);
  312. DtSearchAddMessage (msgbuf);
  313. usrblk.retncode = OE_BAD_QUERY;
  314. return;
  315. }
  316. if (usrblk.dittocount <= 0 || usrblk.dittolist == NULL)
  317. {
  318. DtSearchAddMessage (PROGNAME"317 Hitlist empty. Nothing to search.");
  319. usrblk.retncode = OE_BAD_HITLIST;
  320. return;
  321. }
  322. /* Save stems array so we can restore it later,
  323. * then copy the query to it for use by oe_stems_to_hitwords call.
  324. * Convert to uppercase as we copy.
  325. */
  326. saveusr.stemcount = usrblk.stemcount;
  327. memcpy (saveusr.stems, usrblk.stems,
  328. (size_t) (usrblk.stemcount * DtSrMAXWIDTH_HWORD));
  329. usrblk.stemcount = 1;
  330. ptr = usrblk.stems[0]; /* target */
  331. ptr2 = usrblk.query; /* source */
  332. while (*ptr2 != 0)
  333. *ptr++ = toupper(*ptr2++);
  334. *ptr = 0;
  335. OE_kind_of_stems = STRING_KIND;
  336. /* initialize saveusr loop status stuff maintained between workproc calls */
  337. saveusr.vistano = usrblk.dblk->vistano;
  338. saveusr.iterations = START_FINDSTR_ITERATIONS;
  339. saveusr.dittolist = usrblk.dittolist; /* curr start of each iteration */
  340. saveusr.dittocount = 0; /* number of records containing substring */
  341. /* Call the work procedure that traverses the entire dittolist.
  342. * If NO_ITERATE is specified, it will run to completion.
  343. * Otherwise it will run just its first set of iterations,
  344. * move its own address into usrblk.workproc, then return.
  345. * Until workproc/mainloop is done, the static variable 'saveusr.dittolist'
  346. * will always indicate where the last execution of the loop ended.
  347. * The ditto node for each record which is found to contain
  348. * the string will be removed from dittolist and added to newditlist.
  349. */
  350. usrblk.flags &= ~USR_STOPSRCH; /* init stop button to OFF */
  351. found_one_substring = FALSE; /* init HIT indicator */
  352. findstr_workproc(); /* work proc will set retncode */
  353. return;
  354. } /* oe_findstr_hitl() */
  355. /************************************************/
  356. /* */
  357. /* restore_findstr_hitl */
  358. /* */
  359. /************************************************/
  360. /* Each time the find-string workproc detected the search
  361. * string in a ditto node, it converted its abstract.
  362. * Other nodes were just marked for deletion.
  363. * When the entire dittolist has been traversed,
  364. * or if the user pushes the stop button to stop traversal,
  365. * this cleanup function is called to delete those nodes that
  366. * were marked for deletion. However if NO records were
  367. * ever found containing the string, nothing is deleted and
  368. * the hitlist is restored as it was prior to the beginning of the search.
  369. * The hitwords array is always blown away but the stems
  370. * array is always restored no matter what.
  371. */
  372. static void restore_findstr_hitl (void)
  373. {
  374. DtSrResult *dit, *nextdit;
  375. DtSrResult **lastlink;
  376. long newdittocount = 0L;
  377. /* If the string was ever found in any record,
  378. * delete all nonhits up to the last successful find.
  379. */
  380. #ifdef DEBUG_FINDSTR
  381. printf ("\nRESTORE FINDSTR: totnumhits = %ld\n", saveusr.dittocount);
  382. #endif
  383. if (saveusr.dittocount > 0)
  384. {
  385. dit = usrblk.dittolist;
  386. lastlink = &usrblk.dittolist;
  387. while (dit != NULL)
  388. {
  389. /* On a hit, advance the pointers, advance new dittocount.
  390. * Break the loop on the last hit.
  391. */
  392. if (dit->flags & DIT_FINDSTR)
  393. {
  394. #ifdef DEBUG_FINDSTR
  395. printf ("#%ld HIT %s, \"%s\"\n", newdittocount+1,
  396. dit->reckey, dit->abstract);
  397. #endif
  398. lastlink = &dit->link;
  399. dit = dit->link;
  400. if (++newdittocount >= saveusr.dittocount)
  401. break;
  402. }
  403. /* If this was NOT a hit, delete node,
  404. * and link up loose ends.
  405. */
  406. else
  407. {
  408. #ifdef DEBUG_FINDSTR
  409. printf ("RESTORE DELETING %s\n", dit->reckey);
  410. #endif
  411. nextdit = dit->link;
  412. free (dit);
  413. *lastlink = nextdit;
  414. dit = nextdit;
  415. }
  416. }
  417. /* At this point, we've cleaned up the list
  418. * down to the last hit, or to its end.
  419. * Keep deleting until end of list, or user's stop point.
  420. */
  421. while (dit != NULL)
  422. {
  423. if (!(usrblk.flags & USR_STOPSRCH) /* never stopped */
  424. || !(dit->flags & DIT_STOP)) /* stopped somewhere ahead */
  425. {
  426. #ifdef DEBUG_FINDSTR
  427. printf ("PAST LAST HIT, DELETING %s\n", dit->reckey);
  428. #endif
  429. nextdit = dit->link;
  430. free (dit);
  431. *lastlink = nextdit;
  432. dit = nextdit;
  433. }
  434. else
  435. {
  436. break; /* user stopped at this exact node */
  437. }
  438. }
  439. /* If there's anything left on the list,
  440. * its because user stopped the search here.
  441. * Just count the remaining records for the final tally.
  442. */
  443. while (dit != NULL)
  444. {
  445. newdittocount++;
  446. #ifdef DEBUG_FINDSTR
  447. printf ("#%ld SAVING AFTER STOP %s\n", newdittocount, dit->reckey);
  448. #endif
  449. dit = dit->link;
  450. }
  451. usrblk.dittocount = newdittocount;
  452. } /* endif where at least one record had a string hit */
  453. /* restore the original stems array */
  454. usrblk.stemcount = saveusr.stemcount;
  455. memcpy (usrblk.stems, saveusr.stems,
  456. (size_t) (saveusr.stemcount * DtSrMAXWIDTH_HWORD));
  457. #ifdef DEBUG_FINDSTR
  458. printf ("LEAVING RESTORE now real dittocount = %ld, stemcount = %d\n"
  459. " first stem = '%s'\n", usrblk.dittocount,
  460. usrblk.stemcount, usrblk.stems[0]);
  461. #endif
  462. return;
  463. } /* restore_findstr_hitl() */
  464. /************************************************/
  465. /* */
  466. /* findstr_workproc */
  467. /* */
  468. /************************************************/
  469. /* Called repeatedly to search for character substrings in records
  470. * on the hitlist, and convert their abstracts to KWIC strings.
  471. */
  472. void findstr_workproc (void)
  473. {
  474. int iter;
  475. int entire_list_done;
  476. time_t start_time;
  477. double time_dif;
  478. DtSrResult *dit, *cutdit;
  479. LLIST *bloblist;
  480. /* Test whether user has pushed STOP button since last call.
  481. * The DIT_STOP marks where the search ended for restore_findstr_hitl().
  482. */
  483. if (usrblk.flags & USR_STOPSRCH)
  484. {
  485. saveusr.dittolist->flags |= DIT_STOP;
  486. usrblk.retncode = (found_one_substring)? OE_OK : OE_USER_STOP;
  487. restore_findstr_hitl();
  488. return;
  489. }
  490. #ifdef DEBUG_FINDSTR_ITER
  491. printf ("\nSTART ITERATIONS = %d\n", saveusr.iterations);
  492. #endif
  493. /* initialize the loop */
  494. dit = saveusr.dittolist;
  495. entire_list_done = FALSE;
  496. time (&start_time);
  497. /* Traverse entire dittolist, starting where we last left off.
  498. * Unblob each record and search for the query string.
  499. * If found, mark it and convert its abstract.
  500. * If not found, make sure it's not marked and then continue.
  501. */
  502. for (iter = saveusr.iterations; iter > 0; )
  503. {
  504. /*****usrblk.dba = dit->dba;**** unnecessary?******/
  505. if ((bloblist = ve_getblobs (dit->dba, saveusr.vistano)) == NULL)
  506. {
  507. DtSearchAddMessage (
  508. PROGNAME"390 Corrupted database address on hitlist.");
  509. restore_findstr_hitl();
  510. usrblk.retncode = OE_BAD_HITLIST;
  511. return;
  512. }
  513. usrblk.retncode = oe_unblob (bloblist, FALSE);
  514. if (usrblk.retncode != OE_OK)
  515. return;
  516. if (!oe_stems_to_hitwords (1))
  517. return;
  518. if (usrblk.hitwcount > 0) /* string FOUND */
  519. {
  520. found_one_substring = TRUE;
  521. saveusr.dittocount++;
  522. #ifdef DEBUG_FINDSTR_ITER
  523. printf ("<<--->> HIT numhits=%ld, reckey = %s\n",
  524. saveusr.dittocount, dit->reckey);
  525. #endif
  526. make_one_kwic (dit->abstractp);
  527. dit->flags |= DIT_FINDSTR;
  528. }
  529. else dit->flags = 0; /* string NOT found */
  530. /* advance to next ditto node */
  531. if ((dit = dit->link) == NULL)
  532. {
  533. entire_list_done = TRUE;
  534. break;
  535. }
  536. /* decrement iteration counter unless user said not to */
  537. if (!(usrblk.flags & USR_NO_ITERATE)) iter--;
  538. } /* end iteration loop */
  539. /* End of current set of iterations.
  540. * If main loop is not completed,
  541. * adjust number of iterations to about 1 second,
  542. * save current status, and return to caller.
  543. */
  544. if (!entire_list_done)
  545. {
  546. time_dif = difftime (time(NULL), start_time);
  547. if (time_dif < 1.)
  548. saveusr.iterations = (float) saveusr.iterations * 1.5;
  549. else if (time_dif > 1.)
  550. saveusr.iterations = (double) saveusr.iterations / time_dif;
  551. if (saveusr.iterations < MIN_FINDSTR_ITERATIONS)
  552. saveusr.iterations = MIN_FINDSTR_ITERATIONS;
  553. #ifdef DEBUG_FINDSTR_ITER
  554. printf ("\nEND ITERATIONS = %d, time_dif = %lf\n",
  555. saveusr.iterations, time_dif);
  556. #endif
  557. saveusr.dittolist = dit; /* temp save curr loc in usrblk.dittolist */
  558. usrblk.workproc = findstr_workproc;
  559. usrblk.retncode = OE_SEARCHING;
  560. return;
  561. } /* endif where we are still searching */
  562. /* Completely done! Unless user specified no_iterate,
  563. * calling program should always reset workproc to NULL.
  564. * In case he forgets, dummy_workproc just appends an
  565. * error message to notify programmer of his problem.
  566. */
  567. if (!(usrblk.flags & USR_NO_ITERATE))
  568. usrblk.workproc = dummy_workproc;
  569. if (saveusr.dittocount > 0)
  570. usrblk.retncode = OE_OK;
  571. else
  572. usrblk.retncode = OE_NOTAVAIL;
  573. restore_findstr_hitl();
  574. return;
  575. } /* findstr_workproc() */
  576. /******************************* OEKWIC.C ********************************/