dtsrjoint.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  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: DtSearchFormatObjdate
  27. * DtSearchFreeResults
  28. * DtSearchGetMaxResults
  29. * DtSearchMergeResults
  30. * DtSearchSetMaxResults
  31. * DtSearchSortResults
  32. * DtSearchValidDateString
  33. * aa_check_initialization
  34. * aa_envars
  35. * aa_get_passwd
  36. * ditto_pop
  37. * ditto_sort
  38. * ditto_split
  39. * merge_by_date
  40. * merge_by_prox
  41. *
  42. * ORIGINS: 27
  43. *
  44. *
  45. * (C) COPYRIGHT International Business Machines Corp. 1995, 1996
  46. * All Rights Reserved
  47. * Licensed Materials - Property of IBM
  48. * US Government Users Restricted Rights - Use, duplication or
  49. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  50. */
  51. /**************************** DTSRJOINT.C *************************
  52. * $XConsortium: dtsrjoint.c /main/5 1996/06/23 16:47:42 cde-ibm $
  53. * February 1995.
  54. * Split off of ausapi.c when I converted to client/server model.
  55. * Ausclt.c is virtual copy of ausapi functions in RPC client stub.
  56. * This module contains ausapi utilities that are common to both
  57. * sides (ie do not result in RPC call to server or require
  58. * access to real usrblk). My original version of this program
  59. * was called "aacom" for "ausapi common" but I renamed it to avoid
  60. * conflict with aacomm, the rpc/sockets communications module.
  61. *
  62. * $Log$
  63. * Revision 2.5 1996/04/10 19:52:16 miker
  64. * Added locale independent ISDIGIT macro. Changed function name
  65. * from aa_merge_dittolists to DtSearchMergeResults.
  66. *
  67. * Revision 2.4 1995/12/27 16:11:54 miker
  68. * Remove save_init_dbxxx globals for DtSearchReinit().
  69. *
  70. * Revision 2.3 1995/10/25 22:16:09 miker
  71. * Renamed from aajoint.c. Added prolog.
  72. *
  73. * Log: aajoint.c,v
  74. * Revision 2.2 1995/10/02 20:14:39 miker
  75. * DtSearch function name changes.
  76. * Added const to strdup() prototype for greater portability.
  77. * Changed to more uniform output format in DtSearchFormatObjdate().
  78. *
  79. * Revision 2.1 1995/09/22 15:18:08 miker
  80. * Freeze DtSearch 0.1, AusText 2.1.8
  81. *
  82. * Revision 1.3 1995/08/31 21:31:48 miker
  83. * Renames and minor changes for DtSearch.
  84. *
  85. * Revision 1.2 1995/06/22 18:01:09 miker
  86. * 2.1.6: RPC version no longer user specifiable. Removed aa_versnum etc.
  87. * Added aa_sort_dittolist, date sorting of hitlists by any client.
  88. */
  89. #include "SearchE.h"
  90. #include <termios.h>
  91. #include <unistd.h>
  92. #include <string.h>
  93. #include <stdlib.h>
  94. #ifndef strdup
  95. extern char *strdup (const char *s);
  96. #endif
  97. #define PROGNAME "DTSRJOINT"
  98. #define ISDIGIT(c) ((ascii_charmap [(unsigned int) (c)] & NUMERAL) != 0)
  99. /*------------- GLOBALS VISIBLE TO CALLER -------------------*/
  100. /* see also globals.c */
  101. char **ausapi_dbnamesv = NULL; /* array of database names */
  102. int ausapi_dbnamesc = 0; /* size of dbnames array */
  103. int aa_maxhits = DtSrMAXHITS; /* num hits retnd after
  104. * srch */
  105. /*------------------- PRIVATE GLOBALS ---------------------*/
  106. int aa_is_initialized = FALSE;
  107. int aa_getnews_flag = 1;
  108. long save_init_switches = 0L;
  109. int ditsort_type = 0;
  110. /************************************************/
  111. /* */
  112. /* aa_check_initialization */
  113. /* */
  114. /************************************************/
  115. /* Confirms ausapi_init() was first function called. */
  116. void aa_check_initialization (void)
  117. {
  118. if (aa_is_initialized)
  119. return;
  120. fprintf (aa_stderr,
  121. CATGETS(dtsearch_catd, 2, 37,
  122. "%s First API function call must be DtSearchInit().\n"),
  123. PROGNAME"37");
  124. DtSearchExit (37);
  125. } /* aa_check_initialization() */
  126. /************************************************/
  127. /* */
  128. /* DtSearchValidDateString */
  129. /* */
  130. /************************************************/
  131. /* Subroutine of aa_both_valid_dates(), called once for each date string,
  132. * or can be called from user interface to validate a date string.
  133. * Converts passed date string into valid AusText DtSrObjdate.
  134. * Date string format: "[yy]yy [mm [dd]]",
  135. * 1, 2, or 3 numeric tokens separated by one
  136. * or more nonnumeric chars (whitespace, slashes, etc).
  137. * The first token is a complete year number integer yyyy
  138. * in the range 1900 <= yyyy <= 5995. If the first token contains
  139. * less than 4 digits it is presumed to be the number of years
  140. * since 1900. The month number is the second token mm,
  141. * in the range 1 - 12, and the third token dd is the day, 1 - 31.
  142. * If only two tokens are in the string they are presumed to
  143. * be year and month; the day is presumed to be to 1.
  144. * If only one token is in the string it is presumed to
  145. * be the year; the month is presumed to be 1 and the day
  146. * is presumed to be 1. NULL and empty strings are always
  147. * valid. They mean no date exclusion in the search
  148. * and this function returns objdate 0 for them.
  149. * Returns objdate on successful parse and conversion.
  150. * Returns -1 and err msg if date string is invalid.
  151. */
  152. DtSrObjdate DtSearchValidDateString (char *datestr)
  153. {
  154. DtSrObjdate objdate = 0L;
  155. char parsebuf[64];
  156. char *startp, *endp;
  157. int yy, mm, dd;
  158. int stop_parse = FALSE;
  159. char msgbuf[256];
  160. aa_check_initialization();
  161. if (datestr == NULL) /* null string is valid */
  162. return 0L;
  163. if (datestr[0] == 0) /* empty string is valid */
  164. return 0L;
  165. strncpy (parsebuf, datestr, sizeof (parsebuf));
  166. parsebuf[sizeof (parsebuf) - 1] = 0;
  167. /* yyyy */
  168. for (startp = parsebuf; *startp != 0 && !ISDIGIT(*startp); startp++);
  169. if (*startp == 0) { /* no numeric digits in string */
  170. #ifdef DEBUG_VALDATE
  171. fprintf (aa_stderr, PROGNAME"269 No numeric digits in string\n");
  172. #endif
  173. INVALID_DATESTR:
  174. sprintf (msgbuf,
  175. CATGETS(dtsearch_catd, 2, 115,
  176. "%s '%s' is invalid or incomplete date string.\n"
  177. "The correct format is '[yy]yy [mm [dd]]'."),
  178. PROGNAME"115", datestr);
  179. DtSearchAddMessage (msgbuf);
  180. #ifdef DEBUG_VALDATE
  181. fprintf (aa_stderr, PROGNAME"278 Returning objdate -1\n");
  182. fflush (aa_stderr);
  183. #endif
  184. return -1L;
  185. }
  186. for (endp = startp; ISDIGIT(*endp); endp++);
  187. if (*endp == 0) { /* mm and dd both missing */
  188. mm = 1;
  189. dd = 1;
  190. stop_parse = TRUE;
  191. #ifdef DEBUG_VALDATE
  192. fprintf (aa_stderr, PROGNAME"286 mm and dd both missing\n");
  193. #endif
  194. }
  195. *endp = 0;
  196. yy = atoi (startp);
  197. #ifdef DEBUG_VALDATE
  198. fprintf (aa_stderr, PROGNAME"293 yystr='%s' yy=%d\n", startp, yy);
  199. #endif
  200. if (strlen (startp) < 4)
  201. yy += 1900;
  202. if (yy < 1900 || yy > 5995)
  203. goto INVALID_DATESTR;
  204. if (stop_parse)
  205. goto DATESTR_OK;
  206. /* mm */
  207. for (startp = ++endp; *startp != 0 && !ISDIGIT(*startp); startp++);
  208. if (*startp == 0) { /* no mm in string */
  209. mm = 1;
  210. dd = 1;
  211. #ifdef DEBUG_VALDATE
  212. fprintf (aa_stderr, PROGNAME"309 No mm in string\n");
  213. #endif
  214. goto DATESTR_OK;
  215. }
  216. for (endp = startp; ISDIGIT(*endp); endp++);
  217. if (*endp == 0) { /* no dd in string */
  218. dd = 1;
  219. stop_parse = TRUE;
  220. #ifdef DEBUG_VALDATE
  221. fprintf (aa_stderr, PROGNAME"318 No dd in string\n");
  222. #endif
  223. }
  224. *endp = 0;
  225. mm = atoi (startp);
  226. #ifdef DEBUG_VALDATE
  227. fprintf (aa_stderr, PROGNAME"293 mmstr='%s' mm=%d\n", startp, mm);
  228. #endif
  229. if (mm < 1 || mm > 12)
  230. goto INVALID_DATESTR;
  231. if (stop_parse)
  232. goto DATESTR_OK;
  233. /* dd */
  234. for (startp = ++endp; *startp != 0 && !ISDIGIT(*startp); startp++);
  235. if (*startp == 0) { /* no dd in string */
  236. dd = 1;
  237. #ifdef DEBUG_VALDATE
  238. fprintf (aa_stderr, PROGNAME"336 No dd in string\n");
  239. #endif
  240. goto DATESTR_OK;
  241. }
  242. for (endp = startp; ISDIGIT(*endp); endp++);
  243. *endp = 0;
  244. dd = atoi (startp);
  245. #ifdef DEBUG_VALDATE
  246. fprintf (aa_stderr, PROGNAME"344 ddstr='%s' dd=%d\n", startp, dd);
  247. #endif
  248. if (dd < 1 || dd > 31)
  249. goto INVALID_DATESTR;
  250. DATESTR_OK:
  251. objdate = (yy - 1900) << 20 | (mm-1) << 16 | dd << 11;
  252. #ifdef DEBUG_VALDATE
  253. fprintf (aa_stderr,
  254. PROGNAME"352 Returning objdate %08lx, %d/%d/%d, %s\n",
  255. objdate, yy, mm, dd, objdate2fzkstr(objdate));
  256. fflush (aa_stderr);
  257. #endif
  258. return objdate;
  259. } /* DtSearchValidDateString() */
  260. /************************************************/
  261. /* */
  262. /* DtSearchFormatObjdate */
  263. /* */
  264. /************************************************/
  265. /* Converts objdate in hitlist to displayable string */
  266. char *DtSearchFormatObjdate (DtSrObjdate objdate)
  267. {
  268. static char datestr_buf[24];
  269. if (objdate == 0L)
  270. return "(undated)";
  271. strftime (datestr_buf, sizeof(datestr_buf), "%Y.%m.%d",
  272. objdate2tm (objdate));
  273. return datestr_buf;
  274. } /* DtSearchFormatObjdate() */
  275. /************************************************/
  276. /* */
  277. /* DtSearchGetMaxResults */
  278. /* DtSearchSetMaxResults */
  279. /* */
  280. /************************************************/
  281. int DtSearchGetMaxResults (void)
  282. { return aa_maxhits; }
  283. void DtSearchSetMaxResults (int newmax)
  284. { aa_maxhits = newmax; }
  285. /************************************************/
  286. /* */
  287. /* DtSearchFreeResults */
  288. /* */
  289. /************************************************/
  290. /* Frees storage allocated for the dittolist created
  291. * by DtSearchQuery(), and sets dittolist pointer to NULL.
  292. * Always returns DtSrOK.
  293. */
  294. int DtSearchFreeResults (DtSrResult ** dittolist)
  295. {
  296. free_llist ((LLIST **) dittolist);
  297. return DtSrOK;
  298. } /* DtSearchFreeResults() */
  299. /************************************************/
  300. /* */
  301. /* DtSearchMergeResults */
  302. /* */
  303. /************************************************/
  304. /* Merges one dittolist into another using proximity
  305. * for sort order. Sets 'src' dittolist pointer to NULL.
  306. * Does not change dittocount of either list, user must do that.
  307. * Returns DtSrOK on successful merge,
  308. * else returns DtSrERROR for programming error.
  309. * Formerly named aa_merge_dittolists.
  310. */
  311. int DtSearchMergeResults (DtSrResult **targ_list, DtSrResult **src_list)
  312. {
  313. DtSrResult *targ, *src, *nextsrc, **prevtargl;
  314. if (src_list == NULL || targ_list == NULL)
  315. return DtSrERROR;
  316. /* If there's no 'src' list, return with no changes.
  317. * In other words, merge was successful before we started.
  318. */
  319. if (*src_list == NULL)
  320. return DtSrOK;
  321. /* At this point we know there is a src_list.
  322. * If there's no targ_list, just swap the pointers.
  323. */
  324. if (*targ_list == NULL) {
  325. *targ_list = *src_list;
  326. *src_list = NULL;
  327. return DtSrOK;
  328. }
  329. /* We have two nonempty lists. Now do a real merge.
  330. * Insert src node into targ list only if it's
  331. * proximity is smaller. Otherwise just
  332. * advance to the next targ node.
  333. */
  334. src = *src_list; /* curr src_list node to compare */
  335. nextsrc = src->link; /* next src_list node to compare */
  336. targ = *targ_list; /* curr targ_list node to compare */
  337. prevtargl = targ_list; /* prev targ_list node link pointer */
  338. while (src != NULL && targ != NULL) {
  339. if (src->proximity < targ->proximity) {
  340. /* Insert src node into targ list */
  341. *prevtargl = src;
  342. src->link = targ;
  343. prevtargl = &src->link;
  344. src = nextsrc;
  345. if (src)
  346. nextsrc = src->link;
  347. }
  348. else {
  349. /* just advance to next targ node */
  350. prevtargl = &targ->link;
  351. targ = targ->link;
  352. }
  353. }
  354. /* If there's any src_list left,
  355. * just tack it onto the end of the targ_list.
  356. */
  357. if (src) {
  358. /* advance to end of targ_list */
  359. while (targ) {
  360. prevtargl = &targ->link;
  361. targ = targ->link;
  362. }
  363. *prevtargl = src;
  364. }
  365. *src_list = NULL;
  366. return DtSrOK;
  367. } /* DtSearchMergeResults() */
  368. /************************************************************
  369. * Aa_sort_dittolist(): basically a copy of ditto_sort() from engine,
  370. * but will sort on several different ditto fields
  371. * (currently only date fields implemented),
  372. * and is only used as convenience function on client/gui side.
  373. * The proximity field is always the minor sort key.
  374. * All functions with similar names to engine functions are static
  375. * in this module so they won't collide with same function in engine.
  376. * Performs a recursive split-merge sort on ditto lists.
  377. ************************************************************/
  378. /************************************************/
  379. /* */
  380. /* ditto_pop */
  381. /* */
  382. /************************************************/
  383. /* Subroutine of DtSearchSortResults().
  384. * Detaches first node in a list and returns it...
  385. * If *lst is empty return NULL, else set *lst to the link
  386. * cell of the first DtSrResult node on *lst and return a pointer to
  387. * the first DtSrResult node on *lst.
  388. */
  389. static DtSrResult *ditto_pop (DtSrResult ** lst)
  390. {
  391. DtSrResult *first_node;
  392. first_node = *lst;
  393. if (first_node != NULL)
  394. *lst = first_node->link;
  395. return first_node;
  396. } /* ditto_pop() */
  397. /************************************************/
  398. /* */
  399. /* ditto_split */
  400. /* */
  401. /************************************************/
  402. /* Subroutine of DtSearchSortResults().
  403. * Find the middle node in lst. Set its 'next' pointer to NULL.
  404. * Return the remainder of lst, i.e. a pointer to the
  405. * next node after the middle node.
  406. */
  407. static DtSrResult *ditto_split (DtSrResult * lst)
  408. {
  409. DtSrResult *tail = lst->link;
  410. if (lst == NULL || tail == NULL)
  411. return lst;
  412. /*
  413. * Advance 'tail' to end of list, and advance 'lst' only half
  414. * as often
  415. */
  416. while ((tail != NULL) && ((tail = tail->link) != NULL)) {
  417. lst = lst->link;
  418. tail = tail->link;
  419. }
  420. tail = lst->link;
  421. lst->link = NULL;
  422. return tail;
  423. } /* ditto_split() */
  424. /************************************************/
  425. /* */
  426. /* merge_by_prox */
  427. /* */
  428. /************************************************/
  429. /* Subroutine of DtSearchSortResults().
  430. * Merges two sorted DtSrResult lists together in proximity order.
  431. */
  432. static DtSrResult *merge_by_prox (DtSrResult * l1, DtSrResult * l2)
  433. {
  434. DtSrResult *myqueue = NULL;
  435. DtSrResult *myend = NULL;
  436. DtSrResult *mynext;
  437. while ((l1 != NULL) && (l2 != NULL)) {
  438. /*
  439. * Perform ENQUEUE function. Next item popped off a list is
  440. * the next one in sorted order. It is added to END of
  441. * myqueue to maintain order. THIS IS WHERE THE ACTUAL SORT
  442. * COMPARE FUNCTION IS PERFORMED.
  443. */
  444. mynext = (l1->proximity < l2->proximity) ?
  445. ditto_pop (&l1) : ditto_pop (&l2);
  446. mynext->link = NULL;
  447. if (myqueue == NULL)
  448. myqueue = mynext;
  449. else
  450. myend->link = mynext;
  451. myend = mynext;
  452. }
  453. /*
  454. * Perform JOIN QUEUE function. Append entire list to end of
  455. * queue.
  456. */
  457. if (l1 != NULL)
  458. myend->link = l1;
  459. if (l2 != NULL)
  460. myend->link = l2;
  461. return myqueue;
  462. } /* merge_by_prox() */
  463. /************************************************/
  464. /* */
  465. /* merge_by_date */
  466. /* */
  467. /************************************************/
  468. /* Subroutine of DtSearchSortResults().
  469. * Merges two sorted DtSrResult lists together in objdate order.
  470. */
  471. static DtSrResult *merge_by_date (DtSrResult * l1, DtSrResult * l2)
  472. {
  473. DtSrResult *myqueue = NULL;
  474. DtSrResult *myend = NULL;
  475. DtSrResult *mynext;
  476. while ((l1 != NULL) && (l2 != NULL)) {
  477. /*
  478. * Perform ENQUEUE function. Next item popped off a list is
  479. * the next one in sorted order. It is added to END of
  480. * myqueue to maintain order. THIS IS WHERE THE ACTUAL SORT
  481. * COMPARE FUNCTION IS PERFORMED.
  482. */
  483. if (l1->objdate == l2->objdate)
  484. mynext = (l1->proximity < l2->proximity) ?
  485. ditto_pop (&l1) : ditto_pop (&l2);
  486. else
  487. mynext = (l1->objdate > l2->objdate) ?
  488. ditto_pop (&l1) : ditto_pop (&l2);
  489. mynext->link = NULL;
  490. if (myqueue == NULL)
  491. myqueue = mynext;
  492. else
  493. myend->link = mynext;
  494. myend = mynext;
  495. }
  496. /*
  497. * Perform JOIN QUEUE function. Append entire list to end of
  498. * queue.
  499. */
  500. if (l1 != NULL)
  501. myend->link = l1;
  502. if (l2 != NULL)
  503. myend->link = l2;
  504. return myqueue;
  505. } /* merge_by_date() */
  506. /************************************************/
  507. /* */
  508. /* ditto_sort */
  509. /* */
  510. /************************************************/
  511. /* Subroutine of DtSearchSortResults().
  512. * Sorts a list of DtSrResult structures and returns ptr to sorted list.
  513. * The basic idea is to sort by recursively splitting a list
  514. * into two equal halves and sorting each of those. The recursion
  515. * ends when there are only two small lists which are either
  516. * already sorted or are swapped. This sort rarely runs out
  517. * of stack space because each recursion cuts the list length in
  518. * half so there are at most 1 + log-N-to-the-base-2 items on the stack.
  519. * (e.g. 64,000 nodes = max stack depth of 16: 2**16 = 64K).
  520. */
  521. static DtSrResult *ditto_sort (DtSrResult * lst)
  522. {
  523. DtSrResult *lst2;
  524. if ((lst == NULL) || (lst->link == NULL))
  525. return lst;
  526. lst2 = ditto_split (lst);
  527. switch (ditsort_type) {
  528. case DtSrSORT_PROX:
  529. return merge_by_prox (ditto_sort (lst), ditto_sort (lst2));
  530. case DtSrSORT_DATE:
  531. return merge_by_date (ditto_sort (lst), ditto_sort (lst2));
  532. default:
  533. fprintf (aa_stderr, PROGNAME "525 Invalid Sort Type %d.\n",
  534. ditsort_type);
  535. DtSearchExit (32);
  536. }
  537. } /* ditto_sort() */
  538. /************************************************/
  539. /* */
  540. /* DtSearchSortResults */
  541. /* */
  542. /************************************************/
  543. /* Only publicly visible sort function.
  544. * DtSearchSortResults() was formerly named aa_sort_dittolist.
  545. */
  546. int DtSearchSortResults (DtSrResult ** dittolist, int sort_type)
  547. {
  548. switch (sort_type) {
  549. case DtSrSORT_PROX:
  550. case DtSrSORT_DATE:
  551. ditsort_type = sort_type;
  552. *dittolist = ditto_sort (*dittolist); /* recursive call */
  553. return DtSrOK;
  554. default:
  555. DtSearchAddMessage (PROGNAME "140 "
  556. "Program Error: Invalid sort type.");
  557. return DtSrERROR;
  558. }
  559. } /* DtSearchSortResults() */
  560. /**************************** DTSRJOINT.C *************************/