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 { "&", 5, '&'},
2439 { "'", 6, '\''},
2440 { ">", 4, '>'},
2441 { "<", 4, '<'},
2442 { """, 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