1 /*   accentr.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  * RCS $Id: accentr.c,v 6.10 2005/06/06 18:45:47 kans Exp $
27  *
28  * Author:  Ostell
29  *
30  * Version Creation Date:   4/23/92
31  *
32  * File Description:
33  *       entrez index access library for Entrez
34  *
35  * Modifications:
36  * --------------------------------------------------------------------------
37  * Date     Name        Description of modification
38  * -------  ----------  -----------------------------------------------------
39  * 08-16-94 Brylawski   Added access to mesh term explosion, mesh tree browsing,
40  *                      and on-the-fly neighboring.
41  *
42  * 10-06-94 Schuler     Added EntrezBiostrucGet() function
43  *
44  * 11-20-94 Brylawski   Permitted client to modify on-the-fly neighboring
45  *                      via .entrezrc parameters
46  *
47  * 05-19-95 Schuler     Added rcs Log directive for automatic insertion of
48  *                      modification comments.
49  *
50  * $Log: accentr.c,v $
51  * Revision 6.10  2005/06/06 18:45:47  kans
52  * post warning message if obsolete EntrezInit function is called
53  *
54  * Revision 6.9  2001/09/04 23:28:55  juran
55  * Always assume network access in Mac OS.
56  *
57  * Revision 6.8  2001/08/16 19:40:33  kans
58  * reverted to not assume network - UNIX still does cdrom access compile - and cleaned up junk in log instructions
59  *
60  * Revision 6.7  2001/08/15 20:57:07  juran
61  * Always assume network access.
62  *
63  * Revision 6.6  2000/01/12 20:17:12  vakatov
64  * Get rid of the LIBCALL specifier at EntrezSeqEntryGet()
65  *
66  * Revision 6.5  1999/01/06 14:18:35  grisha
67  * add defines to switch ID0/ID1 usage
68  *
69  * Revision 6.4  1998/12/08 20:38:47  kans
70  * EntrezGIForSeqIdFunc aborts on local, other, general, gi, notset before connecting to Entrez network server
71  *
72  * Revision 6.3  1998/06/12 19:19:06  kans
73  * fixed unix compiler warnings
74  *
75  * Revision 6.2  1998/02/23 17:59:38  kans
76  * mesh and taxonomy hierarchy modes both call NetEntHierarchyGet(term,db,fld)
77  *
78  * Revision 6.1  1997/09/19 13:16:19  kans
79  * removed or ifdef unused variables
80  *
81  * Revision 6.0  1997/08/25 18:12:26  madden
82  * changed to 6.0
83  *
84  * Revision 5.38  1997/07/28 13:30:35  ostell
85  * Moved GetUniGeneIDForSeqId() to seqmgr.c
86  *
87  * Revision 5.37  1997/07/09 19:25:57  kuzio
88  * kludge for corn; and tidied NCBICG
89  *
90  * Revision 5.36  1997/06/26 21:55:10  vakatov
91  * [PC] DLL'd "ncbicdr.lib", "ncbiacc.lib", "ncbinacc.lib" and "ncbicacc.lib"
92  *
93  * Revision 5.35  1997/05/22 20:35:44  epstein
94  * add error strings when fetching Medline and Sequence entries, to identify which UID encountered the problem
95  *
96  * Revision 5.34  1997/04/18 16:01:08  shavirin
97  * Removed annoying compiler messages "Statement not reached"
98  *
99  * Revision 5.33  1997/03/17  16:26:23  brandon
100  * added PMEntrezDetailedInfo
101  *
102  * Revision 5.32  1997/03/13  15:37:14  brandon
103  * added support for retcodes in PmEntrezsequencegets
104  *
105  * Revision 5.31  1997/02/24  17:27:14  brandon
106  * added support for PubMed SeqId functions.
107  *
108  * Revision 5.30  1997/02/24  16:47:51  brandon
109  * added support for named uid lists.
110  *
111  * Revision 5.29  1997/02/19  16:28:29  brandon
112  * fixed EntrezSeqEntryListGet for PM
113  *
114  * Revision 5.28  1997/02/10  20:35:35  brandon
115  * fixed EntrezSeqEntryGet for PMEntrez
116  *
117  * Revision 5.27  1997/02/05  15:53:14  brandon
118  * added PMEntSeqEntryListGet
119  *
120  * Revision 5.26  1997/02/04  15:29:27  brandon
121  * fixed typo
122  *
123  * Revision 5.25  1997/02/03  19:36:48  brandon
124  * added line for PMEntrezHierarchyGet
125  *
126  * Revision 5.24  1997/01/24  22:26:21  kuzio
127  * NCBICG 9000000 kludge
128  *
129  * Revision 5.23  1997/01/23  17:07:19  brandon
130  * modified EntrezTLFree
131  *
132  * Revision 5.22  1997/01/19  15:39:45  brandon
133  * *** empty log message ***
134  *
135  * Revision 5.21  1997/01/16  18:17:43  brandon
136  * added SelectDataSource wrapper
137  *
138  * Revision 5.20  1997/01/14  18:39:16  brandon
139  * added wrapper function GetCurMediaType()
140  *
141  * Revision 5.19  1997/01/13  21:34:02  brandon
142  * *** empty log message ***
143  *
144  * Revision 5.18  1996/12/23  17:50:38  brandon
145  * modified EntrezInit
146  *
147  * Revision 5.17  1996/12/23  04:25:48  brandon
148  * *** empty log message ***
149  *
150  * Revision 5.16  1996/12/23  02:02:29  brandon
151  * *** empty log message ***
152  *
153  * Revision 5.15  1996/12/23  02:00:35  brandon
154  * modified PMAdjustEntrezInfo
155  *
156  * Revision 5.14  1996/12/04  15:06:32  epstein
157  * restore network fetching of MEDLINE entries (accidentally deleted in version 5.12
158  *
159  * Revision 5.13  1996/12/03  19:52:11  brandon
160  * added ifdefs for pubmed
161  *
162  * Revision 5.12  1996/12/02  22:24:02  brandon
163  * *** empty log message ***
164  *
165  * Revision 5.11  1996/12/02  22:10:08  brandon
166  * *** empty log message ***
167  *
168  * Revision 5.10  1996/09/13  14:43:17  brandon
169  * modifed pubmed routines
170  *
171  * Revision 5.9  1996/08/30  16:32:58  brandon
172  * fixed PM links
173  *
174  * Revision 5.8  1996/08/14  19:55:53  epstein
175  * add APIs for fetching pieces of biostruc annots
176  *
177  * Revision 5.7  1996/08/14  17:08:29  brandon
178  * *** empty log message ***
179  *
180  * Revision 5.5  1996/08/14  15:15:05  brandon
181  * added date parameter to tleval functions
182  *
183  * Revision 5.4  1996/07/30  15:28:28  epstein
184  * correct logic when retrieving docsums
185  *
186  * Revision 5.3  1996/07/30  15:27:14  epstein
187  * add kludge for retrieving docsums from ID
188  *
189  * Revision 5.2  1996/07/26  20:28:03  epstein
190  * remove special casing of FLD_PROT for PubMed
191  *
192  * Revision 5.1  1996/07/26  20:19:34  zjing
193  * fix in EntrezBioseqFetchFunc for gis of segmented sequence
194  *
195  * Revision 5.0  1996/05/28  13:55:34  ostell
196  * Set to revision 5.0
197  *
198  * Revision 4.26  1996/05/15  15:03:09  kans
199  * added a conditional to suppress an unused variable warning
200  *
201  * Revision 4.25  1996/05/10  19:35:00  epstein
202  * add Pubmed support
203  *
204  *
205  * Revision 4.24  1996/05/02  20:56:08  epstein
206  * fix logic of obtaining entries from ID server
207  *
208  * Revision 4.23  1996/04/18  16:51:38  kuzio
209  * add KLUDGE_YGG
210  *
211  * Revision 4.22  1996/04/10  14:17:55  ostell
212  * reverted Kludge CEGC to original CESC
213  *
214  * Revision 4.19  1996/03/29  18:52:44  epstein
215  * add support for structure alignments
216  *
217  * Revision 4.18  1996/03/28  21:23:42  epstein
218  * move ID-backending from srventr into accentr
219  *
220  * Revision 4.17  1996/03/26  16:29:40  epstein
221  * migrate byte-swapping functions to ncbimisc.[ch]
222  *
223  * Revision 4.16  1996/03/15  02:46:44  ostell
224  * added Check to EntrezGIForSeqID() to remove calls for SeqId types that
225  * will not be satisfied.
226  *
227  * Revision 4.15  1996/03/11  21:51:03  ostell
228  * made GetUniGeneIDForSeqId() externally visible
229  *
230  * Revision 4.14  1996/02/21  20:29:43  ostell
231  * added KLUDGE_HUMGEN
232  *
233  * Revision 4.13  1996/02/16  16:32:40  kans
234  * CESC and BSNR kludges, allow UniGene as well as UNIGENE
235  *
236  * Revision 4.12  1995/12/05  00:56:43  ostell
237  * fixed UniGene fetch problem in Fetch
238  *
239  * Revision 4.10  1995/10/19  20:27:49  epstein
240  * correct EntrezInit/EntrezFini logic (again)
241  *
242  * Revision 4.9  1995/10/11  13:39:20  epstein
243  * add EntrezIsInited() function
244  *
245  * Revision 4.8  1995/10/02  15:27:11  epstein
246  * add range-checking for Net and MB
247  *
248  * Revision 4.6  1995/09/26  21:41:45  ostell
249  * set hierHead to NULL after freeing data in FreeHierarchyList()
250  *
251  * Revision 4.5  1995/08/28  18:50:12  epstein
252  * more protection against multiple EntrezFini calls
253  *
254  * Revision 4.4  1995/08/25  20:22:00  epstein
255  * add counter to avoid unnecessary EntrezInits
256  *
257  * Revision 4.3  1995/08/22  19:37:02  epstein
258  * add network-based clustering support
259  *
260  * Revision 4.1  1995/08/11  20:25:38  epstein
261  * add max-models support for biostrucs
262  *
263  * Revision 4.0  1995/07/26  13:50:32  ostell
264  * force revision to 4.0
265  *
266  * Revision 2.71  1995/07/25  18:47:57  kans
267  * revert to no Biostruc_supported
268  *
269  * Revision 2.70  1995/07/11  14:53:39  epstein
270  *  move DocSumFree to objentr.c
271  *
272  * Revision 2.69  1995/06/29  15:57:51  epstein
273  * added Complexity argument when fetching structures
274  *
275  * Revision 2.68  95/06/20  15:42:45  epstein
276  * add support for BigMed-based Entrez API
277  *
278  * Revision 2.67  95/06/19  16:42:25  ostell
279  * added fake_seqid in EntrezBioseqFetch. When "sip" was used in
280  * BioseqFindInSeqEntry() call, it was not initialized in the case of a
281  * previously cached SeqEntry (only gi set).
282  *
283  * Revision 2.66  1995/05/24  17:14:41  ostell
284  * added code to maintain connection through multiple nested calles to
285  * EntrezBioseqFetchEnable and Disable
286  *
287  * Revision 2.65  1995/05/16  14:36:20  schuler
288  * Automatic comment insertion enabled
289  *
290  *
291  *
292  * ==========================================================================
293  */
294 
295 #define REVISION_STR "$Revision: 6.10 $"
296 
297 #include <accentr.h>
298 #include <seqmgr.h>
299 #include <sequtil.h>
300 
301 #include <cdconfig.h>
302 /* Must not assume network - unused cdromlib stuff is still tangled in */
303 /* Okay to assume network in Mac OS. */
304 #ifdef __MACOS__
305 #define _NETENT_
306 #endif
307 #ifdef _NETENT_
308 #include <netentr.h>      /* support network access */
309 #else
310 #ifdef _MBENTREZ_
311 #include <mbentrez.h>
312 #define USE_ID0 1
313 #define USE_IDxARCH 1
314 #endif
315 #ifdef _PMENTREZ_
316 #include <pmentrez.h>
317 #define USE_ID1 1
318 #define USE_IDxARCH 1
319 #endif
320 #ifdef USE_ID0
321 #include <id0arch.h>
322 #endif
323 #ifdef USE_ID1
324 #include <id1arch.h>
325 #endif
326 #ifndef _CDENTREZ_
327 #include <cdentrez.h>      /* support cdrom access */
328 #endif
329 #endif /* _NETENT_ */
330 
331 #ifdef _NET_AND_CD_
332 #include <netentr.h>      /* support network access */
333 #endif /* _NET_AND_CD_ */
334 
335 #define MAX_SECS_IN_ADAPTIVE_MATRIX 3
336 #define MAX_CHUNK_IN_ADAPTIVE_MATRIX 12
337 #define ADAPTIVE_MATRIX_INITIAL_CONDITION 8
338 
339 #define HIERARCHY_CACHE_SIZE 200
340 
341 #ifdef USE_IDxARCH
342 #ifdef USE_ID0
343 #define IDxArchInit ID0ArchInit
344 #define IDxArchFini ID0ArchFini
345 #define IDxArchSeqEntryGet ID0ArchSeqEntryGet
346 #define IDxArchGIGet ID0ArchGIGet
347 #endif
348 #ifdef USE_ID1
349 #define IDxArchInit ID1ArchInit
350 #define IDxArchFini ID1ArchFini
351 #define IDxArchSeqEntryGet ID1ArchSeqEntryGet
352 #define IDxArchGIGet ID1ArchGIGet
353 #endif
354 #endif /* USE_IDxARCH */
355 
356 #ifdef _NETENTREZ_
357 Uint1 AdaptiveDocSumMatrix[MAX_CHUNK_IN_ADAPTIVE_MATRIX+1][MAX_SECS_IN_ADAPTIVE_MATRIX+1] = {
358   8,  6,  3,  3,
359   8,  6,  3,  3,
360   8,  6,  3,  3,
361   8,  6,  3,  3,
362   9,  7,  4,  3,
363   9,  8,  5,  3,
364  10,  9,  5,  3,
365  10, 10,  5,  3,
366  11, 10,  5,  3,
367  11, 11,  5,  3,
368  12, 11,  5,  3,
369  12, 11,  5,  3,
370  12, 11,  5,  3
371 };
372 #endif /* _NETENTREZ_ */
373 
374                            /* maximum link records returned */
375 static Int4 MaxLinks = (Int4)(INT2_MAX / sizeof(DocUid));
376 
377 static DocUidPtr      queueduids = NULL; /* Used to queue CD-ROM uid query list */
378 static DocSumPtr PNTR queuedsums = NULL; /* Used to queue network retrieved DocSums */
379 static Int2           numqueued = 0;
380 static DocType        queuedtype;
381 static CharPtr        CombinedInfo = NULL;
382 static DocType        lastTermType;
383 static Int2           lastBooleanMediaType;
384 static Int2           entrezInitCount = 0;
385 #ifdef USE_IDxARCH
386 static Boolean        idConnected = FALSE;
387 static Boolean        idCantConnect= FALSE;
388 static void DisconnID(void);
389 #endif
390 
391 
GetCurMediaType(void)392 static Int2 GetCurMediaType(void)
393 {
394 #ifdef _PMENTREZ_
395   return MEDIUM_DISK;
396 #else
397   return CurMediaType();
398 #endif
399 }
400 
DoSelectDataSource(CharPtr section,CharPtr field1,CharPtr field2)401 static Boolean LIBCALL DoSelectDataSource(CharPtr section, CharPtr field1, CharPtr field2)
402 {
403 #ifdef _PMENTREZ_
404   return TRUE;
405 #else
406   return SelectDataSource (section, field1, field2);
407 #endif
408 }
409 
DoSelectDataSourceByType(DocType type,CharPtr field1,CharPtr field2)410 static Boolean LIBCALL DoSelectDataSourceByType(DocType type, CharPtr field1, CharPtr field2)
411 {
412 #ifdef _PMENTREZ_
413   return TRUE;
414 #else
415   return SelectDataSourceByType(type, field1, field2);
416 #endif
417 }
418 
419 /*****************************************************************************
420 *
421 *   EntrezInit ()
422 *
423 *****************************************************************************/
424 
EntrezInit(CharPtr appl_id,Boolean no_warnings,BoolPtr is_network)425 NLM_EXTERN Boolean LIBCALL EntrezInit (CharPtr appl_id, Boolean no_warnings, BoolPtr is_network)
426 
427 {
428     Boolean cdretval = FALSE;
429     Boolean netretval = FALSE;
430     Boolean mbretval = TRUE;
431     queueduids = NULL;
432     queuedsums = NULL;
433     numqueued = 0;
434 
435 Message (MSG_POSTERR, "The Entrez1 service is obsolete and unsupported.  Please switch to using EntrezSynchronousQuery in the future.");
436 
437     if (is_network != NULL)
438     {
439         *is_network = FALSE;
440     }
441 
442     if (entrezInitCount > 0)
443     {
444 	entrezInitCount++;
445 	return TRUE;
446     }
447 
448 #ifdef _PMENTREZ_
449     mbretval = PMEntrezInit(no_warnings);
450 #else
451 
452 #ifdef _CDENTREZ_
453     cdretval = CdEntrezInit(no_warnings);
454 #endif
455 
456 #ifdef _MBENTREZ_
457     mbretval = MBEntrezInit(no_warnings);
458 #endif
459 
460 #endif
461 
462 #ifdef _NETENTREZ_
463     if (is_network != NULL)
464     {
465         *is_network = TRUE;
466     }
467 
468     netretval = NetEntrezInit(appl_id, no_warnings);
469 
470 #endif
471 
472 #ifdef _PMENTREZ_
473 
474     MaxLinks = INT4_MAX;
475 
476 #else
477 
478     if (!cdretval && !netretval)
479     { /* partial success (one of two) is O.K. */
480         return FALSE;
481     }
482 
483     MaxLinks = EntrezGetMaxLinks();
484 
485 #endif
486 
487     if (mbretval)
488         entrezInitCount++;
489     return mbretval;
490 }
491 
492 /*****************************************************************************
493 *
494 *   EntrezIsInited ()
495 *
496 *****************************************************************************/
EntrezIsInited(void)497 NLM_EXTERN Boolean LIBCALL EntrezIsInited(void)
498 {
499   return (entrezInitCount > 0);
500 }
501 
502 /*****************************************************************************
503 *
504 *   EntrezFini ()
505 *
506 *****************************************************************************/
507 
ClearQueuedDocSums(void)508 static void ClearQueuedDocSums (void)
509 
510 {
511     Int2  i;
512 
513     if (queueduids != NULL) {
514         queueduids = (DocUidPtr) MemFree (queueduids);
515     }
516     if (queuedsums != NULL) {
517         for (i = 0; i < numqueued; i++) {
518           if (queuedsums [i] != NULL) {
519             queuedsums [i] = DocSumFree (queuedsums [i]);
520           }
521         }
522         queuedsums = (DocSumPtr PNTR) MemFree (queuedsums);
523     }
524     numqueued = 0;
525 }
526 
527 static void FreeHierarchyList PROTO((void));
528 
EntrezFini(void)529 NLM_EXTERN void LIBCALL EntrezFini (void)
530 
531 {
532     ClearQueuedDocSums ();
533     FreeHierarchyList ();
534     if (CombinedInfo != NULL)
535     {
536         CombinedInfo = (CharPtr) MemFree(CombinedInfo);
537     }
538 
539     if (entrezInitCount <= 0)
540         return;
541     if (--entrezInitCount > 0)
542         return;
543 
544 #ifdef USE_IDxARCH
545     DisconnID ();
546 #endif
547 #ifdef _CDENTREZ_
548     CdEntrezFini();
549 #endif
550 #ifdef _MBENTREZ_
551     MBEntrezFini();
552 #endif
553 #ifdef _PMENTREZ_
554     PMEntrezFini();
555 #endif
556 #ifdef _NETENTREZ_
557     NetEntrezFini();
558 #endif
559 }
560 
561 /*****************************************************************************
562 *
563 *   EntrezInfoPtr EntrezGetInfo()
564 *
565 *****************************************************************************/
EntrezGetInfo(void)566 NLM_EXTERN EntrezInfoPtr LIBCALL EntrezGetInfo (void)
567 
568 {
569     static EntrezInfoPtr cip = NULL;
570 
571 #if defined(_CDENTREZ_) && (defined(_MBENTREZ_) || defined(_PMENTREZ_))
572 #ifdef _MBENTREZ_
573     return MBAdjustEntrezInfo (CdEntrezGetInfo());
574 #else
575     return PMEntrezGetInfo();
576 #endif
577 #else
578     if (cip == NULL)
579         cip = EntrezInfoMerge();
580 
581     /* as a last resort, fall back on the old, faithful function */
582     if (cip == NULL)
583 #ifdef _CDENTREZ_
584         return CdEntrezGetInfo();
585 #else
586         return NetEntrezGetInfo();
587 #endif
588     else
589         return cip;
590 #endif
591 }
592 
593 /*****************************************************************************
594 *
595 *   CharPtr EntrezDetailedInfo()
596 *       returns either NULL (if no info is available), or a pointer to a
597 *       statically allocated string containing formatted status information
598 *
599 *****************************************************************************/
EntrezDetailedInfo(void)600 NLM_EXTERN CharPtr LIBCALL EntrezDetailedInfo (void)
601 
602 {
603     CharPtr cdinfo = NULL;
604     CharPtr netinfo = NULL;
605     CharPtr extrainfo = NULL;
606     Int2 extrainfoLen = 0;
607     DocType db;
608     CharPtr str;
609     EntrezInfoPtr eip;
610 
611 #ifdef _PMENTREZ_
612     cdinfo = PMEntrezDetailedInfo();
613 #endif
614 
615 #ifdef _CDENTREZ_
616     cdinfo = CdEntrezDetailedInfo();
617 #endif
618 #ifdef _NETENTREZ_
619     netinfo = NetEntrezDetailedInfo();
620 #endif
621     if ((eip = EntrezGetInfo()) != NULL)
622     {
623         extrainfo = MemNew(StringLen(eip->descr) + 400);
624         StrCpy(extrainfo, "\n\nCURRENT MEDIA\n  ");
625         StrCat(extrainfo, eip->descr);
626         extrainfoLen = StringLen(extrainfo);
627         sprintf(&extrainfo[extrainfoLen], "\n  Version %ld.%ld",
628                 (long) eip->version, (long) eip->issue);
629         extrainfoLen = StringLen(extrainfo);
630         if (eip->types != NULL)
631         {
632             for (db = 0; db < eip->type_count; db++)
633             {
634                 if (eip->types[0].num > 0)
635                 {
636                     if (eip->type_info != NULL)
637                     {
638                         str = eip->type_info[db].name;
639                     } else {
640                         str = eip->type_names[db];
641                     }
642                     sprintf(&extrainfo[extrainfoLen], "\n  # %s entries = %ld",
643                             str, (long) (eip->types[db].num));
644                     extrainfoLen = StringLen(extrainfo);
645                 }
646             }
647         }
648         StrCat(extrainfo, "\n");
649         extrainfoLen = StringLen(extrainfo);
650     }
651 
652     if (CombinedInfo != NULL)
653         MemFree(CombinedInfo);
654     if ((CombinedInfo = MemNew(StringLen(cdinfo) + StringLen(netinfo) + 4 + extrainfoLen)) == NULL)
655     {
656         MemFree(extrainfo);
657         return cdinfo; /* better than nothing */
658     }
659     StringCpy(CombinedInfo, cdinfo);
660     StringCat(CombinedInfo, "\n\n");
661     StringCat(CombinedInfo, netinfo);
662     StringCat(CombinedInfo, extrainfo);
663     MemFree(extrainfo);
664 
665     return CombinedInfo;
666 }
667 
668 /*****************************************************************************
669 *
670 *   EntrezGetMaxLinks()
671 *       returns max links in link set allowed by system
672 *
673 *****************************************************************************/
EntrezGetMaxLinks(void)674 NLM_EXTERN Int4 LIBCALL EntrezGetMaxLinks (void)
675 
676 {
677     Int4 maxlinks = INT4_MAX;
678     Int4 links = 0;
679     Boolean cdSelected = FALSE;
680 
681     if (! DoSelectDataSource(ENTR_LINKS_CHAN, "INFO", NULL))
682     {
683         /* ERROR, data unobtainable */
684         return -1;
685     }
686 
687     do {
688         switch (GetCurMediaType()) {
689 #ifdef _CDENTREZ_
690         case MEDIUM_CD:
691             /* for ergonomics, check a maximum of one CD */
692             cdSelected = TRUE;
693             /* no break */
694         case MEDIUM_DISK:
695             links = CdEntGetMaxLinks();
696             break;
697 #endif
698 #ifdef _NETENTREZ_
699         case MEDIUM_NETWORK:
700             links = NetEntGetMaxLinks();
701             break;
702 #endif
703         default:
704             break;
705         }
706         maxlinks = MIN(maxlinks, links);
707     } while (!cdSelected && SelectNextDataSource());
708 
709     if (maxlinks == INT4_MAX)
710         maxlinks = -1;
711     return maxlinks;
712 }
713 
714 /*****************************************************************************
715 *
716 *   EntrezSetUserMaxLinks(num)
717 *       user settable maximum
718 *       can't be > EntrezGetMaxLinks()
719 *
720 *****************************************************************************/
EntrezSetUserMaxLinks(Int4 num)721 NLM_EXTERN Int4 LIBCALL EntrezSetUserMaxLinks (Int4 num)
722 
723 {
724     Int4 big;
725 
726     big = EntrezGetMaxLinks();
727     if (big < num)
728         num = big;
729     MaxLinks = num;
730     return num;
731 }
732 
733 /*****************************************************************************
734 *
735 *   EntrezGetUserMaxLinks()
736 *       returns current value of MaxLinks
737 *
738 *****************************************************************************/
EntrezGetUserMaxLinks(void)739 NLM_EXTERN Int4 LIBCALL EntrezGetUserMaxLinks (void)
740 
741 {
742     return MaxLinks;
743 }
744 
745 /*****************************************************************************
746 *
747 *   EntrezCreateNamedUidList(term, type, field, num, uids)
748 *       Creates a term node in the entrez set structure if one does not
749 *       yet exist, and loads the posting file from the uid parameter.
750 *
751 *****************************************************************************/
EntrezCreateNamedUidList(CharPtr term,DocType type,DocField field,Int4 num,DocUidPtr uids)752 NLM_EXTERN void LIBCALL EntrezCreateNamedUidList (CharPtr term, DocType type, DocField field, Int4 num, DocUidPtr uids)
753 
754 {
755 
756 #ifdef _PMENTREZ_
757   PMEntrezCreateNamedUIDList(term,type,num,uids);
758   return;
759 #else
760 
761     if (! DoSelectDataSourceByType(type, "TERMS", NULL))
762     {
763         return;
764     }
765 
766     switch (GetCurMediaType ()) {
767 #ifdef _CDENTREZ_
768     case MEDIUM_CD:
769     case MEDIUM_DISK:
770         CdEntrezCreateNamedUidList (term, type, field, num, uids);
771         break;
772 #endif
773 #ifdef _NETENTREZ_
774     case MEDIUM_NETWORK:
775         NetEntrezCreateNamedUidList (term, type, field, num, uids);
776         break;
777 #endif
778     default:
779         break;
780     }
781 #endif /* _PMENTREZ_ */
782 }
783 
784 /*****************************************************************************
785 *
786 *   EntrezCreateNamedUidListX(term, type, field, bsp)
787 *       Creates a term node in the entrez set structure if one does not
788 *       yet exist, and loads the posting file from the uid parameter.
789 *
790 *****************************************************************************/
EntrezCreateNamedUidListX(CharPtr term,DocType type,DocField field,ByteStorePtr bsp)791 NLM_EXTERN void LIBCALL EntrezCreateNamedUidListX (CharPtr term, DocType type, DocField field, ByteStorePtr bsp)
792 
793 {
794 
795 #ifdef _PMENTREZ_
796   PMEntrezCreateNamedUIDListBSP(term,type,bsp);
797   return;
798 #else
799 
800     if (! DoSelectDataSourceByType(type, "TERMS", NULL))
801     {
802         return;
803     }
804 
805     switch (GetCurMediaType ()) {
806 #ifdef _CDENTREZ_
807     case MEDIUM_CD:
808     case MEDIUM_DISK:
809         CdEntrezCreateNamedUidListX (term, type, field, bsp);
810         break;
811 #endif
812 #ifdef _NETENTREZ_
813     case MEDIUM_NETWORK:
814         NetEntrezCreateNamedUidListX (term, type, field, bsp);
815         break;
816 #endif
817     default:
818         break;
819     }
820 #endif /* _PMENTREZ_ */
821 }
822 
823 
824 /*****************************************************************************
825 *
826 *   EntrezTLNew (type)
827 *       Creates linked list of asn nodes for constructing boolean query on
828 *       terms.  First node points to processing info.
829 *       Remaining nodes contain symbols for AND,
830 *       OR, LEFT PARENTHESIS, RIGHT PARENTHESIS, or a SPECIAL or TOTAL term
831 *       specification.  The term specification nodes point to a CdTerm or a
832 *       string.
833 *
834 *****************************************************************************/
835 
EntrezTLNew(DocType type)836 NLM_EXTERN ValNodePtr LIBCALL EntrezTLNew (DocType type)
837 
838 {
839     if (! DoSelectDataSourceByType(type, "BOOLEANS", NULL))
840     {
841         return NULL;
842     }
843 
844     switch ( lastBooleanMediaType = GetCurMediaType() ) {
845 #ifdef _CDENTREZ_
846     case MEDIUM_CD:
847     case MEDIUM_DISK:
848 #ifdef _MBENTREZ_
849         if (type == TYP_ML)
850             return MBEntTLNew(type);
851 #endif
852 #ifdef _PMENTREZ_
853 	  return PMEntTLNew(type);
854 #else
855           return CdEntTLNew(type);
856 #endif /* _PMENTREZ_ */
857 #endif
858 #ifdef _NETENTREZ_
859     case MEDIUM_NETWORK:
860         return NetEntTLNew(type);
861 #endif
862     default:
863         return NULL;
864     }
865 }
866 
867 /*****************************************************************************
868 *
869 *   EntrezTLAddTerm (elst, term, type, field, special)
870 *       Adds a term node to a boolean algebraic term query.
871 *
872 *****************************************************************************/
873 
EntrezTLAddTerm(ValNodePtr elst,CharPtr term,DocType type,DocField field,Boolean special)874 NLM_EXTERN ValNodePtr LIBCALL EntrezTLAddTerm (ValNodePtr elst, CharPtr term, DocType type, DocField field, Boolean special)
875 {
876     return EntrezTLAddTermWithRange (elst, term, type, field, special, NULL);
877 }
878 
EntrezTLAddTermWithRange(ValNodePtr elst,CharPtr term,DocType type,DocField field,Boolean special,CharPtr highRange)879 NLM_EXTERN ValNodePtr LIBCALL EntrezTLAddTermWithRange (ValNodePtr elst, CharPtr term, DocType type, DocField field, Boolean special, CharPtr highRange)
880 
881 {
882     switch (lastBooleanMediaType) {
883 #ifdef _CDENTREZ_
884     case MEDIUM_CD:
885     case MEDIUM_DISK:
886 #ifdef _MBENTREZ_
887         if (type == TYP_ML)
888             return MBEntTLAddTerm (elst, term, type, field, special, highRange);
889 #endif
890 
891 #ifdef _PMENTREZ_
892 	return PMEntTLAddTerm (elst, term, type, field, special, highRange);
893 #else
894         return CdEntTLAddTerm (elst, term, type, field, special, highRange);
895 #endif /* _PMENTREZ_ */
896 
897 #endif
898 #ifdef _NETENTREZ_
899     case MEDIUM_NETWORK:
900         return NetEntTLAddTerm (elst, term, type, field, special, highRange);
901 #endif
902     default:
903         return NULL;
904     }
905 }
906 
907 /*****************************************************************************
908 *
909 *   EntrezTLFree (elst)
910 *       Frees a boolean algebraic term query list.
911 *
912 *****************************************************************************/
913 
EntrezTLFree(ValNodePtr elst)914 NLM_EXTERN ValNodePtr LIBCALL EntrezTLFree (ValNodePtr elst)
915 
916 {
917 #ifdef _PMENTREZ_
918   return PMEntTLFree(elst);
919 #else
920 
921     switch (lastBooleanMediaType) {
922 #ifdef _CDENTREZ_
923     case MEDIUM_CD:
924     case MEDIUM_DISK:
925 #ifdef _MBENTREZ_
926       {
927 	if (elst != NULL && elst->choice == NULLSYM)
928 	  {
929 	    CdTermPtr eset = (CdTermPtr) elst->data.ptrvalue;
930 
931 	    if (eset != NULL && eset->type == TYP_ML)
932 	      {
933 		return MBEntTLFree(elst);
934 	      }
935 	  }
936       }
937 #endif
938       return CdEntTLFree(elst);
939 #endif
940 
941 #ifdef _NETENTREZ_
942     case MEDIUM_NETWORK:
943         return NetEntTLFree(elst);
944 #endif
945     default:
946         return NULL;
947 
948     }
949 
950 #endif
951 
952 }
953 
954 /*****************************************************************************
955 *
956 *   EntrezTLAddLParen (elst)
957 *       Adds a LEFT PAREN node to a boolean algebraic term query.
958 *
959 *****************************************************************************/
960 
EntrezTLAddLParen(ValNodePtr elst)961 NLM_EXTERN ValNodePtr LIBCALL EntrezTLAddLParen (ValNodePtr elst)
962 
963 {
964   ValNodePtr anp;
965 
966   anp = NULL;
967   if (elst != NULL) {
968     anp = ValNodeNew (elst);
969     if (anp != NULL) {
970       anp->choice = LPAREN;
971     }
972   }
973   return anp;
974 }
975 
976 /*****************************************************************************
977 *
978 *   EntrezTLAddRParen (elst)
979 *       Adds a RIGHT PAREN node to a boolean algebraic term query.
980 *
981 *****************************************************************************/
982 
EntrezTLAddRParen(ValNodePtr elst)983 NLM_EXTERN ValNodePtr LIBCALL EntrezTLAddRParen (ValNodePtr elst)
984 
985 {
986   ValNodePtr anp;
987 
988   anp = NULL;
989   if (elst != NULL) {
990     anp = ValNodeNew (elst);
991     if (anp != NULL) {
992       anp->choice = RPAREN;
993     }
994   }
995   return anp;
996 }
997 
998 /*****************************************************************************
999 *
1000 *   CdEntTLAddAND (elst)
1001 *       Adds an AND node to a boolean algebraic term query.
1002 *
1003 *****************************************************************************/
1004 
EntrezTLAddAND(ValNodePtr elst)1005 NLM_EXTERN ValNodePtr LIBCALL EntrezTLAddAND (ValNodePtr elst)
1006 
1007 {
1008   ValNodePtr anp;
1009 
1010   anp = NULL;
1011   if (elst != NULL) {
1012     anp = ValNodeNew (elst);
1013     if (anp != NULL) {
1014       anp->choice = ANDSYMBL;
1015     }
1016   }
1017   return anp;
1018 }
1019 
1020 /*****************************************************************************
1021 *
1022 *   EntrezTLAddOR (elst)
1023 *       Adds an OR node to a boolean algebraic term query.
1024 *
1025 *****************************************************************************/
1026 
EntrezTLAddOR(ValNodePtr elst)1027 NLM_EXTERN ValNodePtr LIBCALL EntrezTLAddOR (ValNodePtr elst)
1028 
1029 {
1030   ValNodePtr anp;
1031 
1032   anp = NULL;
1033   if (elst != NULL) {
1034     anp = ValNodeNew (elst);
1035     if (anp != NULL) {
1036       anp->choice = ORSYMBL;
1037     }
1038   }
1039   return anp;
1040 }
1041 
1042 /*****************************************************************************
1043 *
1044 *   EntrezTLAddBUTNOT (elst)
1045 *       Adds an BUTNOT node to a boolean algebraic term query.
1046 *
1047 *****************************************************************************/
1048 
EntrezTLAddBUTNOT(ValNodePtr elst)1049 NLM_EXTERN ValNodePtr LIBCALL EntrezTLAddBUTNOT (ValNodePtr elst)
1050 
1051 {
1052   ValNodePtr anp;
1053 
1054   anp = NULL;
1055   if (elst != NULL) {
1056     anp = ValNodeNew (elst);
1057     if (anp != NULL) {
1058       anp->choice = BUTNOTSYMBL;
1059     }
1060   }
1061   return anp;
1062 }
1063 
1064 /*****************************************************************************
1065 *
1066 *   EntrezTLEval (elst)
1067 *       Evaluates a boolean algebraic term query list, returning a pointer to
1068 *       a LinkSet containing the resultant unique identifiers.
1069 *
1070 *****************************************************************************/
1071 
1072 
EntrezPMTLEval(ValNodePtr elst,void * edc)1073 NLM_EXTERN LinkSetPtr LIBCALL EntrezPMTLEval (ValNodePtr elst, void * edc)
1074 {
1075 
1076     switch (lastBooleanMediaType) {
1077 #ifdef _CDENTREZ_
1078     case MEDIUM_CD:
1079     case MEDIUM_DISK:
1080 #if defined(_MBENTREZ_) || defined(_PMENTREZ_)
1081         {
1082 	    if (elst != NULL && elst->choice == NULLSYM)
1083 	    {
1084 		CdTermPtr eset = (CdTermPtr) elst->data.ptrvalue;
1085 #ifdef _MBENTREZ_
1086 		if (eset != NULL && eset->type == TYP_ML)
1087 		{
1088                     return MBEntTLEval(elst);
1089 #else
1090 		if (eset != NULL && DatabaseExistsInPubMed(eset->type))
1091 		{
1092                     return PMEntTLEval(eset -> type,elst,edc);
1093 #endif
1094 		}
1095 	    }
1096 	}
1097 #endif
1098         return CdEntTLEval(elst);
1099 #endif
1100 #ifdef _NETENTREZ_
1101     case MEDIUM_NETWORK:
1102         return NetEntTLEval(elst);
1103 #endif
1104     default:
1105         return NULL;
1106     }
1107 }
1108 
1109 NLM_EXTERN LinkSetPtr LIBCALL EntrezTLEval (ValNodePtr elst)
1110 {
1111   return EntrezPMTLEval (elst,NULL);
1112 }
1113 
1114 /*****************************************************************************
1115 *
1116 *   EntrezTLEvalCount (elst)
1117 *       Evaluates a boolean algebraic term query list, returning the count
1118 *       of resulting UIDs.
1119 *****************************************************************************/
1120 
1121 NLM_EXTERN Int4 LIBCALL EntrezPMTLEvalCount (ValNodePtr elst, void * edc)
1122 {
1123     Int4 retval;
1124 
1125     switch (lastBooleanMediaType) {
1126 #ifdef _CDENTREZ_
1127     case MEDIUM_CD:
1128     case MEDIUM_DISK:
1129 #if defined(_MBENTREZ_) || defined(_PMENTREZ_)
1130         {
1131 	    if (elst != NULL && elst->choice == NULLSYM)
1132 	    {
1133 		CdTermPtr eset = (CdTermPtr) elst->data.ptrvalue;
1134 
1135 #ifdef _MBENTREZ_
1136 		if (eset != NULL && eset->type == TYP_ML)
1137 		{
1138 		  return MBEntTLEvalCount(elst);
1139 #else
1140 		if (eset != NULL && DatabaseExistsInPubMed(eset->type))
1141 		{
1142 		 return PMEntTLEvalCount(eset -> type, elst,edc);
1143 #endif
1144 		}
1145 	    }
1146 	}
1147 #endif
1148         retval = CdEntTLEvalCount(elst);
1149         return retval;
1150 #endif
1151 #ifdef _NETENTREZ_
1152     case MEDIUM_NETWORK:
1153         retval = NetEntTLEvalCount(elst);
1154         return retval;
1155 #endif
1156     default:
1157         return 0;
1158     }
1159 }
1160 
1161 NLM_EXTERN Int4 LIBCALL EntrezTLEvalCount (ValNodePtr elst)
1162 {
1163   return EntrezPMTLEvalCount (elst, NULL);
1164 }
1165 
1166 
1167 /*****************************************************************************
1168 *
1169 *   EntrezTLEvalX (elst)
1170 *       Evaluates a boolean algebraic term query list, returning a pointer to
1171 *       a ByteStore containing the resultant unique identifiers.  The number
1172 *       of UIDs is calculated as BSLen (bsp) / sizeof (DocUid).
1173 *
1174 *****************************************************************************/
1175 
1176 NLM_EXTERN ByteStorePtr LIBCALL EntrezPMTLEvalX (ValNodePtr elst, void * edc)
1177 {
1178     ByteStorePtr bsp;
1179 
1180     switch (lastBooleanMediaType) {
1181 #ifdef _CDENTREZ_
1182     case MEDIUM_CD:
1183     case MEDIUM_DISK:
1184 #if defined(_MBENTREZ_) || defined(_PMENTREZ_)
1185         {
1186 	    if (elst != NULL && elst->choice == NULLSYM)
1187 	    {
1188 		CdTermPtr eset = (CdTermPtr) elst->data.ptrvalue;
1189 #ifdef _MBENTREZ_
1190 		if (eset != NULL && eset->type == TYP_ML)
1191 		{
1192                     bsp = MBEntTLEvalX(elst);
1193 #else
1194 		if (eset != NULL && DatabaseExistsInPubMed(eset->type))
1195 		{
1196                     bsp = PMEntTLEvalX(eset -> type, elst,edc);
1197 #endif
1198                     if (bsp != NULL) {
1199                         BSSeek (bsp, 0L, 0);
1200                     }
1201                     return bsp;
1202 		}
1203 	    }
1204 	}
1205 #endif
1206         bsp = CdEntTLEvalX(elst);
1207         if (bsp != NULL) {
1208             BSSeek (bsp, 0L, 0);
1209         }
1210         return bsp;
1211 #endif
1212 #ifdef _NETENTREZ_
1213     case MEDIUM_NETWORK:
1214         bsp = NetEntTLEvalX(elst);
1215         if (bsp != NULL) {
1216             BSSeek (bsp, 0L, 0);
1217         }
1218         return bsp;
1219 #endif
1220     default:
1221         return NULL;
1222     }
1223 }
1224 
1225 NLM_EXTERN ByteStorePtr LIBCALL EntrezTLEvalX (ValNodePtr elst)
1226 {
1227   return(EntrezPMTLEvalX(elst,NULL));
1228 }
1229 
1230 
1231 #ifdef USE_IDxARCH
1232 static Boolean
1233 ConnectID(void)
1234 {
1235     if (!idConnected && !idCantConnect)
1236     {
1237         if (IDxArchInit())
1238         {
1239             idConnected = TRUE;
1240         } else {
1241             idCantConnect = TRUE;
1242         }
1243     }
1244 
1245     return idConnected;
1246 }
1247 
1248 static void
1249 DisconnID(void)
1250 {
1251     if (idConnected)
1252         IDxArchFini();
1253     idConnected = FALSE;
1254     idCantConnect = FALSE;
1255 }
1256 #endif /* USE_IDxARCH */
1257 
1258 /*****************************************************************************
1259 *
1260 *   DocSumPtr EntrezDocSum(type, uid)
1261 *
1262 *****************************************************************************/
1263 NLM_EXTERN DocSumPtr LIBCALL EntrezDocSum (DocType type, DocUid uid)
1264 
1265 {
1266     DocSumPtr dsp;
1267 
1268 #ifdef _PMENTREZ_
1269     return PMDocSum(type, uid);
1270 #else
1271 
1272     if (! DoSelectDataSourceByType(type, "DOCSUMS", NULL))
1273     { /* ERROR, data unobtainable */
1274         return NULL;
1275     }
1276 
1277     do {
1278         switch (GetCurMediaType())
1279         {
1280 #ifdef _CDENTREZ_
1281         case MEDIUM_CD:
1282         case MEDIUM_DISK:
1283 #ifdef _MBENTREZ_
1284             if (type == TYP_ML)
1285 	    {
1286 		return MBDocSum(type, uid);
1287 	    }
1288 #endif
1289             if ((dsp = CdDocSum (type, uid)) != NULL)
1290                 return dsp;
1291 #ifdef USE_IDxARCH
1292             if (type != TYP_ST && type != TYP_CH && ConnectID())
1293             {
1294                 SeqEntryPtr sep;
1295                 Char fname[PATH_MAX];
1296                 AsnIoPtr aip;
1297                 DocSumPtr dsp = NULL;
1298 
1299                 if ((sep = IDxArchSeqEntryGet(uid, NULL, 0)) != NULL)
1300                 {
1301                     TmpNam(fname);
1302                     aip = AsnIoOpen(fname, "w");
1303                     SeqEntryAsnWrite(sep, aip, NULL);
1304                     AsnIoClose(aip);
1305                     aip = AsnIoOpen(fname, "r");
1306                     dsp = CdSeqSumAsnRead(aip, uid);
1307                     SeqEntryFree(sep);
1308                     AsnIoClose(aip);
1309                     FileRemove(fname);
1310                     return dsp;
1311                 }
1312             }
1313 #endif /* USE_IDxARCH */
1314             break;
1315 #endif
1316 #ifdef _NETENTREZ_
1317         case MEDIUM_NETWORK:
1318             if ((dsp = NetDocSum (type, uid)) != NULL)
1319                 return dsp;
1320             break;
1321 #endif
1322         default:
1323             break;
1324         }
1325     } while (SelectNextDataSource());
1326 
1327     return NULL;
1328 
1329 #endif
1330 }
1331 
1332 /*****************************************************************************
1333 *
1334 *   EntrezDocSumListGet(numuid, type, uids, callback)
1335 *
1336 *****************************************************************************/
1337 static Int2 DocSumQueueGet (Int2 numuid, DocType type, DocSumListCallBack callback)
1338 
1339 {
1340   DocSumPtr  dsp;
1341   int        count = 0;
1342   int        i;
1343   Boolean    goOn;
1344 
1345   if (callback == NULL) {
1346     ClearQueuedDocSums ();
1347     return 0;
1348   }
1349   if (type != queuedtype) {
1350     ClearQueuedDocSums ();
1351     return 0;
1352   }
1353   goOn = TRUE;
1354   count = 0;
1355   if (numuid > numqueued) {
1356     numuid = numqueued;
1357   }
1358 
1359   i = 0;
1360   while (i < numqueued && goOn) {
1361     if (queueduids [i] != 0) {
1362       if (queuedsums != NULL) {
1363         dsp = queuedsums [i];
1364       } else {
1365         dsp = EntrezDocSum (type, queueduids [i]);
1366       }
1367       if (dsp != NULL) {
1368         count++;
1369         goOn = callback (dsp, dsp->uid);
1370         queueduids [i] = 0;
1371         if (queuedsums != NULL) {
1372           queuedsums [i] = NULL;
1373         }
1374       } else {
1375         count++;
1376         goOn = callback (NULL, queueduids [i]);
1377         queueduids [i] = 0;
1378         if (queuedsums != NULL) {
1379           queuedsums [i] = NULL;
1380         }
1381       }
1382     }
1383     i++;
1384   }
1385   if (i >= numqueued) {
1386     if (queuedsums != NULL) {
1387       queuedsums = (DocSumPtr PNTR) MemFree (queuedsums);
1388     }
1389     queueduids = (DocUidPtr) MemFree (queueduids);
1390     numqueued = 0;
1391   }
1392 
1393   return count;
1394 }
1395 
1396 NLM_EXTERN Int2 LIBCALL EntrezDocSumListGet (Int2 numuid, DocType type, DocUidPtr uids,
1397                                  DocSumListCallBack callback)
1398 
1399 {
1400   DocSumPtr  dsp;
1401   int        count = 0;
1402   int        i;
1403   Boolean    goOn;
1404   DocUidPtr  uidlist;
1405 #ifdef _NETENTREZ_
1406   Int2       chunkSize;
1407   Int2       chunkStart;
1408   Int2       predictedNextChunk;
1409   Int2       actual;
1410   DocSumPtr  PNTR result;
1411   static Int2 adaptiveChunkSize = ADAPTIVE_MATRIX_INITIAL_CONDITION;
1412   time_t     timeElapsed, startTime;
1413 #endif
1414 
1415   /* For ergonomics, DocSums are fetched from the CD-ROM and displayed */
1416   /* one at a time. For efficiency, all DocSums are fetched from the   */
1417   /* network at once, and subsequently all are displayed.              */
1418 
1419   if (uids == NULL && queueduids != NULL && callback != NULL) {
1420     return DocSumQueueGet (numuid, queuedtype, callback);
1421   }
1422   ClearQueuedDocSums ();
1423   queuedtype = type;
1424   if (numuid == 0) {
1425     return 0;
1426   }
1427   if (uids == NULL) {
1428     return 0;
1429   }
1430   goOn = TRUE;
1431   count = 0;
1432   uidlist = (DocUidPtr) MemNew (sizeof (DocUid) * numuid);
1433   if (uidlist != NULL) {
1434     for (i = 0; i < numuid; i++) {
1435       uidlist [i] = uids [i];
1436     }
1437 #ifdef _NETENTREZ_
1438 
1439     if (! DoSelectDataSourceByType(type, "DOCSUMS", NULL))
1440     { /* ERROR, data unobtainable */
1441       uidlist = (DocUidPtr) MemFree(uidlist);
1442       return 0;
1443     }
1444 
1445     /* if the first-found media type is NET, try to get them all from the  */
1446     /* net; otherwise, to heck with it, just get them one at a time, below */
1447     if (GetCurMediaType() == MEDIUM_NETWORK) {
1448       result = (DocSumPtr PNTR) MemNew (sizeof (DocSumPtr) * numuid);
1449       if (result != NULL) {
1450         i = 0;
1451         chunkStart = 0;
1452         chunkSize = adaptiveChunkSize;
1453         while (chunkStart < numuid && goOn)
1454         {
1455           /* if ( the callback told us that it doesn't need any more right   */
1456           /*      now, OR if we would be getting too many ) THEN             */
1457           /*    get all of the remaining docsums in one shot                 */
1458           if (callback == NULL || !goOn || (chunkSize + chunkStart) >= numuid)
1459             chunkSize = numuid - chunkStart;
1460 
1461           /* Ask for some to be computed in advance, because it can take the*/
1462           /* application a long time to process the ones which it _does_    */
1463           /* receive this time                                              */
1464           predictedNextChunk = MIN(numuid - (chunkStart+chunkSize), chunkSize);
1465           startTime = GetSecs();
1466           actual = NetDocSumListGet (&result[chunkStart], (Int2)(chunkSize +
1467                                      predictedNextChunk), type,
1468                                      &uids[chunkStart], predictedNextChunk);
1469           chunkStart += chunkSize;
1470 
1471           timeElapsed = GetSecs() - startTime;
1472           if (timeElapsed < 0)
1473               timeElapsed = 0;
1474           if (timeElapsed > MAX_SECS_IN_ADAPTIVE_MATRIX)
1475               timeElapsed = MAX_SECS_IN_ADAPTIVE_MATRIX;
1476           if (chunkSize > MAX_CHUNK_IN_ADAPTIVE_MATRIX)
1477               chunkSize = MAX_CHUNK_IN_ADAPTIVE_MATRIX;
1478           adaptiveChunkSize = AdaptiveDocSumMatrix[chunkSize][timeElapsed];
1479           chunkSize = adaptiveChunkSize;
1480 
1481           if (goOn && callback != NULL) {
1482             while (i < chunkStart && goOn) {
1483               dsp = result [i];
1484               if (dsp != NULL) {
1485                 count++;
1486                 goOn = callback (dsp, dsp->uid);
1487                 uidlist [i] = 0;
1488                 result [i] = NULL;
1489               } else {
1490                 count++;
1491                 goOn = callback (NULL, uidlist [i]);
1492                 uidlist [i] = 0;
1493                 result [i] = NULL;
1494               }
1495               i++;
1496             }
1497           }
1498         }
1499 
1500         if (count < numuid) { /* enqueue remaining docsums */
1501           queueduids = uidlist;
1502           queuedsums = result;
1503           numqueued = numuid;
1504         } else {
1505           MemFree (uidlist);
1506           MemFree (result);
1507         }
1508       }
1509       return count;
1510     }
1511 #endif
1512 
1513     /* get them one at a time */
1514     if (callback != NULL) {
1515       i = 0;
1516       while (i < numuid && goOn) {
1517         dsp = EntrezDocSum (type, uidlist [i]);
1518         if (dsp != NULL) {
1519           count++;
1520           goOn = callback (dsp, dsp->uid);
1521           uidlist [i] = 0;
1522         } else {
1523           count++;
1524           goOn = callback (NULL, uidlist [i]);
1525           uidlist [i] = 0;
1526         }
1527         i++;
1528       }
1529     }
1530     if (count < numuid) {
1531       queueduids = uidlist;
1532       numqueued = numuid;
1533     } else {
1534       MemFree (uidlist);
1535     }
1536   }
1537   return count;
1538 }
1539 
1540 
1541 /*****************************************************************************
1542 *
1543 *   EntrezTermListByTerm (type, field, term, numterms, proc, first_page)
1544 *       Gets Terms starting at term
1545 *       returns pages read
1546 *       sets first_page to first page read
1547 *
1548 *****************************************************************************/
1549 NLM_EXTERN Int2 LIBCALL EntrezTermListByTerm (DocType type, DocField field, CharPtr term, Int2 numterms, TermListProc proc, Int2Ptr first_page)
1550 
1551 {
1552     if (! DoSelectDataSourceByType(type, "TERMS", NULL))
1553     {
1554         return 0;
1555     }
1556 
1557 
1558     lastTermType = type;
1559 
1560     switch (GetCurMediaType())
1561     {
1562 #ifdef _CDENTREZ_
1563     case MEDIUM_CD:
1564     case MEDIUM_DISK:
1565 #ifdef _MBENTREZ_
1566         if (type == TYP_ML && field != FLD_PROT /* FLD_PROT is MeSH glossary */)
1567         {
1568             return MBTermListByTerm(type, field, term, numterms, proc, first_page);
1569         }
1570 #endif
1571 #ifdef _PMENTREZ_
1572 	if (DatabaseExistsInPubMed(type))
1573         {
1574             return PMTermListByTerm(type, field, term, numterms, proc, first_page);
1575         }
1576 #endif
1577         return CdTermListByTerm(type, field, term, numterms, proc, first_page);
1578 #endif
1579 #ifdef _NETENTREZ_
1580     case MEDIUM_NETWORK:
1581         return NetTermListByTerm(type, field, term, numterms, proc, first_page);
1582 #endif
1583     default:
1584         return 0;
1585     }
1586 }
1587 
1588 /*****************************************************************************
1589 *
1590 *   EntrezTermListByPage (type, field, page, numpage, proc)
1591 *       Gets terms starting at page, for numpage, by calling proc
1592 *       returns pages read
1593 *
1594 *****************************************************************************/
1595 NLM_EXTERN Int2 LIBCALL EntrezTermListByPage (DocType type, DocField field, Int2 page, Int2 numpage, TermListProc proc)
1596 
1597 {
1598     if (! DoSelectDataSourceByType(type, "TERMS", NULL))
1599     {
1600         return 0;
1601     }
1602 
1603     lastTermType = type;
1604 
1605     switch (GetCurMediaType())
1606     {
1607 #ifdef _CDENTREZ_
1608     case MEDIUM_CD:
1609     case MEDIUM_DISK:
1610 #ifdef _MBENTREZ_
1611         if (type == TYP_ML && field != FLD_PROT /* FLD_PROT is MeSH glossary */)
1612         {
1613             return MBTermListByPage(type, field, page, numpage, proc);
1614         }
1615 #endif
1616 #ifdef _PMENTREZ_
1617 	if (DatabaseExistsInPubMed(type))
1618         {
1619             return PMTermListByPage(type, field, page, numpage, proc);
1620         }
1621 #endif
1622         return CdTermListByPage(type, field, page, numpage, proc);
1623 #endif
1624 #ifdef _NETENTREZ_
1625     case MEDIUM_NETWORK:
1626         return NetTermListByPage(type, field, page, numpage, proc);
1627 #endif
1628     default:
1629         return 0;
1630     }
1631 }
1632 
1633 /*****************************************************************************
1634 *
1635 *   EntrezFindTerm(type, field, term, spec, total)
1636 *       returns count of special and total for a term
1637 *       if term ends with  "...", does a truncated merge of the term
1638 *
1639 *****************************************************************************/
1640 NLM_EXTERN Boolean LIBCALL EntrezFindTerm (DocType type, DocField field, CharPtr term, Int4Ptr spcl, Int4Ptr totl)
1641 
1642 {
1643     if (! DoSelectDataSourceByType(type, "TERMS", NULL))
1644     {
1645         return 0;
1646     }
1647 
1648     switch (GetCurMediaType())
1649     {
1650 #ifdef _CDENTREZ_
1651     case MEDIUM_CD:
1652     case MEDIUM_DISK:
1653 #ifdef _MBENTREZ_
1654         if (type == TYP_ML && field != FLD_PROT /* FLD_PROT is MeSH glossary */)
1655         {
1656             return MBEntrezFindTerm (type, field, term, spcl, totl);
1657         }
1658 #endif
1659 #ifdef _PMENTREZ_
1660 	if (DatabaseExistsInPubMed(type))
1661         {
1662             return PMEntrezFindTerm (type, field, term, spcl, totl);
1663         }
1664 #endif
1665         return CdEntrezFindTerm (type, field, term, spcl, totl);
1666 #endif
1667 #ifdef _NETENTREZ_
1668     case MEDIUM_NETWORK:
1669         return NetEntrezFindTerm (type, field, term, spcl, totl);
1670 #endif
1671     default:
1672         return 0;
1673     }
1674 }
1675 
1676 
1677 /*****************************************************************************
1678 *
1679 *   EntrezUidLinks()
1680 *       retrieves links to other uids
1681 *
1682 *****************************************************************************/
1683 NLM_EXTERN LinkSetPtr LIBCALL EntrezUidLinks (DocType type, DocUid uid, DocType link_to_type)
1684 
1685 {
1686     LinkSetPtr lsp;
1687 
1688     if (! SelectDataLinksByTypes(type, link_to_type))
1689     {
1690         return NULL;
1691     }
1692 
1693     do {
1694         switch (GetCurMediaType())
1695         {
1696 #ifdef _CDENTREZ_
1697         case MEDIUM_CD:
1698         case MEDIUM_DISK:
1699 #ifdef _MBENTREZ_
1700             if (type == TYP_ML && link_to_type == TYP_ML)
1701             {
1702                 return MBUidLinks(type, uid, link_to_type);
1703             }
1704 #endif
1705 #ifdef _PMENTREZ_
1706 	    return PMUidLinks(type, uid, link_to_type);
1707 #else
1708             if ((lsp = CdUidLinks(type, uid, link_to_type)) != NULL)
1709                 return lsp;
1710             break;
1711 #endif /* _PMENTREZ_ */
1712 
1713 #endif
1714 #ifdef _NETENTREZ_
1715         case MEDIUM_NETWORK:
1716             if ((lsp = NetUidLinks(type, uid, link_to_type)) != NULL)
1717                 return lsp;
1718             break;
1719 #endif
1720         default:
1721             break;
1722         }
1723     } while (SelectNextDataSource());
1724 
1725     return NULL;
1726 }
1727 
1728 
1729 /*****************************************************************************
1730 *
1731 *   EntrezLinkUidList(type, link_to_type, numuid, uids)
1732 *       returns count of input uids processed
1733 *       returns -1 on error
1734 *       if neighbors (type == link_to_type)
1735 *           sums weights for same uids
1736 *       if (more than EntrezUserMaxLinks() uids, frees uids and weights,
1737 *           but leaves num set)
1738 *
1739 *****************************************************************************/
1740 NLM_EXTERN Int2 LIBCALL EntrezLinkUidList (LinkSetPtr PNTR result, DocType type, DocType link_to_type, Int2 numuid, Int4Ptr uids, Boolean mark_missing)
1741 
1742 {
1743     Int2 obtained_ids = 0;
1744     Int4Ptr local_uids;
1745     Int4Ptr best_obtained_uids;
1746     Int2 best_obtained_ids = 0;
1747     LinkSetPtr best_lsp = NULL;
1748     LinkSetPtr lsp;
1749     Int2 i;
1750     Int2 missing = 0;
1751     Int2 fewest_missing = numuid + 1;
1752     Boolean badErr = FALSE;
1753 
1754     if (numuid == 0)
1755         return 0;
1756 
1757     if (! SelectDataLinksByTypes(type, link_to_type))
1758     { /* ERROR, data unobtainable */
1759         return 0;
1760     }
1761 
1762     local_uids = (Int4Ptr) MemNew(numuid * sizeof(Int4));
1763     best_obtained_uids = (Int4Ptr) MemNew(numuid * sizeof(Int4));
1764 
1765     /* Try the various available data sources, and return "successfully" if   */
1766     /* a data source is located with neighbors for all requested UIDs.        */
1767     /* If no such data source can be located, then try all data sources,      */
1768     /* selecting the one for which the most possible UIDs have neighbors.     */
1769     /* When two or more UIDs have the same number of UIDs with neighbors, use */
1770     /* the number of obtained neighbors as a tie-breaker.                     */
1771 
1772     do {
1773         MemCopy (local_uids, uids, numuid * sizeof(*uids));
1774 
1775         switch (GetCurMediaType())
1776         {
1777 #ifdef _CDENTREZ_
1778         case MEDIUM_CD:
1779         case MEDIUM_DISK:
1780 #ifdef _MBENTREZ_
1781             if (type == TYP_ML && link_to_type == TYP_ML)
1782             {
1783 		obtained_ids = MBLinkUidList(&lsp, type, link_to_type, numuid,
1784 				             local_uids, TRUE);
1785                 break;
1786             }
1787 #endif
1788 #ifdef _PMENTREZ_
1789 	    obtained_ids = PMLinkUidList(&lsp, type, link_to_type, numuid,
1790 					 local_uids, TRUE);
1791 	    break;
1792 
1793 #else
1794             obtained_ids =  CdLinkUidList(&lsp, type, link_to_type, numuid,
1795                                           local_uids, TRUE);
1796             break;
1797 
1798 #endif /* _PMENTREZ_ */
1799 #endif
1800 #ifdef _NETENTREZ_
1801         case MEDIUM_NETWORK:
1802             obtained_ids =  NetLinkUidList(&lsp, type, link_to_type, numuid,
1803                                            local_uids, TRUE);
1804             break;
1805 #endif
1806         default:
1807             badErr = TRUE;
1808             break;
1809         }
1810 
1811         if (badErr)
1812             break;
1813 
1814         for (missing = 0, i = 0; i < numuid; i++)
1815         {
1816             if (local_uids[i] < 0)
1817                 missing++;
1818         }
1819 
1820         if (missing == 0) /* success */
1821         {
1822             break;
1823         }
1824 
1825         if (missing <= fewest_missing)
1826         {
1827             if (missing < fewest_missing || best_lsp == NULL ||
1828                 lsp->num > best_lsp->num)
1829             { /* found a better match */
1830                 if (best_lsp != NULL)
1831                     LinkSetFree(best_lsp);
1832                 best_lsp = lsp;
1833                 fewest_missing = missing;
1834                 best_obtained_ids = obtained_ids;
1835                 MemCopy(best_obtained_uids, local_uids, numuid * sizeof(*uids));
1836             }
1837         }
1838         else {
1839             LinkSetFree(lsp);
1840         }
1841     } while (SelectNextDataSource()); /* until we've run out of options */
1842 
1843     if (missing == 0)
1844     { /* found neighbors for all UIDs */
1845         if (best_lsp != NULL)
1846             LinkSetFree(best_lsp);
1847         *result = lsp;
1848         if (mark_missing)
1849             MemCopy(uids, local_uids, numuid * sizeof(*uids));
1850         MemFree(local_uids);
1851         MemFree(best_obtained_uids);
1852         return obtained_ids;
1853     }
1854     else { /* couldn't find links for all; return best */
1855         *result = best_lsp;
1856         if (mark_missing)
1857             MemCopy(uids, best_obtained_uids, numuid * sizeof(*uids));
1858         MemFree(local_uids);
1859         MemFree(best_obtained_uids);
1860         return best_obtained_ids;
1861     }
1862 }
1863 
1864 /*****************************************************************************
1865 *
1866 *   EntrezMedlineEntryListGet (result, numuid, uids, mark_missing)
1867 *       returns a count of entries read
1868 *       if (mark_missing) ids which could not be located are made negative
1869 *
1870 *****************************************************************************/
1871 NLM_EXTERN Int2 LIBCALL EntrezMedlineEntryListGet(MedlineEntryPtr PNTR result, Int2 numuid,
1872                          Int4Ptr uids, Boolean mark_missing)
1873 {
1874     Int2    obtained_ids = 0;
1875     Int4Ptr local_uids;
1876     int     unmatched;
1877     Int4Ptr map;
1878     Boolean first_time;
1879     MedlineEntryPtr PNTR res;
1880     Int2    i;
1881 
1882     if (numuid == 0)
1883         return 0;
1884 
1885 #ifdef _PMENTREZ_
1886     return PMEntMedlineEntryListGet (result, numuid, uids);
1887 #else
1888 
1889     first_time = TRUE;
1890 
1891     if (! DoSelectDataSource(ENTR_REF_CHAN, "RECORDS", NULL)) /* MEDLINE DATA (Abstracts) */
1892     {
1893         /* ERROR, data unobtainable */
1894         return 0;
1895     }
1896 
1897     local_uids = (Int4Ptr) MemDup(uids, numuid * sizeof(*uids));
1898     res = (MedlineEntryPtr PNTR) MemNew(numuid * sizeof(MedlineEntryPtr));
1899     map = (Int4Ptr) MemNew(numuid * sizeof(Int4));
1900 
1901     do {
1902         switch (GetCurMediaType())
1903         {
1904 #ifdef _CDENTREZ_
1905         case MEDIUM_CD:
1906         case MEDIUM_DISK:
1907 #ifdef _MBENTREZ_
1908             obtained_ids += MBEntMedlineEntryListGet (res, numuid, local_uids, TRUE);
1909             break;
1910 #endif
1911             obtained_ids += CdEntMedlineEntryListGet (res, numuid, local_uids, TRUE);
1912         break;
1913 #endif
1914 #ifdef _NETENTREZ_
1915         case MEDIUM_NETWORK:
1916             obtained_ids += NetEntMedlineEntryListGet (res, numuid, local_uids, TRUE);
1917             break;
1918 #endif
1919         default:
1920             break;
1921         }
1922 
1923         for (unmatched = 0, i = 0; i < numuid; i++)
1924         {
1925             if (local_uids[i] >= 0) /* found this one */
1926             {
1927                 if (first_time)
1928                 {
1929                     result[i] = res[i];
1930                 }
1931                 else
1932                 { /* map the location */
1933                     result[map[i]] = res[i];
1934                 }
1935             }
1936             else {
1937                 if (first_time)
1938                 {
1939                     result[i] = NULL;
1940                     if (mark_missing)
1941                         uids[i] = local_uids[i];
1942                     map[unmatched] = i;
1943                 }
1944                 else {
1945                     map[unmatched] = map[i];
1946                 }
1947                 local_uids[unmatched] = ABS(local_uids[i]);
1948                 unmatched++;
1949             }
1950         }
1951 
1952         numuid = unmatched;
1953         first_time = FALSE;
1954 
1955     } while (numuid > 0 && SelectNextDataSource()); /* until we've run out of options */
1956 
1957     MemFree (local_uids);
1958     MemFree (res);
1959     MemFree (map);
1960 
1961     return obtained_ids;
1962 #endif
1963 }
1964 
1965 /*****************************************************************************
1966 *
1967 *   EntrezMedlineEntryGet(uid)
1968 *       get one MedlineEntry
1969 *
1970 *****************************************************************************/
1971 NLM_EXTERN MedlineEntryPtr LIBCALL EntrezMedlineEntryGet (Int4 uid)
1972 
1973 {
1974     MedlineEntryPtr mep = NULL;
1975     ErrStrId errorID;
1976     char errorString[35];
1977 
1978         sprintf(errorString, "(EntrezMedlineEntryGet: %ld)",(long)uid);
1979         errorID = Nlm_ErrUserInstall(errorString, 0);
1980 
1981     EntrezMedlineEntryListGet(&mep, 1, &uid, FALSE);
1982     Nlm_ErrUserDelete(errorID);
1983 
1984     return mep;
1985 }
1986 
1987 
1988 /*****************************************************************************
1989 *
1990 *   EntrezPubmedEntryListGet (result, numuid, uids, mark_missing)
1991 *       returns a count of entries read
1992 *       if (mark_missing) ids which could not be located are made negative
1993 *
1994 *****************************************************************************/
1995 #ifdef _PMENTREZ_
1996 
1997 Int2 LIBCALL EntrezPubmedEntryListGet(PubmedEntryPtr PNTR result, Int2 numuid,
1998                          Int4Ptr uids, Boolean mark_missing)
1999 {
2000     Int2    obtained_ids = 0;
2001     Int4Ptr local_uids;
2002     int     unmatched;
2003     Int4Ptr map;
2004     Boolean first_time;
2005     PubmedEntryPtr PNTR res;
2006     Int2    i;
2007 
2008     if (numuid == 0)
2009         return 0;
2010 
2011     first_time = TRUE;
2012 
2013     if (! DoSelectDataSource(ENTR_REF_CHAN, "RECORDS", NULL))
2014       {
2015         /* ERROR, data unobtainable */
2016         return 0;
2017       }
2018 
2019     local_uids = (Int4Ptr) MemDup(uids, numuid * sizeof(*uids));
2020     res = (PubmedEntryPtr PNTR) MemNew(numuid * sizeof(PubmedEntryPtr));
2021     map = (Int4Ptr) MemNew(numuid * sizeof(Int4));
2022 
2023     do {
2024         switch (GetCurMediaType())
2025         {
2026 #ifdef _CDENTREZ_
2027         case MEDIUM_CD:
2028         case MEDIUM_DISK:
2029 #ifdef _PMENTREZ_
2030             obtained_ids += PubmedEntryListGet (res, numuid, local_uids, TRUE);
2031             break;
2032 #endif
2033         break;
2034 #endif
2035 #ifdef _NETENTREZ_
2036         case MEDIUM_NETWORK:
2037             obtained_ids += NetEntPubmedEntryListGet (res, numuid, local_uids, TRUE);
2038             break;
2039 #endif
2040         default:
2041             break;
2042         }
2043 
2044         for (unmatched = 0, i = 0; i < numuid; i++)
2045         {
2046             if (local_uids[i] >= 0) /* found this one */
2047             {
2048                 if (first_time)
2049                 {
2050                     result[i] = res[i];
2051                 }
2052                 else
2053                 { /* map the location */
2054                     result[map[i]] = res[i];
2055                 }
2056             }
2057             else {
2058                 if (first_time)
2059                 {
2060                     result[i] = NULL;
2061                     if (mark_missing)
2062                         uids[i] = local_uids[i];
2063                     map[unmatched] = i;
2064                 }
2065                 else {
2066                     map[unmatched] = map[i];
2067                 }
2068                 local_uids[unmatched] = ABS(local_uids[i]);
2069                 unmatched++;
2070             }
2071         }
2072 
2073         numuid = unmatched;
2074         first_time = FALSE;
2075 
2076     } while (numuid > 0 && SelectNextDataSource()); /* until we've run out of options */
2077 
2078     MemFree (local_uids);
2079     MemFree (res);
2080     MemFree (map);
2081 
2082     return obtained_ids;
2083 }
2084 
2085 /*****************************************************************************
2086 *
2087 *   EntrezPubmedEntryGet(uid)
2088 *       get one PubmedEntry
2089 *
2090 *****************************************************************************/
2091 PubmedEntryPtr LIBCALL EntrezPubmedEntryGet (Int4 uid)
2092 
2093 {
2094     PubmedEntryPtr mep = NULL;
2095 
2096     EntrezPubmedEntryListGet(&mep, 1, &uid, FALSE);
2097     return mep;
2098 }
2099 
2100 #endif
2101 
2102 /*****************************************************************************
2103 *
2104 *   EntrezBiostrucGet(uid, Int4 mdlLvl, Int4 maxModels)
2105 *       get one Biostruc
2106 *
2107 *****************************************************************************/
2108 
2109 #ifdef Biostruc_supported
2110 
2111 NLM_EXTERN BiostrucPtr LIBCALL EntrezBiostrucGet (DocUid uid, Int4 mdlLvl, Int4 maxModels)
2112 {
2113     BiostrucPtr retval = NULL;
2114 
2115 #ifdef _PMENTREZ_
2116     return PMEntrezBiostrucGet(uid,mdlLvl,maxModels);
2117 #else
2118 
2119     if (! DoSelectDataSource(ENTR_SEQ_CHAN, "RECORDS", NULL)) /* SEQUENCE DATA (Abstracts) */
2120     {
2121         /* ERROR, data unobtainable */
2122         return NULL;
2123     }
2124 
2125     switch (GetCurMediaType())
2126     {
2127 #ifdef _CDENTREZ_
2128     case MEDIUM_CD:
2129     case MEDIUM_DISK:
2130         return CdEntrezBiostrucGet(uid, mdlLvl, maxModels);
2131 #endif
2132 #ifdef _NETENTREZ_
2133     case MEDIUM_NETWORK:
2134         NetEntrezBiostrucListGet(&retval, mdlLvl, maxModels, 1, &uid, FALSE);
2135         return retval;
2136 #endif
2137     default:
2138         return NULL;
2139     }
2140 #endif
2141 }
2142 
2143 NLM_EXTERN BiostrucAnnotSetPtr LIBCALL EntrezBiostrucAnnotSetGet (DocUid uid)
2144 {
2145     if (! DoSelectDataSource(ENTR_SEQ_CHAN, "RECORDS", NULL)) /* SEQUENCE DATA (Abstracts) */
2146     {
2147         /* ERROR, data unobtainable */
2148         return NULL;
2149     }
2150 
2151     switch (GetCurMediaType())
2152     {
2153 #ifdef _CDENTREZ_
2154     case MEDIUM_CD:
2155     case MEDIUM_DISK:
2156         return CdEntrezBiostrucAnnotSetGet(uid);
2157 #endif
2158 #ifdef _NETENTREZ_
2159     case MEDIUM_NETWORK:
2160         return NetEntrezBiostrucAnnotSetGet(uid);
2161 #endif
2162     default:
2163         return NULL;
2164     }
2165 }
2166 
2167 NLM_EXTERN LinkSetPtr LIBCALL EntrezBiostrucFeatIds(DocUid mmdbid, Int2 feature_type, Int4 feature_set_id)
2168 {
2169     if (! DoSelectDataSource(ENTR_SEQ_CHAN, "RECORDS", NULL)) /* SEQUENCE DATA (Abstracts) */
2170     {
2171         /* ERROR, data unobtainable */
2172         return NULL;
2173     }
2174 
2175     switch (GetCurMediaType())
2176     {
2177 #ifdef _CDENTREZ_
2178     case MEDIUM_CD:
2179     case MEDIUM_DISK:
2180         return CdEntrezBiostrucFeatIds(mmdbid, feature_type, feature_set_id);
2181 #endif
2182 #ifdef _NETENTREZ_
2183     case MEDIUM_NETWORK:
2184         return NetEntrezBiostrucFeatIds(mmdbid, feature_type, feature_set_id);
2185 #endif
2186     default:
2187         return NULL;
2188     }
2189 }
2190 
2191 
2192 NLM_EXTERN BiostrucAnnotSetPtr LIBCALL EntrezBiostrucAnnotSetGetByFid (DocUid mmdbid, Int4 feature_id, Int4 feature_set_id)
2193 {
2194     if (! DoSelectDataSource(ENTR_SEQ_CHAN, "RECORDS", NULL)) /* SEQUENCE DATA (Abstracts) */
2195     {
2196         /* ERROR, data unobtainable */
2197         return NULL;
2198     }
2199 
2200     switch (GetCurMediaType())
2201     {
2202 #ifdef _CDENTREZ_
2203     case MEDIUM_CD:
2204     case MEDIUM_DISK:
2205         return CdEntrezBiostrucAnnotSetGetByFid (mmdbid, feature_id, feature_set_id);
2206 #endif
2207 #ifdef _NETENTREZ_
2208     case MEDIUM_NETWORK:
2209         return NetEntrezBiostrucAnnotSetGetByFid (mmdbid, feature_id, feature_set_id);
2210 #endif
2211     default:
2212         return NULL;
2213     }
2214 }
2215 
2216 #else
2217 
2218 NLM_EXTERN BiostrucPtr LIBCALL EntrezBiostrucGet (DocUid uid, Int4 mdlLvl, Int4 maxModels)
2219 {
2220         return NULL;
2221 }
2222 
2223 NLM_EXTERN BiostrucAnnotSetPtr LIBCALL EntrezBiostrucAnnotSetGet (DocUid uid)
2224 {
2225         return NULL;
2226 }
2227 
2228 NLM_EXTERN LinkSetPtr LIBCALL EntrezBiostrucFeatIds(DocUid mmdbid, Int2 feature_type, Int4 feature_set_id)
2229 {
2230         return NULL;
2231 }
2232 
2233 NLM_EXTERN BiostrucAnnotSetPtr LIBCALL EntrezBiostrucAnnotSetGetByFid (DocUid mmdbid, Int4 feature_id, Int4 feature_set_id)
2234 {
2235         return NULL;
2236 }
2237 #endif
2238 
2239 
2240 
2241 /*****************************************************************************
2242 *
2243 *   EntrezSeqEntryListGet (result, numuid, uids, retcode, mark_missing)
2244 *       returns a count of entries read
2245 *       if (mark_missing) ids which could not be located are made negative
2246 *       retcode is defined in objsset.h
2247 *
2248 *****************************************************************************/
2249 NLM_EXTERN Int2 LIBCALL EntrezSeqEntryListGet (SeqEntryPtr PNTR result, Int2 numuid, Int4Ptr uids, Int2 retcode, Boolean mark_missing)
2250 
2251 {
2252     Int2    obtained_ids = 0;
2253     Int4Ptr local_uids;
2254     int     unmatched;
2255     Int4Ptr map;
2256     Boolean first_time;
2257     SeqEntryPtr PNTR res;
2258     Int2    i;
2259     /* DocType type; */
2260 
2261     if (numuid == 0)
2262         return 0;
2263 
2264 #ifdef _PMENTREZ_
2265     return PMEntSeqEntryListGet (result, numuid, uids,retcode);
2266 #else
2267 
2268     first_time = TRUE;
2269 
2270     if (! DoSelectDataSource(ENTR_SEQ_CHAN, "RECORDS", NULL)) /* SEQUENCE DATA (Abstracts) */
2271     {
2272         /* ERROR, data unobtainable */
2273         return 0;
2274     }
2275 
2276     local_uids = (Int4Ptr) MemDup(uids, numuid * sizeof(*uids));
2277     res = (SeqEntryPtr PNTR) MemNew(numuid * sizeof(SeqEntryPtr));
2278     map = (Int4Ptr) MemNew(numuid * sizeof(Int4));
2279 
2280     do {
2281         switch (GetCurMediaType())
2282         {
2283 #ifdef _CDENTREZ_
2284         case MEDIUM_CD:
2285         case MEDIUM_DISK:
2286             if (retcode == -2)
2287                 obtained_ids = 0;
2288             else
2289                 obtained_ids += CdEntSeqEntryListGet (res, numuid, local_uids,
2290                                                       retcode, TRUE);
2291 #ifdef USE_IDxARCH
2292             if (retcode != -1 && obtained_ids < numuid && ConnectID())
2293             {
2294                 Int2 i;
2295 
2296                 /* for entries which are to be explicitly retrieved from ID */
2297                 if (retcode == -2)
2298                     retcode = 0;
2299 
2300                 for (i = 0; i < numuid; i++)
2301                 {
2302                     if (res[i] == NULL)
2303                     {
2304                         if ((res[i] = IDxArchSeqEntryGet(ABS(local_uids[i]),
2305 							 NULL, retcode))
2306                              != NULL)
2307                         {
2308                             local_uids[i] = ABS(local_uids[i]);
2309                             obtained_ids++;
2310                         }
2311                     }
2312                 }
2313             }
2314 #endif /* USE_IDxARCH */
2315         break;
2316 #endif
2317 #ifdef _NETENTREZ_
2318         case MEDIUM_NETWORK:
2319             obtained_ids += NetEntSeqEntryListGet (res, numuid, local_uids,
2320                                                 retcode, TRUE);
2321             break;
2322 #endif
2323         default:
2324             break;
2325         }
2326 
2327         for (unmatched = 0, i = 0; i < numuid; i++)
2328         {
2329             if (local_uids[i] >= 0) /* found this one */
2330             {
2331                 if (first_time)
2332                 {
2333                     result[i] = res[i];
2334                 }
2335                 else
2336                 { /* map the location */
2337                     result[map[i]] = res[i];
2338                 }
2339             }
2340             else {
2341                 if (first_time)
2342                 {
2343                     result[i] = NULL;
2344                     if (mark_missing)
2345                         uids[i] = local_uids[i];
2346                     map[unmatched] = i;
2347                 }
2348                 else {
2349                     map[unmatched] = map[i];
2350                 }
2351                 local_uids[unmatched] = ABS(local_uids[i]);
2352                 unmatched++;
2353             }
2354         }
2355 
2356         numuid = unmatched;
2357         first_time = FALSE;
2358 
2359     } while (numuid > 0 && SelectNextDataSource()); /* until we've run out of options */
2360 
2361     MemFree (local_uids);
2362     MemFree (res);
2363     MemFree (map);
2364 
2365     return obtained_ids;
2366 #endif
2367 }
2368 
2369 /*****************************************************************************
2370 *
2371 *   EntrezSeqEntryGet(uid, retcode)
2372 *       get one SeqEntry
2373 *
2374 *****************************************************************************/
2375 NLM_EXTERN SeqEntryPtr EntrezSeqEntryGet (Int4 uid, Int2 retcode)
2376 
2377 {
2378     SeqEntryPtr sep = NULL;
2379     ErrStrId errorID;
2380     char errorString[32];
2381 
2382 	if (! uid) return sep;
2383         sprintf(errorString, "(EntrezSeqEntryGet: %ld)",(long)uid);
2384         errorID = Nlm_ErrUserInstall(errorString, 0);
2385 
2386     EntrezSeqEntryListGet(&sep, 1, &uid, retcode, FALSE);
2387     Nlm_ErrUserDelete(errorID);
2388     return sep;
2389 }
2390 
2391 /*****************************************************************************
2392 *
2393 *   EntrezFindSeqId(sip)
2394 *       given a Seq-id, get the uid.
2395 *       returns 0 on failure
2396 *
2397 *****************************************************************************/
2398 NLM_EXTERN Int4 LIBCALL EntrezFindSeqId (SeqIdPtr sip)
2399 {
2400 #ifdef _CDENTREZ_
2401   Int4 uid;
2402 #endif
2403 
2404 #ifdef _PMENTREZ_
2405   return PMEntrezSeqIdToGI(sip);
2406 #else
2407 
2408 	if (sip == NULL) return 0;
2409 	switch (sip->choice)
2410 	{
2411 		case SEQID_NOT_SET:
2412 		case SEQID_LOCAL:
2413 		case SEQID_OTHER:
2414 		case SEQID_GENERAL:
2415 			return 0;
2416 		default:
2417 			break;
2418 	}
2419 
2420     if (! DoSelectDataSourceByType(TYP_SEQ, "TERMS", NULL))
2421     {
2422         return 0;
2423     }
2424 
2425     switch (GetCurMediaType())
2426     {
2427 #ifdef _CDENTREZ_
2428     case MEDIUM_CD:
2429     case MEDIUM_DISK:
2430         uid = CdEntrezFindSeqId(sip);
2431 #ifdef USE_IDxARCH
2432         if (uid == 0 && ConnectID())
2433         {
2434  	    TextSeqIdPtr tsip;
2435 
2436             switch (sip->choice) {
2437             case SEQID_GENBANK:
2438             case SEQID_EMBL:
2439             case SEQID_PIR:
2440             case SEQID_SWISSPROT:
2441             case SEQID_DDBJ:
2442             case SEQID_PRF:
2443             case SEQID_OTHER:
2444                 if ((tsip = (TextSeqIdPtr) sip->data.ptrvalue) != NULL)
2445                 {
2446                     if (tsip->name != NULL)
2447                     {
2448                         StringUpper(tsip->name);
2449                     }
2450                     if (tsip->accession != NULL)
2451                     {
2452                         StringUpper(tsip->accession);
2453                     }
2454                     if (sip->choice == SEQID_PIR)
2455                     {
2456                         if (tsip->name == NULL)
2457                         { /* move accession to name */
2458                             tsip->accession = tsip->name;
2459                             tsip->name = NULL;
2460                         } else { /* destroy accession */
2461                             tsip->accession = (CharPtr) MemFree (tsip->accession);
2462                         }
2463                     } else {
2464                         if (tsip->name != NULL && tsip->accession != NULL)
2465                         {
2466                             tsip->name = (CharPtr) MemFree (tsip->name);
2467                         }
2468                     }
2469                 }
2470                 break;
2471             default:
2472                 break;
2473             }
2474             uid = IDxArchGIGet(sip);
2475         }
2476 #endif
2477         return uid;
2478 #endif
2479 #ifdef _NETENTREZ_
2480     case MEDIUM_NETWORK:
2481         return NetEntrezFindSeqId(sip);
2482 #endif
2483     default:
2484         return 0;
2485     }
2486 #endif /* _PMENTREZ_ */
2487 
2488 }
2489 
2490 
2491 /*****************************************************************************
2492 *
2493 *   EntrezSeqIdForGI(gi)
2494 *
2495 *****************************************************************************/
2496 NLM_EXTERN SeqIdPtr LIBCALL EntrezSeqIdForGI (Int4 gi)
2497 {
2498     SeqIdPtr sip = NULL;
2499 
2500 #ifdef _PMENTREZ_
2501     return PMEntrezGIToSeqId(gi);
2502 #else
2503 
2504     if (! gi) return sip;
2505 
2506     if (! DoSelectDataSourceByType(TYP_SEQ, "DOCSUMS", NULL))
2507     { /* ERROR, data unobtainable */
2508         return NULL;
2509     }
2510 
2511     do {
2512         switch (GetCurMediaType())
2513         {
2514 #ifdef _CDENTREZ_
2515         case MEDIUM_CD:
2516         case MEDIUM_DISK:
2517             if ((sip = CdSeqIdForGI (gi)) != NULL)
2518                 return sip;
2519             break;
2520 #endif
2521 #ifdef _NETENTREZ_
2522         case MEDIUM_NETWORK:
2523             if ((sip = NetSeqIdForGI (gi)) != NULL)
2524                 return sip;
2525             break;
2526 #endif
2527         default:
2528             break;
2529         }
2530     } while (SelectNextDataSource());
2531 
2532     return sip;
2533 
2534 #endif /* _PMENTREZ_ */
2535 }
2536 
2537 
2538 /*****************************************************************************
2539 *
2540 *   EntrezMlSumListGet (result, numuid, uids)
2541 *       returns a count of entries read
2542 *       head of linked list is in result
2543 *
2544 *****************************************************************************/
2545 NLM_EXTERN Int2 LIBCALL EntrezMlSumListGet (DocSumPtr PNTR result, Int2 numuid, Int4Ptr uids)
2546 
2547 {
2548     Int2 obtained_ids = 0;
2549     Int4Ptr local_uids;
2550     Int2 unmatched;
2551     Int4Ptr map;
2552     Boolean first_time = TRUE;
2553     DocSumPtr PNTR res;
2554     Int2    i;
2555 
2556     if (numuid == 0)
2557         return 0;
2558 
2559     if (! DoSelectDataSource(ENTR_LINKS_CHAN, ENTR_REF_CHAN, ENTR_REF_CHAN))
2560     { /* ERROR, data unobtainable */
2561         return 0;
2562     }
2563 
2564     /* Iteratively try different data sources, working on an incrementally    */
2565     /* reduced number of UIDs, until either docsums have been found for all   */
2566     /* UIDs or,  all data sources have been exhausted. The algorithm uses a   */
2567     /* mapping mechanism to ensure that requests from a small subset of the   */
2568     /* initial requests always map their results back to the original result  */
2569     /* and uids vectors in a correct manner.                                  */
2570 
2571     local_uids = (Int4Ptr) MemDup(uids, numuid * sizeof(*uids));
2572     res = (DocSumPtr PNTR) MemNew(numuid * sizeof(DocSumPtr));
2573     map = (Int4Ptr) MemNew(numuid * sizeof(Int4));
2574 
2575     do {
2576         switch (GetCurMediaType())
2577         {
2578 #ifdef _CDENTREZ_
2579         case MEDIUM_CD:
2580         case MEDIUM_DISK:
2581 #ifdef _MBENTREZ_
2582             obtained_ids = MBEntMlSumListGet (res, numuid, local_uids);
2583             break;
2584 #endif
2585 #ifdef _PMENTREZ_
2586             obtained_ids = PMEntMlSumListGet (res, numuid, local_uids);
2587             break;
2588 #else
2589             obtained_ids = CdEntMlSumListGet (res, numuid, local_uids);
2590             break;
2591 #endif  /* _PMENTREZ_ */
2592 
2593 #endif
2594 #ifdef _NETENTREZ_
2595         case MEDIUM_NETWORK:
2596             obtained_ids = NetDocSumListGet (res, numuid, TYP_ML, local_uids, 0);
2597             break;
2598 #endif
2599         default:
2600             break;
2601         }
2602 
2603         for (unmatched = 0, i = 0; i < numuid; i++)
2604         {
2605             if (res[i] != NULL) /* found this one */
2606             {
2607                 if (first_time)
2608                 {
2609                     result[i] = res[i];
2610                 }
2611                 else
2612                 { /* map the location */
2613                     result[map[i]] = res[i];
2614                 }
2615             }
2616             else { /* not found */
2617                 if (first_time)
2618                 {
2619                     result[i] = NULL;
2620                     map[unmatched] = i;
2621                 }
2622                 else {
2623                     map[unmatched] = map[i];
2624                 }
2625                 local_uids[unmatched] = local_uids[i];
2626                 unmatched++;
2627             }
2628         }
2629 
2630         numuid = unmatched;
2631         first_time = FALSE;
2632 
2633     } while (numuid > 0 && SelectNextDataSource()); /* until we've run out of options */
2634 
2635     MemFree (local_uids);
2636     MemFree (res);
2637     MemFree (map);
2638 
2639     return obtained_ids;
2640 }
2641 
2642 /*****************************************************************************
2643 *
2644 *   EntrezSeqSumListGet (result, numuid, uids)
2645 *       returns a count of entries read
2646 *       head of linked list is in result
2647 *
2648 *****************************************************************************/
2649 NLM_EXTERN Int2 LIBCALL EntrezSeqSumListGet (DocSumPtr PNTR result, Int2 numuid, DocType type, Int4Ptr uids)          /* Gi numbers */
2650 
2651 {
2652     Int2      obtained_ids = 0;
2653     Int4Ptr   local_uids;
2654     Int2      unmatched;
2655     Int4Ptr   map;
2656     Boolean   first_time = TRUE;
2657     DocSumPtr PNTR res;
2658     Int2      i;
2659 
2660     if (numuid == 0)
2661         return 0;
2662 
2663     if (! DoSelectDataSource(ENTR_LINKS_CHAN, ENTR_SEQ_CHAN, ENTR_SEQ_CHAN))
2664     { /* ERROR, data unobtainable */
2665         return 0;
2666     }
2667 
2668     /* Iteratively try different data sources, working on an incrementally    */
2669     /* reduced number of UIDs, until either docsums have been found for all   */
2670     /* UIDs or,  all data sources have been exhausted. The algorithm uses a   */
2671     /* mapping mechanism to ensure that requests from a small subset of the   */
2672     /* initial requests always map their results back to the original result  */
2673     /* and uids vectors in a correct manner.                                  */
2674 
2675     local_uids = (Int4Ptr) MemDup(uids, numuid * sizeof(*uids));
2676     res = (DocSumPtr PNTR) MemNew(numuid * sizeof(DocSumPtr));
2677     map = (Int4Ptr) MemNew(numuid * sizeof(Int4));
2678 
2679     do {
2680         switch (GetCurMediaType())
2681         {
2682 #ifdef _CDENTREZ_
2683         case MEDIUM_CD:
2684         case MEDIUM_DISK:
2685             obtained_ids = CdEntSeqSumListGet (res, numuid, type, local_uids);
2686         break;
2687 #endif
2688 #ifdef _NETENTREZ_
2689         case MEDIUM_NETWORK:
2690             obtained_ids = NetDocSumListGet (res, numuid, type, local_uids, 0);
2691             break;
2692 #endif
2693         default:
2694             break;
2695         }
2696 
2697         for (unmatched = 0, i = 0; i < numuid; i++)
2698         {
2699 #ifdef USE_IDxARCH
2700             if (res[i] == NULL) /* missing this one, try again */
2701 	    {
2702                 if ((res[i] = EntrezDocSum (type, local_uids [i])) != NULL)
2703                     obtained_ids++;
2704 	    }
2705 #endif /* USE_IDxARCH */
2706             if (res[i] != NULL) /* found this one */
2707             {
2708                 if (first_time)
2709                 {
2710                     result[i] = res[i];
2711                 }
2712                 else
2713                 { /* map the location */
2714                     result[map[i]] = res[i];
2715                 }
2716             }
2717             else { /* not found */
2718                 if (first_time)
2719                 {
2720                     result[i] = NULL;
2721                     map[unmatched] = i;
2722                 }
2723                 else {
2724                     map[unmatched] = map[i];
2725                 }
2726                 local_uids[unmatched] = local_uids[i];
2727                 unmatched++;
2728             }
2729         }
2730 
2731         numuid = unmatched;
2732         first_time = FALSE;
2733 
2734     } while (numuid > 0 && SelectNextDataSource()); /* until we've run out of options */
2735 
2736     MemFree (local_uids);
2737     MemFree (res);
2738     MemFree (map);
2739 
2740     return obtained_ids;
2741 }
2742 
2743 typedef struct cachedParent {
2744     CharPtr term;
2745     CharPtr parent;
2746     DocType db;
2747     DocField fld;
2748 } CachedParent, PNTR CachedParentPtr;
2749 
2750 static ValNodePtr hierHead = NULL;
2751 
2752 static void
2753 FreeHierarchyList(void)
2754 {
2755     ValNodePtr v;
2756     CachedParentPtr q;
2757 
2758     for (v = hierHead; v != NULL; v = v->next)
2759     {
2760         q = (CachedParentPtr) v->data.ptrvalue;
2761         MemFree(q->term);
2762         MemFree(q->parent);
2763         MemFree(q);
2764         v->data.ptrvalue = NULL;
2765     }
2766     hierHead = ValNodeFree(hierHead);
2767 }
2768 
2769 static EntrezHierarchyPtr DoEntrezHierarchyGet(CharPtr term, DocType db, DocField fld)
2770 {
2771   switch (GetCurMediaType())
2772     {
2773 #ifdef _CDENTREZ_
2774     case MEDIUM_CD:
2775     case MEDIUM_DISK:
2776 #ifdef _MBENTREZ_
2777       return NULL;
2778 #endif
2779       return NULL;
2780 #endif
2781 
2782 #ifdef _NETENTREZ_
2783     case MEDIUM_NETWORK:
2784       return NetEntHierarchyGet(term,db,fld);
2785 #endif
2786     default:
2787       return NULL;
2788     }
2789 }
2790 
2791 
2792 NLM_EXTERN EntrezHierarchyPtr LIBCALL EntrezHierarchyGet(CharPtr term, DocType db, DocField fld)
2793 {
2794 #ifdef _PMENTREZ_
2795 
2796   return PMEntrezHierarchyGet(term,db,fld);
2797 
2798 #else
2799 
2800     /*
2801     if (term == NULL || (db != TYP_ML && fld != FLD_ORGN_HIER) ||
2802        (db == TYP_ML && fld != FLD_MESH_HIER))
2803     {
2804         return NULL;
2805     }
2806     */
2807 
2808     return DoEntrezHierarchyGet (term,db,fld);
2809 
2810 #endif
2811 }
2812 
2813 NLM_EXTERN Boolean LIBCALL EntrezCanNeighborText (void)
2814 {
2815     if (! SelectDataLinksByTypes(TYP_ML, TYP_ML))
2816     { /* ERROR, data unobtainable */
2817         return FALSE;
2818     }
2819 
2820     switch (GetCurMediaType())
2821     {
2822 #ifdef _CDENTREZ_
2823     case MEDIUM_CD:
2824     case MEDIUM_DISK:
2825 #ifdef _MBENTREZ_
2826         return TRUE;
2827 #endif
2828         return FALSE;
2829 #endif
2830 #ifdef _NETENTREZ_
2831     case MEDIUM_NETWORK:
2832         return NetEntCanNeighborText();
2833 #endif
2834     default:
2835         return FALSE;
2836     }
2837 }
2838 
2839 
2840 NLM_EXTERN LinkSetPtr LIBCALL EntrezDoNeighborText (EntrezNeighborTextPtr entp)
2841 {
2842     if (! SelectDataLinksByTypes(TYP_ML, TYP_ML))
2843     { /* ERROR, data unobtainable */
2844         return NULL;
2845     }
2846 
2847     switch (GetCurMediaType()) {
2848 #ifdef _CDENTREZ_
2849     case MEDIUM_CD:
2850     case MEDIUM_DISK:
2851 #ifdef _MBENTREZ_
2852         return MBEntDoNeighborText(entp);
2853 #endif
2854         return NULL;
2855 #endif
2856 #ifdef _NETENTREZ_
2857     case MEDIUM_NETWORK:
2858         return NetEntDoNeighborText(entp);
2859 #endif
2860     default:
2861         return NULL;
2862     }
2863 }
2864 
2865 
2866 /**************************************************
2867 *
2868 *    EntrezNeighborTextNew()
2869 *
2870 **************************************************/
2871 
2872 NLM_EXTERN EntrezNeighborTextPtr LIBCALL EntrezNeighborTextNew(void)
2873 {
2874    EntrezNeighborTextPtr ptr = MemNew((size_t) sizeof(EntrezNeighborText));
2875 
2876    return ptr;
2877 
2878 }
2879 
2880 
2881 /**************************************************
2882 *
2883 *    EntrezNeighborTextFree()
2884 *
2885 **************************************************/
2886 
2887 NLM_EXTERN EntrezNeighborTextPtr LIBCALL EntrezNeighborTextFree(EntrezNeighborTextPtr ptr)
2888 {
2889 
2890    if(ptr == NULL) {
2891       return NULL;
2892    }
2893    MemFree(ptr -> normalText);
2894    MemFree(ptr -> specialText);
2895    return MemFree(ptr);
2896 }
2897 
2898 
2899 NLM_EXTERN Boolean LIBCALL EntrezExpandedMedlineFeatures (void)
2900 {
2901 
2902     if (! SelectDataLinksByTypes(TYP_ML, TYP_ML))
2903     { /* ERROR, data unobtainable */
2904         return FALSE;
2905     }
2906 
2907     switch (GetCurMediaType())
2908     {
2909 #ifdef _CDENTREZ_
2910     case MEDIUM_CD:
2911     case MEDIUM_DISK:
2912 #ifdef _MBENTREZ_
2913         return TRUE;
2914 #endif
2915         return FALSE;
2916 #endif
2917 #ifdef _NETENTREZ_
2918     case MEDIUM_NETWORK:
2919         return NetEntExpandedMedlineFeatures();
2920 #endif
2921     default:
2922         return FALSE;
2923     }
2924 }
2925 
2926 
2927 
2928 NLM_EXTERN EntrezHierarchyPtr LIBCALL EntrezHierarchyFree(EntrezHierarchyPtr ehp)
2929 {
2930       Int2 i;
2931 
2932       if (ehp == NULL)
2933          return NULL;
2934       for (i = 0; i < ehp->numInLineage; i++)
2935          MemFree (ehp->lineage[i]);
2936       MemFree (ehp->lineage);
2937       for (i = 0; i < ehp->numChildren; i++)
2938       {
2939           MemFree (ehp->children[i].name);
2940       }
2941       MemFree (ehp->children);
2942       MemFree (ehp->term);
2943       MemFree (ehp->canonicalForm);
2944       MemFree (ehp);
2945 
2946       return NULL;
2947 }
2948 
2949 typedef struct entrezfetch {
2950         Uint1 EntrezBioseqFetchState;
2951         CharPtr EntrezBioseqFetchAppName;
2952         Boolean is_net;
2953 		  Uint2 ctr;        /* counts iterations of enable disable */
2954 } EntrezFetchStruct, PNTR EntrezFetchStructPtr;
2955 
2956 typedef struct entrezfetchuserdata {
2957 	Int4 gi;
2958 	Int2 retcode;
2959 } EntrezFetchUserData, PNTR EntrezFetchUserDataPtr;
2960 
2961 #define EBFS_DISABLE 0     /* EntrezBioseqFetch not in use (default) */
2962 #define EBFS_INIT    1     /* EntrezBioseqFetchEnable called, but not EntrezInit */
2963 #define EBFS_READY   2     /* EntrezInit has been called */
2964 
2965 static CharPtr procname[3] = {
2966 	"EntrezBioseqFetch",
2967 	"EntrezSeqIdForGI",
2968 	"EntrezGIForSeqId" };
2969 
2970 static Int2 LIBCALLBACK EntrezBioseqFetchFunc PROTO((Pointer data));
2971 static Int2 LIBCALLBACK EntrezSeqIdForGIFunc PROTO((Pointer data));
2972 static Int2 LIBCALLBACK EntrezGIForSeqIdFunc PROTO((Pointer data));
2973 
2974 /*****************************************************************************
2975 *
2976 *   The Following two functions allow access by BioseqFetch using the
2977 *   SeqMgr.  The application should call EntrezBioseqFetchEnable() at the start
2978 *   of the application and EntrezBioseqFetchDisable() at the end; This
2979 *   will make EntrezBioseqFetch() the "remote" access procedure for the
2980 *   SeqMgr. EntrezInit() will only be called on the first fetch unless "now"
2981 *   is true;
2982 *
2983 *****************************************************************************/
2984 NLM_EXTERN Boolean LIBCALL EntrezBioseqFetchEnable(CharPtr progname, Boolean now)
2985 {
2986         Boolean result;
2987         EntrezFetchStructPtr efsp;
2988         ObjMgrPtr omp;
2989         ObjMgrProcPtr ompp;
2990 
2991               /* check if already enabled ***/
2992 
2993         omp = ObjMgrGet();
2994         ompp = ObjMgrProcFind(omp, 0, procname[0], OMPROC_FETCH);
2995         if (ompp != NULL)   /* already initialized */
2996         		efsp = (EntrezFetchStructPtr)(ompp->procdata);
2997 		  else
2998 		  {
2999 	         efsp = MemNew(sizeof(EntrezFetchStruct));
3000 		      efsp->EntrezBioseqFetchAppName = StringSave(progname);
3001 
3002       		ObjMgrProcLoad(OMPROC_FETCH, procname[0], procname[0], OBJ_SEQID, 0,OBJ_BIOSEQ,0,
3003                         (Pointer)efsp, EntrezBioseqFetchFunc, PROC_PRIORITY_DEFAULT);
3004 
3005 				ObjMgrProcLoad(OMPROC_FETCH, procname[1], procname[1], OBJ_SEQID, SEQID_GI,OBJ_SEQID,0,
3006                         (Pointer)efsp, EntrezSeqIdForGIFunc, PROC_PRIORITY_DEFAULT);
3007 
3008       		ObjMgrProcLoad(OMPROC_FETCH, procname[2], procname[2], OBJ_SEQID, 0,OBJ_SEQID,SEQID_GI,
3009                         (Pointer)efsp, EntrezGIForSeqIdFunc, PROC_PRIORITY_DEFAULT);
3010 		  }
3011 
3012 		  efsp->ctr++;    /* count number of enables */
3013 
3014 		  if (efsp->EntrezBioseqFetchState == EBFS_READY)  /* nothing more to do */
3015 			  return TRUE;
3016 
3017         if (now)
3018         {
3019                 result = EntrezInit(progname, TRUE, &(efsp->is_net));
3020                 if (! result)
3021                 {
3022                         return result;
3023                 }
3024                 efsp->EntrezBioseqFetchState = EBFS_READY;
3025         }
3026         else
3027                 efsp->EntrezBioseqFetchState = EBFS_INIT;
3028 
3029 
3030         return TRUE;
3031 
3032 }
3033 
3034 /*****************************************************************************
3035 *
3036 *   EntrezBioseqFetchDisable()
3037 *
3038 *****************************************************************************/
3039 NLM_EXTERN void LIBCALL EntrezBioseqFetchDisable(void)
3040 {
3041         ObjMgrPtr omp;
3042         ObjMgrProcPtr ompp;
3043         EntrezFetchStructPtr efsp;
3044 
3045         omp = ObjMgrGet();
3046         ompp = ObjMgrProcFind(omp, 0, procname[0], OMPROC_FETCH);
3047         if (ompp == NULL)   /* not initialized */
3048                 return;
3049 
3050         efsp = (EntrezFetchStructPtr)(ompp->procdata);
3051 		  if (! efsp->ctr)   /* no enables active */
3052 			  return;
3053 
3054 		  efsp->ctr--;
3055 		  if (efsp->ctr)   /* connection still pending */
3056 			  return;
3057 
3058         if (efsp->EntrezBioseqFetchState == EBFS_READY)
3059                 EntrezFini();
3060 
3061 		  efsp->EntrezBioseqFetchState = EBFS_DISABLE;  /* not active */
3062 
3063         return;
3064 }
3065 
3066 /*****************************************************************************
3067 *
3068 *   EntrezFetchFreeFunc(ptr)
3069 *     removes EntrezFetchUserData
3070 *
3071 *****************************************************************************/
3072 static Pointer LIBCALLBACK EntrezFetchFreeFunc (Pointer ptr)
3073 {
3074 	EntrezFetchUserDataPtr efudp;
3075 
3076 	efudp = (EntrezFetchUserDataPtr)ptr;
3077 	return MemFree(efudp);
3078 }
3079 
3080 /*****************************************************************************
3081 *
3082 *   EntrezBioseqFetchFunc(data)
3083 *       callback for EntrezBioseqFetch
3084 *
3085 *****************************************************************************/
3086 static Int2 LIBCALLBACK EntrezBioseqFetchFunc (Pointer data)
3087 {
3088         OMProcControlPtr ompcp;
3089         ObjMgrProcPtr ompp;
3090         EntrezFetchStructPtr efsp;
3091         SeqIdPtr sip;
3092         OMUserDataPtr omdp;
3093         Boolean result;
3094         BioseqPtr bsp = NULL;
3095         Int4 gi=0;
3096         SeqEntryPtr sep;
3097 	/* ValNode fake_seqid; */
3098 			EntrezFetchUserDataPtr efudp;
3099 			Int2 retcode=0;
3100 
3101         ompcp = (OMProcControlPtr)data;
3102         ompp = ompcp->proc;
3103         efsp = (EntrezFetchStructPtr)(ompp->procdata);
3104 
3105 		  if (efsp->EntrezBioseqFetchState == EBFS_DISABLE)  /* shut off */
3106 		  {
3107 		  	    return OM_MSG_RET_OK;    /* not done, go on to next */
3108 		  }
3109         else if (efsp->EntrezBioseqFetchState == EBFS_INIT)
3110         {
3111                 result = EntrezInit(efsp->EntrezBioseqFetchAppName, TRUE, &(efsp->is_net));
3112                 if (! result)
3113                     return OM_MSG_RET_ERROR;
3114                 efsp->EntrezBioseqFetchState = EBFS_READY;
3115         }
3116 
3117         if (efsp->EntrezBioseqFetchState != EBFS_READY)
3118                 return OM_MSG_RET_ERROR;
3119 
3120                                         /* check for cached gi */
3121         if (ompcp->input_entityID)
3122         {
3123                 omdp = ObjMgrGetUserData(ompcp->input_entityID,ompp->procid, OMPROC_FETCH, 0);
3124                 if (omdp != NULL)
3125 					 {
3126 						efudp = (EntrezFetchUserDataPtr)(omdp->userdata.ptrvalue);
3127 						if (efudp != NULL)
3128 						{
3129 							gi = efudp->gi;
3130 							retcode = efudp->retcode;
3131 						}
3132 					}
3133         }
3134 
3135         if (! gi)           /* not cached, try input id */
3136         {
3137                 sip = (SeqIdPtr)(ompcp->input_data);
3138                 if (sip == NULL)
3139                         return OM_MSG_RET_ERROR;
3140 
3141                 if (sip->choice != SEQID_GI)
3142 					 {
3143 						   gi = GetUniGeneIDForSeqId(sip);  /* UniGene? */
3144 							if (gi)                          /* yes */
3145 								retcode = -1;
3146 							else
3147                         gi = EntrezFindSeqId(sip);
3148 					 }
3149                 else
3150                         gi = sip->data.intvalue;
3151         }
3152 
3153         if (! gi) return OM_MSG_RET_OK;  /* no error but call next proc */
3154 
3155         sep = EntrezSeqEntryGet(gi, retcode);
3156         if (sep == NULL) return OM_MSG_RET_ERROR;
3157 
3158 	    /* if (retcode >= 0)
3159 		{
3160 			fake_seqid.choice = SEQID_GI;
3161 			fake_seqid.data.intvalue = gi;
3162 			fake_seqid.next = NULL;
3163 			sip = &fake_seqid;
3164 		} */
3165 
3166         sip = (SeqIdPtr)(ompcp->input_data);
3167         bsp = BioseqFindInSeqEntry(sip, sep);
3168         ompcp->output_data = (Pointer)bsp;
3169         ompcp->output_entityID = ObjMgrGetEntityIDForChoice(sep);
3170 
3171                   /* store the cache info */
3172         omdp = ObjMgrAddUserData(ompcp->output_entityID, ompp->procid, OMPROC_FETCH, 0);
3173 		  efudp = (EntrezFetchUserDataPtr)MemNew(sizeof(EntrezFetchUserData));
3174         omdp->userdata.ptrvalue = efudp;
3175 		  efudp->gi = gi;
3176 		  efudp->retcode = retcode;
3177 		  omdp->freefunc = EntrezFetchFreeFunc;
3178 
3179         return OM_MSG_RET_DONE;   /* data found, don't call further functions */
3180 }
3181 
3182 /*****************************************************************************
3183 *
3184 *   EntrezSeqIdForGIFunc(data)
3185 *       callback for EntrezSeqIdForGI
3186 *
3187 *****************************************************************************/
3188 static Int2 LIBCALLBACK EntrezSeqIdForGIFunc (Pointer data)
3189 {
3190         OMProcControlPtr ompcp;
3191         ObjMgrProcPtr ompp;
3192         EntrezFetchStructPtr efsp;
3193         SeqIdPtr sip, sip2;
3194 		  Boolean result;
3195 
3196         ompcp = (OMProcControlPtr)data;
3197         ompp = ompcp->proc;
3198         efsp = (EntrezFetchStructPtr)(ompp->procdata);
3199 
3200 		  if (efsp->EntrezBioseqFetchState == EBFS_DISABLE)  /* shut off */
3201 		  {
3202 		  	    return OM_MSG_RET_OK;    /* not done, go on to next */
3203 		  }
3204         else if (efsp->EntrezBioseqFetchState == EBFS_INIT)
3205         {
3206                 result = EntrezInit(efsp->EntrezBioseqFetchAppName, TRUE, &(efsp->is_net));
3207                 if (! result)
3208                     return OM_MSG_RET_ERROR;
3209                 efsp->EntrezBioseqFetchState = EBFS_READY;
3210         }
3211 
3212         if (efsp->EntrezBioseqFetchState != EBFS_READY)
3213                 return OM_MSG_RET_ERROR;
3214 
3215         sip = (SeqIdPtr)(ompcp->input_data);
3216         if (sip == NULL)
3217                 return OM_MSG_RET_ERROR;
3218 		  if (sip->choice != SEQID_GI)
3219 					 return OM_MSG_RET_ERROR;
3220 
3221         sip2 = EntrezSeqIdForGI(sip->data.intvalue);
3222         if (sip2 == NULL) return OM_MSG_RET_OK;
3223 
3224         ompcp->output_data = (Pointer)sip2;
3225 							/* not registering right now */
3226 
3227         return OM_MSG_RET_DONE;   /* data found, don't call further functions */
3228 }
3229 
3230 /*****************************************************************************
3231 *
3232 *   EntrezGIForSeqIdFunc(data)
3233 *       callback for EntrezGIForSeqId
3234 *
3235 *****************************************************************************/
3236 static Int2 LIBCALLBACK EntrezGIForSeqIdFunc (Pointer data)
3237 {
3238         OMProcControlPtr ompcp;
3239         ObjMgrProcPtr ompp;
3240         EntrezFetchStructPtr efsp;
3241         SeqIdPtr sip, sip2;
3242 		  Int4 gi;
3243 		  Boolean result;
3244 
3245         ompcp = (OMProcControlPtr)data;
3246 		if (ompcp == NULL)
3247                 return OM_MSG_RET_ERROR;
3248 
3249         sip = (SeqIdPtr)(ompcp->input_data);
3250         if (sip == NULL)
3251             return OM_MSG_RET_ERROR;
3252 
3253 		switch (sip->choice) {
3254 			case SEQID_NOT_SET:
3255 			case SEQID_LOCAL:
3256 			case SEQID_OTHER:
3257 			case SEQID_GENERAL:
3258 			case SEQID_GI:
3259 				return OM_MSG_RET_ERROR;
3260 			default:
3261 				break;
3262 		}
3263 
3264         ompp = ompcp->proc;
3265         efsp = (EntrezFetchStructPtr)(ompp->procdata);
3266 
3267 		  if (efsp->EntrezBioseqFetchState == EBFS_DISABLE)  /* shut off */
3268 		  {
3269 		  	    return OM_MSG_RET_OK;    /* not done, go on to next */
3270 		  }
3271         else if (efsp->EntrezBioseqFetchState == EBFS_INIT)
3272         {
3273                 result = EntrezInit(efsp->EntrezBioseqFetchAppName, TRUE, &(efsp->is_net));
3274                 if (! result)
3275                     return OM_MSG_RET_ERROR;
3276                 efsp->EntrezBioseqFetchState = EBFS_READY;
3277         }
3278 
3279         if (efsp->EntrezBioseqFetchState != EBFS_READY)
3280                 return OM_MSG_RET_ERROR;
3281 
3282 		  gi = EntrezFindSeqId(sip);
3283         if (! gi) return OM_MSG_RET_OK;
3284 
3285 		  sip2 = ValNodeNew(NULL);
3286 		  sip2->choice = SEQID_GI;
3287 		  sip2->data.intvalue = gi;
3288 
3289         ompcp->output_data = (Pointer)sip2;
3290 							/* not registering right now */
3291 
3292         return OM_MSG_RET_DONE;   /* data found, don't call further functions */
3293 }
3294 
3295 NLM_EXTERN Boolean LIBCALL EntrezCanBlast(void)
3296 {
3297     if (! SelectDataLinksByTypes(TYP_AA, TYP_AA))
3298     { /* ERROR, data unobtainable */
3299         return FALSE;
3300     }
3301 
3302     switch (GetCurMediaType())
3303     {
3304 #ifdef _CDENTREZ_
3305     case MEDIUM_CD:
3306     case MEDIUM_DISK:
3307         return FALSE;
3308 #endif
3309 #ifdef _NETENTREZ_
3310     case MEDIUM_NETWORK:
3311         return NetEntCanBlast();
3312 #endif
3313     default:
3314         return FALSE;
3315     }
3316 }
3317 
3318 NLM_EXTERN LinkSetPtr LIBCALL EntrezBlastBioseq(BioseqPtr bsp, DocType db, CharPtr program, CharPtr database, CharPtr options, Boolean usemonitor)
3319 {
3320     if (! SelectDataLinksByTypes(db, db))
3321     { /* ERROR, data unobtainable */
3322         return NULL;
3323     }
3324 
3325     switch (GetCurMediaType()) {
3326 #ifdef _CDENTREZ_
3327     case MEDIUM_CD:
3328     case MEDIUM_DISK:
3329         return NULL;
3330 #endif
3331 #ifdef _NETENTREZ_
3332     case MEDIUM_NETWORK:
3333         return NetEntBlastBioseq(bsp, db, program, database, options, usemonitor);
3334 #endif
3335     default:
3336         return NULL;
3337     }
3338 }
3339 
3340 NLM_EXTERN Int4 LIBCALL EntrezClusterAnalysis(DocUidPtr uids, Int4 numuids, DocField fld, Int4 minCluster, Int4 maxCluster, Int4 maxTerms, CharPtr *terms, Int4Ptr termTotals)
3341 {
3342 
3343     if (! SelectDataLinksByTypes(TYP_ML, TYP_ML))
3344     { /* ERROR, data unobtainable */
3345         return FALSE;
3346     }
3347 
3348     switch (GetCurMediaType())
3349     {
3350 #ifdef _CDENTREZ_
3351     case MEDIUM_CD:
3352     case MEDIUM_DISK:
3353 #ifdef _MBENTREZ_
3354         return MBEntrezClusterAnalysis(uids, numuids, fld, minCluster, maxCluster, maxTerms, terms, termTotals);
3355 #endif
3356         return -1;
3357 #endif
3358 #ifdef _NETENTREZ_
3359     case MEDIUM_NETWORK:
3360         return NetEntClusterAnalysis(uids, numuids, fld, minCluster, maxCluster, maxTerms, terms, termTotals);
3361 #endif
3362     default:
3363         return -1;
3364     }
3365 }
3366 
3367 
3368