1 /*   ncbimisc.c
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * File Name:  ncbimisc.c
27 *
28 * Author:  Gish, Kans, Ostell, Schuler
29 *
30 * Version Creation Date:   10/23/91
31 *
32 * $Revision: 6.62 $
33 *
34 * File Description:
35 *   	miscellaneous functions
36 *
37 * Modifications:
38 * --------------------------------------------------------------------------
39 * Date     Name        Description of modification
40 * -------  ----------  -----------------------------------------------------
41 *
42 * ==========================================================================
43 */
44 
45 #include <ncbi.h>
46 #include <ncbiwin.h>
47 
48 #ifdef OS_MAC
49 #include <TextUtils.h>
50 #endif
51 
52 /* Missing from /usr/include/gcc/darwin/3.3/machine/limits.h */
53 #ifdef __MWERKS__
54 #ifdef OS_UNIX_DARWIN
55 #ifndef __CHAR_BIT__
56 #define __CHAR_BIT__ 8
57 #endif
58 #endif
59 #endif
60 /* End missing from /usr/include/gcc/darwin/3.3/machine/limits.h */
61 
62 /*
63 TRIPLE_MARK is the character inserted before the thousands, millions,
64 billions, etc. digit positions.  Change TRIPLE_MARK to a period
65 for the International scene, or define it as '\0' if no magnitude
66 markers are desired.
67 */
68 #define TRIPLE_MARK	','
69 
70 #define MISC_COMMAS 1 /* insert commas only when |value| >= 10,000 */
71 #define MISC_ALLCOMMAS 2 /* insert commas for any |value| >= 1,000 */
72 #define MISC_ANYCOMMAS (MISC_COMMAS|MISC_ALLCOMMAS)
73 #define MISC_PLUSSIGNS 4 /* prepend a plus sign (+) to positive values */
74 
75 
76 /*
77 buf[NBUFS][] is a circularly-maintained list of buffers for storing
78 the results of calls to Nlm_Ltostr() and Nlm_Ultostr().  Up to NBUFS
79 usages of either function in a single printf() may be made.
80 NBUFS should be defined large enough to satisfy _all_ likely occurrences.
81 */
82 #define NBUFS 10 /* No. of static buffers for the ASCII results */
83 
84 static int	bufno = 0; /* current buffer marker in the circular list */
85 static char	buf[NBUFS][(CHAR_BIT)*sizeof(long)/2];
86 
87 /* divray[] is a fixed array of power-of-10 divisors which must be initialized*/
88 static Uint8 divray[CHAR_BIT*sizeof(Uint8)/2];
89 /* divray_max is related to the maximum precision available in a long int */
90 static int	divray_max;
91 
92 /* commaray[] is a fixed array that identifies positions where commas belong */
93 static char	commaray[DIM(divray)];
94 
95 /* divray_init() initializes divray[] */
96 static void divray_init PROTO((void));
97 
98 /* ncbi_ultostr() is the basic (unsigned) integer-to-ASCII conversion engine */
99 static void ncbi_ultostr PROTO((char *buff, Uint8 value, int commas));
100 
101 /* ulwidth() is the basic length-determiner for integer-ASCII conversions */
102 static int ulwidth PROTO((unsigned long value, int commas));
103 
104 /* heapify() is the basic heap-sort function used by Nlm_HeapSort() */
105 static void	heapify PROTO((Nlm_CharPtr b0, Nlm_CharPtr b, Nlm_CharPtr lim, Nlm_CharPtr last, size_t w, int (LIBCALLBACK *compar) (Nlm_VoidPtr, Nlm_VoidPtr) ));
106 
107 /* divray_init -- initialize array of divisors and array of marker locations */
108 static void
divray_init(void)109 divray_init (void)
110 
111 {
112 	Uint8	j = UINT8_MAX, k = 1;
113 
114 	for (divray_max=0; divray_max < DIM(divray) && j != 0; ++divray_max) {
115 		divray[divray_max] = k;
116 		if ((divray_max+1)%3 == 0)
117 			commaray[divray_max] = (TRIPLE_MARK != '\0');
118 		j /= 10;
119 		k *= 10;
120 	}
121 	--divray_max;
122 }
123 
124 /* ncbi_ultostr is the basic (unsigned) integer->ASCII conversion engine */
125 static void
ncbi_ultostr(char * buff,Uint8 value,int commas)126 ncbi_ultostr (char *buff, Uint8 value, int commas)
127 {
128 	Uint8 value_orig = value;
129 	int	i, quotient;
130 
131 	if (divray_max == 0)
132 		divray_init();
133 
134 	/*
135 	Insert commas when value_orig >= 10000 (the Macintosh Way),
136 	unless MISC_ALLCOMMAS is set.
137 	*/
138 	commas = ((commas&MISC_ALLCOMMAS) && value >= 1000)
139 				|| (commas && value > (10*1000));
140 
141 	for (i=divray_max; i > 0 && divray[i] > value; --i)
142 		;
143 
144 	for (; i >= 0; --i) {
145 		if (commas && commaray[i] != NULLB && value != value_orig)
146 			*buff++ = TRIPLE_MARK;
147 		quotient = (int)(value / divray[i]);
148 		*buff++ = (char) '0' + (char) quotient;
149 		switch (quotient) {
150 		case 0: break;
151 		case 1: value -=   divray[i]; break;
152 		case 2: value -= 2*divray[i]; break;
153 		case 3: value -= 3*divray[i]; break;
154 		case 4: value -= 4*divray[i]; break;
155 		case 5: value -= 5*divray[i]; break;
156 		case 6: value -= 6*divray[i]; break;
157 		case 7: value -= 7*divray[i]; break;
158 		case 8: value -= 8*divray[i]; break;
159 		case 9: value -= 9*divray[i]; break;
160 		default: value -= quotient*divray[i]; break; /* shouldn't be taken */
161 		}
162 	}
163 	*buff = NULLB; /* tack on a NUL terminator */
164 	return;
165 }
166 /* Nlm_Int8tostr -- convert a signed long integer to ASCII */
Nlm_Int8tostr(Nlm_Int8 value,int opts)167 NLM_EXTERN char * LIBCALL Nlm_Int8tostr (Nlm_Int8 value, int opts)
168 
169 {
170 	char	*bp0, *bp;
171 
172     bp0 = bp = &buf[bufno][0];
173 	if (++bufno >= NBUFS)
174 		bufno = 0;
175 
176 	if (value < 0) {
177 		*bp++ = '-';
178 		value = -value;
179 	}
180 	else
181 		if (opts&MISC_PLUSSIGNS && value > 0)
182 			*bp++ = '+';
183 
184 	ncbi_ultostr(bp, (Uint8)value, opts&MISC_ANYCOMMAS);
185 
186     return bp0;
187 }
188 
189 /* Nlm_Ltostr -- convert a signed long integer to ASCII */
Nlm_Ltostr(long value,int opts)190 NLM_EXTERN char * LIBCALL Nlm_Ltostr (long value, int opts)
191 
192 {
193 	char	*bp0, *bp;
194 
195     bp0 = bp = &buf[bufno][0];
196 	if (++bufno >= NBUFS)
197 		bufno = 0;
198 
199 	if (value < 0) {
200 		*bp++ = '-';
201 		value = -value;
202 	}
203 	else
204 		if (opts&MISC_PLUSSIGNS && value > 0)
205 			*bp++ = '+';
206 
207 	ncbi_ultostr(bp, (Uint8)value, opts&MISC_ANYCOMMAS);
208 
209     return bp0;
210 }
211 
212 /* Nlm_Ultostr convert an unsigned long integer to ASCII */
Nlm_Ultostr(unsigned long value,int opts)213 NLM_EXTERN char * LIBCALL Nlm_Ultostr (unsigned long value, int opts)
214 
215 {
216 	char	*bp0, *bp;
217 
218     bp = bp0 = &buf[bufno][0];
219 	if (++bufno >= NBUFS)
220 		bufno = 0;
221 
222 	if (opts&MISC_PLUSSIGNS && value > 0)
223 		*bp++ = '+';
224 
225 	ncbi_ultostr(bp, (Uint8) value, opts&MISC_ANYCOMMAS);
226 
227     return bp0;
228 }
229 
230 /*
231 Return the length (in characters) of the ASCII base 10 representation
232 of the specified integer.
233 
234 If "opts&MISC_COMMAS" is non-zero, consider the additional length required
235 for commas before the thousands, millions, billions, etc.  positions.
236 
237 If "opts&MISC_ALLCOMMAS" is non-zero, insert commas even when the value
238 of the integer is less than 10,000.
239 
240 If "opts&MISC_PLUSSIGNS" is non-zero, consider the length of a plus sign
241 in front of any positive value, as well as the standard minus sign in front
242 of negative values.
243 */
Nlm_Lwidth(long value,int opts)244 NLM_EXTERN int LIBCALL Nlm_Lwidth (long value, int opts)
245 
246 {
247 	int	len;
248 
249 	if (value < 0) {
250 		len = 1; /* account for the minus sign */
251 		value = -value;
252 	}
253 	else
254 		/* account for a plus sign */
255 		len = (opts&MISC_PLUSSIGNS) && (value > 0);
256 
257 	return len + ulwidth(value, opts&MISC_ANYCOMMAS);
258 }
259 
260 /*
261 Return the length (in characters) of the ASCII base 10 representation
262 of the specified unsigned integer.
263 */
Nlm_Ulwidth(unsigned long value,int opts)264 NLM_EXTERN int LIBCALL Nlm_Ulwidth (unsigned long value, int opts)
265 
266 {
267 	int	len;
268 
269 	len = ulwidth(value, opts&MISC_ANYCOMMAS);
270 	return len + ((opts&MISC_PLUSSIGNS) && (value > 0));
271 }
272 
273 static int
ulwidth(unsigned long value,int commas)274 ulwidth (unsigned long value, int commas)
275 
276 {
277 	int	j, len;
278 
279 	if (divray_max == 0)
280 		divray_init();
281 
282 	for (len=divray_max; len > 0 && divray[len] > value; --len)
283 		;
284 
285 	if ((commas&MISC_ALLCOMMAS) || (commas && value >= (10*1000)) ) {
286 		for (j = len-1; j > 1; --j)
287 			len += (commaray[j] != 0);
288 	}
289 	return len+1;
290 }
291 
292 /*
293 	Nlm_HeapSort -- sort a list using an heap sort algorithm
294 
295 	Performance is guaranteed O(NlogN).  Compared to BSD UNIX(TM) qsort,
296 	Nlm_HeapSort averages about half as fast--which may be acceptable
297 	for a portable, public domain function which qsort is not.
298 
299 	This code was derived from original work by Professor Webb Miller
300 	(Penn. State University), but don't blame him for this mess or any errors.
301 
302 	7/31/90 WRG
303 	6/18/92 Modified for segmented memory safety.  JMO
304 */
305 
Nlm_HeapSort(Nlm_VoidPtr b,size_t nel,size_t width,int (LIBCALLBACK * compar)PROTO ((Nlm_VoidPtr,Nlm_VoidPtr)))306 NLM_EXTERN void LIBCALL Nlm_HeapSort (Nlm_VoidPtr b, size_t nel, size_t width, int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )))	/* Element comparison routine */
307 
308 {
309 	register Nlm_CharPtr	base = (Nlm_CharPtr)b;
310 	register size_t	i;
311 	register char	ch;
312 	register Nlm_CharPtr 	base0 = (Nlm_CharPtr)base, lim, basef;
313 
314 	if (nel < 2)
315 		return;
316 
317 	lim = &base[((nel-2)/2)*width];
318 	basef = &base[(nel-1)*width];
319 	i = nel/2;
320 	for (base = &base0[(i - 1)*width]; i > 0; base = base - width) {
321 		heapify(base0, base, lim, basef, width, compar);
322 		i--;
323 	}
324 
325 	for (base = &base0[(nel-1)*width]; base > base0; base -= width) {
326 		for (i=0; i<width; ++i) {
327 			ch = base0[i];
328 			base0[i] = base[i];
329 			base[i] = ch;
330 		}
331 		lim = base0 + ((base-base0)/2 - width);
332 		if (base > base0+width)
333 			heapify(base0, base0, lim, base-width, width, compar);
334 	}
335 }
336 
337 static void
heapify(Nlm_CharPtr base0,Nlm_CharPtr base,Nlm_CharPtr lim,Nlm_CharPtr last,size_t width,int (LIBCALLBACK * compar)PROTO ((Nlm_VoidPtr,Nlm_VoidPtr)))338 heapify (Nlm_CharPtr base0, Nlm_CharPtr base, Nlm_CharPtr lim, Nlm_CharPtr last, size_t width, int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )))
339 
340 {
341 	register size_t	i;
342 	register char	ch;
343 	register Nlm_CharPtr left_son, large_son;
344 
345 	left_son = base0 + 2*(base-base0) + width;
346 	while (base <= lim) {
347 		if (left_son == last)
348 			large_son = left_son;
349 		else
350 			large_son = (*compar)(left_son, left_son+width) >= 0 ?
351 							left_son : left_son+width;
352 		if ((*compar)(base, large_son) < 0) {
353 			for (i=0; i<width; ++i) {
354 				ch = base[i];
355 				base[i] = large_son[i];
356 				large_son[i] = ch;
357 			}
358 			base = large_son;
359 			left_son = base0 + 2*(base-base0) + width;
360 		} else
361 			break;
362 	}
363 }
364 
365 /* helper for Nlm_StableMergeSort */
366 static void
367 mergesort_helper( Nlm_CharPtr b, size_t nel, size_t width, int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )), Nlm_CharPtr scratch, Nlm_CharPtr output );
368 
369 
370 /* Also guaranteed O(NlogN) and guarantees a stable sort.
371    That is, elements which are the same
372    according to the compar function are kept in the same order. */
Nlm_StableMergeSort(Nlm_VoidPtr b,size_t nel,size_t width,int (LIBCALLBACK * compar)PROTO ((Nlm_VoidPtr,Nlm_VoidPtr)))373 NLM_EXTERN void LIBCALL Nlm_StableMergeSort (Nlm_VoidPtr b, size_t nel, size_t width, int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )))	/* Element comparison routine */
374 
375 {
376   Nlm_CharPtr scratch = NULL;
377   Nlm_CharPtr output = NULL;
378 
379   if( nel < 1 ) {
380     return; /* nothing to do */
381   }
382 
383   /* We create scratch spaces which will be used throughout the
384      sort. */
385   scratch = (Nlm_CharPtr) Nlm_MemNew( nel * width );
386   output = (Nlm_CharPtr) Nlm_MemNew( nel * width );
387 
388   mergesort_helper( (Nlm_CharPtr)b, nel, width, compar, scratch, output );
389   memmove( b, output, nel * width );
390 
391   /* free our scratch space, which is no longer needed */
392   Nlm_MemFree(scratch);
393   Nlm_MemFree(output);
394 }
395 
396 /* This helper for Nlm_StableMergeSort sorts b and puts the
397    result in output.  It uses "scratch" for its own internal
398    scratch space. */
399 static void
mergesort_helper(Nlm_CharPtr b,size_t nel,size_t width,int (LIBCALLBACK * compar)PROTO ((Nlm_VoidPtr,Nlm_VoidPtr)),Nlm_CharPtr scratch,Nlm_CharPtr output)400 mergesort_helper( Nlm_CharPtr b, size_t nel, size_t width, int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )), Nlm_CharPtr scratch, Nlm_CharPtr output )
401 {
402   Nlm_CharPtr output_ptr = NULL;
403   Nlm_CharPtr left_ptr = NULL;
404   Nlm_CharPtr right_ptr = NULL;
405   Nlm_CharPtr midpoint_ptr = NULL;
406   Nlm_CharPtr one_past_end_ptr = NULL;
407   int compar_result = 0;
408 
409   /* non-recursive base case */
410   if( 1 == nel ) {
411     memmove( output, b, width );
412     return;
413   }
414 
415   /* divide-and-conquer: split roughly in half and sort each subarray,
416      with intermediate results ending up in the scratch array
417      ( the subcalls use "output" as a scratch space ) */
418   mergesort_helper( b, nel/2, width, compar, output, scratch );
419   mergesort_helper( b + (nel/2)*width, ((nel + 1) / 2), width, compar, output, scratch + (nel/2)*width );
420 
421   /* merge the sorted subarrays from scratch into output */
422   output_ptr = output;
423   left_ptr = scratch;
424   midpoint_ptr = scratch + (nel/2)*width;
425   right_ptr = midpoint_ptr;
426   one_past_end_ptr = scratch + (nel * width);
427 
428   while( left_ptr < midpoint_ptr && right_ptr < one_past_end_ptr ) {
429     compar_result = (*compar)( left_ptr, right_ptr );
430     if( compar_result <= 0 ) {
431       memmove( output_ptr, left_ptr, width );
432       left_ptr += width;
433       output_ptr += width;
434     } else if( compar_result > 0 ) {
435       memmove( output_ptr, right_ptr, width );
436       right_ptr += width;
437       output_ptr += width;
438     }
439   }
440 
441   if( left_ptr < midpoint_ptr ) {
442     /* right_ptr no longer valid, so just bulk copy from left_ptr */
443     memmove( output_ptr, left_ptr, midpoint_ptr - left_ptr );
444   } else if( right_ptr < one_past_end_ptr ) {
445     /* left_ptr no longer valid, so just bulk copy from right_ptr */
446     memmove( output_ptr, right_ptr, one_past_end_ptr - right_ptr );
447   }
448 }
449 
450 /*****************************************************************************
451 *
452 *   ValNodeNew(vnp)
453 *      adds after last node in list if vnp not NULL
454 *
455 *****************************************************************************/
ValNodeNew(ValNodePtr vnp)456 NLM_EXTERN ValNodePtr LIBCALL ValNodeNew (ValNodePtr vnp)
457 
458 {
459 	ValNodePtr newnode;
460 
461 	newnode = (ValNodePtr) Nlm_MemNew(sizeof(ValNode));
462 	if (vnp != NULL)
463     {
464         while (vnp->next != NULL)
465             vnp = vnp->next;
466 		vnp->next = newnode;
467     }
468 	return newnode;
469 }
470 
471 /*****************************************************************************
472 *
473 *   ValNodeLen(vnp)
474 *      returns the number of nodes in the linked list
475 *
476 *****************************************************************************/
ValNodeLen(ValNodePtr vnp)477 NLM_EXTERN Nlm_Int4 LIBCALL ValNodeLen (ValNodePtr vnp)
478 
479 {
480 	Nlm_Int4 len;
481 
482 	len = 0;
483 	while (vnp != NULL) {
484 		len++;
485 		vnp = vnp->next;
486 	}
487 	return len;
488 }
489 
490 /*****************************************************************************
491 *
492 *   ValNodeAdd(head)
493 *      adds after last node in list if *head not NULL
494 *      If *head is NULL, sets it to the new ValNode
495 *      returns pointer to the NEW node added
496 *
497 *****************************************************************************/
ValNodeAdd(ValNodePtr PNTR head)498 NLM_EXTERN ValNodePtr LIBCALL ValNodeAdd (ValNodePtr PNTR head)
499 
500 {
501 	ValNodePtr newnode;
502 
503 	if (head != NULL)
504 	{
505 		newnode = ValNodeNew(*head);
506 		if (*head == NULL)
507 			*head = newnode;
508 	}
509 	else
510 		newnode = ValNodeNew(NULL);
511 
512 	return newnode;
513 }
514 
515 /*****************************************************************************
516 *
517 *   ValNodeLink(head, newnode)
518 *      adds newnode at end of chain
519 *      if (*head == NULL) *head = newnode
520 *      ALWAYS returns pointer to START of chain
521 *
522 *****************************************************************************/
ValNodeLink(ValNodePtr PNTR head,ValNodePtr newnode)523 NLM_EXTERN ValNodePtr LIBCALL ValNodeLink (ValNodePtr PNTR head, ValNodePtr newnode)
524 {
525    ValNodePtr vnp;
526 
527    if (head == NULL)
528 	 return newnode;
529 
530    vnp = *head;
531 
532    if (vnp != NULL )
533    {
534         while (vnp->next != NULL)
535             vnp = vnp->next;
536         vnp->next = newnode;
537     }
538     else
539 		*head = newnode;
540 
541    return *head;
542 }
543 
544 /*****************************************************************************
545 *
546 *   ValNodeAddStr (head, choice, str)
547 *      adds like ValNodeAdd()
548 *      sets newnode->choice = choice (if choice does not matter, use 0)
549 *      sets newnode->data.ptrvalue = str
550 *         does NOT copy str
551 *      if str == NULL, does not add a ValNode
552 *
553 *****************************************************************************/
ValNodeAddStr(ValNodePtr PNTR head,Nlm_Int2 choice,Nlm_CharPtr str)554 NLM_EXTERN ValNodePtr LIBCALL ValNodeAddStr (ValNodePtr PNTR head, Nlm_Int2 choice, Nlm_CharPtr str)
555 {
556 	ValNodePtr newnode;
557 
558 	if (str == NULL) return NULL;
559 
560 	newnode = ValNodeAdd(head);
561 	if (newnode != NULL)
562 	{
563 		newnode->choice = (Nlm_Uint1)choice;
564 		newnode->data.ptrvalue = (Nlm_VoidPtr)str;
565 	}
566 
567 	return newnode;
568 }
569 
570 /*****************************************************************************
571 *
572 *   ValNodeCopyStr (head, choice, str)
573 *      adds like ValNodeAdd()
574 *      sets newnode->choice = choice (if choice does not matter, use 0)
575 *      sets newnode->data.ptrvalue = str
576 *         makes a COPY of str
577 *      if str == NULL, does not add a ValNode
578 *
579 *****************************************************************************/
ValNodeCopyStr(ValNodePtr PNTR head,Nlm_Int2 choice,const char * str)580 NLM_EXTERN ValNodePtr LIBCALL ValNodeCopyStr (ValNodePtr PNTR head, Nlm_Int2 choice, const char* str)
581 {
582 	ValNodePtr newnode;
583 
584 	if (str == NULL) return NULL;
585 
586 	newnode = ValNodeAdd(head);
587 	if (newnode != NULL)
588 	{
589 		newnode->choice = (Nlm_Uint1)choice;
590 		newnode->data.ptrvalue = StringSave(str);
591 	}
592 
593 	return newnode;
594 }
595 
ValNodeCopyStrExEx(ValNodePtr PNTR head,ValNodePtr PNTR tail,Nlm_Int2 choice,const char * str,const char * pfx,const char * sfx)596 NLM_EXTERN ValNodePtr LIBCALL ValNodeCopyStrExEx (ValNodePtr PNTR head, ValNodePtr PNTR tail, Nlm_Int2 choice, const char* str, const char* pfx, const char* sfx)
597 
598 {
599     size_t       len, pfx_len, sfx_len, str_len;
600 	ValNodePtr   newnode = NULL, vnp;
601     Nlm_CharPtr  ptr, tmp;
602 
603 	if (str == NULL) return NULL;
604 
605     newnode = ValNodeNew (NULL);
606     if (newnode == NULL) return NULL;
607 
608     str_len = StringLen (str);
609     pfx_len = StringLen (pfx);
610     sfx_len = StringLen (sfx);
611 
612     len = str_len + pfx_len + sfx_len;
613 
614     if (head != NULL) {
615         if (*head == NULL) {
616             *head = newnode;
617         }
618     }
619 
620     if (tail != NULL) {
621         if (*tail != NULL) {
622             vnp = *tail;
623             while (vnp->next != NULL) {
624               vnp = vnp->next;
625             }
626             vnp->next = newnode;
627         }
628         *tail = newnode;
629     }
630 
631     ptr = Nlm_MemNew (sizeof (Nlm_Char) * (len + 2));
632     if (ptr == NULL) return NULL;
633 
634     tmp = ptr;
635     if (pfx_len > 0) {
636       tmp = Nlm_StringMove (tmp, pfx);
637     }
638     if (str_len > 0) {
639       tmp = Nlm_StringMove (tmp, str);
640     }
641     if (sfx_len > 0) {
642       tmp = Nlm_StringMove (tmp, sfx);
643     }
644 
645 	if (newnode != NULL) {
646 		newnode->choice = (Nlm_Uint1)choice;
647 		newnode->data.ptrvalue = ptr;
648 	}
649 
650 	return newnode;
651 }
652 
ValNodeCopyStrEx(ValNodePtr PNTR head,ValNodePtr PNTR tail,Nlm_Int2 choice,const char * str)653 NLM_EXTERN ValNodePtr LIBCALL ValNodeCopyStrEx (ValNodePtr PNTR head, ValNodePtr PNTR tail, Nlm_Int2 choice, const char* str)
654 
655 {
656   return ValNodeCopyStrExEx (head, tail, choice, str, NULL, NULL);
657 }
658 
659 /*****************************************************************************
660 *
661 *   ValNodeAddInt (head, choice, value)
662 *      adds like ValNodeAdd()
663 *      sets newnode->choice = choice (if choice does not matter, use 0)
664 *      sets newnode->data.intvalue = value
665 *
666 *****************************************************************************/
ValNodeAddInt(ValNodePtr PNTR head,Nlm_Int2 choice,Nlm_Int4 value)667 NLM_EXTERN ValNodePtr LIBCALL ValNodeAddInt (ValNodePtr PNTR head, Nlm_Int2 choice, Nlm_Int4 value)
668 {
669 	ValNodePtr newnode;
670 
671 	newnode = ValNodeAdd(head);
672 	if (newnode != NULL)
673 	{
674 		newnode->choice = (Nlm_Uint1)choice;
675 		newnode->data.intvalue = value;
676 	}
677 
678 	return newnode;
679 }
680 
681 /*****************************************************************************
682 *
683 *   ValNodeAddBigInt (head, choice, value)
684 *      adds like ValNodeAdd()
685 *      sets newnode->choice = choice (if choice does not matter, use 0)
686 *      sets newnode->data.bigintvalue = value
687 *
688 *****************************************************************************/
ValNodeAddBigInt(ValNodePtr PNTR head,Nlm_Int2 choice,Nlm_Int8 value)689 NLM_EXTERN ValNodePtr LIBCALL ValNodeAddBigInt (ValNodePtr PNTR head, Nlm_Int2 choice, Nlm_Int8 value)
690 {
691 	ValNodePtr newnode;
692 
693 	newnode = ValNodeAdd(head);
694 	if (newnode != NULL)
695 	{
696 		newnode->choice = (Nlm_Uint1)choice;
697 		newnode->data.bigintvalue = value;
698 	}
699 
700 	return newnode;
701 }
702 
703 /*****************************************************************************
704 *
705 *   ValNodeAddBoolean (head, choice, value)
706 *      adds like ValNodeAdd()
707 *      sets newnode->choice = choice (if choice does not matter, use 0)
708 *      sets newnode->data.boolvalue = value
709 *
710 *****************************************************************************/
ValNodeAddBoolean(ValNodePtr PNTR head,Nlm_Int2 choice,Nlm_Boolean value)711 NLM_EXTERN ValNodePtr LIBCALL ValNodeAddBoolean (ValNodePtr PNTR head, Nlm_Int2 choice, Nlm_Boolean value)
712 {
713 	ValNodePtr newnode;
714 
715 	newnode = ValNodeAdd(head);
716 	if (newnode != NULL)
717 	{
718 		newnode->choice = (Nlm_Uint1)choice;
719 		newnode->data.boolvalue = value;
720 	}
721 
722 	return newnode;
723 }
724 
725 /*****************************************************************************
726 *
727 *   ValNodeAddFloat (head, choice, value)
728 *      adds like ValNodeAdd()
729 *      sets newnode->choice = choice (if choice does not matter, use 0)
730 *      sets newnode->data.realvalue = value
731 *
732 *****************************************************************************/
ValNodeAddFloat(ValNodePtr PNTR head,Nlm_Int2 choice,Nlm_FloatHi value)733 NLM_EXTERN ValNodePtr LIBCALL ValNodeAddFloat (ValNodePtr PNTR head, Nlm_Int2 choice, Nlm_FloatHi value)
734 {
735 	ValNodePtr newnode;
736 
737 	newnode = ValNodeAdd(head);
738 	if (newnode != NULL)
739 	{
740 		newnode->choice = (Nlm_Uint1)choice;
741 		newnode->data.realvalue = value;
742 	}
743 
744 	return newnode;
745 }
746 
747 /*****************************************************************************
748 *
749 *   ValNodeAddPointer (head, choice, value)
750 *      adds like ValNodeAdd()
751 *      sets newnode->choice = choice (if choice does not matter, use 0)
752 *      sets newnode->data.ptrvalue = value
753 *
754 *****************************************************************************/
ValNodeAddPointer(ValNodePtr PNTR head,Nlm_Int2 choice,Nlm_VoidPtr value)755 NLM_EXTERN ValNodePtr LIBCALL ValNodeAddPointer (ValNodePtr PNTR head, Nlm_Int2 choice, Nlm_VoidPtr value)
756 {
757 	ValNodePtr newnode;
758 
759 	newnode = ValNodeAdd(head);
760 	if (newnode != NULL)
761 	{
762 		newnode->choice = (Nlm_Uint1)choice;
763 		newnode->data.ptrvalue = value;
764 	}
765 
766 	return newnode;
767 }
768 
ValNodeAddPointerEx(ValNodePtr PNTR head,ValNodePtr PNTR tail,Nlm_Int2 choice,Nlm_VoidPtr value)769 NLM_EXTERN ValNodePtr LIBCALL ValNodeAddPointerEx (ValNodePtr PNTR head, ValNodePtr PNTR tail, Nlm_Int2 choice, Nlm_VoidPtr value)
770 {
771 	ValNodePtr newnode = NULL;
772     ValNodePtr vnp;
773 
774     newnode = ValNodeNew (NULL);
775     if (newnode == NULL) return NULL;
776 
777     if (head != NULL) {
778         if (*head == NULL) {
779             *head = newnode;
780         }
781     }
782 
783     if (tail != NULL) {
784         if (*tail != NULL) {
785             vnp = *tail;
786             while (vnp->next != NULL) {
787               vnp = vnp->next;
788             }
789             vnp->next = newnode;
790         }
791         *tail = newnode;
792     }
793 
794 	if (newnode != NULL)
795 	{
796 		newnode->choice = (Nlm_Uint1)choice;
797 		newnode->data.ptrvalue = value;
798 	}
799 
800 	return newnode;
801 }
802 
803 /*****************************************************************************
804 *
805 *   ValNodeAddFunction (head, choice, value)
806 *      adds like ValNodeAdd()
807 *      sets newnode->choice = choice (if choice does not matter, use 0)
808 *      sets newnode->data.funcvalue = value
809 *
810 *****************************************************************************/
ValNodeAddFunction(ValNodePtr PNTR head,Nlm_Int2 choice,Nlm_FnPtr value)811 NLM_EXTERN ValNodePtr LIBCALL ValNodeAddFunction (ValNodePtr PNTR head, Nlm_Int2 choice, Nlm_FnPtr value)
812 {
813 	ValNodePtr newnode;
814 
815 	newnode = ValNodeAdd(head);
816 	if (newnode != NULL)
817 	{
818 		newnode->choice = (Nlm_Uint1)choice;
819 		newnode->data.funcvalue = value;
820 	}
821 
822 	return newnode;
823 }
824 
825 /*****************************************************************************
826 *
827 *   ValNodeFree(vnp)
828 *   	frees whole chain of ValNodes
829 *       Does NOT free associated data pointers
830 *           see ValNodeFreeData()
831 *
832 *****************************************************************************/
ValNodeFree(ValNodePtr vnp)833 NLM_EXTERN ValNodePtr LIBCALL ValNodeFree (ValNodePtr vnp)
834 {
835 	ValNodePtr next;
836 
837 	while (vnp != NULL)
838 	{
839 		next = vnp->next;
840 		Nlm_MemFree(vnp);
841 		vnp = next;
842 	}
843 	return NULL;
844 }
845 
846 /*****************************************************************************
847 *
848 *   ValNodeFreeData(vnp)
849 *   	frees whole chain of ValNodes
850 *       frees associated data pointers - BEWARE of this if these are not
851 *           allocated single memory block structures.
852 *
853 *****************************************************************************/
ValNodeFreeData(ValNodePtr vnp)854 NLM_EXTERN ValNodePtr LIBCALL ValNodeFreeData (ValNodePtr vnp)
855 {
856 	ValNodePtr next;
857 
858 	while (vnp != NULL)
859 	{
860 		Nlm_MemFree(vnp->data.ptrvalue);
861 		next = vnp->next;
862 		Nlm_MemFree(vnp);
863 		vnp = next;
864 	}
865 	return NULL;
866 }
867 
868 /*****************************************************************************
869 *
870 *   ValNodePtr ValNodeExtract(headptr, choice)
871 *       removes first node in chain where ->choice == choice
872 *       rejoins chain after removing the node
873 *       sets node->next to NULL
874 *
875 *****************************************************************************/
ValNodeExtract(ValNodePtr PNTR headptr,Nlm_Int2 choice)876 NLM_EXTERN ValNodePtr LIBCALL ValNodeExtract (ValNodePtr PNTR headptr, Nlm_Int2 choice)
877 {
878     ValNodePtr last = NULL,
879         vnp = * headptr;
880 
881     while (vnp != NULL)
882     {
883         if (vnp->choice == (Nlm_Uint1)choice)
884         {
885             if (last == NULL)    /* first one */
886                 * headptr = vnp->next;
887             else
888                 last->next = vnp->next;
889 
890             vnp->next = NULL;
891             return vnp;
892         }
893         else
894         {
895             last = vnp;
896             vnp = vnp->next;
897         }
898     }
899 
900     return NULL;    /* not found */
901 }
902 
903 /*****************************************************************************
904 *
905 *   ValNodePtr ValNodeExtractList(headptr, choice)
906 *       removes ALL nodes in chain where ->choice == choice
907 *       rejoins chain after removing the nodes
908 *       returns independent chain of extracted nodes
909 *
910 *****************************************************************************/
ValNodeExtractList(ValNodePtr PNTR headptr,Nlm_Int2 choice)911 NLM_EXTERN ValNodePtr LIBCALL ValNodeExtractList (ValNodePtr PNTR headptr, Nlm_Int2 choice)
912 {
913     ValNodePtr last = NULL, first = NULL, vnp;
914 
915     while ((vnp = ValNodeExtract(headptr, choice)) != NULL)
916     {
917 		if (last == NULL)
918 		{
919 			last = vnp;
920 			first = vnp;
921 		}
922 		else
923 			last->next = vnp;
924 		last = vnp;
925 	}
926 
927     return first;
928 }
929 
930 /*****************************************************************************
931 *
932 *   ValNodeFindNext (head, curr, choice)
933 *   	Finds next ValNode with vnp->choice == choice after curr
934 *       If curr == NULL, starts at head of list
935 *       If choice < 0 , returns all ValNodes
936 *       Returns NULL, when no more found
937 *
938 *****************************************************************************/
ValNodeFindNext(ValNodePtr head,ValNodePtr curr,Nlm_Int2 choice)939 NLM_EXTERN ValNodePtr LIBCALL ValNodeFindNext (ValNodePtr head, ValNodePtr curr, Nlm_Int2 choice)
940 {
941 	if (head == NULL) return NULL;
942 
943 	if (curr == NULL)
944 		curr = head;
945 	else
946 		curr = curr->next;
947 
948 	while (curr != NULL)
949 	{
950 		if ((choice < 0) || (curr->choice == (Nlm_Uint1)choice))
951 			return curr;
952 		curr = curr->next;
953 	}
954 
955 	return curr;
956 }
957 
958 /*****************************************************************************
959 *
960 *   ValNodeSort(list, compar)
961 *   	Copied from SortValNode in jzcoll, renamed, for more general access
962 *   	Makes array from ValNode list, calls HeapSort, reconnects ValNode list
963 *
964 *****************************************************************************/
ValNodeSort(ValNodePtr list,int (LIBCALLBACK * compar)PROTO ((Nlm_VoidPtr,Nlm_VoidPtr)))965 NLM_EXTERN ValNodePtr LIBCALL ValNodeSort (ValNodePtr list, int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )))
966 {
967 	ValNodePtr tmp, PNTR head;
968 	Nlm_Int4 count, i;
969 
970 	if (list == NULL) return NULL;
971 
972 	count = ValNodeLen (list);
973 	head = (ValNodePtr *) MemNew (((size_t) count + 1) * sizeof (ValNodePtr));
974 	for (tmp = list, i = 0; tmp != NULL && i < count; i++) {
975 		head [i] = tmp;
976 		tmp = tmp->next;
977 	}
978 
979 	HeapSort (head, (size_t) count, sizeof (ValNodePtr), compar);
980 	for (i = 0; i < count; i++) {
981 		tmp = head [i];
982 		tmp->next = head [i + 1];
983 	}
984 	list = head [0];
985 	MemFree (head);
986 
987 	return list;
988 }
989 
990 
991 /*****************************************************************************
992 *
993 *   ValNodeIsSorted(list, compar)
994 *   	Looks for first instance of compar not being true.
995 *     If all true, then is sorted, otherwise not.
996 *
997 *****************************************************************************/
ValNodeIsSorted(ValNodePtr list,int (LIBCALLBACK * compar)PROTO ((Nlm_VoidPtr,Nlm_VoidPtr)))998 NLM_EXTERN Nlm_Boolean LIBCALL ValNodeIsSorted (ValNodePtr list, int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )))
999 {
1000   Nlm_Boolean rval = TRUE;
1001 
1002   if (list == NULL || compar == NULL) {
1003     return TRUE;
1004   }
1005   while (list->next != NULL && rval) {
1006     if (compar (&list, &(list->next)) > 0) {
1007       rval = FALSE;
1008     }
1009     list = list->next;
1010   }
1011   return rval;
1012 }
1013 
1014 
1015 NLM_EXTERN void LIBCALL
ValNodeUnique(ValNodePtr PNTR list,int (LIBCALLBACK * compar)PROTO ((Nlm_VoidPtr,Nlm_VoidPtr)),ValNodePtr (LIBCALLBACK * valnodefree)PROTO ((ValNodePtr)))1016 ValNodeUnique
1017 (ValNodePtr PNTR list,
1018  int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )),
1019  ValNodePtr (LIBCALLBACK *valnodefree ) PROTO ((ValNodePtr)))
1020 {
1021   ValNodePtr vnp, tmp;
1022 
1023   if (list == NULL || *list == NULL || compar == NULL || valnodefree == NULL) return;
1024 
1025   vnp = *list;
1026   while (vnp->next != NULL) {
1027     if (compar (&vnp, &(vnp->next)) == 0) {
1028       tmp = vnp->next;
1029       vnp->next = tmp->next;
1030       tmp->next = NULL;
1031       tmp = valnodefree (tmp);
1032     } else {
1033       vnp = vnp->next;
1034     }
1035   }
1036 }
1037 
1038 
1039 NLM_EXTERN ValNodePtr LIBCALL
ValNodeDupList(ValNodePtr orig,ValNodePtr (LIBCALLBACK * copy)PROTO ((ValNodePtr)))1040 ValNodeDupList
1041 (ValNodePtr orig,
1042  ValNodePtr (LIBCALLBACK *copy )PROTO ((ValNodePtr)))
1043 {
1044   ValNodePtr list = NULL, prev = NULL, vnp, new_vnp;
1045 
1046   if (copy == NULL) {
1047     return NULL;
1048   }
1049   for (vnp = orig; vnp != NULL; vnp = vnp->next) {
1050     new_vnp = copy (vnp);
1051     if (new_vnp != NULL) {
1052       if (prev == NULL) {
1053         list = new_vnp;
1054       } else {
1055         prev->next = new_vnp;
1056       }
1057       prev = new_vnp;
1058     }
1059   }
1060   return list;
1061 }
1062 
1063 
1064 NLM_EXTERN void LIBCALL
ValNodeInsert(ValNodePtr PNTR list,ValNodePtr new_item,int (LIBCALLBACK * compar)PROTO ((Nlm_VoidPtr,Nlm_VoidPtr)))1065 ValNodeInsert
1066 (ValNodePtr PNTR list,
1067  ValNodePtr new_item,
1068  int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )))
1069 {
1070   ValNodePtr vnp, vnp_prev = NULL;
1071 
1072   if (list == NULL || new_item == NULL) {
1073     return;
1074   }
1075   if (*list == NULL) {
1076     *list = new_item;
1077   } else if (compar == NULL) {
1078     ValNodeLink (list, new_item);
1079   } else {
1080     vnp = *list;
1081     while (vnp != NULL && compar (&vnp, &new_item) < 1) {
1082       vnp_prev = vnp;
1083       vnp = vnp->next;
1084     }
1085     if (vnp_prev == NULL) {
1086       new_item->next= *list;
1087       *list = new_item;
1088     } else {
1089       new_item->next= vnp_prev->next;
1090       vnp_prev->next= new_item;
1091     }
1092   }
1093 }
1094 
1095 
1096 NLM_EXTERN void LIBCALL
ValNodePurge(ValNodePtr PNTR list,Nlm_Boolean (LIBCALLBACK * do_remove)PROTO ((ValNodePtr)),ValNodePtr (LIBCALLBACK * valnodefree)PROTO ((ValNodePtr)))1097 ValNodePurge
1098 (ValNodePtr PNTR list,
1099  Nlm_Boolean (LIBCALLBACK *do_remove ) PROTO ((ValNodePtr)),
1100  ValNodePtr (LIBCALLBACK *valnodefree ) PROTO ((ValNodePtr)))
1101 {
1102   ValNodePtr vnp_prev = NULL, vnp, vnp_next;
1103 
1104   if (list == NULL || do_remove == NULL) {
1105     return;
1106   }
1107   for (vnp = *list; vnp != NULL; vnp = vnp_next) {
1108     vnp_next = vnp->next;
1109     if (do_remove (vnp)) {
1110       if (vnp_prev == NULL) {
1111         *list = vnp_next;
1112       } else {
1113         vnp_prev->next = vnp_next;
1114       }
1115       vnp->next = NULL;
1116       if (valnodefree == NULL) {
1117         vnp = ValNodeFree (vnp);
1118       } else {
1119         vnp = valnodefree (vnp);
1120       }
1121     } else {
1122       vnp_prev = vnp;
1123     }
1124   }
1125 }
1126 
1127 
ValNodeCompare(ValNodePtr vnp1,ValNodePtr vnp2,int (LIBCALLBACK * compar)(Nlm_VoidPtr,Nlm_VoidPtr))1128 NLM_EXTERN int LIBCALL ValNodeCompare PROTO ((ValNodePtr vnp1, ValNodePtr vnp2, int (LIBCALLBACK *compar) (Nlm_VoidPtr, Nlm_VoidPtr)))
1129 {
1130   int rval = 0;
1131   if (compar == NULL) {
1132     return 0;
1133   }
1134   while (vnp1 != NULL && vnp2 != NULL && rval == 0)
1135   {
1136     rval = compar (&vnp1, &vnp2);
1137     vnp1 = vnp1->next;
1138     vnp2 = vnp2->next;
1139   }
1140   if (rval == 0)
1141   {
1142     if (vnp1 == NULL && vnp2 == NULL)
1143     {
1144       rval = 0;
1145     }
1146     else if (vnp1 == NULL)
1147     {
1148       rval = -1;
1149     }
1150     else
1151     {
1152       rval = 1;
1153     }
1154   }
1155   return rval;
1156 }
1157 
1158 
1159 /*****************************************************************************
1160 *
1161 *   ValNodeMergeStrs(list)
1162 *   	Merges chain of val node strings into a single character array
1163 *
1164 *****************************************************************************/
ValNodeMergeStrs(ValNodePtr list)1165 NLM_EXTERN Nlm_CharPtr LIBCALL ValNodeMergeStrs (ValNodePtr list)
1166 
1167 {
1168   size_t       len;
1169   Nlm_CharPtr  ptr;
1170   Nlm_CharPtr  str;
1171   Nlm_CharPtr  tmp;
1172   ValNodePtr   vnp;
1173 
1174 
1175   if (list == NULL) return NULL;
1176 
1177   for (vnp = list, len = 0; vnp != NULL; vnp = vnp->next) {
1178     str = (Nlm_CharPtr) vnp->data.ptrvalue;
1179     len += Nlm_StringLen (str);
1180   }
1181   if (len == 0) return NULL;
1182 
1183   ptr = Nlm_MemNew (sizeof (Nlm_Char) * (len + 2));
1184   if (ptr == NULL) return NULL;
1185 
1186   for (vnp = list, tmp = ptr; vnp != NULL; vnp = vnp->next) {
1187     str = (Nlm_CharPtr) vnp->data.ptrvalue;
1188     tmp = Nlm_StringMove (tmp, str);
1189   }
1190 
1191   return ptr;
1192 }
1193 
ValNodeMergeStrsExEx(ValNodePtr list,Nlm_CharPtr separator,Nlm_CharPtr pfx,Nlm_CharPtr sfx)1194 NLM_EXTERN Nlm_CharPtr LIBCALL ValNodeMergeStrsExEx (ValNodePtr list, Nlm_CharPtr separator, Nlm_CharPtr pfx, Nlm_CharPtr sfx)
1195 
1196 {
1197   size_t       len;
1198   size_t       lens;
1199   size_t       pfx_len;
1200   Nlm_CharPtr  ptr;
1201   Nlm_CharPtr  sep;
1202   size_t       sfx_len;
1203   Nlm_CharPtr  str;
1204   Nlm_CharPtr  tmp;
1205   ValNodePtr   vnp;
1206 
1207   if (list == NULL) return NULL;
1208 
1209   pfx_len = StringLen (pfx);
1210   sfx_len = StringLen (sfx);
1211 
1212   lens = StringLen (separator);
1213 
1214   for (vnp = list, len = 0; vnp != NULL; vnp = vnp->next) {
1215     str = (Nlm_CharPtr) vnp->data.ptrvalue;
1216     len += Nlm_StringLen (str);
1217     len += lens;
1218   }
1219   if (len == 0) return NULL;
1220   len += pfx_len + sfx_len;
1221 
1222   ptr = Nlm_MemNew (sizeof (Nlm_Char) * (len + 2));
1223   if (ptr == NULL) return NULL;
1224 
1225   tmp = ptr;
1226   if (pfx_len > 0) {
1227     tmp = Nlm_StringMove (tmp, pfx);
1228   }
1229   sep = NULL;
1230   for (vnp = list; vnp != NULL; vnp = vnp->next) {
1231     tmp = Nlm_StringMove (tmp, sep);
1232     str = (Nlm_CharPtr) vnp->data.ptrvalue;
1233     tmp = Nlm_StringMove (tmp, str);
1234     sep = separator;
1235   }
1236   if (sfx_len > 0) {
1237     tmp = Nlm_StringMove (tmp, sfx);
1238   }
1239 
1240   return ptr;
1241 }
1242 
ValNodeMergeStrsEx(ValNodePtr list,Nlm_CharPtr separator)1243 NLM_EXTERN Nlm_CharPtr LIBCALL ValNodeMergeStrsEx (ValNodePtr list, Nlm_CharPtr separator)
1244 
1245 {
1246   return ValNodeMergeStrsExEx (list, separator, NULL, NULL);
1247 }
1248 
MergeStringArray(Nlm_CharPtr PNTR local,size_t numitems)1249 NLM_EXTERN Nlm_CharPtr LIBCALL MergeStringArray (Nlm_CharPtr PNTR local, size_t numitems)
1250 
1251 {
1252   size_t       len = 0;
1253   Nlm_Int2     i;
1254   Nlm_CharPtr  rsult;
1255   Nlm_CharPtr  str;
1256   Nlm_CharPtr  tmp;
1257 
1258   if (local == NULL || numitems < 1) return NULL;
1259 
1260   for (i = 0; /* local [i] != NULL */ i < numitems; i++) {
1261     str = local [i];
1262     if (StringHasNoText (str)) continue;
1263     len += StringLen (str) + 2;
1264   }
1265 
1266   if (len < 1) return NULL;
1267 
1268   rsult = (Nlm_CharPtr) MemNew (len + 3);
1269   if (rsult == NULL) return NULL;
1270   tmp = rsult;
1271 
1272   for (i = 0; /* local [i] != NULL */ i < numitems; i++) {
1273     str = local [i];
1274     if (StringHasNoText (str)) continue;
1275     tmp = StringMove (tmp, str);
1276     tmp = StringMove (tmp, "\n");
1277   }
1278 
1279   return rsult;
1280 }
1281 
1282 /*****************************************************************************
1283 *
1284 *   Start Of Node List Functions
1285 *
1286 *****************************************************************************/
1287 
NodeListNew(void)1288 NLM_EXTERN ValNodePtr LIBCALL NodeListNew (void)
1289 
1290 {
1291   ValNodePtr  vnp;
1292 
1293   vnp = ValNodeNew (NULL);
1294   return vnp;
1295 }
1296 
NodeListFree(ValNodePtr head)1297 NLM_EXTERN ValNodePtr LIBCALL NodeListFree (ValNodePtr head)
1298 
1299 {
1300   if (head != NULL) {
1301     ValNodeFreeData (head);
1302   }
1303   return NULL;
1304 }
1305 
NodeListLen(ValNodePtr head)1306 NLM_EXTERN Nlm_Int2 LIBCALL NodeListLen (ValNodePtr head)
1307 
1308 {
1309   Nlm_Int2  item;
1310 
1311   item = 0;
1312   if (head != NULL) {
1313     while (head->next != NULL) {
1314       head = head->next;
1315       item++;
1316     }
1317   }
1318   return item;
1319 }
1320 
NodeListFind(ValNodePtr head,Nlm_Int2 item,Nlm_Boolean extend)1321 NLM_EXTERN ValNodePtr LIBCALL NodeListFind (ValNodePtr head, Nlm_Int2 item, Nlm_Boolean extend)
1322 
1323 {
1324   ValNodePtr  vnp;
1325 
1326   vnp = NULL;
1327   if (head != NULL && item > 0) {
1328     vnp = head;
1329     while (vnp->next != NULL && item > 0) {
1330       vnp = vnp->next;
1331       item--;
1332     }
1333     if (extend) {
1334       while (item > 0) {
1335         vnp = ValNodeNew (vnp);
1336         item--;
1337       }
1338     } else if (item > 0) {
1339       vnp = NULL;
1340     }
1341   }
1342   return vnp;
1343 }
1344 
NodeListRead(ValNodePtr head,Nlm_Int2 item,Nlm_VoidPtr ptr,size_t size)1345 NLM_EXTERN Nlm_Boolean LIBCALL NodeListRead (ValNodePtr head, Nlm_Int2 item, Nlm_VoidPtr ptr, size_t size)
1346 
1347 {
1348   Nlm_Boolean  copied;
1349   Nlm_BytePtr  dst;
1350   Nlm_BytePtr  src;
1351   ValNodePtr   vnp;
1352 
1353   copied = FALSE;
1354   if (head != NULL && item > 0 && ptr != NULL) {
1355     vnp = NodeListFind (head, item, FALSE);
1356     if (vnp != NULL && vnp->data.ptrvalue != NULL) {
1357       dst = (Nlm_BytePtr) ptr;
1358       src = (Nlm_BytePtr) (vnp->data.ptrvalue);
1359       while (size > 0) {
1360         *dst = *src;
1361         dst++;
1362         src++;
1363         size--;
1364       }
1365       copied = TRUE;
1366     } else {
1367       Nlm_MemFill (ptr, 0, size);
1368     }
1369   }
1370   return copied;
1371 }
1372 
Nlm_WriteToNode(ValNodePtr vnp,Nlm_VoidPtr ptr,size_t size)1373 static Nlm_Boolean LIBCALL Nlm_WriteToNode (ValNodePtr vnp, Nlm_VoidPtr ptr, size_t size)
1374 
1375 {
1376   Nlm_Boolean  copied;
1377   Nlm_BytePtr  dst;
1378   Nlm_BytePtr  src;
1379 
1380   copied = FALSE;
1381   if (vnp != NULL) {
1382     vnp->data.ptrvalue = MemFree (vnp->data.ptrvalue);
1383     if (ptr != NULL) {
1384       vnp->data.ptrvalue = MemNew (size);
1385       if (vnp->data.ptrvalue != NULL) {
1386         dst = (Nlm_BytePtr) (vnp->data.ptrvalue);
1387         src = (Nlm_BytePtr) ptr;
1388         while (size > 0) {
1389           *dst = *src;
1390           dst++;
1391           src++;
1392           size--;
1393         }
1394         copied = TRUE;
1395       }
1396     }
1397   }
1398   return copied;
1399 }
1400 
NodeListWrite(ValNodePtr head,Nlm_Int2 item,Nlm_VoidPtr ptr,size_t size)1401 NLM_EXTERN Nlm_Boolean LIBCALL NodeListWrite (ValNodePtr head, Nlm_Int2 item, Nlm_VoidPtr ptr, size_t size)
1402 
1403 {
1404   Nlm_Boolean  copied;
1405   ValNodePtr   vnp;
1406 
1407   copied = FALSE;
1408   if (head != NULL && item > 0 && ptr != NULL) {
1409     vnp = NodeListFind (head, item, TRUE);
1410     copied = Nlm_WriteToNode (vnp, ptr, size);
1411   }
1412   return copied;
1413 }
1414 
NodeListAppend(ValNodePtr head,Nlm_VoidPtr ptr,size_t size)1415 NLM_EXTERN Nlm_Boolean LIBCALL NodeListAppend (ValNodePtr head, Nlm_VoidPtr ptr, size_t size)
1416 
1417 {
1418   Nlm_Boolean  copied;
1419   ValNodePtr   vnp;
1420 
1421   copied = FALSE;
1422   if (head != NULL && ptr != NULL) {
1423     vnp = ValNodeNew (head);
1424     copied = Nlm_WriteToNode (vnp, ptr, size);
1425   }
1426   return copied;
1427 }
1428 
NodeListInsert(ValNodePtr head,Nlm_Int2 item,Nlm_VoidPtr ptr,size_t size)1429 NLM_EXTERN Nlm_Boolean LIBCALL NodeListInsert (ValNodePtr head, Nlm_Int2 item, Nlm_VoidPtr ptr, size_t size)
1430 
1431 {
1432   Nlm_Boolean  copied;
1433   ValNodePtr   prev;
1434   ValNodePtr   vnp;
1435 
1436   copied = FALSE;
1437   if (head != NULL && item > 0 && ptr != NULL) {
1438     if (item > 1) {
1439       prev = NodeListFind (head, (Nlm_Int2)(item - 1), FALSE);
1440     } else {
1441       prev = head;
1442     }
1443     if (prev != NULL) {
1444       vnp = ValNodeNew (NULL);
1445       if (vnp != NULL) {
1446         vnp->next = prev->next;
1447         prev->next = vnp;
1448         copied = Nlm_WriteToNode (vnp, ptr, size);
1449       }
1450     }
1451   }
1452   return copied;
1453 }
1454 
NodeListReplace(ValNodePtr head,Nlm_Int2 item,Nlm_VoidPtr ptr,size_t size)1455 NLM_EXTERN Nlm_Boolean LIBCALL NodeListReplace (ValNodePtr head, Nlm_Int2 item, Nlm_VoidPtr ptr, size_t size)
1456 
1457 {
1458   Nlm_Boolean  copied;
1459   ValNodePtr   vnp;
1460 
1461   copied = FALSE;
1462   if (head != NULL && item > 0 && ptr != NULL) {
1463     vnp = NodeListFind (head, item, FALSE);
1464     copied = Nlm_WriteToNode (vnp, ptr, size);
1465   }
1466   return copied;
1467 }
1468 
NodeListDelete(ValNodePtr head,Nlm_Int2 item)1469 NLM_EXTERN Nlm_Boolean LIBCALL NodeListDelete (ValNodePtr head, Nlm_Int2 item)
1470 
1471 {
1472   Nlm_Boolean  deleted;
1473   ValNodePtr   prev;
1474   ValNodePtr   vnp;
1475 
1476   deleted = FALSE;
1477   if (head != NULL && item > 0) {
1478     if (item > 1) {
1479       prev = NodeListFind (head, (Nlm_Int2)(item - 1), FALSE);
1480     } else {
1481       prev = head;
1482     }
1483     if (prev != NULL) {
1484       vnp = prev->next;
1485       if (vnp != NULL) {
1486         prev->next = vnp->next;
1487         Nlm_MemFree (vnp->data.ptrvalue);
1488         Nlm_MemFree (vnp);
1489         deleted = TRUE;
1490       }
1491     }
1492   }
1493   return deleted;
1494 }
1495 
1496 
1497 /*****************************************************************************
1498 *
1499 *   End Of Node List Functions
1500 *
1501 *****************************************************************************/
1502 
1503 #if defined(OS_MAC) || defined(OS_UNIX_DARWIN)
1504 
1505 /* C2PStr() and P2CStr() may or may not exist in Carbon, so we now always roll our own. */
1506 
Nlm_CtoPstr(Nlm_CharPtr str)1507 void Nlm_CtoPstr (Nlm_CharPtr str)
1508 {
1509     char *ioStr = (char *) str;
1510 	size_t len = strlen(ioStr);
1511 	if (len > 255) {
1512 		len = 255;
1513 	}
1514 	memmove(ioStr + 1, ioStr, len);
1515 	ioStr[0] = len;
1516 }
1517 
Nlm_PtoCstr(Nlm_CharPtr str)1518 void Nlm_PtoCstr (Nlm_CharPtr str)
1519 {
1520     StringPtr ioStr = (StringPtr) str;
1521 	Byte len = ioStr[0];
1522 	memmove(ioStr, ioStr + 1, len);
1523 	ioStr[len] = '\0';
1524 }
1525 
1526 #endif
1527 
1528 
Nlm_SwitchUint2(Nlm_Uint2 value)1529 NLM_EXTERN Nlm_Uint2 Nlm_SwitchUint2 (Nlm_Uint2 value)
1530 
1531 {
1532 	Nlm_Uint2  m;
1533 	m  = ((value & (Nlm_Uint2)0xFF00) >> 8);
1534 	m |= ((value & (Nlm_Uint2)0x00FF) << 8);
1535 	return m;
1536 }
1537 
Nlm_SwitchUint2Buff(Nlm_Uint2 * buff,int count)1538 NLM_EXTERN void Nlm_SwitchUint2Buff (Nlm_Uint2 *buff, int count)
1539 {
1540 	Nlm_Uint2 *ptr, n, m;
1541 
1542 	for (ptr=buff; count >0; --count)
1543 	{
1544 		n = *ptr;
1545 		m  = ((n & (Nlm_Uint2)0xFF00) >> 8);
1546 		m |= ((n & (Nlm_Uint2)0x00FF) << 8);
1547 		*ptr++ = m;
1548 	}
1549 }
1550 
Nlm_SwitchLong(unsigned long value)1551 NLM_EXTERN unsigned long  Nlm_SwitchLong (unsigned long value)
1552 {
1553 	unsigned long  m;
1554 	m  = ((value & (unsigned long)0xFF000000) >> 24);
1555 	m |= ((value & (unsigned long)0x00FF0000) >> 8);
1556 	m |= ((value & (unsigned long)0x0000FF00) << 8);
1557 	m |= ((value & (unsigned long)0x000000FF) << 24);
1558 	return m;
1559 }
1560 
Nlm_SwitchLongBuff(unsigned long * buff,int count)1561 NLM_EXTERN void Nlm_SwitchLongBuff (unsigned long *buff, int count)
1562 {
1563 	unsigned long *ptr, n, m;
1564 
1565 	for (ptr=buff; count >0; --count)
1566 	{
1567 		n = *ptr;
1568 		m  = ((n & (unsigned long)0xFF000000) >> 24);
1569 		m |= ((n & (unsigned long)0x00FF0000) >> 8);
1570 		m |= ((n & (unsigned long)0x0000FF00) << 8);
1571 		m |= ((n & (unsigned long)0x000000FF) << 24);
1572 		*ptr++ = m;
1573 	}
1574 }
1575 
Nlm_SwitchUint4(Nlm_Uint4 value)1576 NLM_EXTERN Nlm_Uint4  Nlm_SwitchUint4 (Nlm_Uint4 value)
1577 {
1578 	Nlm_Uint4  m;
1579 	m  = ((value & (Nlm_Uint4)0xFF000000) >> 24);
1580 	m |= ((value & (Nlm_Uint4)0x00FF0000) >> 8);
1581 	m |= ((value & (Nlm_Uint4)0x0000FF00) << 8);
1582 	m |= ((value & (Nlm_Uint4)0x000000FF) << 24);
1583 	return m;
1584 }
1585 
Nlm_SwitchUint4Buff(Nlm_Uint4 * buff,int count)1586 NLM_EXTERN void Nlm_SwitchUint4Buff (Nlm_Uint4 *buff, int count)
1587 {
1588 	Nlm_Uint4 *ptr, n, m;
1589 
1590 	for (ptr=buff; count >0; --count)
1591 	{
1592 		n = *ptr;
1593 		m  = ((n & (Nlm_Uint4)0xFF000000) >> 24);
1594 		m |= ((n & (Nlm_Uint4)0x00FF0000) >> 8);
1595 		m |= ((n & (Nlm_Uint4)0x0000FF00) << 8);
1596 		m |= ((n & (Nlm_Uint4)0x000000FF) << 24);
1597 		*ptr++ = m;
1598 	}
1599 }
1600 
1601 
1602 /* the following ListXXX() functions previously resided in ni_list.c */
1603 
1604 /*
1605  * Purpose:     Insert an item as the next element in a doubly linked list(ring)
1606  *
1607  * Parameters:
1608  *   elem           Next element to be inserted; this is data only,not a NodePtr
1609  *   ap             Insertion point
1610  *
1611  * Returns:
1612  *                The newly allocated NodePtr, containing forward and backward
1613  *                pointers and a pointer to elem
1614  *
1615  *
1616  * Description:
1617  *              Allocate the necessary memory for a "Node", attach the
1618  *              caller's data to that Node, and insert the Node after the
1619  *              specified node in the list, maintaining the integrity of
1620  *              a doubly-linked ring. If there are no other items in the
1621  *              ring, create a "minimal" ring which consists of the single
1622  *              Node pointing to itself in both directions.
1623  *
1624  * Note:
1625  *              Most "list" data is actually stored in a doubly-linked ring, as
1626  *              shown below. Furthermore, note that each node only contains a
1627  *              pointer to the actual data in the list, rather than the actual
1628  *              data itself.
1629  *
1630  *          +------------------------------------------------------------------+
1631  *          ^                                                                  |
1632  *          |       +-------------------------------------------------------+  |
1633  *          |       |                                                       ^  |
1634  *          |       V                                                       |  |
1635  *          |   +-------+       +-------+                       +-------+   |  |
1636  *          |   | next  |------>| next  |------> ...    ------->| next  |-->+  |
1637  *          |   +-------+       +-------+                       +-------+      |
1638  *          +<--| last  |<------| last  |<------ ...    <-------| last  |<-----+
1639  *              +-------+       +-------+                       +-------+
1640  *              | elem  |       | elem  |                       | elem  |
1641  *              +-------+       +-------+                       +-------+
1642  *                  |               |                               |
1643  *                  |               |                               |
1644  *                  V               V                               V
1645  *              +-------+       +-------+                       +-------+
1646  *              | actual|       | actual|                       | actual|
1647  *              | data  |       | data  |                       | data  |
1648  *              +-------+       +-------+                       +-------+
1649  */
1650 
1651 NLM_EXTERN NodePtr  LIBCALL
ListInsert(Nlm_VoidPtr elem,NodePtr ap)1652 ListInsert(Nlm_VoidPtr elem, NodePtr ap)                     /* ptr to node to insert after */
1653 {
1654     NodePtr             np;
1655 
1656     if (elem == NULL)
1657         return NULL;
1658 
1659     np = (NodePtr) MemNew(sizeof(Node));
1660     np->elem = elem;
1661 
1662     if (ap == NULL) {           /* no nodes in list */
1663         np->last = np;
1664         np->next = np;
1665         return np;
1666     }
1667     else {                              /* 1 or more nodes in list */
1668         np->next = ap->next;
1669         ap->next = np;
1670         np->next->last = np;
1671         np->last = ap;
1672         return np;
1673     }
1674 } /* ListInsert */
1675 
1676 
1677 
1678 /*
1679  * Purpose:     Insert an item as the previous element in a doubly linked
1680  *              list(ring)
1681  *
1682  * Parameters:
1683  *   elem           Next element to be inserted; this is data only,not a NodePtr
1684  *   ap             Insertion point
1685  *
1686  * Returns:
1687  *                The newly allocated NodePtr, containing forward and backward
1688  *                pointers and a pointer to elem
1689  *
1690  *
1691  * Description:
1692  *              Insert the specified item into the ring, before the specified
1693  *              insertion point. In the case where the specified insertion
1694  *              point was NULL, this is equivalent to ListInsert().
1695  */
1696 
1697 NLM_EXTERN NodePtr  LIBCALL
ListInsertPrev(Nlm_VoidPtr elem,NodePtr ap)1698 ListInsertPrev(Nlm_VoidPtr elem, NodePtr ap)                     /* ptr to node to insert before */
1699 {
1700     NodePtr             np;
1701 
1702     np = ap;
1703     if (ap != NULL)
1704         ap = ap->last;          /* previous node */
1705 
1706     ap = ListInsert(elem, ap);
1707     return (np == NULL) ? ap : np;
1708 } /* ListInsertPrev */
1709 
1710 
1711 
1712 /*
1713  * Purpose:     Delete a single node from a list or ring
1714  *
1715  * Parameters:
1716  *   np             Node to be deleted
1717  *
1718  * Returns:
1719  *                A pointer to the "next" node in the list/ring, after the
1720  *                deleted node.
1721  *
1722  *
1723  * Description:
1724  *              Delete the specified node from a list or ring. It is the
1725  *              responsibility of the caller to free the memory associated
1726  *              with the "elem" (data), if appropriate.
1727  */
1728 
1729 NLM_EXTERN NodePtr  LIBCALL
ListDelete(NodePtr np)1730 ListDelete(NodePtr np)
1731 {
1732     NodePtr             nextnode, lastnode;
1733 
1734     if (np == NULL)
1735         return NULL;
1736 
1737     nextnode = np->next;
1738     lastnode = np->last;
1739 
1740     if (nextnode == NULL && lastnode == NULL)   /* only node in a list */
1741         ;
1742     else if (nextnode == NULL) {                /* last in a list */
1743         np->last->next = NULL;
1744         nextnode = np->last;
1745     }
1746     else if (lastnode == NULL) {                /* first in a list */
1747         np->next->last = NULL;
1748         nextnode = np->next;
1749     }
1750     else if (np == nextnode)                    /* last in a ring */
1751         nextnode = NULL;
1752     else {                                      /* node with both neighbors */
1753         np->last->next = nextnode;
1754         np->next->last = np->last;
1755     }
1756 
1757     MemFree(np);                        /* assumes element memory has been freed */
1758     return nextnode;
1759 } /* ListDelete */
1760 
1761 
1762 
1763 /*
1764  * Purpose:     Get the next element from a list or ring (non-destructively)
1765  *
1766  * Parameters:
1767  *   np             Node before the node to be selected
1768  *
1769  * Returns:
1770  *                A pointer to the "next" node in the list/ring (or NULL
1771  *                if the list/ring was NULL). Note that for a list, the
1772  *                returned value can also be NULL.
1773  *
1774  *
1775  * Description:
1776  *              Return the "next" node in the list or rin.g
1777  */
1778 
1779 NLM_EXTERN NodePtr  LIBCALL
ListGetNext(NodePtr np)1780 ListGetNext(NodePtr np)
1781 {
1782     if (np == NULL)
1783         return NULL;
1784     return np->next;
1785 } /* ListGetNext */
1786 
1787 
1788 
1789 /*
1790  * Purpose:     Swap two adjacent nodes in a list or ring
1791  *
1792  * Parameters:
1793  *   np1            "Prior" node
1794  *   np2            "Next" node
1795  *
1796  *
1797  * Description:
1798  *              Swap the two specified elements, provided that they are
1799  *              adjacent, and np1 precedes np2.
1800  */
1801 
1802 NLM_EXTERN void  LIBCALL
ListSwapAdj(NodePtr np1,NodePtr np2)1803 ListSwapAdj(NodePtr np1, NodePtr np2)       /* priornode, nextnode */
1804 {
1805     if (np1 == NULL || np2 == NULL || np1->next->last != np1) /* must be sane */
1806         return;
1807 
1808     if (np1->next != np2 || np2->last != np1)             /* must be in order */
1809         return;
1810 
1811     if (np1->last != NULL)
1812         np1->last->next = np2;
1813 
1814     if (np2->next != NULL)
1815         np2->next->last = np1;
1816 
1817     np1->next = np2->next;
1818     np2->last = np1->last;
1819 
1820     np1->last = np2;
1821     np2->next = np1;
1822 } /* ListSwapAdj */
1823 
1824 
1825 
1826 /*
1827  * Purpose:     Sort the specified ring/list
1828  *
1829  * Parameters:
1830  *   head           Head of the list to be sorted
1831  *   cmpfunc        Comparison function (return values are like memcmp())
1832  *   order          ASCEND or DESCEND
1833  *
1834  * Returns:
1835  *              A pointer to the first element of the sorted ring or list
1836  *
1837  *
1838  * Description:
1839  *              Sort the specified list, in place, using bubble sort, and
1840  *              the specified comparison function. Determine prior to sorting
1841  *              whether this is a list or a ring. If it's a ring, break the
1842  *              ring prior to sorting, and restore it to a ring topology
1843  *              after sorting has been completed.
1844  */
1845 
1846 NLM_EXTERN NodePtr  LIBCALL
ListSort(NodePtr head,int (* cmpfunc)PROTO ((NodePtr,NodePtr)),int order)1847 ListSort(NodePtr head, int (*cmpfunc )PROTO ((NodePtr, NodePtr )), int order)
1848                        /* 0 if equal, LT 0 if 1st element > 2nd element */
1849 {
1850     NodePtr     np;
1851     Nlm_Boolean sorted = FALSE, ring;
1852     int         result;
1853 
1854     if (head == NULL)
1855         return NULL;
1856     if (head->last == NULL)
1857         ring = FALSE;
1858     else
1859         ring = TRUE;
1860     if (ring)
1861         ListBreakRing(head);
1862 
1863     /* just bubble sort for now */
1864 
1865     while (! sorted) {
1866         np = head;
1867         sorted = TRUE;
1868 
1869         while (np->next != NULL) {
1870             result = (*cmpfunc)(np, np->next);
1871             if ((result > 0 && order == ASCEND) || (result < 0 && order == DESCEND)) {
1872                 sorted = FALSE;
1873                 if (np == head)
1874                     head = np->next;    /* keep head pointing at 1st element */
1875                 ListSwapAdj(np, np->next);
1876             }
1877             else
1878                 np = np->next;
1879         }
1880     }
1881 
1882     if (ring)
1883         ListConnectRing(head);
1884     return head;        /* ptr to first element */
1885 } /* ListSort */
1886 
1887 
1888 
1889 /*
1890  * Purpose:     Break the specified ring into a non-circular (linear) list
1891  *
1892  * Parameters:
1893  *   np             Head of the ring to be broken
1894  *
1895  *
1896  * Description:
1897  *              Break the specified ring between its head and tail.
1898  *
1899  * Note:
1900  *              This function may be called safely (without effect) if the
1901  *              passed parameter is already a list, rather than a ring.
1902  */
1903 
1904 NLM_EXTERN void  LIBCALL
ListBreakRing(NodePtr np)1905 ListBreakRing(NodePtr np)
1906 {
1907     if (np == NULL)
1908         return;
1909     if (np->last == NULL)
1910         return;
1911 
1912     np->last->next = NULL;
1913     np->last = NULL;
1914 } /* ListBreakRing */
1915 
1916 
1917 
1918 /*
1919  * Purpose:     Convert a list into a ring.
1920  *
1921  * Parameters:
1922  *   head           Head of the list to be connected
1923  *
1924  *
1925  * Description:
1926  *              Connect the specified list between its head and tail, producing
1927  *              a ring.
1928  *
1929  * Note:
1930  *              This function may be called safely (without effect) if the
1931  *              passed parameter is already a ring, rather than a list.
1932  */
1933 
1934 NLM_EXTERN void  LIBCALL
ListConnectRing(NodePtr head)1935 ListConnectRing(NodePtr head)
1936 {
1937     NodePtr     np;
1938 
1939     if (head == NULL)
1940         return;
1941 
1942     np = head;
1943 
1944     while (np->next != NULL) {
1945         np = np->next;
1946         if (np == head)
1947             return;
1948     }
1949 
1950     np->next = head;
1951     head->last = np;
1952 } /* ListConnectRing */
1953 
1954 
1955 /*
1956  * Purpose:     Copy a list where the list elements are character strings
1957  *
1958  * Parameters:
1959  *   strlist        List to be copied
1960  *
1961  * Returns:
1962  *              A copy of the original list (which may be NULL)
1963  *
1964  *
1965  * Description:
1966  *              Create a list which is a copy of the original list, and
1967  *              also make copies of the strings.
1968  *
1969  * Note:
1970  *              There is no obvious way to make a generic list copying
1971  *              routine, because, in general, the length of each list
1972  *              element is unknown. This is a simple case where it is
1973  *              easy to copy a list.
1974  */
1975 
1976 NLM_EXTERN NodePtr LIBCALL
ListStrCopy(NodePtr strlist)1977 ListStrCopy (NodePtr strlist)
1978 {
1979     NodePtr newlist = NULL;
1980     NodePtr np = strlist;
1981     Nlm_CharPtr stringtext;
1982 
1983     if (strlist == NULL)
1984         return NULL;
1985 
1986     do {
1987         stringtext = StringSave((Nlm_CharPtr) np->elem);
1988         newlist = ListInsert(stringtext, newlist);
1989         np = ListGetNext(np);
1990     } while (np != NULL && np != strlist);
1991 
1992     return newlist->next; /* points to 1st element in new list */
1993 }
1994 
1995 
1996 /*
1997  * Purpose:     Delete a list where the list elements are character strings
1998  *
1999  * Parameters:
2000  *   np             List to be deleted
2001  *
2002  *
2003  * Description:
2004  *              Delete the list nodes and the character string data associated
2005  *              with each node.
2006  *
2007  * Note:
2008  *              This routine will work for any list element which is a single
2009  *              block of memory. However, it will not work in the more general
2010  *              case where a list element in turn references other memory
2011  *              which must also be freed.
2012  */
2013 
2014 NLM_EXTERN void LIBCALL
ListStrDel(NodePtr np)2015 ListStrDel (NodePtr np)
2016 {
2017     while (np != NULL)
2018     {
2019         MemFree (np->elem);
2020         np = ListDelete(np);
2021     }
2022 }
2023 
2024 
Nlm_PlatformName(void)2025 NLM_EXTERN const Nlm_Char* Nlm_PlatformName(void)
2026 {
2027 /* Mac */
2028 #if defined(OS_MAC)
2029 #  if defined(PROC_PPC)
2030   return "MacOS_PPC";
2031 #  elif defined(PROC_I80X86)
2032   return "MacOS_386";
2033 #  elif defined(PROC_MC680X0)
2034   return "MacOS_68K";
2035 #  else
2036   return "MacOS";
2037 #  endif
2038 
2039 /* VMS */
2040 #elif defined(OS_VMS)
2041 #  if defined(OS_AXP_VMS)
2042   return "AXP/OpenVMS";
2043 #  else
2044   return "VMS";
2045 #  endif
2046 
2047 /* UNIX */
2048 #elif defined(OS_UNIX)
2049 #  if defined(PROC_IBM370)
2050   return "IBM370_AIX";
2051 #  elif defined(OS_UNIX_SUN)
2052   return "SunOS";
2053 #  elif defined(OS_UNIX_SOL)
2054   return "Solaris";
2055 #  elif defined(OS_UNIX_OSF1) && defined(PROC_ALPHA)
2056   return "Alpha_OSF1";
2057 #  elif defined(COMP_AUX)
2058   return "Mac_AUX";
2059 #  elif defined(COMP_CRAY) && defined(PROC_YMP)
2060   return "Cray";
2061 #  elif defined(PROC_CONVEX)
2062   return "Convex";
2063 #  elif defined(PROC_HPPA) && !defined(OS_UNIX_LINUX)
2064   return "HPUX";
2065 #  elif defined(OS_UNIX_NEXT)
2066   return "NEXT";
2067 #  elif defined(PROC_MIPS) && !defined(OS_UNIX_LINUX)
2068   return "SGI_MIPS";
2069 #  elif defined(OS_UNIX_ULTRIX)
2070   return "ULTRIX";
2071 #  elif defined(OS_UNIX_SYSV) && defined(PROC_SPARC)
2072   return "SystemV_SPARC";
2073 #  elif defined(OS_UNIX_AIX)
2074   return "AIX";
2075 #  elif defined(OS_UNIX_LINUX)
2076 #    if defined(PROC_ALPHA)
2077   return "LINUX_ALPHA";
2078 #    else
2079   return "LINUX";
2080 #    endif
2081 #  elif defined(OS_UNIX_NETBSD)
2082   return "NetBSD";
2083 #  elif defined(OS_UNIX_FREEBSD)
2084   return "FreeBSD";
2085 #  else
2086   return "UNIX";
2087 #  endif
2088 
2089 /* PC */
2090 #elif defined(OS_MSWIN)
2091 #  if defined(WIN16)
2092   return "WIN16";
2093 #  elif defined(WIN32)
2094   return "WIN32";
2095 #  else
2096   return "MSWIN";
2097 #  endif
2098 
2099 /* NT */
2100 #elif defined(OS_WINNT)
2101   return "WIN_NT";
2102 
2103 /* Unknown */
2104 #else
2105   return "Unknown";
2106 
2107 #endif
2108 }
2109 
2110 
2111 /**
2112  * MD5 stuff (used for security purposes)
2113  */
2114 
2115 /*
2116  * Note: this code is harmless on little-endian machines.
2117  */
2118 #ifdef IS_BIG_ENDIAN
2119 static
2120 void
byteReverse(Nlm_UcharPtr buf,Nlm_Uint4 longs)2121 byteReverse(Nlm_UcharPtr buf, Nlm_Uint4 longs)
2122 {
2123     Nlm_Uint4 t;
2124     do {
2125 	t = (Nlm_Uint4) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
2126 	    ((unsigned) buf[1] << 8 | buf[0]);
2127 	*(Nlm_Uint4Ptr) buf = t;
2128 	buf += 4;
2129     } while (--longs);
2130 }
2131 #endif
2132 
2133 /*
2134  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
2135  * initialization constants.
2136  */
2137 NLM_EXTERN void LIBCALL
Nlm_MD5Init(Nlm_MD5ContextPtr ctx)2138 Nlm_MD5Init(Nlm_MD5ContextPtr ctx)
2139 {
2140     ctx->buf[0] = 0x67452301;
2141     ctx->buf[1] = 0xefcdab89;
2142     ctx->buf[2] = 0x98badcfe;
2143     ctx->buf[3] = 0x10325476;
2144 
2145     ctx->bits[0] = 0;
2146     ctx->bits[1] = 0;
2147 }
2148 
2149 /*
2150  * Update context to reflect the concatenation of another buffer full
2151  * of bytes.
2152  */
2153 NLM_EXTERN void LIBCALL
Nlm_MD5Update(Nlm_MD5ContextPtr ctx,Nlm_UcharPtr buf,Nlm_Uint4 len)2154 Nlm_MD5Update(Nlm_MD5ContextPtr ctx, Nlm_UcharPtr buf, Nlm_Uint4 len)
2155 {
2156     Nlm_Uint4 t;
2157 
2158     /* Update bitcount */
2159 
2160     t = ctx->bits[0];
2161     if ((ctx->bits[0] = t + ((Nlm_Uint4) len << 3)) < t)
2162 	ctx->bits[1]++;		/* Carry from low to high */
2163     ctx->bits[1] += len >> 29;
2164 
2165     t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
2166 
2167     /* Handle any leading odd-sized chunks */
2168 
2169     if (t) {
2170 	Nlm_UcharPtr p = (Nlm_UcharPtr) ctx->in + t;
2171 
2172 	t = 64 - t;
2173 	if (len < t) {
2174 	    memcpy(p, buf, len);
2175 	    return;
2176 	}
2177 	memcpy(p, buf, t);
2178 #ifdef IS_BIG_ENDIAN
2179 	byteReverse(ctx->in, 16);
2180 #endif
2181 	Nlm_MD5Transform(ctx->buf, (Nlm_Uint4Ptr) ctx->in);
2182 	buf += t;
2183 	len -= t;
2184     }
2185     /* Process data in 64-byte chunks */
2186 
2187     while (len >= 64) {
2188 	memcpy(ctx->in, buf, 64);
2189 #ifdef IS_BIG_ENDIAN
2190 	byteReverse(ctx->in, 16);
2191 #endif
2192 	Nlm_MD5Transform(ctx->buf, (Nlm_Uint4Ptr) ctx->in);
2193 	buf += 64;
2194 	len -= 64;
2195     }
2196 
2197     /* Handle any remaining bytes of data. */
2198     memcpy(ctx->in, buf, len);
2199 }
2200 
2201 /*
2202  * Final wrapup - pad to 64-byte boundary with the bit pattern
2203  * 1 0* (64-bit count of bits processed, MSB-first)
2204  */
2205 NLM_EXTERN void LIBCALL
Nlm_MD5Final(Nlm_MD5ContextPtr ctx,Nlm_Uchar digest[16])2206 Nlm_MD5Final(Nlm_MD5ContextPtr ctx, Nlm_Uchar digest[16])
2207 {
2208     Nlm_Uint4 count;
2209     Nlm_UcharPtr p;
2210 
2211     /* Compute number of bytes mod 64 */
2212     count = (ctx->bits[0] >> 3) & 0x3F;
2213 
2214     /* Set the first char of padding to 0x80.  This is safe since there is
2215        always at least one byte free */
2216     p = ctx->in + count;
2217     *p++ = 0x80;
2218 
2219     /* Bytes of padding needed to make 64 bytes */
2220     count = 64 - 1 - count;
2221 
2222     /* Pad out to 56 mod 64 */
2223     if (count < 8) {
2224 	/* Two lots of padding:  Pad the first block to 64 bytes */
2225 	memset(p, 0, count);
2226 #ifdef IS_BIG_ENDIAN
2227 	byteReverse(ctx->in, 16);
2228 #endif
2229 	Nlm_MD5Transform(ctx->buf, (Nlm_Uint4Ptr) ctx->in);
2230 
2231 	/* Now fill the next block with 56 bytes */
2232 	memset(ctx->in, 0, 56);
2233     } else {
2234 	/* Pad block to 56 bytes */
2235 	memset(p, 0, count - 8);
2236     }
2237 #ifdef IS_BIG_ENDIAN
2238 	byteReverse(ctx->in, 14);
2239 #endif
2240 
2241     /* Append length in bits and transform */
2242     ((Nlm_Uint4Ptr) ctx->in)[14] = ctx->bits[0];
2243     ((Nlm_Uint4Ptr) ctx->in)[15] = ctx->bits[1];
2244 
2245     Nlm_MD5Transform(ctx->buf, (Nlm_Uint4Ptr) ctx->in);
2246 #ifdef IS_BIG_ENDIAN
2247     byteReverse((Nlm_UcharPtr) ctx->buf, 4);
2248 #endif
2249     memcpy(digest, ctx->buf, 16);
2250     memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
2251 }
2252 
2253 /* The four core functions - F1 is optimized somewhat */
2254 
2255 /* #define F1(x, y, z) (x & y | ~x & z) */
2256 #define F1(x, y, z) (z ^ (x & (y ^ z)))
2257 #define F2(x, y, z) F1(z, x, y)
2258 #define F3(x, y, z) (x ^ y ^ z)
2259 #define F4(x, y, z) (y ^ (x | ~z))
2260 
2261 /* This is the central step in the MD5 algorithm. */
2262 #define MD5STEP(f, w, x, y, z, data, s) \
2263 	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
2264 
2265 /*
2266  * The core of the MD5 algorithm, this alters an existing MD5 hash to
2267  * reflect the addition of 16 longwords of new data.  MD5Update blocks
2268  * the data and converts bytes into longwords for this routine.
2269  */
2270 NLM_EXTERN void LIBCALL
Nlm_MD5Transform(Nlm_Uint4 buf[4],Nlm_Uint4 in[16])2271 Nlm_MD5Transform(Nlm_Uint4 buf[4], Nlm_Uint4 in[16])
2272 {
2273     register Nlm_Uint4 a, b, c, d;
2274 
2275     a = buf[0];
2276     b = buf[1];
2277     c = buf[2];
2278     d = buf[3];
2279 
2280     MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
2281     MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
2282     MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
2283     MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
2284     MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
2285     MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
2286     MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
2287     MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
2288     MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
2289     MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
2290     MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
2291     MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
2292     MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
2293     MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
2294     MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
2295     MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
2296 
2297     MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
2298     MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
2299     MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
2300     MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
2301     MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
2302     MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
2303     MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
2304     MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
2305     MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
2306     MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
2307     MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
2308     MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
2309     MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
2310     MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
2311     MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
2312     MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
2313 
2314     MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
2315     MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
2316     MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
2317     MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
2318     MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
2319     MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
2320     MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
2321     MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
2322     MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
2323     MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
2324     MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
2325     MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
2326     MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
2327     MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
2328     MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
2329     MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
2330 
2331     MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
2332     MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
2333     MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
2334     MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
2335     MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
2336     MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
2337     MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
2338     MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
2339     MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
2340     MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
2341     MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
2342     MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
2343     MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
2344     MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
2345     MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
2346     MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
2347 
2348     buf[0] += a;
2349     buf[1] += b;
2350     buf[2] += c;
2351     buf[3] += d;
2352 }
2353 
2354 /*----- Here is simplified MD4 algorithm, that used in Blast E-mail server
2355   and formatdb ------ */
2356 
2357 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
2358 #define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
2359 #define H(x, y, z) ((x) ^ (y) ^ (z))
2360 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
2361 
2362 #define FF(a, b, c, d, x, s) { \
2363     (a) += F ((b), (c), (d)) + (x); \
2364 	(a) = ROTATE_LEFT ((a), (s)); \
2365 }
2366 #define GG(a, b, c, d, x, s) { \
2367     (a) += G ((b), (c), (d)) + (x) + (Nlm_Uint4)0x5a827999; \
2368 	(a) = ROTATE_LEFT ((a), (s)); \
2369 }
2370 #define HH(a, b, c, d, x, s) { \
2371     (a) += H ((b), (c), (d)) + (x) + (Nlm_Uint4)0x6ed9eba1; \
2372 	(a) = ROTATE_LEFT ((a), (s)); \
2373 }
2374 
2375 /* This function calculates checksum from a buffer */
Nlm_GetChecksum(Nlm_CharPtr p)2376 Nlm_Uint4 Nlm_GetChecksum(Nlm_CharPtr p)
2377 {
2378     Nlm_Int4 len;
2379     struct Hash {
2380 	Nlm_Uint4 x1;
2381 	Nlm_Uint4 x2;
2382 	Nlm_Uint4 x3;
2383 	Nlm_Uint4 x4;
2384 	Nlm_Uint4 x5;
2385 	Nlm_Uint4 x6;
2386 	Nlm_Uint4 x7;
2387 	Nlm_Uint4 x8;
2388 	Nlm_Uint4 x9;
2389 	Nlm_Uint4 x10;
2390 	Nlm_Uint4 x11;
2391 	Nlm_Uint4 x12;
2392     } Hash;
2393 
2394     Nlm_Uint4 a = 0x67452301;
2395     Nlm_Uint4 b = 0xefcdab89;
2396     Nlm_Uint4 c = 0x98badcfe;
2397     Nlm_Uint4 d = 0x10325476;
2398 
2399     if (p == NULL || p[0] == NULLB)
2400 	return 0;
2401 
2402     MemSet(&Hash, 0, sizeof(Hash));
2403     MemCopy(&Hash, p,
2404 	    (len = StringLen(p)) > sizeof(Hash)? sizeof(Hash) : len);
2405 
2406     FF (a, b, c, d, Hash.x1, 3);   /* 1 */
2407     FF (d, a, b, c, Hash.x2, 7);   /* 2 */
2408     FF (c, d, a, b, Hash.x3, 11);  /* 3 */
2409     FF (b, c, d, a, Hash.x4, 19);  /* 4 */
2410 
2411     GG (a, b, c, d, Hash.x5, 3);   /* 17 */
2412     GG (d, a, b, c, Hash.x6, 5);   /* 18 */
2413     GG (c, d, a, b, Hash.x7, 9);   /* 19 */
2414     GG (b, c, d, a, Hash.x8, 13);  /* 20 */
2415 
2416     HH (b, c, d, a, Hash.x9, 15);  /* 40 */
2417     HH (a, b, c, d, Hash.x10, 3);  /* 41 */
2418     HH (d, a, b, c, Hash.x11, 9);  /* 42 */
2419     HH (c, d, a, b, Hash.x12, 11); /* 43 */
2420 
2421     return (a+b+c+d);
2422 }
2423 
2424 /*  ----- End of simplified MD4 algorithm ------ */
2425 
2426 
2427 /* XML parsing section */
2428 
2429 /* function to decode ampersand-protected symbols */
2430 
2431 typedef struct xmltable {
2432   Nlm_CharPtr  code;
2433   size_t       len;
2434   Nlm_Char     letter;
2435 } Nlm_XmlTable, PNTR Nlm_XmlTablePtr;
2436 
2437 static Nlm_XmlTable xmlcodes [] = {
2438   { "&amp;",  5, '&'},
2439   { "&apos;", 6, '\''},
2440   { "&gt;",   4, '>'},
2441   { "&lt;",   4, '<'},
2442   { "&quot;", 6, '"'},
2443   { NULL,     0, '\0'}
2444 };
2445 
DecodeXml(Nlm_CharPtr str)2446 NLM_EXTERN Nlm_CharPtr DecodeXml (
2447   Nlm_CharPtr str
2448 )
2449 
2450 {
2451   Nlm_Char         ch;
2452   Nlm_CharPtr      dst, src;
2453   Nlm_Int2         i;
2454   Nlm_XmlTablePtr  xtp;
2455 
2456   if (StringHasNoText (str)) return str;
2457 
2458   src = str;
2459   dst = str;
2460   ch = *src;
2461   while (ch != '\0') {
2462     if (ch == '&') {
2463       xtp = NULL;
2464       for (i = 0; xmlcodes [i].code != NULL; i++) {
2465         if (StringNICmp (src, xmlcodes [i].code, xmlcodes [i].len) == 0) {
2466           xtp = &(xmlcodes [i]);
2467           break;
2468         }
2469       }
2470       if (xtp != NULL) {
2471         *dst = xtp->letter;
2472         dst++;
2473         src += xtp->len;
2474       } else {
2475         *dst = ch;
2476         dst++;
2477         src++;
2478       }
2479     } else {
2480       *dst = ch;
2481       dst++;
2482       src++;
2483     }
2484     ch = *src;
2485   }
2486   *dst = '\0';
2487 
2488   return str;
2489 }
2490 
EncodeXmlProc(Nlm_CharPtr str,Nlm_Boolean notJustBrackets)2491 static Nlm_CharPtr EncodeXmlProc (
2492   Nlm_CharPtr str,
2493   Nlm_Boolean notJustBrackets
2494 )
2495 
2496 {
2497   Nlm_Char         ch;
2498   Nlm_CharPtr      dst, src, tag, tmp;
2499   Nlm_Int2         i;
2500   size_t           len = 1;
2501   Nlm_XmlTablePtr  xtp;
2502 
2503   if (str == NULL) return NULL;
2504 
2505   tmp = str;
2506   ch = *tmp;
2507   while (ch != '\0') {
2508     len++;
2509     for (i = 0; xmlcodes [i].code != NULL; i++) {
2510       if (ch == xmlcodes [i].letter) {
2511         len += xmlcodes [i].len;
2512         break;
2513       }
2514     }
2515     tmp++;
2516     ch = *tmp;
2517   }
2518 
2519   if (len == 0) return NULL;
2520 
2521   tmp = (Nlm_CharPtr) MemNew (len + 1);
2522   if (tmp == NULL) return NULL;
2523 
2524   src = str;
2525   dst = tmp;
2526   ch = *src;
2527   while (ch != '\0') {
2528     xtp = NULL;
2529     if (notJustBrackets || ch == '<' || ch == '>') {
2530       for (i = 0; xmlcodes [i].code != NULL; i++) {
2531         if (ch == xmlcodes [i].letter) {
2532           xtp = &(xmlcodes [i]);
2533           break;
2534         }
2535       }
2536     }
2537     if (xtp != NULL) {
2538       tag = xtp->code;
2539       ch = *tag;
2540       while (ch != '\0') {
2541         *dst = ch;
2542         dst++;
2543         tag++;
2544         ch = *tag;
2545       }
2546     } else {
2547       *dst = ch;
2548       dst++;
2549     }
2550     src++;
2551     ch = *src;
2552   }
2553   *dst = '\0';
2554 
2555   return tmp;
2556 }
2557 
EncodeXml(Nlm_CharPtr str)2558 NLM_EXTERN Nlm_CharPtr EncodeXml (
2559   Nlm_CharPtr str
2560 )
2561 
2562 {
2563   return EncodeXmlProc (str, TRUE);
2564 }
2565 
EncodeXmlEx(Nlm_CharPtr str)2566 NLM_EXTERN Nlm_CharPtr EncodeXmlEx (
2567   Nlm_CharPtr str
2568 )
2569 
2570 {
2571   return EncodeXmlProc (str, FALSE);
2572 }
2573 
2574 #define XML_START_TAG  1
2575 #define XML_END_TAG    2
2576 #define XML_ATTRIBUTE  3
2577 #define XML_CONTENT    4
2578 
2579 /* first pass - tokenize XML into linear ValNode chain */
2580 
TokenizeXmlLine(ValNodePtr PNTR headp,ValNodePtr PNTR tailp,Nlm_CharPtr str)2581 static void TokenizeXmlLine (
2582   ValNodePtr PNTR headp,
2583   ValNodePtr PNTR tailp,
2584   Nlm_CharPtr str
2585 )
2586 
2587 {
2588   Nlm_CharPtr     atr, fst, lst, nxt, ptr;
2589   Nlm_Char        ch, cha, chf, chl, quo;
2590   Nlm_Boolean     doStart, doEnd;
2591 
2592   if (headp == NULL || tailp == NULL) return;
2593   if (StringHasNoText (str)) return;
2594 
2595   ptr = str;
2596   ch = *ptr;
2597 
2598   while (ch != '\0') {
2599     if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t') {
2600       /* ignore whitespace between tags */
2601       ptr++;
2602       ch = *ptr;
2603 
2604     } else if (ch == '<') {
2605 
2606       /* process XML tag */
2607       /* skip past left angle bracket */
2608       ptr++;
2609 
2610       /* keep track of pointers to first character after < and last character before > in XML tag */
2611       fst = ptr;
2612       lst = ptr;
2613       ch = *ptr;
2614       while (ch != '\0' && ch != '>') {
2615         lst = ptr;
2616         ptr++;
2617         ch = *ptr;
2618       }
2619       if (ch != '\0') {
2620         *ptr = '\0';
2621         ptr++;
2622         ch = *ptr;
2623       }
2624 
2625       chf = *fst;
2626       chl = *lst;
2627       if (chf == '?' || chf == '!') {
2628         /* skip processing instructions */
2629       } else {
2630         /* initial default - if no slashes are present, just do start tag */
2631         doStart = TRUE;
2632         doEnd = FALSE;
2633         /* check for slash just after < or just before > symbol */
2634         if (chf == '/') {
2635           /* slash after <, just do end tag */
2636           fst++;
2637           doStart = FALSE;
2638           doEnd = TRUE;
2639         } else if (chl == '/') {
2640           /* slash before > - self-closing tag - do start tag and end tag - content will be empty */
2641           *lst = '\0';
2642           doEnd = TRUE;
2643         }
2644 
2645         /* skip past first space to look for attribute strings before closing > symbol */
2646         atr = fst;
2647         cha = *atr;
2648         while (cha != '\0' && cha != ' ') {
2649           atr++;
2650           cha = *atr;
2651         }
2652         if (cha != '\0') {
2653           *atr = '\0';
2654           atr++;
2655           cha = *atr;
2656         }
2657 
2658         /* report start tag */
2659         if (doStart) {
2660           TrimSpacesAroundString (fst);
2661           ValNodeCopyStrEx (headp, tailp, XML_START_TAG, fst);
2662         }
2663 
2664         /* report individual attribute tag="value" clauses */
2665         while (cha != '\0') {
2666           nxt = atr;
2667           cha = *nxt;
2668           /* skip to equal sign */
2669           while (cha != '\0' && cha != '=') {
2670             nxt++;
2671             cha = *nxt;
2672           }
2673           if (cha != '\0') {
2674             nxt++;
2675             cha = *nxt;
2676           }
2677           quo = '\0';
2678           if (cha == '"' || cha == '\'') {
2679             quo = cha;
2680             nxt++;
2681             cha = *nxt;
2682           }
2683           while (cha != '\0' && cha != quo) {
2684             nxt++;
2685             cha = *nxt;
2686           }
2687           if (cha != '\0') {
2688             nxt++;
2689             cha = *nxt;
2690           }
2691           *nxt = '\0';
2692           TrimSpacesAroundString (atr);
2693           ValNodeCopyStrEx (headp, tailp, XML_ATTRIBUTE, atr);
2694           *nxt = cha;
2695           atr = nxt;
2696         }
2697 
2698         /* report end tag */
2699         if (doEnd) {
2700           TrimSpacesAroundString (fst);
2701           ValNodeCopyStrEx (headp, tailp, XML_END_TAG, fst);
2702         }
2703       }
2704 
2705     } else {
2706 
2707       /* process content between tags */
2708       fst = ptr;
2709       ptr++;
2710       ch = *ptr;
2711       while (ch != '\0' && ch != '<') {
2712         ptr++;
2713         ch = *ptr;
2714       }
2715       if (ch != '\0') {
2716         *ptr = '\0';
2717       }
2718 
2719       /* report content string */
2720       TrimSpacesAroundString (fst);
2721       DecodeXml (fst);
2722       ValNodeCopyStrEx (headp, tailp, XML_CONTENT, fst);
2723       /*
2724       if (ch != '\0') {
2725         *ptr = ch;
2726       }
2727       */
2728     }
2729   }
2730 }
2731 
TokenizeXmlString(Nlm_CharPtr str)2732 static ValNodePtr TokenizeXmlString (
2733   Nlm_CharPtr str
2734 )
2735 
2736 {
2737   ValNodePtr  head = NULL, tail = NULL;
2738 
2739   if (StringHasNoText (str)) return NULL;
2740 
2741   TokenizeXmlLine (&head, &tail, str);
2742 
2743   return head;
2744 }
2745 
2746 /* second pass - process ValNode chain into hierarchical structure */
2747 
ProcessAttribute(Nlm_CharPtr str)2748 static Nlm_XmlObjPtr ProcessAttribute (
2749   Nlm_CharPtr str
2750 )
2751 
2752 {
2753   Nlm_XmlObjPtr  attr = NULL;
2754   Nlm_Char       ch, chf, chl, quo;
2755   Nlm_CharPtr    eql, lst;
2756 
2757   if (StringHasNoText (str)) return NULL;
2758 
2759   eql = str;
2760   ch = *eql;
2761   while (ch != '\0' && ch != '=') {
2762     eql++;
2763     ch = *eql;
2764   }
2765   if (ch == '\0') return NULL;
2766 
2767   *eql = '\0';
2768   eql++;
2769   ch = *eql;
2770   quo = ch;
2771   if (quo == '"' || quo == '\'') {
2772     eql++;
2773     ch = *eql;
2774   }
2775   chf = *eql;
2776   if (chf == '\0') return NULL;
2777 
2778   lst = eql;
2779   chl = *lst;
2780   while (chl != '\0' && chl != quo) {
2781     lst++;
2782     chl = *lst;
2783   }
2784   if (chl != '\0') {
2785     *lst = '\0';
2786   }
2787 
2788   if (StringHasNoText (str) || StringHasNoText (eql)) return NULL;
2789 
2790   attr = (Nlm_XmlObjPtr) MemNew (sizeof (Nlm_XmlObj));
2791   if (attr == NULL) return NULL;
2792 
2793   TrimSpacesAroundString (str);
2794   TrimSpacesAroundString (eql);
2795   DecodeXml (str);
2796   DecodeXml (eql);
2797   attr->name = StringSave (str);
2798   attr->contents = StringSave (eql);
2799 
2800   return attr;
2801 }
2802 
ProcessStartTag(ValNodePtr PNTR curr,Nlm_XmlObjPtr parent,Nlm_CharPtr name)2803 static Nlm_XmlObjPtr ProcessStartTag (
2804   ValNodePtr PNTR curr,
2805   Nlm_XmlObjPtr parent,
2806   Nlm_CharPtr name
2807 )
2808 
2809 {
2810   Nlm_XmlObjPtr  attr, child, lastattr = NULL, lastchild = NULL, xop = NULL;
2811   Nlm_Uint1      choice;
2812   Nlm_CharPtr    str;
2813   ValNodePtr     vnp;
2814 
2815   if (curr == NULL) return NULL;
2816 
2817   xop = (Nlm_XmlObjPtr) MemNew (sizeof (Nlm_XmlObj));
2818   if (xop == NULL) return NULL;
2819 
2820   xop->name = StringSave (name);
2821   xop->parent = parent;
2822 
2823   while (*curr != NULL) {
2824 
2825     vnp = *curr;
2826     str = (Nlm_CharPtr) vnp->data.ptrvalue;
2827     choice = vnp->choice;
2828 
2829     /* advance to next token */
2830     *curr = vnp->next;
2831 
2832     TrimSpacesAroundString (str);
2833 
2834     if (StringHasNoText (str)) {
2835       /* skip */
2836     } else if (choice == XML_START_TAG) {
2837 
2838       /* recursive call to process next level */
2839       child = ProcessStartTag (curr, xop, str);
2840       /* link into children list */
2841       if (child != NULL) {
2842         if (xop->children == NULL) {
2843           xop->children = child;
2844         }
2845         if (lastchild != NULL) {
2846           lastchild->next = child;
2847         }
2848         lastchild = child;
2849       }
2850 
2851     } else if (choice == XML_END_TAG) {
2852 
2853       /* pop out of recursive call */
2854       return xop;
2855 
2856     } else if (choice == XML_ATTRIBUTE) {
2857 
2858       /* get attributes within tag */
2859       attr = ProcessAttribute (str);
2860       if (attr != NULL) {
2861         if (xop->attributes == NULL) {
2862           xop->attributes = attr;
2863         }
2864         if (lastattr != NULL) {
2865           lastattr->next = attr;
2866         }
2867         lastattr = attr;
2868       }
2869 
2870     } else if (choice == XML_CONTENT) {
2871 
2872       /* get contact between start and end tags */
2873       xop->contents = StringSave (str);
2874     }
2875   }
2876 
2877   return xop;
2878 }
2879 
SetSuccessors(Nlm_XmlObjPtr xop,Nlm_XmlObjPtr prev,Nlm_Int2 level)2880 static Nlm_XmlObjPtr SetSuccessors (
2881   Nlm_XmlObjPtr xop,
2882   Nlm_XmlObjPtr prev,
2883   Nlm_Int2 level
2884 )
2885 
2886 {
2887   Nlm_XmlObjPtr  tmp;
2888 
2889   if (xop == NULL) return NULL;
2890   xop->level = level;
2891 
2892   if (prev != NULL) {
2893     prev->successor = xop;
2894   }
2895 
2896   prev = xop;
2897   for (tmp = xop->children; tmp != NULL; tmp = tmp->next) {
2898     prev = SetSuccessors (tmp, prev, level + 1);
2899   }
2900 
2901   return prev;
2902 }
2903 
ParseXmlTokens(ValNodePtr head)2904 static Nlm_XmlObjPtr ParseXmlTokens (
2905   ValNodePtr head
2906 )
2907 
2908 {
2909   ValNodePtr     curr;
2910   Nlm_XmlObjPtr  xop;
2911 
2912   if (head == NULL) return NULL;
2913 
2914   curr = head;
2915 
2916   xop = ProcessStartTag (&curr, NULL, "root");
2917   if (xop == NULL) return NULL;
2918 
2919   SetSuccessors (xop, NULL, 1);
2920 
2921   return xop;
2922 }
2923 
XmlPathSuffixIs(Nlm_XmlObjPtr xop,Nlm_CharPtr suffix)2924 NLM_EXTERN Nlm_Boolean XmlPathSuffixIs (
2925   Nlm_XmlObjPtr xop,
2926   Nlm_CharPtr suffix
2927 )
2928 
2929 {
2930   Nlm_Char       buf [512];
2931   Nlm_CharPtr    nodeFilter = NULL;
2932   Nlm_XmlObjPtr  parent = NULL;
2933   Nlm_CharPtr    parentFilter = NULL;
2934   Nlm_CharPtr    ptr;
2935 
2936   if (xop == NULL) return FALSE;
2937   parent = xop->parent;
2938 
2939   if (StringHasNoText (suffix)) return TRUE;
2940   if (StringLen (suffix) >= sizeof (buf) - 2) return FALSE;
2941 
2942   StringCpy (buf, suffix);
2943 
2944   ptr = StringRChr (buf, '/');
2945   if (ptr != NULL) {
2946     *ptr = '\0';
2947     ptr++;
2948     nodeFilter = ptr;
2949     /* now look for parent substring */
2950     if (StringDoesHaveText (buf)) {
2951       ptr = StringRChr (buf, '/');
2952       if (ptr != NULL) {
2953         *ptr = '\0';
2954         ptr++;
2955         parentFilter = ptr;
2956       } else {
2957         parentFilter = buf;
2958       }
2959     }
2960   } else {
2961     nodeFilter = buf;
2962   }
2963 
2964   /* check node and parent names */
2965   if (StringHasNoText (nodeFilter) || (StringICmp (xop->name, nodeFilter) == 0)) {
2966     if (StringHasNoText (parentFilter) || parent != NULL && StringICmp (parent->name, parentFilter) == 0) {
2967       return TRUE;
2968     }
2969   }
2970 
2971   return FALSE;
2972 }
2973 
VisitXmlNodeProc(Nlm_XmlObjPtr xop,Nlm_XmlObjPtr parent,Nlm_Int2 level,Nlm_VoidPtr userdata,VisitXmlNodeFunc callback,Nlm_CharPtr nodeFilter,Nlm_CharPtr parentFilter,Nlm_CharPtr attrTagFilter,Nlm_CharPtr attrValFilter,Nlm_Int2 maxDepth)2974 static Nlm_Int4 VisitXmlNodeProc (
2975   Nlm_XmlObjPtr xop,
2976   Nlm_XmlObjPtr parent,
2977   Nlm_Int2 level,
2978   Nlm_VoidPtr userdata,
2979   VisitXmlNodeFunc callback,
2980   Nlm_CharPtr nodeFilter,
2981   Nlm_CharPtr parentFilter,
2982   Nlm_CharPtr attrTagFilter,
2983   Nlm_CharPtr attrValFilter,
2984   Nlm_Int2 maxDepth
2985 )
2986 
2987 {
2988   Nlm_XmlObjPtr  attr, tmp;
2989   Nlm_Int4       index = 0;
2990   Nlm_Boolean    okay;
2991 
2992   if (xop == NULL) return index;
2993 
2994   /* check depth limit */
2995   if (level > maxDepth) return index;
2996 
2997   okay = TRUE;
2998 
2999   /* check attribute filters */
3000   if (StringDoesHaveText (attrTagFilter)) {
3001     okay = FALSE;
3002     for (attr = xop->attributes; attr != NULL; attr = attr->next) {
3003       if (StringICmp (attr->name, attrTagFilter) == 0) {
3004         if (StringHasNoText (attrValFilter) || StringICmp (attr->contents, attrValFilter) == 0) {
3005           okay = TRUE;
3006           break;
3007         }
3008       }
3009     }
3010   } else if (StringDoesHaveText (attrValFilter)) {
3011     okay = FALSE;
3012     for (attr = xop->attributes; attr != NULL; attr = attr->next) {
3013       if (StringICmp (attr->contents, attrValFilter) == 0) {
3014         okay = TRUE;
3015         break;
3016       }
3017     }
3018   }
3019 
3020   /* check node name filter */
3021   if (StringDoesHaveText (nodeFilter)) {
3022     if (StringICmp (xop->name, nodeFilter) != 0) {
3023       okay = FALSE;
3024     }
3025   }
3026 
3027   /* check parent name filter */
3028   if (StringDoesHaveText (parentFilter)) {
3029     if (parent != NULL && StringICmp (parent->name, parentFilter) != 0) {
3030       okay = FALSE;
3031     }
3032   }
3033 
3034   if (okay) {
3035     /* call callback for this node if all filter tests pass */
3036     if (callback != NULL) {
3037       callback (xop, parent, level, userdata);
3038     }
3039     index++;
3040   }
3041 
3042   /* visit children */
3043   for (tmp = xop->children; tmp != NULL; tmp = tmp->next) {
3044     index += VisitXmlNodeProc (tmp, xop, level + 1, userdata, callback, nodeFilter,
3045                                parentFilter, attrTagFilter, attrValFilter, maxDepth);
3046   }
3047 
3048   return index;
3049 }
3050 
VisitXmlNodes(Nlm_XmlObjPtr xop,Nlm_VoidPtr userdata,VisitXmlNodeFunc callback,Nlm_CharPtr nodeFilter,Nlm_CharPtr parentFilter,Nlm_CharPtr attrTagFilter,Nlm_CharPtr attrValFilter,Nlm_Int2 maxDepth)3051 NLM_EXTERN Nlm_Int4 VisitXmlNodes (
3052   Nlm_XmlObjPtr xop,
3053   Nlm_VoidPtr userdata,
3054   VisitXmlNodeFunc callback,
3055   Nlm_CharPtr nodeFilter,
3056   Nlm_CharPtr parentFilter,
3057   Nlm_CharPtr attrTagFilter,
3058   Nlm_CharPtr attrValFilter,
3059   Nlm_Int2 maxDepth
3060 )
3061 
3062 {
3063   Nlm_Int4  index = 0;
3064 
3065   if (xop == NULL) return index;
3066 
3067   if (maxDepth == 0) {
3068     maxDepth = INT2_MAX;
3069   }
3070 
3071   index += VisitXmlNodeProc (xop, NULL, 1, userdata, callback, nodeFilter,
3072                              parentFilter, attrTagFilter, attrValFilter, maxDepth);
3073 
3074   return index;
3075 }
3076 
VisitXmlAttributes(Nlm_XmlObjPtr xop,Nlm_VoidPtr userdata,VisitXmlNodeFunc callback,Nlm_CharPtr attrTagFilter,Nlm_CharPtr attrValFilter)3077 NLM_EXTERN Nlm_Int4 VisitXmlAttributes (
3078   Nlm_XmlObjPtr xop,
3079   Nlm_VoidPtr userdata,
3080   VisitXmlNodeFunc callback,
3081   Nlm_CharPtr attrTagFilter,
3082   Nlm_CharPtr attrValFilter
3083 )
3084 
3085 {
3086   Nlm_XmlObjPtr  attr;
3087   Nlm_Int4       index = 0;
3088   Nlm_Boolean    okay;
3089 
3090   if (xop == NULL) return index;
3091 
3092   for (attr = xop->attributes; attr != NULL; attr = attr->next) {
3093 
3094     okay = TRUE;
3095 
3096     /* check attribute filters */
3097     if (StringDoesHaveText (attrTagFilter)) {
3098       okay = FALSE;
3099       if (StringICmp (attr->name, attrTagFilter) == 0) {
3100         if (StringHasNoText (attrValFilter) || StringICmp (attr->contents, attrValFilter) == 0) {
3101           okay = TRUE;
3102         }
3103       }
3104     } else if (StringDoesHaveText (attrValFilter)) {
3105       okay = FALSE;
3106       if (StringICmp (attr->contents, attrValFilter) == 0) {
3107         okay = TRUE;
3108       }
3109     }
3110 
3111     if (okay) {
3112       /* call callback for this attribute */
3113       if (callback != NULL) {
3114         callback (attr, xop, 0, userdata);
3115       }
3116       index++;
3117     }
3118   }
3119 
3120   return index;
3121 }
3122 
FreeXmlObject(Nlm_XmlObjPtr xop)3123 NLM_EXTERN Nlm_XmlObjPtr FreeXmlObject (
3124   Nlm_XmlObjPtr xop
3125 )
3126 
3127 {
3128   Nlm_XmlObjPtr  curr, next;
3129 
3130   if (xop == NULL) return NULL;
3131 
3132   MemFree (xop->name);
3133   MemFree (xop->contents);
3134 
3135   curr = xop->attributes;
3136   while (curr != NULL) {
3137     next = curr->next;
3138     curr->next = NULL;
3139     FreeXmlObject (curr);
3140     curr = next;
3141   }
3142 
3143   curr = xop->children;
3144   while (curr != NULL) {
3145     next = curr->next;
3146     curr->next = NULL;
3147     FreeXmlObject (curr);
3148     curr = next;
3149   }
3150 
3151   MemFree (xop);
3152 
3153   return NULL;
3154 }
3155 
ParseXmlString(Nlm_CharPtr str)3156 NLM_EXTERN Nlm_XmlObjPtr ParseXmlString (
3157   Nlm_CharPtr str
3158 )
3159 
3160 {
3161   ValNodePtr     head;
3162   Nlm_XmlObjPtr  root, xop;
3163   Nlm_CharPtr    tmp;
3164 
3165   if (StringHasNoText (str)) return NULL;
3166   tmp = StringSave (str);
3167   if (tmp == NULL) return NULL;
3168 
3169   head = TokenizeXmlString (tmp);
3170   MemFree (tmp);
3171 
3172   if (head == NULL) return NULL;
3173 
3174   root = ParseXmlTokens (head);
3175   ValNodeFreeData (head);
3176 
3177   if (root == NULL) return NULL;
3178   xop = root->children;
3179   root->children = NULL;
3180   FreeXmlObject (root);
3181 
3182   return xop;
3183 }
3184 
3185 /*
3186 Note: Use <urlquery.h> QUERY_CopyResultsToString (conn) to get XML string
3187 directly from network connection without going through file intermediate.
3188 */
3189 
XmlFileToString(FILE * ifp)3190 NLM_EXTERN Nlm_CharPtr XmlFileToString (
3191   FILE *ifp
3192 )
3193 
3194 {
3195   FileCache    fc;
3196   Nlm_Char     line [4096];
3197   Nlm_CharPtr  str;
3198   ValNodePtr   head = NULL, tail = NULL;
3199 
3200   if (ifp == NULL) return NULL;
3201 
3202   if (! FileCacheSetup (&fc, ifp)) return NULL;
3203 
3204   str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
3205 
3206   while (str != NULL) {
3207     TrimSpacesAroundString (str);
3208     CompressSpaces (str);
3209 
3210     ValNodeCopyStrEx (&head, &tail, 0, line);
3211 
3212     /*
3213     line [0] = ' ';
3214     line [1] = '\0';
3215     */
3216     str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
3217   }
3218 
3219   str = ValNodeMergeStrs (head);
3220   ValNodeFreeData (head);
3221 
3222   return str;
3223 }
3224 
PrintXmlObject(Nlm_XmlObjPtr master,FILE * fp,Nlm_Boolean useTabs,Nlm_Boolean altSelfClose,Nlm_Int2 level)3225 static void PrintXmlObject (
3226   Nlm_XmlObjPtr master,
3227   FILE *fp,
3228   Nlm_Boolean useTabs,
3229   Nlm_Boolean altSelfClose,
3230   Nlm_Int2 level
3231 )
3232 
3233 {
3234   Nlm_XmlObjPtr  attr, xop;
3235   Nlm_Int2       i;
3236   Nlm_CharPtr    tmp, tmp1, tmp2;
3237   Nlm_CharPtr    spaces = "  ";
3238 
3239   if (master == NULL || fp == NULL) return;
3240 
3241   if (useTabs) {
3242     spaces = "\t";
3243   }
3244 
3245   for (xop = master; xop != NULL; xop = xop->next) {
3246     if (StringHasNoText (xop->name)) continue;
3247     for (i = 0; i < level; i++) {
3248       fprintf (fp, "%s", spaces);
3249     }
3250     fprintf (fp, "<%s", xop->name);
3251     for (attr = xop->attributes; attr != NULL; attr = attr->next) {
3252       if (StringHasNoText (attr->name) || StringHasNoText (attr->contents)) continue;
3253       tmp1 = EncodeXml (attr->name);
3254       tmp2 = EncodeXml (attr->contents);
3255       if (tmp1 != NULL && tmp2 != NULL) {
3256         fprintf (fp, " %s=\"%s\"", tmp1, tmp2);
3257       }
3258       MemFree (tmp1);
3259       MemFree (tmp2);
3260     }
3261     if (xop->contents != NULL) {
3262       tmp = EncodeXml (xop->contents);
3263       if (tmp != NULL) {
3264         fprintf (fp, ">%s", tmp);
3265       }
3266       MemFree (tmp);
3267       fprintf (fp, "</%s>", xop->name);
3268     } else if (xop->children != NULL) {
3269       fprintf (fp, ">\n");
3270       PrintXmlObject (xop->children, fp, useTabs, altSelfClose, level + 1);
3271       for (i = 0; i < level; i++) {
3272         fprintf (fp, "%s", spaces);
3273       }
3274       fprintf (fp, "</%s>", xop->name);
3275     } else if (altSelfClose) {
3276       fprintf (fp, "></%s>", xop->name);
3277     } else {
3278       fprintf (fp, "/>");
3279     }
3280     fprintf (fp, "\n");
3281   }
3282 }
3283 
3284 /*
3285 static void AltPrintXmlObject (
3286   Nlm_XmlObjPtr master,
3287   FILE *fp
3288 )
3289 
3290 {
3291   Nlm_XmlObjPtr  xop;
3292   Nlm_CharPtr    tmp;
3293 
3294   if (master == NULL || fp == NULL) return;
3295 
3296   for (xop = master; xop != NULL; xop = xop->successor) {
3297     if (StringHasNoText (xop->name)) continue;
3298     fprintf (fp, "<%s", xop->name);
3299     if (xop->contents != NULL) {
3300       tmp = EncodeXml (xop->contents);
3301       if (tmp != NULL) {
3302         fprintf (fp, ">%s", tmp);
3303       }
3304       MemFree (tmp);
3305       fprintf (fp, "</%s>", xop->name);
3306     } else {
3307       fprintf (fp, ">", xop->name);
3308     }
3309     fprintf (fp, "\n");
3310   }
3311 }
3312 */
3313 
3314 
WriteXmlObject(Nlm_XmlObjPtr xop,FILE * fp)3315 NLM_EXTERN void WriteXmlObject (
3316   Nlm_XmlObjPtr xop,
3317   FILE *fp
3318 )
3319 
3320 {
3321   if (xop == NULL || fp == NULL) return;
3322 
3323   PrintXmlObject (xop, fp, FALSE, FALSE, 0);
3324 }
3325 
WriteXmlObjectEx(Nlm_XmlObjPtr xop,FILE * fp,Nlm_Boolean useTabs,Nlm_Boolean altSelfClose)3326 NLM_EXTERN void WriteXmlObjectEx (
3327   Nlm_XmlObjPtr xop,
3328   FILE *fp,
3329   Nlm_Boolean useTabs,
3330   Nlm_Boolean altSelfClose
3331 )
3332 
3333 {
3334   if (xop == NULL || fp == NULL) return;
3335 
3336   PrintXmlObject (xop, fp, useTabs, altSelfClose, 0);
3337 }
3338 
3339