msgutil.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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: austext_malloc
  27. * clean_wrap
  28. * cutnode_llist
  29. * free_llist
  30. * join_llists
  31. * merge_llist
  32. * nowstring
  33. * pop_llist
  34. * sort_llist
  35. * split_llist
  36. *
  37. * ORIGINS: 27
  38. *
  39. *
  40. * (C) COPYRIGHT International Business Machines Corp. 1991,1995
  41. * All Rights Reserved
  42. * Licensed Materials - Property of IBM
  43. * US Government Users Restricted Rights - Use, duplication or
  44. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  45. */
  46. /*************************** MSGUTIL.C *************************
  47. * $XConsortium: msgutil.c /main/9 1996/11/25 18:47:48 drk $
  48. * August 1991.
  49. * Utilites for generic manipulation of linked lists and binary trees.
  50. * All utilities require that the link fields be the first fields
  51. * in each structure. Also includes an error message mechanism
  52. * that is absolutely independent of user interface (UI)--
  53. * not even stdio is used. The trick is to append all
  54. * error/information messages to the end of a linked list that
  55. * eventually will be returned to the UI to be displayed
  56. * in whatever manner is appropriate. (However a generic stdio
  57. * print facility for the linked msglists is also provided
  58. * for dumping the list before crashing or when stdio is ok).
  59. *
  60. * With 2 exceptions, all messages should contain only
  61. * printable ascii characters and the space character.
  62. * Control characters and extended ascii graphics chars are verboten.
  63. * The exceptions are \n and \r, which are always permitted.
  64. *
  65. * The most common fatal error in opera and other text analysis
  66. * systems occurs when a memory allocation fails. Therefore
  67. * this module contains a generic 'safe malloc' function
  68. * which tests for failure and prints all outstanding messages
  69. * before exiting if malloc fails. It also uses DtSearchExit()
  70. * for the actual abort so other system dependent stuff can be
  71. * performed before going down.
  72. *
  73. * $Log$
  74. * Revision 2.4 1996/03/05 17:58:29 miker
  75. * Replace isspace() with ref to locale independent ascii_charmap[].
  76. *
  77. * Revision 2.3 1995/10/25 16:46:00 miker
  78. * Added prolog.
  79. *
  80. * Revision 2.2 1995/10/19 20:58:05 miker
  81. * Fix segfault in cleanwrap() if text contains single word > wraplen.
  82. *
  83. * Revision 2.1 1995/09/22 21:20:35 miker
  84. * Freeze DtSearch 0.1, AusText 2.1.8
  85. *
  86. * Revision 1.8 1995/09/05 18:21:23 miker
  87. * For DtSearch, rename and move universal msglist functions to msgs.c.
  88. */
  89. #include "SearchP.h"
  90. /****#include <ctype.h>****/
  91. #include <string.h>
  92. #include <stdlib.h>
  93. #define XOS_USE_NO_LOCKING
  94. #define X_INCLUDE_TIME_H
  95. #include <X11/Xos_r.h>
  96. #define PROGNAME "MSGUTIL"
  97. #define MAX_LINELEN 77
  98. #define MS_misc 1
  99. CMPLL compare_llist = NULL; /* global function pointer */
  100. /************************************************/
  101. /* */
  102. /* nowstring */
  103. /* */
  104. /************************************************/
  105. /* Returns ptr to static string where the current time
  106. * is formatted in human readable form. Used in audit
  107. * records, debugging logs, and error messages.
  108. */
  109. char *nowstring (time_t * now)
  110. {
  111. static char buf[128];
  112. time_t mynow;
  113. struct tm * time_ptr;
  114. _Xltimeparams localtime_buf;
  115. if (now == NULL) {
  116. now = &mynow;
  117. time (now);
  118. }
  119. time_ptr = _XLocaltime(now, localtime_buf);
  120. strftime (buf, sizeof (buf),
  121. CATGETS(dtsearch_catd, MS_misc, 2, "%Y/%m/%d,%H:%M:%S"),
  122. time_ptr);
  123. return buf;
  124. } /* nowstring() */
  125. /************************************************/
  126. /* */
  127. /* free_llist */
  128. /* */
  129. /************************************************/
  130. /* Frees storage for all items in an LLIST and
  131. * sets it top-of-list pointer to NULL. This works only for lists
  132. * created by append_msglist, append_textblobs, and other LLIST
  133. * structures where the data and the node itself
  134. * are allocated in one call to malloc().
  135. */
  136. void free_llist (LLIST ** llhead)
  137. {
  138. LLIST *next;
  139. LLIST *ll = *llhead;
  140. while (ll != NULL) {
  141. next = ll->link;
  142. free (ll);
  143. ll = next;
  144. }
  145. *llhead = NULL;
  146. return;
  147. } /* free_llist() */
  148. /************************************************/
  149. /* */
  150. /* join_llists */
  151. /* */
  152. /************************************************/
  153. /* Merges two list by appending sublist to end of mainlist,
  154. * then setting sublist to NULL. Originally either list can be NULL.
  155. * Mainlist is represented by ptr to ptr so it can be modified if NULL.
  156. * Sublist is ptr to ptr so it can be SET to NULL after join.
  157. * Method:
  158. * Init pp = ptr to first 'link' field in list,
  159. * i.e. the ptr to a ptr passed by the caller.
  160. * Usually this will be the addr of the top of the list pointer.
  161. * Then advance it to point to the last link in the list.
  162. *
  163. * Note that this function works for any LLIST including those
  164. * whose 'data' pointer is not allocated concurrently with the node.
  165. */
  166. void join_llists (LLIST ** mainlist, LLIST ** sublist)
  167. {
  168. LLIST **pp;
  169. for (pp = mainlist; *pp != NULL; pp = &((*pp)->link));
  170. *pp = *sublist;
  171. *sublist = NULL;
  172. return;
  173. } /* join_llists() */
  174. /************************************************/
  175. /* */
  176. /* pop_llist */
  177. /* */
  178. /************************************************/
  179. /* Detaches first node in an llist and returns it.
  180. * If *llistp is empty return NULL, else set *llistp to the link
  181. * cell of the first LLIST node on *llistp and return a pointer to
  182. * the first LLIST node on *llistp. Used mainly by merge_llist(),
  183. * which is itself called by sort_llist(), but can be called by
  184. * anyone needing to remove the first element of an llist.
  185. */
  186. LLIST *pop_llist (LLIST ** llistp)
  187. {
  188. LLIST *first_node = *llistp;
  189. if (first_node != NULL)
  190. *llistp = first_node->link;
  191. return first_node;
  192. } /* pop_llist() */
  193. /************************************************/
  194. /* */
  195. /* cutnode_llist */
  196. /* */
  197. /************************************************/
  198. /* Detaches any specified node in an llist and rejoins the
  199. * loose ends of the llist. *llistp may become NULL.
  200. * Returns NULL if *llistp is initially NULL or if node is not on llist,
  201. * else returns the detached node.
  202. */
  203. LLIST *cutnode_llist (LLIST * node, LLIST ** llistp)
  204. {
  205. LLIST **pp; /* link addr pointing to current node */
  206. for (pp = llistp; *pp != NULL; pp = &((*pp)->link)) {
  207. if (*pp == node)
  208. break;
  209. }
  210. if (*pp == NULL)
  211. return NULL;
  212. *pp = node->link; /* join the loose ends */
  213. return node;
  214. } /* cutnode_llist() */
  215. /************************************************/
  216. /* */
  217. /* split_llist */
  218. /* */
  219. /************************************************/
  220. /* Subroutine of sort_llist().
  221. * Find the middle node in lst. Set its 'link' pointer to NULL.
  222. * Return the remainder of lst, i.e. a pointer to the
  223. * next node after the middle node.
  224. */
  225. static LLIST *split_llist (LLIST * lst)
  226. {
  227. LLIST *tail;
  228. if (lst == NULL || lst->link)
  229. return lst;
  230. tail = lst->link;
  231. /* advance 'tail' to end of list, and advance 'lst' only half as often */
  232. while ((tail != NULL) && ((tail = tail->link) != NULL)) {
  233. lst = lst->link;
  234. tail = tail->link;
  235. }
  236. tail = lst->link;
  237. lst->link = NULL;
  238. return tail;
  239. } /* split_llist() */
  240. /************************************************/
  241. /* */
  242. /* merge_llist */
  243. /* */
  244. /************************************************/
  245. /* Subroutine of sort_llist(). Merges two sorted LLISTs together. */
  246. static LLIST *merge_llist (LLIST * l1, LLIST * l2)
  247. {
  248. LLIST *myqueue = NULL;
  249. LLIST *myend = NULL;
  250. LLIST *mynext;
  251. while ((l1 != NULL) && (l2 != NULL)) {
  252. /*
  253. * Perform ENQUEUE function. Next item popped off a list is
  254. * the next one in sorted order. It is added to END of
  255. * myqueue to maintain order. THIS IS WHERE THE ACTUAL SORT
  256. * COMPARE FUNCTION IS PERFORMED.
  257. */
  258. mynext = (compare_llist (l1, l2) < 0) ?
  259. pop_llist (&l1) : pop_llist (&l2);
  260. mynext->link = NULL;
  261. if (myqueue == NULL)
  262. myqueue = mynext;
  263. else
  264. myend->link = mynext;
  265. myend = mynext;
  266. }
  267. /* attach the remainder of whichever list is left to the end of queue */
  268. if (l1 != NULL)
  269. myend->link = l1;
  270. if (l2 != NULL)
  271. myend->link = l2;
  272. return myqueue;
  273. } /* merge_llist() */
  274. /************************************************/
  275. /* */
  276. /* sort_llist */
  277. /* */
  278. /************************************************/
  279. /* Sorts a list of LLIST structures and returns ptr to sorted list.
  280. * The basic idea is to sort by recursively splitting a list
  281. * into two equal halves and sorting each of those. The recursion
  282. * ends when there are only two small lists which are either
  283. * already sorted or are swapped. This sort rarely runs out
  284. * of stack space because each recursion cuts the list length in
  285. * half so there are at most 1 + log-N-to-the-base-2 items on the stack.
  286. * (e.g. 64,000 nodes = max stack depth of 16: 2**16 = 64K).
  287. *
  288. * The compare function accepts pointers to two LLIST structures.
  289. * It returns <0, =0, or >0 based on whether the first structure (left)
  290. * is <, =, or > the second (right) structure in sort order.
  291. * For efficiency's sake, a pointer to the compare function is placed
  292. * in the global variable 'compare_llist' before calling
  293. * sort_llist the first time, rather than continually
  294. * passing it to all these nested functions.
  295. */
  296. LLIST *sort_llist (LLIST * lst)
  297. {
  298. LLIST *lst2;
  299. if ((lst == NULL) || (lst->link == NULL))
  300. return lst;
  301. lst2 = split_llist (lst);
  302. return merge_llist (sort_llist (lst), sort_llist (lst2));
  303. } /* sort_llist() */
  304. /************************************************/
  305. /* */
  306. /* austext_malloc */
  307. /* */
  308. /************************************************/
  309. /* 'location' may be NULL. Last arg (formerly msglist) is isgnored.
  310. * Renamed from safe_malloc() to force compile errors if args not changed.
  311. */
  312. void *austext_malloc (size_t size, char *location, void *ignore)
  313. {
  314. static void *ptr;
  315. char *outofmem_msg;
  316. if ((ptr = malloc (size)) != NULL)
  317. return ptr;
  318. ptr = ((aa_argv0) ? aa_argv0 : "");
  319. if (location == NULL)
  320. location = CATGETS(dtsearch_catd, MS_misc, 1, "<null>");
  321. outofmem_msg = CATGETS(dtsearch_catd, MS_misc, 3,
  322. "*** %sOut of Memory at %s asking for %lu bytes! ***\n");
  323. fprintf (aa_stderr, outofmem_msg, ptr, location, size);
  324. fflush (aa_stderr);
  325. if (ausapi_msglist)
  326. fprintf (aa_stderr, "%s\n", DtSearchGetMessages ());
  327. fflush (aa_stderr);
  328. DtSearchExit (43);
  329. return NULL;
  330. } /* austext_malloc */
  331. /************************************************/
  332. /* */
  333. /* clean_wrap */
  334. /* */
  335. /************************************************/
  336. /* Utility which provides a way of breaking up long
  337. * messages which contain no control characters into lines
  338. * whose linefeed breaks occur at even word boundaries,
  339. * and whose lengths are controlled by the caller.
  340. * It should only be called when text itself may be
  341. * modified and may safely contain a linefeed (ascii 0x0A).
  342. * Converts a long text string into several lines by overlaying
  343. * the whitespace char nearest to the end of every line with \n.
  344. * Restarts length count if \n is found already within string.
  345. * Does nothing if passed wrap length = 0.
  346. * Does not append \n to end of string. Does not alter string length.
  347. * Returns total number of lines (\n's + trailing piece of last line),
  348. * or returns 0 if wraplen == 0.
  349. */
  350. int clean_wrap (char *string, int wraplen)
  351. {
  352. char *nlptr, *breakptr;
  353. int linecount = 0;
  354. if (wraplen <= 0)
  355. return 0;
  356. while (strlen (string) > wraplen) {
  357. breakptr = string + wraplen;
  358. /* Look for \n within the next wraplen */
  359. for (nlptr = string; nlptr < breakptr; nlptr++)
  360. if (*nlptr == '\n')
  361. break;
  362. if (nlptr < breakptr) {
  363. string = ++nlptr;
  364. goto LINE_DONE;
  365. }
  366. /* Otherwise back up to the first whitespace before last word */
  367. for (nlptr = breakptr - 1; nlptr > string; nlptr--)
  368. if (ascii_charmap[*nlptr] & WHITESPACE) {
  369. *nlptr = '\n';
  370. string = ++nlptr;
  371. goto LINE_DONE;
  372. }
  373. /* No whitespace at all in "text" before wraplen!
  374. * No choice but to overlay the last char.
  375. */
  376. *(--breakptr) = '\n';
  377. string = ++breakptr;
  378. LINE_DONE:
  379. linecount++;
  380. }
  381. /* Done wrapping. now just count remaining lines in string. */
  382. while (*string != 0)
  383. if (*string++ == '\n')
  384. linecount++;
  385. if (*(string - 1) != '\n')
  386. linecount++;
  387. return linecount;
  388. } /* clean_wrap() */
  389. /********************** MSGUTIL.C *************************/