~ubuntu-branches/ubuntu/raring/ncbi-tools6/raring

« back to all changes in this revision

Viewing changes to corelib/ncbimisc.c

  • Committer: Package Import Robot
  • Author(s): Aaron M. Ucko
  • Date: 2011-09-05 18:55:02 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: package-import@ubuntu.com-20110905185502-iuvmoe65ytljhckn
Tags: 6.1.20110713-1
* New upstream release.
* debian/*.symbols: update accordingly.
* make/makeshlb.unx: link libcn3dOGL.so against -lm for sqrt.
* doc/man/*.1: update for new release.
* debian/rules:
  - (VIB): add asnmacro, as upstream takes care to publish binaries thereof.
  - Retire obsolete multiarch-unaware checks for libpthread.
  - Fully modernize Debhelper usage; in particular, transition to overrides.
* debian/compat: advance to 9 per rules modernization.
* debian/ncbi-tools-bin.install: add asnmacro.
* make/makenet.unx: link asnmacro only against libraries it directly needs.
* doc/man/asnmacro.1: give asnmacro a man page.
* doc/man/Psequin.1: list it in SEE ALSO.
* network/id1arch/idfetch.c: revert redundant change (from #295110).
* Convert to multiarch.
  - debian/rules: Install libraries (and ncbithr.o) to multiarch directories.
  - debian/lib*.install: match multiarch library paths.
  - debian/control:
    + Build-Depends: debhelper (>= 8.1.3~), implying a recent dpkg-dev.
    + Set Multi-Arch: as appropriate across the board, and specify
      Pre-Depends: ${misc:Pre-Depends} for runtime libraries.
* debian/*.lintian-overrides: drop leading slashes for Lintian 2.5.x.
* debian/control: Standards-Version: 3.9.2 (already compliant).

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
*
30
30
* Version Creation Date:   10/23/91
31
31
*
32
 
* $Revision: 6.38 $
 
32
* $Revision: 6.54 $
33
33
*
34
34
* File Description: 
35
35
*       miscellaneous functions
362
362
        }
363
363
}
364
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. */
 
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 
 
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
 
365
450
/*****************************************************************************
366
451
*
367
452
*   ValNodeNew(vnp)
508
593
        return newnode;
509
594
}
510
595
 
 
596
NLM_EXTERN ValNodePtr LIBCALL ValNodeCopyStrEx (ValNodePtr PNTR head, ValNodePtr PNTR tail, Nlm_Int2 choice, const char* str)
 
597
 
 
598
{
 
599
        ValNodePtr newnode = NULL;
 
600
    ValNodePtr vnp;
 
601
 
 
602
        if (str == NULL) return NULL;
 
603
 
 
604
    newnode = ValNodeNew (NULL);
 
605
    if (newnode == NULL) return NULL;
 
606
 
 
607
    if (head != NULL) {
 
608
        if (*head == NULL) {
 
609
            *head = newnode;
 
610
        }
 
611
    }
 
612
 
 
613
    if (tail != NULL) {
 
614
        if (*tail != NULL) {
 
615
            vnp = *tail;
 
616
            while (vnp->next != NULL) {
 
617
              vnp = vnp->next;
 
618
            }
 
619
            vnp->next = newnode;
 
620
        }
 
621
        *tail = newnode;
 
622
    }
 
623
 
 
624
        if (newnode != NULL) {
 
625
                newnode->choice = (Nlm_Uint1)choice;
 
626
                newnode->data.ptrvalue = StringSave(str);
 
627
        }
 
628
 
 
629
        return newnode;
 
630
}
 
631
 
511
632
/*****************************************************************************
512
633
*
513
634
*   ValNodeAddInt (head, choice, value)
618
739
        return newnode;
619
740
}
620
741
 
 
742
NLM_EXTERN ValNodePtr LIBCALL ValNodeAddPointerEx (ValNodePtr PNTR head, ValNodePtr PNTR tail, Nlm_Int2 choice, Nlm_VoidPtr value)
 
743
{
 
744
        ValNodePtr newnode = NULL;
 
745
    ValNodePtr vnp;
 
746
 
 
747
    newnode = ValNodeNew (NULL);
 
748
    if (newnode == NULL) return NULL;
 
749
 
 
750
    if (head != NULL) {
 
751
        if (*head == NULL) {
 
752
            *head = newnode;
 
753
        }
 
754
    }
 
755
 
 
756
    if (tail != NULL) {
 
757
        if (*tail != NULL) {
 
758
            vnp = *tail;
 
759
            while (vnp->next != NULL) {
 
760
              vnp = vnp->next;
 
761
            }
 
762
            vnp->next = newnode;
 
763
        }
 
764
        *tail = newnode;
 
765
    }
 
766
 
 
767
        if (newnode != NULL)
 
768
        {
 
769
                newnode->choice = (Nlm_Uint1)choice;
 
770
                newnode->data.ptrvalue = value;
 
771
        }
 
772
 
 
773
        return newnode;
 
774
}
 
775
 
621
776
/*****************************************************************************
622
777
*
623
778
*   ValNodeAddFunction (head, choice, value)
806
961
}
807
962
 
808
963
 
 
964
/*****************************************************************************
 
965
*
 
966
*   ValNodeIsSorted(list, compar)
 
967
*       Looks for first instance of compar not being true.
 
968
*     If all true, then is sorted, otherwise not.
 
969
*
 
970
*****************************************************************************/
 
971
NLM_EXTERN Nlm_Boolean LIBCALL ValNodeIsSorted (ValNodePtr list, int (LIBCALLBACK *compar )PROTO ((Nlm_VoidPtr, Nlm_VoidPtr )))
 
972
{
 
973
  Nlm_Boolean rval = TRUE;
 
974
 
 
975
  if (list == NULL || compar == NULL) {
 
976
    return TRUE;
 
977
  }
 
978
  while (list->next != NULL && rval) {
 
979
    if (compar (&list, &(list->next)) > 0) {
 
980
      rval = FALSE;
 
981
    }
 
982
    list = list->next;
 
983
  }
 
984
  return rval;
 
985
}
 
986
 
 
987
 
809
988
NLM_EXTERN void LIBCALL
810
989
ValNodeUnique 
811
990
(ValNodePtr PNTR list,
830
1009
}
831
1010
 
832
1011
 
 
1012
NLM_EXTERN ValNodePtr LIBCALL
 
1013
ValNodeDupList 
 
1014
(ValNodePtr orig,
 
1015
 ValNodePtr (LIBCALLBACK *copy )PROTO ((ValNodePtr)))
 
1016
{
 
1017
  ValNodePtr list = NULL, prev = NULL, vnp, new_vnp;
 
1018
 
 
1019
  if (copy == NULL) {
 
1020
    return NULL;
 
1021
  }
 
1022
  for (vnp = orig; vnp != NULL; vnp = vnp->next) {
 
1023
    new_vnp = copy (vnp);
 
1024
    if (new_vnp != NULL) {
 
1025
      if (prev == NULL) {
 
1026
        list = new_vnp;
 
1027
      } else {
 
1028
        prev->next = new_vnp;
 
1029
      }
 
1030
      prev = new_vnp;
 
1031
    }
 
1032
  }
 
1033
  return list;
 
1034
}
 
1035
 
 
1036
 
833
1037
NLM_EXTERN void LIBCALL
834
1038
ValNodeInsert
835
1039
(ValNodePtr PNTR list,
960
1164
  return ptr;
961
1165
}
962
1166
 
 
1167
NLM_EXTERN Nlm_CharPtr LIBCALL ValNodeMergeStrsExEx (ValNodePtr list, Nlm_CharPtr separator, Nlm_CharPtr pfx, Nlm_CharPtr sfx)
 
1168
 
 
1169
{
 
1170
  size_t       len;
 
1171
  size_t       lens;
 
1172
  size_t       pfx_len;
 
1173
  Nlm_CharPtr  ptr;
 
1174
  Nlm_CharPtr  sep;
 
1175
  size_t       sfx_len;
 
1176
  Nlm_CharPtr  str;
 
1177
  Nlm_CharPtr  tmp;
 
1178
  ValNodePtr   vnp;
 
1179
 
 
1180
  if (list == NULL) return NULL;
 
1181
 
 
1182
  pfx_len = StringLen (pfx);
 
1183
  sfx_len = StringLen (sfx);
 
1184
 
 
1185
  lens = StringLen (separator);
 
1186
 
 
1187
  for (vnp = list, len = 0; vnp != NULL; vnp = vnp->next) {
 
1188
    str = (Nlm_CharPtr) vnp->data.ptrvalue;
 
1189
    len += Nlm_StringLen (str);
 
1190
    len += lens;
 
1191
  }
 
1192
  if (len == 0) return NULL;
 
1193
  len += pfx_len + sfx_len;
 
1194
 
 
1195
  ptr = Nlm_MemNew (sizeof (Nlm_Char) * (len + 2));
 
1196
  if (ptr == NULL) return NULL;
 
1197
 
 
1198
  tmp = ptr;
 
1199
  if (pfx_len > 0) {
 
1200
    tmp = Nlm_StringMove (tmp, pfx);
 
1201
  }
 
1202
  sep = NULL;
 
1203
  for (vnp = list; vnp != NULL; vnp = vnp->next) {
 
1204
    tmp = Nlm_StringMove (tmp, sep);
 
1205
    str = (Nlm_CharPtr) vnp->data.ptrvalue;
 
1206
    tmp = Nlm_StringMove (tmp, str);
 
1207
    sep = separator;
 
1208
  }
 
1209
  if (sfx_len > 0) {
 
1210
    tmp = Nlm_StringMove (tmp, sfx);
 
1211
  }
 
1212
 
 
1213
  return ptr;
 
1214
}
 
1215
 
 
1216
NLM_EXTERN Nlm_CharPtr LIBCALL ValNodeMergeStrsEx (ValNodePtr list, Nlm_CharPtr separator)
 
1217
 
 
1218
{
 
1219
  return ValNodeMergeStrsExEx (list, separator, NULL, NULL);
 
1220
}
 
1221
 
963
1222
/*****************************************************************************
964
1223
*
965
1224
*   Start Of Node List Functions
2103
2362
}
2104
2363
 
2105
2364
/*  ----- End of simplified MD4 algorithm ------ */
 
2365
 
 
2366
 
 
2367
/* XML parsing section */
 
2368
 
 
2369
/* function to decode ampersand-protected symbols */
 
2370
 
 
2371
typedef struct xmltable {
 
2372
  Nlm_CharPtr  code;
 
2373
  size_t       len;
 
2374
  Nlm_Char     letter;
 
2375
} Nlm_XmlTable, PNTR Nlm_XmlTablePtr;
 
2376
 
 
2377
static Nlm_XmlTable xmlcodes [] = {
 
2378
  { "&amp;",  5, '&'},
 
2379
  { "&apos;", 6, '\''},
 
2380
  { "&gt;",   4, '>'},
 
2381
  { "&lt;",   4, '<'},
 
2382
  { "&quot;", 6, '"'},
 
2383
  { NULL,     0, '\0'}
 
2384
};
 
2385
 
 
2386
static Nlm_CharPtr DecodeXml (
 
2387
  Nlm_CharPtr str
 
2388
)
 
2389
 
 
2390
{
 
2391
  Nlm_Char         ch;
 
2392
  Nlm_CharPtr      dst, src;
 
2393
  Nlm_Int2         i;
 
2394
  Nlm_XmlTablePtr  xtp;
 
2395
 
 
2396
  if (StringHasNoText (str)) return str;
 
2397
 
 
2398
  src = str;
 
2399
  dst = str;
 
2400
  ch = *src;
 
2401
  while (ch != '\0') {
 
2402
    if (ch == '&') {
 
2403
      xtp = NULL;
 
2404
      for (i = 0; xmlcodes [i].code != NULL; i++) {
 
2405
        if (StringNICmp (src, xmlcodes [i].code, xmlcodes [i].len) == 0) {
 
2406
          xtp = &(xmlcodes [i]);
 
2407
          break;
 
2408
        }
 
2409
      }
 
2410
      if (xtp != NULL) {
 
2411
        *dst = xtp->letter;
 
2412
        dst++;
 
2413
        src += xtp->len;
 
2414
      } else {
 
2415
        *dst = ch;
 
2416
        dst++;
 
2417
        src++;
 
2418
      }
 
2419
    } else {
 
2420
      *dst = ch;
 
2421
      dst++;
 
2422
      src++;
 
2423
    }
 
2424
    ch = *src;
 
2425
  }
 
2426
  *dst = '\0';
 
2427
 
 
2428
  return str;
 
2429
}
 
2430
 
 
2431
static Nlm_CharPtr EncodeXml (
 
2432
  Nlm_CharPtr str
 
2433
)
 
2434
 
 
2435
{
 
2436
  Nlm_Char         ch;
 
2437
  Nlm_CharPtr      dst, src, tag, tmp;
 
2438
  Nlm_Int2         i;
 
2439
  size_t           len = 1;
 
2440
  Nlm_XmlTablePtr  xtp;
 
2441
 
 
2442
  if (str == NULL) return NULL;
 
2443
 
 
2444
  tmp = str;
 
2445
  ch = *tmp;
 
2446
  while (ch != '\0') {
 
2447
    len++;
 
2448
    for (i = 0; xmlcodes [i].code != NULL; i++) {
 
2449
      if (ch == xmlcodes [i].letter) {
 
2450
        len += xmlcodes [i].len;
 
2451
        break;
 
2452
      }
 
2453
    }
 
2454
    tmp++;
 
2455
    ch = *tmp;
 
2456
  }
 
2457
 
 
2458
  if (len == 0) return NULL;
 
2459
 
 
2460
  tmp = (Nlm_CharPtr) MemNew (len + 1);
 
2461
  if (tmp == NULL) return NULL;
 
2462
 
 
2463
  src = str;
 
2464
  dst = tmp;
 
2465
  ch = *src;
 
2466
  while (ch != '\0') {
 
2467
    xtp = NULL;
 
2468
    for (i = 0; xmlcodes [i].code != NULL; i++) {
 
2469
      if (ch == xmlcodes [i].letter) {
 
2470
        xtp = &(xmlcodes [i]);
 
2471
        break;
 
2472
      }
 
2473
    }
 
2474
    if (xtp != NULL) {
 
2475
      tag = xtp->code;
 
2476
      ch = *tag;
 
2477
      while (ch != '\0') {
 
2478
        *dst = ch;
 
2479
        dst++;
 
2480
        tag++;
 
2481
        ch = *tag;
 
2482
      }
 
2483
    } else {
 
2484
      *dst = ch;
 
2485
      dst++;
 
2486
    }
 
2487
    src++;
 
2488
    ch = *src;
 
2489
  }
 
2490
  *dst = '\0';
 
2491
 
 
2492
  return tmp;
 
2493
}
 
2494
 
 
2495
#define XML_START_TAG  1
 
2496
#define XML_END_TAG    2
 
2497
#define XML_ATTRIBUTE  3
 
2498
#define XML_CONTENT    4
 
2499
 
 
2500
/* first pass - tokenize XML into linear ValNode chain */
 
2501
 
 
2502
static void TokenizeXmlLine (
 
2503
  ValNodePtr PNTR headp,
 
2504
  ValNodePtr PNTR tailp,
 
2505
  Nlm_CharPtr str
 
2506
)
 
2507
 
 
2508
{
 
2509
  Nlm_CharPtr     atr, fst, lst, nxt, ptr;
 
2510
  Nlm_Char        ch, cha, chf, chl, quo;
 
2511
  Nlm_Boolean     doStart, doEnd;
 
2512
 
 
2513
  if (headp == NULL || tailp == NULL) return;
 
2514
  if (StringHasNoText (str)) return;
 
2515
 
 
2516
  ptr = str;
 
2517
  ch = *ptr;
 
2518
 
 
2519
  while (ch != '\0') {
 
2520
    if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t') {
 
2521
      /* ignore whitespace between tags */
 
2522
      ptr++;
 
2523
      ch = *ptr;
 
2524
 
 
2525
    } else if (ch == '<') {
 
2526
 
 
2527
      /* process XML tag */
 
2528
      /* skip past left angle bracket */
 
2529
      ptr++;
 
2530
 
 
2531
      /* keep track of pointers to first character after < and last character before > in XML tag */
 
2532
      fst = ptr;
 
2533
      lst = ptr;
 
2534
      ch = *ptr;
 
2535
      while (ch != '\0' && ch != '>') {
 
2536
        lst = ptr;
 
2537
        ptr++;
 
2538
        ch = *ptr;
 
2539
      }
 
2540
      if (ch != '\0') {
 
2541
        *ptr = '\0';
 
2542
        ptr++;
 
2543
        ch = *ptr;
 
2544
      }
 
2545
 
 
2546
      chf = *fst;
 
2547
      chl = *lst;
 
2548
      if (chf == '?' || chf == '!') {
 
2549
        /* skip processing instructions */
 
2550
      } else {
 
2551
        /* initial default - if no slashes are present, just do start tag */
 
2552
        doStart = TRUE;
 
2553
        doEnd = FALSE;
 
2554
        /* check for slash just after < or just before > symbol */
 
2555
        if (chf == '/') {
 
2556
          /* slash after <, just do end tag */
 
2557
          fst++;
 
2558
          doStart = FALSE;
 
2559
          doEnd = TRUE;
 
2560
        } else if (chl == '/') {
 
2561
          /* slash before > - self-closing tag - do start tag and end tag - content will be empty */
 
2562
          *lst = '\0';
 
2563
          doEnd = TRUE;
 
2564
        }
 
2565
 
 
2566
        /* skip past first space to look for attribute strings before closing > symbol */
 
2567
        atr = fst;
 
2568
        cha = *atr;
 
2569
        while (cha != '\0' && cha != ' ') {
 
2570
          atr++;
 
2571
          cha = *atr;
 
2572
        }
 
2573
        if (cha != '\0') {
 
2574
          *atr = '\0';
 
2575
          atr++;
 
2576
          cha = *atr;
 
2577
        }
 
2578
 
 
2579
        /* report start tag */
 
2580
        if (doStart) {
 
2581
          TrimSpacesAroundString (fst);
 
2582
          ValNodeCopyStrEx (headp, tailp, XML_START_TAG, fst);
 
2583
        }
 
2584
 
 
2585
        /* report individual attribute tag="value" clauses */
 
2586
        while (cha != '\0') {
 
2587
          nxt = atr;
 
2588
          cha = *nxt;
 
2589
          /* skip to equal sign */
 
2590
          while (cha != '\0' && cha != '=') {
 
2591
            nxt++;
 
2592
            cha = *nxt;
 
2593
          }
 
2594
          if (cha != '\0') {
 
2595
            nxt++;
 
2596
            cha = *nxt;
 
2597
          }
 
2598
          quo = '\0';
 
2599
          if (cha == '"' || cha == '\'') {
 
2600
            quo = cha;
 
2601
            nxt++;
 
2602
            cha = *nxt;
 
2603
          }
 
2604
          while (cha != '\0' && cha != quo) {
 
2605
            nxt++;
 
2606
            cha = *nxt;
 
2607
          }
 
2608
          if (cha != '\0') {
 
2609
            nxt++;
 
2610
            cha = *nxt;
 
2611
          }
 
2612
          *nxt = '\0';
 
2613
          TrimSpacesAroundString (atr);
 
2614
          ValNodeCopyStrEx (headp, tailp, XML_ATTRIBUTE, atr);
 
2615
          *nxt = cha;
 
2616
          atr = nxt;
 
2617
        }
 
2618
 
 
2619
        /* report end tag */
 
2620
        if (doEnd) {
 
2621
          TrimSpacesAroundString (fst);
 
2622
          ValNodeCopyStrEx (headp, tailp, XML_END_TAG, fst);
 
2623
        }
 
2624
      }
 
2625
 
 
2626
    } else {
 
2627
 
 
2628
      /* process content between tags */
 
2629
      fst = ptr;
 
2630
      ptr++;
 
2631
      ch = *ptr;
 
2632
      while (ch != '\0' && ch != '<') {
 
2633
        ptr++;
 
2634
        ch = *ptr;
 
2635
      }
 
2636
      if (ch != '\0') {
 
2637
        *ptr = '\0';
 
2638
      }
 
2639
 
 
2640
      /* report content string */
 
2641
      TrimSpacesAroundString (fst);
 
2642
      DecodeXml (fst);
 
2643
      ValNodeCopyStrEx (headp, tailp, XML_CONTENT, fst);
 
2644
      /*
 
2645
      if (ch != '\0') {
 
2646
        *ptr = ch;
 
2647
      }
 
2648
      */
 
2649
    }
 
2650
  }
 
2651
}
 
2652
 
 
2653
static ValNodePtr TokenizeXmlString (
 
2654
  Nlm_CharPtr str
 
2655
)
 
2656
 
 
2657
{
 
2658
  ValNodePtr  head = NULL, tail = NULL;
 
2659
 
 
2660
  if (StringHasNoText (str)) return NULL;
 
2661
 
 
2662
  TokenizeXmlLine (&head, &tail, str);
 
2663
 
 
2664
  return head;
 
2665
}
 
2666
 
 
2667
/* second pass - process ValNode chain into hierarchical structure */
 
2668
 
 
2669
static Nlm_XmlObjPtr ProcessAttribute (
 
2670
  Nlm_CharPtr str
 
2671
)
 
2672
 
 
2673
{
 
2674
  Nlm_XmlObjPtr  attr = NULL;
 
2675
  Nlm_Char       ch, chf, chl, quo;
 
2676
  Nlm_CharPtr    eql, lst;
 
2677
 
 
2678
  if (StringHasNoText (str)) return NULL;
 
2679
 
 
2680
  eql = str;
 
2681
  ch = *eql;
 
2682
  while (ch != '\0' && ch != '=') {
 
2683
    eql++;
 
2684
    ch = *eql;
 
2685
  }
 
2686
  if (ch == '\0') return NULL;
 
2687
 
 
2688
  *eql = '\0';
 
2689
  eql++;
 
2690
  ch = *eql;
 
2691
  quo = ch;
 
2692
  if (quo == '"' || quo == '\'') {
 
2693
    eql++;
 
2694
    ch = *eql;
 
2695
  }
 
2696
  chf = *eql;
 
2697
  if (chf == '\0') return NULL;
 
2698
 
 
2699
  lst = eql;
 
2700
  chl = *lst;
 
2701
  while (chl != '\0' && chl != quo) {
 
2702
    lst++;
 
2703
    chl = *lst;
 
2704
  }
 
2705
  if (chl != '\0') {
 
2706
    *lst = '\0';
 
2707
  }
 
2708
 
 
2709
  if (StringHasNoText (str) || StringHasNoText (eql)) return NULL;
 
2710
 
 
2711
  attr = (Nlm_XmlObjPtr) MemNew (sizeof (Nlm_XmlObj));
 
2712
  if (attr == NULL) return NULL;
 
2713
 
 
2714
  TrimSpacesAroundString (str);
 
2715
  TrimSpacesAroundString (eql);
 
2716
  DecodeXml (str);
 
2717
  DecodeXml (eql);
 
2718
  attr->name = StringSave (str);
 
2719
  attr->contents = StringSave (eql);
 
2720
 
 
2721
  return attr;
 
2722
}
 
2723
 
 
2724
static Nlm_XmlObjPtr ProcessStartTag (
 
2725
  ValNodePtr PNTR curr,
 
2726
  Nlm_CharPtr name
 
2727
)
 
2728
 
 
2729
{
 
2730
  Nlm_XmlObjPtr  attr, child, lastattr = NULL, lastchild = NULL, xop = NULL;
 
2731
  Nlm_Uint1      choice;
 
2732
  Nlm_CharPtr    str;
 
2733
  ValNodePtr     vnp;
 
2734
 
 
2735
  if (curr == NULL) return NULL;
 
2736
 
 
2737
  xop = (Nlm_XmlObjPtr) MemNew (sizeof (Nlm_XmlObj));
 
2738
  if (xop == NULL) return NULL;
 
2739
 
 
2740
  xop->name = StringSave (name);
 
2741
 
 
2742
  while (*curr != NULL) {
 
2743
 
 
2744
    vnp = *curr;
 
2745
    str = (Nlm_CharPtr) vnp->data.ptrvalue;
 
2746
    choice = vnp->choice;
 
2747
 
 
2748
    /* advance to next token */
 
2749
    *curr = vnp->next;
 
2750
 
 
2751
    TrimSpacesAroundString (str);
 
2752
 
 
2753
    if (StringHasNoText (str)) {
 
2754
      /* skip */
 
2755
    } else if (choice == XML_START_TAG) {
 
2756
 
 
2757
      /* recursive call to process next level */
 
2758
      child = ProcessStartTag (curr, str);
 
2759
      /* link into children list */
 
2760
      if (child != NULL) {
 
2761
        if (xop->children == NULL) {
 
2762
          xop->children = child;
 
2763
        }
 
2764
        if (lastchild != NULL) {
 
2765
          lastchild->next = child;
 
2766
        }
 
2767
        lastchild = child;
 
2768
      }
 
2769
 
 
2770
    } else if (choice == XML_END_TAG) {
 
2771
 
 
2772
      /* pop out of recursive call */
 
2773
      return xop;
 
2774
 
 
2775
    } else if (choice == XML_ATTRIBUTE) {
 
2776
 
 
2777
      /* get attributes within tag */
 
2778
      attr = ProcessAttribute (str);
 
2779
      if (attr != NULL) {
 
2780
        if (xop->attributes == NULL) {
 
2781
          xop->attributes = attr;
 
2782
        }
 
2783
        if (lastattr != NULL) {
 
2784
          lastattr->next = attr;
 
2785
        }
 
2786
        lastattr = attr;
 
2787
      }
 
2788
 
 
2789
    } else if (choice == XML_CONTENT) {
 
2790
 
 
2791
      /* get contact between start and end tags */
 
2792
      xop->contents = StringSave (str);
 
2793
    }
 
2794
  }
 
2795
 
 
2796
  return xop;
 
2797
}
 
2798
 
 
2799
static Nlm_XmlObjPtr ParseXmlTokens (
 
2800
  ValNodePtr head
 
2801
)
 
2802
 
 
2803
{
 
2804
  ValNodePtr  curr;
 
2805
 
 
2806
  if (head == NULL) return NULL;
 
2807
 
 
2808
  curr = head;
 
2809
 
 
2810
  return ProcessStartTag (&curr, "root");
 
2811
}
 
2812
 
 
2813
static Nlm_Int4 VisitXmlNodeProc (
 
2814
  Nlm_XmlObjPtr xop,
 
2815
  Nlm_XmlObjPtr parent,
 
2816
  Nlm_Int2 level,
 
2817
  Nlm_VoidPtr userdata,
 
2818
  VisitXmlNodeFunc callback,
 
2819
  Nlm_CharPtr nodeFilter,
 
2820
  Nlm_CharPtr parentFilter,
 
2821
  Nlm_CharPtr attrTagFilter,
 
2822
  Nlm_CharPtr attrValFilter,
 
2823
  Nlm_Int2 maxDepth
 
2824
)
 
2825
 
 
2826
{
 
2827
  Nlm_XmlObjPtr  attr, tmp;
 
2828
  Nlm_Int4       index = 0;
 
2829
  Nlm_Boolean    okay;
 
2830
 
 
2831
  if (xop == NULL) return index;
 
2832
 
 
2833
  /* check depth limit */
 
2834
  if (level > maxDepth) return index;
 
2835
 
 
2836
  okay = TRUE;
 
2837
 
 
2838
  /* check attribute filters */
 
2839
  if (StringDoesHaveText (attrTagFilter)) {
 
2840
    okay = FALSE;
 
2841
    for (attr = xop->attributes; attr != NULL; attr = attr->next) {
 
2842
      if (StringICmp (attr->name, attrTagFilter) == 0) {
 
2843
        if (StringHasNoText (attrValFilter) || StringICmp (attr->contents, attrValFilter) == 0) {
 
2844
          okay = TRUE;
 
2845
          break;
 
2846
        }
 
2847
      }
 
2848
    }
 
2849
  } else if (StringDoesHaveText (attrValFilter)) {
 
2850
    okay = FALSE;
 
2851
    for (attr = xop->attributes; attr != NULL; attr = attr->next) {
 
2852
      if (StringICmp (attr->contents, attrValFilter) == 0) {
 
2853
        okay = TRUE;
 
2854
        break;
 
2855
      }
 
2856
    }
 
2857
  }
 
2858
 
 
2859
  /* check node name filter */
 
2860
  if (StringDoesHaveText (nodeFilter)) {
 
2861
    if (StringICmp (xop->name, nodeFilter) != 0) {
 
2862
      okay = FALSE;
 
2863
    }
 
2864
  }
 
2865
 
 
2866
  /* check parent name filter */
 
2867
  if (StringDoesHaveText (parentFilter)) {
 
2868
    if (parent != NULL && StringICmp (parent->name, parentFilter) != 0) {
 
2869
      okay = FALSE;
 
2870
    }
 
2871
  }
 
2872
 
 
2873
  if (okay) {
 
2874
    /* call callback for this node if all filter tests pass */
 
2875
    if (callback != NULL) {
 
2876
      callback (xop, parent, level, userdata);
 
2877
    }
 
2878
    index++;
 
2879
  }
 
2880
 
 
2881
  /* visit children */
 
2882
  for (tmp = xop->children; tmp != NULL; tmp = tmp->next) {
 
2883
    index += VisitXmlNodeProc (tmp, xop, level + 1, userdata, callback, nodeFilter,
 
2884
                               parentFilter, attrTagFilter, attrValFilter, maxDepth);
 
2885
  }
 
2886
 
 
2887
  return index;
 
2888
}
 
2889
 
 
2890
NLM_EXTERN Nlm_Int4 VisitXmlNodes (
 
2891
  Nlm_XmlObjPtr xop,
 
2892
  Nlm_VoidPtr userdata,
 
2893
  VisitXmlNodeFunc callback,
 
2894
  Nlm_CharPtr nodeFilter,
 
2895
  Nlm_CharPtr parentFilter,
 
2896
  Nlm_CharPtr attrTagFilter,
 
2897
  Nlm_CharPtr attrValFilter,
 
2898
  Nlm_Int2 maxDepth
 
2899
)
 
2900
 
 
2901
{
 
2902
  Nlm_Int4  index = 0;
 
2903
 
 
2904
  if (xop == NULL) return index;
 
2905
 
 
2906
  if (maxDepth == 0) {
 
2907
    maxDepth = INT2_MAX;
 
2908
  }
 
2909
 
 
2910
  index += VisitXmlNodeProc (xop, NULL, 1, userdata, callback, nodeFilter,
 
2911
                             parentFilter, attrTagFilter, attrValFilter, maxDepth);
 
2912
 
 
2913
  return index;
 
2914
}
 
2915
 
 
2916
NLM_EXTERN Nlm_Int4 VisitXmlAttributes (
 
2917
  Nlm_XmlObjPtr xop,
 
2918
  Nlm_VoidPtr userdata,
 
2919
  VisitXmlNodeFunc callback,
 
2920
  Nlm_CharPtr attrTagFilter,
 
2921
  Nlm_CharPtr attrValFilter
 
2922
)
 
2923
 
 
2924
{
 
2925
  Nlm_XmlObjPtr  attr;
 
2926
  Nlm_Int4       index = 0;
 
2927
  Nlm_Boolean    okay;
 
2928
 
 
2929
  if (xop == NULL) return index;
 
2930
 
 
2931
  for (attr = xop->attributes; attr != NULL; attr = attr->next) {
 
2932
 
 
2933
    okay = TRUE;
 
2934
 
 
2935
    /* check attribute filters */
 
2936
    if (StringDoesHaveText (attrTagFilter)) {
 
2937
      okay = FALSE;
 
2938
      if (StringICmp (attr->name, attrTagFilter) == 0) {
 
2939
        if (StringHasNoText (attrValFilter) || StringICmp (attr->contents, attrValFilter) == 0) {
 
2940
          okay = TRUE;
 
2941
        }
 
2942
      }
 
2943
    } else if (StringDoesHaveText (attrValFilter)) {
 
2944
      okay = FALSE;
 
2945
      if (StringICmp (attr->contents, attrValFilter) == 0) {
 
2946
        okay = TRUE;
 
2947
      }
 
2948
    }
 
2949
 
 
2950
    if (okay) {
 
2951
      /* call callback for this attribute */
 
2952
      if (callback != NULL) {
 
2953
        callback (attr, xop, 0, userdata);
 
2954
      }
 
2955
      index++;
 
2956
    }
 
2957
  }
 
2958
 
 
2959
  return index;
 
2960
}
 
2961
 
 
2962
NLM_EXTERN Nlm_XmlObjPtr FreeXmlObject (
 
2963
  Nlm_XmlObjPtr xop
 
2964
)
 
2965
 
 
2966
{
 
2967
  Nlm_XmlObjPtr  curr, next;
 
2968
 
 
2969
  if (xop == NULL) return NULL;
 
2970
 
 
2971
  MemFree (xop->name);
 
2972
  MemFree (xop->contents);
 
2973
 
 
2974
  curr = xop->attributes;
 
2975
  while (curr != NULL) {
 
2976
    next = curr->next;
 
2977
    curr->next = NULL;
 
2978
    FreeXmlObject (curr);
 
2979
    curr = next;
 
2980
  }
 
2981
 
 
2982
  curr = xop->children;
 
2983
  while (curr != NULL) {
 
2984
    next = curr->next;
 
2985
    curr->next = NULL;
 
2986
    FreeXmlObject (curr);
 
2987
    curr = next;
 
2988
  }
 
2989
 
 
2990
  MemFree (xop);
 
2991
 
 
2992
  return NULL;
 
2993
}
 
2994
 
 
2995
NLM_EXTERN Nlm_XmlObjPtr ParseXmlString (
 
2996
  Nlm_CharPtr str
 
2997
)
 
2998
 
 
2999
{
 
3000
  ValNodePtr     head;
 
3001
  Nlm_XmlObjPtr  root, xop;
 
3002
  Nlm_CharPtr    tmp;
 
3003
 
 
3004
  if (StringHasNoText (str)) return NULL;
 
3005
  tmp = StringSave (str);
 
3006
  if (tmp == NULL) return NULL;
 
3007
 
 
3008
  head = TokenizeXmlString (tmp);
 
3009
  MemFree (tmp);
 
3010
 
 
3011
  if (head == NULL) return NULL;
 
3012
 
 
3013
  root = ParseXmlTokens (head);
 
3014
  ValNodeFreeData (head);
 
3015
 
 
3016
  if (root == NULL) return NULL;
 
3017
  xop = root->children;
 
3018
  root->children = NULL;
 
3019
  FreeXmlObject (root);
 
3020
 
 
3021
  return xop;
 
3022
}
 
3023
 
 
3024
/*
 
3025
Note: Use <urlquery.h> QUERY_CopyResultsToString (conn) to get XML string
 
3026
directly from network connection without going through file intermediate.
 
3027
*/
 
3028
 
 
3029
NLM_EXTERN Nlm_CharPtr XmlFileToString (
 
3030
  FILE *ifp
 
3031
)
 
3032
 
 
3033
{
 
3034
  FileCache    fc;
 
3035
  Nlm_Char     line [4096];
 
3036
  Nlm_CharPtr  str;
 
3037
  ValNodePtr   head = NULL, tail = NULL;
 
3038
 
 
3039
  if (ifp == NULL) return NULL;
 
3040
 
 
3041
  if (! FileCacheSetup (&fc, ifp)) return NULL;
 
3042
 
 
3043
  str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
 
3044
 
 
3045
  while (str != NULL) {
 
3046
    TrimSpacesAroundString (str);
 
3047
    CompressSpaces (str);
 
3048
 
 
3049
    ValNodeCopyStrEx (&head, &tail, 0, line);
 
3050
 
 
3051
    /*
 
3052
    line [0] = ' ';
 
3053
    line [1] = '\0';
 
3054
    */
 
3055
    str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
 
3056
  }
 
3057
 
 
3058
  str = ValNodeMergeStrs (head);
 
3059
  ValNodeFreeData (head);
 
3060
 
 
3061
  return str;
 
3062
}
 
3063
 
 
3064
static void PrintXmlObject (
 
3065
  Nlm_XmlObjPtr master,
 
3066
  FILE *fp,
 
3067
  Nlm_Boolean useTabs,
 
3068
  Nlm_Boolean altSelfClose,
 
3069
  Nlm_Int2 level
 
3070
)
 
3071
 
 
3072
{
 
3073
  Nlm_XmlObjPtr  attr, xop;
 
3074
  Nlm_Int2       i;
 
3075
  Nlm_CharPtr    tmp, tmp1, tmp2;
 
3076
  Nlm_CharPtr    spaces = "  ";
 
3077
 
 
3078
  if (master == NULL || fp == NULL) return;
 
3079
 
 
3080
  if (useTabs) {
 
3081
    spaces = "\t";
 
3082
  }
 
3083
 
 
3084
  for (xop = master; xop != NULL; xop = xop->next) {
 
3085
    if (StringHasNoText (xop->name)) continue;
 
3086
    for (i = 0; i < level; i++) {
 
3087
      fprintf (fp, "%s", spaces);
 
3088
    }
 
3089
    fprintf (fp, "<%s", xop->name);
 
3090
    for (attr = xop->attributes; attr != NULL; attr = attr->next) {
 
3091
      if (StringHasNoText (attr->name) || StringHasNoText (attr->contents)) continue;
 
3092
      tmp1 = EncodeXml (attr->name);
 
3093
      tmp2 = EncodeXml (attr->contents);
 
3094
      if (tmp1 != NULL && tmp2 != NULL) {
 
3095
        fprintf (fp, " %s=\"%s\"", tmp1, tmp2);
 
3096
      }
 
3097
      MemFree (tmp1);
 
3098
      MemFree (tmp2);
 
3099
    }
 
3100
    if (xop->contents != NULL) {
 
3101
      tmp = EncodeXml (xop->contents);
 
3102
      if (tmp != NULL) {
 
3103
        fprintf (fp, ">%s", tmp);
 
3104
      }
 
3105
      MemFree (tmp);
 
3106
      fprintf (fp, "</%s>", xop->name);
 
3107
    } else if (xop->children != NULL) {
 
3108
      fprintf (fp, ">\n");
 
3109
      PrintXmlObject (xop->children, fp, useTabs, altSelfClose, level + 1);
 
3110
      for (i = 0; i < level; i++) {
 
3111
        fprintf (fp, "%s", spaces);
 
3112
      }
 
3113
      fprintf (fp, "</%s>", xop->name);
 
3114
    } else if (altSelfClose) {
 
3115
      fprintf (fp, "></%s>", xop->name);
 
3116
    } else {
 
3117
      fprintf (fp, "/>");
 
3118
    }
 
3119
    fprintf (fp, "\n");
 
3120
  }
 
3121
}
 
3122
 
 
3123
NLM_EXTERN void WriteXmlObject (
 
3124
  Nlm_XmlObjPtr xop,
 
3125
  FILE *fp
 
3126
)
 
3127
 
 
3128
{
 
3129
  if (xop == NULL || fp == NULL) return;
 
3130
 
 
3131
  PrintXmlObject (xop, fp, FALSE, FALSE, 0);
 
3132
}
 
3133
 
 
3134
NLM_EXTERN void WriteXmlObjectEx (
 
3135
  Nlm_XmlObjPtr xop,
 
3136
  FILE *fp,
 
3137
  Nlm_Boolean useTabs,
 
3138
  Nlm_Boolean altSelfClose
 
3139
)
 
3140
 
 
3141
{
 
3142
  if (xop == NULL || fp == NULL) return;
 
3143
 
 
3144
  PrintXmlObject (xop, fp, useTabs, altSelfClose, 0);
 
3145
}
 
3146