1 /*  objpub.c
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * File Name:  objpub.c
27 *
28 * Author:  James Ostell
29 *
30 * Version Creation Date: 4/1/91
31 *
32 * $Revision: 6.10 $
33 *
34 * File Description:  Object manager for module NCBI-Pub
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38 * Date	   Name        Description of modification
39 * -------  ----------  -----------------------------------------------------
40 * 05-13-93 Schuler     All public functions are now declared LIBCALL.
41 *
42 *
43 * $Log: objpub.c,v $
44 * Revision 6.10  2015/10/23 00:04:24  kans
45 * NOIJRA Clear av DataVal variable on AsnWrite, needed for supporting Int8 integers in ASN.1
46 *
47 * Revision 6.9  2010/03/09 16:56:39  bollin
48 * Include Medline/PMID in Medline article formatting.
49 *
50 * Revision 6.8  2009/10/02 19:44:49  kans
51 * address clang static analyzer warnings
52 *
53 * Revision 6.7  2005/12/29 13:46:18  bollin
54 * added PubdescContentMatch function
55 *
56 * Revision 6.6  2004/04/01 13:43:08  lavr
57 * Spell "occurred", "occurrence", and "occurring"
58 *
59 * Revision 6.5  2002/01/08 20:48:22  kans
60 * PubLabelUnique internal call to PubLabelUnique (..., unique), not PubLabel
61 *
62 * Revision 6.4  2001/11/20 14:50:54  kans
63 * PubLabelUnique return immediately if PMID or MUID, already unique
64 *
65 * Revision 6.3  2000/06/15 19:13:28  yaschenk
66 * PubAsnWrite should not fail when pmid is stripped
67 *
68 * Revision 6.2  1998/12/30 20:28:34  ostell
69 * fixed bug in PubLabelUnique() for author list. If alp->names is NULL,
70 * diff was not initialized. So operations using diff moved inside
71 * if (vnp2 != NULL)
72 *
73 * Revision 6.1  1998/08/24 18:28:08  kans
74 * removed solaris -v -fd warnings
75 *
76 * Revision 6.0  1997/08/25 18:50:27  madden
77 * Revision changed to 6.0
78 *
79 * Revision 4.12  1997/06/19 18:41:46  vakatov
80 * [WIN32,MSVC++]  Adopted for the "NCBIOBJ.LIB" DLL'ization
81 *
82 * Revision 4.11  1996/09/12 18:42:53  epstein
83 * spec_version fixes as suggested by J. Kans
84 *
85  * Revision 4.10  1996/07/30  15:22:20  epstein
86  * correct logic errors for different spec_versions
87  *
88  * Revision 4.9  1996/07/01  17:46:53  tatiana
89  * month and day added to PubLabelUnique() in submission label
90  *
91  * Revision 4.8  1996/05/30  21:11:24  tatiana
92  * fill in the result buffer if cgp->cit is the only field set (in PubLabelUnique).
93  *
94  * Revision 4.7  1996/03/29  21:09:59  ostell
95  * added support for PubMedId
96  *
97  * Revision 4.6  1996/03/01  18:08:53  tatiana
98  * fix in PubLabelUnique
99  *
100  * Revision 4.5  1995/10/17  18:10:28  tatiana
101  * fix in PubLabelUnique
102  *
103  * Revision 4.4  1995/10/13  14:04:26  tatiana
104  * a bug fixed in PubLabelUnique
105  *
106  * Revision 4.3  1995/09/07  14:16:55  tatiana
107  * fix in PubLabelUnique function
108  *
109  * Revision 4.2  1995/08/30  22:25:21  kans
110  * cap->title uses ->data.ptrvalue
111  *
112  * Revision 4.1  1995/08/30  18:33:53  ostell
113  * added PubLabelUnique function
114  *
115  * Revision 4.0  1995/07/26  13:48:06  ostell
116  * force revision to 4.0
117  *
118  * Revision 3.7  1995/05/15  21:22:00  ostell
119  * added Log line
120  *
121 *
122 *
123 * ==========================================================================
124 */
125 #include <objpub.h>		   /* the pub interface */
126 #include <asnpub.h>        /* the AsnTool header */
127 #include <objmgr.h>
128 
129 static Boolean loaded = FALSE;
130 
131 /*****************************************************************************
132 *
133 *   Pub ObjMgr Routines
134 *
135 *****************************************************************************/
136 static CharPtr pubtypename = "Pub";
137 
PubNewFunc(void)138 static Pointer LIBCALLBACK PubNewFunc (void)
139 {
140 	return (Pointer) ValNodeNew(NULL);
141 }
142 
PubFreeFunc(Pointer data)143 static Pointer LIBCALLBACK PubFreeFunc (Pointer data)
144 {
145 	return (Pointer) PubFree ((ValNodePtr) data);
146 }
147 
PubAsnWriteFunc(Pointer data,AsnIoPtr aip,AsnTypePtr atp)148 static Boolean LIBCALLBACK PubAsnWriteFunc (Pointer data, AsnIoPtr aip, AsnTypePtr atp)
149 {
150 	return PubAsnWrite((ValNodePtr)data, aip, atp);
151 }
152 
PubAsnReadFunc(AsnIoPtr aip,AsnTypePtr atp)153 static Pointer LIBCALLBACK PubAsnReadFunc (AsnIoPtr aip, AsnTypePtr atp)
154 {
155 	return (Pointer) PubAsnRead (aip, atp);
156 }
157 
PubLabelFunc(Pointer data,CharPtr buffer,Int2 buflen,Uint1 content)158 static Int2 LIBCALLBACK PubLabelFunc ( Pointer data, CharPtr buffer, Int2 buflen, Uint1 content)
159 {
160  	return PubLabel((ValNodePtr)data, buffer, buflen, content);
161 }
162 
PubSubTypeFunc(Pointer ptr)163 static Uint2 LIBCALLBACK PubSubTypeFunc (Pointer ptr)
164 {
165 	if (ptr == NULL)
166 		return 0;
167 	return (Uint2)((ValNodePtr)ptr)->choice;
168 }
169 
170 /*****************************************************************************
171 *
172 *   CitSub ObjMgr Routines
173 *
174 *****************************************************************************/
175 static CharPtr seqsubcittypename = "Cit";
176 
CitSubNewFunc(void)177 static Pointer LIBCALLBACK CitSubNewFunc (void)
178 {
179 	return (Pointer) CitSubNew();
180 }
181 
CitSubFreeFunc(Pointer data)182 static Pointer LIBCALLBACK CitSubFreeFunc (Pointer data)
183 {
184 	return (Pointer) CitSubFree ((CitSubPtr) data);
185 }
186 
CitSubAsnWriteFunc(Pointer data,AsnIoPtr aip,AsnTypePtr atp)187 static Boolean LIBCALLBACK CitSubAsnWriteFunc (Pointer data, AsnIoPtr aip, AsnTypePtr atp)
188 {
189 	return CitSubAsnWrite((CitSubPtr)data, aip, atp);
190 }
191 
CitSubAsnReadFunc(AsnIoPtr aip,AsnTypePtr atp)192 static Pointer LIBCALLBACK CitSubAsnReadFunc (AsnIoPtr aip, AsnTypePtr atp)
193 {
194 	return (Pointer) CitSubAsnRead (aip, atp);
195 }
196 
CitSubLabelFunc(Pointer data,CharPtr buffer,Int2 buflen,Uint1 content)197 static Int2 LIBCALLBACK CitSubLabelFunc ( Pointer data, CharPtr buffer, Int2 buflen, Uint1 content)
198 {
199 	ValNode vn;
200 
201 	vn.choice = PUB_Sub;
202 	vn.data.ptrvalue = data;
203 	vn.next = NULL;
204 
205  	return PubLabel(&vn, buffer, buflen, content);
206 }
207 
208 
209 /*****************************************************************************
210 *
211 *   PubSet ObjMgr Routines
212 *
213 *****************************************************************************/
214 static CharPtr pubsettypename = "PubSet";
215 
PubSetNewFunc(void)216 static Pointer LIBCALLBACK PubSetNewFunc (void)
217 {
218 	return (Pointer) ValNodeNew(NULL);
219 }
220 
PubSetFreeFunc(Pointer data)221 static Pointer LIBCALLBACK PubSetFreeFunc (Pointer data)
222 {
223 	return (Pointer) PubSetFree ((ValNodePtr) data);
224 }
225 
PubSetAsnWriteFunc(Pointer data,AsnIoPtr aip,AsnTypePtr atp)226 static Boolean LIBCALLBACK PubSetAsnWriteFunc (Pointer data, AsnIoPtr aip, AsnTypePtr atp)
227 {
228 	return PubSetAsnWrite((ValNodePtr)data, aip, atp);
229 }
230 
PubSetAsnReadFunc(AsnIoPtr aip,AsnTypePtr atp)231 static Pointer LIBCALLBACK PubSetAsnReadFunc (AsnIoPtr aip, AsnTypePtr atp)
232 {
233 	return (Pointer) PubSetAsnRead (aip, atp);
234 }
235 
PubSetLabelFunc(Pointer data,CharPtr buffer,Int2 buflen,Uint1 content)236 static Int2 LIBCALLBACK PubSetLabelFunc ( Pointer data, CharPtr buffer, Int2 buflen, Uint1 content)
237 {
238 	return PubSetLabel ((ValNodePtr)data, buffer, buflen, content);
239 }
240 
PubSetLabel(ValNodePtr pubset,CharPtr buffer,Int2 buflen,Uint1 content)241 NLM_EXTERN Int2 LIBCALL PubSetLabel (ValNodePtr pubset, CharPtr buffer, Int2 buflen, Uint1 content)
242 {
243 	static CharPtr set_names[8] = {
244 		"NotSet",
245 		"Pub",
246 		"Medline",
247 		"Articles",
248 		"Journals",
249 		"Books",
250 		"Procs",
251 		"Patents" };
252 	Int2 diff, len, i = 0;
253 	Char tbuf[40];
254 	ValNodePtr vnp;
255 
256 	if ((pubset == NULL) || (buflen < 1))
257 		return 0;
258 
259 	if ((pubset->choice >=1) && (pubset->choice <= 7))
260 		i= (Int2)(pubset->choice);
261 
262 	len = buflen;
263 
264 	if (content == OM_LABEL_TYPE)
265 		return LabelCopy(buffer, set_names[i], buflen);
266 
267 	if (content != OM_LABEL_CONTENT)
268 	{
269 		diff = LabelCopyExtra(buffer, set_names[i], buflen, NULL, ": ");
270 		buflen -= diff;
271 		buffer += diff;
272 	}
273 
274 	i=0;
275 	for (vnp = (ValNodePtr)(pubset->data.ptrvalue); vnp != NULL; vnp = vnp->next)
276 		i++;
277 
278 	if (i == 1)
279 		sprintf(tbuf, "1 pub");
280 	else
281 		sprintf(tbuf, "%d pubs", (int)i);
282 
283 	diff = LabelCopy(buffer, tbuf, buflen);
284 	buflen -= diff;
285 	buffer += diff;
286 
287 	return (len - buflen);   /* no special SUMMARY yet */
288 }
289 
PubSetSubTypeFunc(Pointer ptr)290 static Uint2 LIBCALLBACK PubSetSubTypeFunc (Pointer ptr)
291 {
292 	if (ptr == NULL)
293 		return 0;
294 	return (Uint2)((ValNodePtr)ptr)->choice;
295 }
296 
297 /*****************************************************************************
298 *
299 *   PubAsnLoad()
300 *
301 *****************************************************************************/
PubAsnLoad(void)302 NLM_EXTERN Boolean LIBCALL PubAsnLoad (void)
303 {
304     if (loaded)
305         return TRUE;
306     loaded = TRUE;
307 
308     if (! GeneralAsnLoad())
309     {
310         loaded = FALSE;
311         return FALSE;
312     }
313     if (! BiblioAsnLoad())
314     {
315         loaded = FALSE;
316         return FALSE;
317     }
318     if (! MedlineAsnLoad())
319     {
320         loaded = FALSE;
321         return FALSE;
322     }
323     if (! AsnLoad())
324     {
325         loaded = FALSE;
326         return FALSE;
327     }
328 
329 	ObjMgrTypeLoad(OBJ_PUB, "Pub", pubtypename, "Publication",
330 		PUB, PubNewFunc, PubAsnReadFunc, PubAsnWriteFunc,
331 		PubFreeFunc, PubLabelFunc, PubSubTypeFunc);
332 
333 	ObjMgrTypeLoad(OBJ_SEQSUB_CIT, "Cit", seqsubcittypename, "Submission Citation",
334 		PUB_sub, CitSubNewFunc, CitSubAsnReadFunc, CitSubAsnWriteFunc,
335 		CitSubFreeFunc, CitSubLabelFunc, NULL);
336 
337 	ObjMgrTypeLoad(OBJ_SEQFEAT_CIT, "Seqfeat.cit", "Cit", "Feature Citation",
338 		PUB, PubNewFunc, PubAsnReadFunc, PubAsnWriteFunc,
339 		PubFreeFunc, PubLabelFunc, PubSubTypeFunc);
340 
341 	ObjMgrTypeLoad(OBJ_PUB_SET, "Pub-set", pubsettypename, "Set of Publications",
342 		PUB_SET, PubSetNewFunc, PubSetAsnReadFunc, PubSetAsnWriteFunc,
343 		PubSetFreeFunc, PubSetLabelFunc, PubSetSubTypeFunc);
344 
345     return TRUE;
346 }
347 
348 
349 /*****************************************************************************
350 *
351 *   Pub Routines
352 *
353 *****************************************************************************/
354 /*****************************************************************************
355 *
356 *   Pub is a choice using an ValNode
357 *   choice:
358 *   0 = not set
359     1 = gen Cit-gen ,        -- general or generic unparsed
360     2 = sub Cit-sub ,        -- submission
361     3 = medline Medline-entry ,
362     4 = muid INTEGER ,       -- medline uid
363     5 = article Cit-art ,
364     6 = journal Cit-jour ,
365     7 = book Cit-book ,
366     8 = proc Cit-proc ,      -- proceedings of a meeting
367     9 = patent Cit-pat ,
368     10 = pat-id Id-pat ,      -- identify a patent
369     11 = man Cit-let ,        -- manuscript or letter
370     12 = equiv Pub-equiv      -- set of equivalent citation forms for 1 pub
371 	13 = pmid INTEGER         -- PubMedId
372 *
373 *****************************************************************************/
374 /*****************************************************************************
375 *
376 *   PubFree(anp)
377 *       Frees one pub and associated data
378 *
379 *****************************************************************************/
PubFree(ValNodePtr anp)380 NLM_EXTERN ValNodePtr LIBCALL PubFree (ValNodePtr anp)
381 {
382     Pointer pnt;
383 
384     if (anp == NULL)
385         return anp;
386 
387     pnt = anp->data.ptrvalue;
388     switch (anp->choice)
389     {
390         case 1:                   /* gen */
391             CitGenFree((CitGenPtr)pnt);
392 			break;
393         case 2:                   /* sub */
394             CitSubFree((CitSubPtr)pnt);
395             break;
396         case 3:                   /* medline */
397             MedlineEntryFree((MedlineEntryPtr)pnt);
398             break;
399         case 4:                   /* uid in intvalue */
400             break;
401         case 5:                   /* article */
402             CitArtFree((CitArtPtr)pnt);
403             break;
404         case 6:                   /* journal */
405             CitJourFree((CitJourPtr)pnt);
406             break;
407         case 7:                   /* book */
408         case 8:                   /* proceedings */
409         case 11:                  /* manuscript */
410             CitBookFree((CitBookPtr)pnt);
411             break;
412         case 9:                   /* patent */
413             CitPatFree((CitPatPtr)pnt);
414             break;
415         case 10:                  /* patent id */
416             IdPatFree((IdPatPtr)pnt);
417             break;
418         case 12:
419             PubEquivFree((ValNodePtr)pnt);
420             break;
421 		case 13:                  /* pubmedid */
422 			break;
423     }
424 
425 	ObjMgrDelete(OBJ_PUB, (Pointer)anp);
426 
427 	return (ValNodePtr)MemFree(anp);
428 }
429 
430 /*****************************************************************************
431 *
432 *   PubAsnWrite(anp, aip, atp)
433 *   	atp is the current type (if identifier of a parent struct)
434 *       if atp == NULL, then assumes it stands alone (Pub ::=)
435 *
436 *****************************************************************************/
PubAsnWrite(ValNodePtr anp,AsnIoPtr aip,AsnTypePtr orig)437 NLM_EXTERN Boolean LIBCALL PubAsnWrite (ValNodePtr anp, AsnIoPtr aip, AsnTypePtr orig)
438 {
439 	DataVal av;
440 	AsnTypePtr atp, writetype = NULL;
441     Pointer pnt;
442     AsnWriteFunc func = NULL;
443     Boolean retval = FALSE;
444 
445 	if (! loaded)
446 	{
447 		if (! PubAsnLoad())
448 			return FALSE;
449 	}
450 
451 	if (aip == NULL)
452 		return FALSE;
453 
454 	atp = AsnLinkType(orig, PUB);   /* link local tree */
455     if (atp == NULL) return FALSE;
456 
457 	if (anp == NULL) { AsnNullValueMsg(aip, atp); goto erret; }
458 
459     MemSet ((Pointer) (&av), 0, sizeof (DataVal));
460 
461 	if ((aip->spec_version > 0 && aip->spec_version < 5) && anp->choice >= 13)  /* ASN4 strip new value */
462 	{
463 		ErrPostEx(SEV_ERROR,0,0,"ASN4: PubMedId stripped");
464 		retval=TRUE;
465 		goto erret;
466 	}
467 
468 	av.ptrvalue = (Pointer)anp;
469 	if (! AsnWriteChoice(aip, atp, (Int2)anp->choice, &av)) goto erret;
470 
471     pnt = anp->data.ptrvalue;
472     switch (anp->choice)
473     {
474         case 1:                   /* gen */
475             writetype = PUB_gen;
476             func = (AsnWriteFunc) CitGenAsnWrite;
477             break;
478         case 2:                   /* sub */
479             writetype = PUB_sub;
480             func = (AsnWriteFunc) CitSubAsnWrite;
481             break;
482         case 3:                   /* medline */
483             writetype = PUB_medline;
484             func = (AsnWriteFunc) MedlineEntryAsnWrite;
485             break;
486         case 4:                   /* uid in intvalue */
487             av.intvalue = anp->data.intvalue;
488             if (! AsnWrite(aip, PUB_muid, &av)) goto erret;
489             break;
490         case 5:                   /* article */
491             writetype = PUB_article;
492             func = (AsnWriteFunc) CitArtAsnWrite;
493             break;
494         case 6:                   /* journal */
495             writetype = PUB_journal;
496             func = (AsnWriteFunc) CitJourAsnWrite;
497             break;
498         case 7:                   /* book */
499             writetype = PUB_book;
500             func = (AsnWriteFunc) CitBookAsnWrite;
501             break;
502         case 8:                   /* proceedings */
503             writetype = PUB_proc;
504             func = (AsnWriteFunc) CitProcAsnWrite;
505             break;
506         case 11:                  /* manuscript */
507             writetype = PUB_man;
508             func = (AsnWriteFunc) CitLetAsnWrite;
509             break;
510         case 9:                   /* patent */
511             writetype = PUB_patent;
512             func = (AsnWriteFunc) CitPatAsnWrite;
513             break;
514         case 10:                  /* patent id */
515             writetype = PUB_pat_id;
516             func = (AsnWriteFunc) IdPatAsnWrite;
517             break;
518         case 12:                  /* equiv */
519             writetype = PUB_equiv;
520             func = (AsnWriteFunc) PubEquivAsnWrite;
521             break;
522         case 13:                   /* pmid in intvalue */
523             av.intvalue = anp->data.intvalue;
524             if (! AsnWrite(aip, PUB_pmid, &av)) goto erret;
525             break;
526    }
527     if (writetype != NULL)
528     {
529         if (! (*func)(pnt, aip, writetype)) goto erret;
530     }
531     retval = TRUE;
532 erret:
533 	AsnUnlinkType(orig);       /* unlink local tree */
534 	return retval;
535 }
536 /*****************************************************************************
537 *
538 *   PubAsnRead(aip, atp)
539 *   	atp is the current type (if identifier of a parent struct)
540 *            assumption is readIdent has occurred
541 *       if atp == NULL, then assumes it stands alone and read ident
542 *            has not occurred.
543 *
544 *****************************************************************************/
PubAsnRead(AsnIoPtr aip,AsnTypePtr orig)545 NLM_EXTERN ValNodePtr LIBCALL PubAsnRead (AsnIoPtr aip, AsnTypePtr orig)
546 {
547 	DataVal av;
548 	AsnTypePtr atp;
549     ValNodePtr anp=NULL;
550     Uint1 choice = 0;
551     AsnReadFunc func = NULL;
552 
553 	if (! loaded)
554 	{
555 		if (! PubAsnLoad())
556 			return anp;
557 	}
558 
559 	if (aip == NULL)
560 		return anp;
561 
562 	if (orig == NULL)           /* Pub ::= (self contained) */
563 		atp = AsnReadId(aip, amp, PUB);
564 	else
565 		atp = AsnLinkType(orig, PUB);    /* link in local tree */
566     if (atp == NULL) return anp;
567 
568 	anp = ValNodeNew(NULL);
569     if (anp == NULL) goto erret;
570 
571 	if (AsnReadVal(aip, atp, &av) <= 0) goto erret;    /* read the CHOICE value (nothing) */
572 	atp = AsnReadId(aip, amp, atp);  /* find the choice */
573     if (atp == NULL) goto erret;
574 
575 	if (atp == PUB_gen)
576     {
577         choice = 1;
578         func = (AsnReadFunc) CitGenAsnRead;
579     }
580     else if (atp == PUB_sub)
581     {
582         choice = 2;
583         func = (AsnReadFunc) CitSubAsnRead;
584     }
585     else if (atp == PUB_medline)
586     {
587         choice = 3;
588         func = (AsnReadFunc) MedlineEntryAsnRead;
589     }
590     else if (atp == PUB_muid)
591     {
592         choice = 4;
593         if (AsnReadVal(aip, atp, &anp->data) <= 0) goto erret;
594     }
595     else if (atp == PUB_article)
596     {
597         choice = 5;
598         func = (AsnReadFunc) CitArtAsnRead;
599     }
600     else if (atp == PUB_journal)
601     {
602         choice = 6;
603         func = (AsnReadFunc) CitJourAsnRead;
604     }
605     else if (atp == PUB_book)
606     {
607         choice = 7;
608         func = (AsnReadFunc) CitBookAsnRead;
609     }
610     else if (atp == PUB_proc)
611     {
612         choice = 8;
613         func = (AsnReadFunc) CitProcAsnRead;
614     }
615     else if (atp == PUB_patent)
616     {
617         choice = 9;
618         func = (AsnReadFunc) CitPatAsnRead;
619     }
620     else if (atp == PUB_pat_id)
621     {
622         choice = 10;
623         func = (AsnReadFunc) IdPatAsnRead;
624     }
625     else if (atp == PUB_man)
626     {
627         choice = 11;
628         func = (AsnReadFunc) CitLetAsnRead;
629     }
630     else if (atp == PUB_equiv)
631     {
632         choice = 12;
633         func = (AsnReadFunc) PubEquivAsnRead;
634     }
635     else if (atp == PUB_pmid)
636     {
637         choice = 13;
638         if (AsnReadVal(aip, atp, &anp->data) <= 0) goto erret;
639     }
640 
641     anp->choice = choice;
642     if ((choice != 4) && (choice != 13) && func != NULL)
643     {
644         anp->data.ptrvalue = (* func)(aip, atp);
645         if (anp->data.ptrvalue == NULL) goto erret;
646     }
647 ret:
648 	AsnUnlinkType(orig);       /* unlink local tree */
649 	return anp;
650 erret:
651     anp = PubFree(anp);
652     goto ret;
653 }
654 
655 /*****************************************************************************
656 *
657 *   PubSet is a choice using an ValNode
658 *   choice:
659 *   0 = not set
660     1 = pub Pub ,        -- mixed pubs
661     3 = medline Medline-entry ,    -- use same mapping as Pub for these
662     5 = article Cit-art ,
663     6 = journal Cit-jour ,
664     7 = book Cit-book ,
665     8 = proc Cit-proc ,      -- proceedings of a meeting
666     9 = patent Cit-pat ,
667 *
668 *   PubSet->data.ptrvalue points to chain of Pub (even if not mixed) so
669 *      each Pub is self identifying anyway and Pub routines can be used
670 *****************************************************************************/
671 /*****************************************************************************
672 *
673 *   PubSetFree(anp)
674 *       Frees one Pub-set and associated data
675 *
676 *****************************************************************************/
PubSetFree(ValNodePtr anp)677 NLM_EXTERN ValNodePtr LIBCALL PubSetFree (ValNodePtr anp)
678 {
679     if (anp == NULL)
680         return anp;
681 
682     PubEquivFree((ValNodePtr)anp->data.ptrvalue);
683 
684 	ObjMgrDelete(OBJ_PUB_SET, (Pointer)anp);
685 
686     return (ValNodePtr)MemFree(anp);
687 }
688 
689 /*****************************************************************************
690 *
691 *   PubSetAsnWrite(anp, aip, atp)
692 *   	atp is the current type (if identifier of a parent struct)
693 *       if atp == NULL, then assumes it stands alone (PubSet ::=)
694 *
695 *****************************************************************************/
PubSetAsnWrite(ValNodePtr anp,AsnIoPtr aip,AsnTypePtr orig)696 NLM_EXTERN Boolean LIBCALL PubSetAsnWrite (ValNodePtr anp, AsnIoPtr aip, AsnTypePtr orig)
697 {
698 	DataVal av;
699 	AsnTypePtr atp, settype = NULL, elementtype;
700     Pointer pnt;
701     Uint1 choice;
702     AsnWriteFunc func = NULL;
703 	ValNodePtr oldanp;
704     Boolean retval = FALSE;
705 
706 	if (! loaded)
707 	{
708 		if (! PubAsnLoad())
709 			return FALSE;
710 	}
711 
712 	if (aip == NULL)
713 		return FALSE;
714 
715 	atp = AsnLinkType(orig, PUB_SET);   /* link local tree */
716     if (atp == NULL) return FALSE;
717 
718 	if (anp == NULL) { AsnNullValueMsg(aip, atp); goto erret; }
719 
720     MemSet ((Pointer) (&av), 0, sizeof (DataVal));
721 
722 	av.ptrvalue = (Pointer)anp;
723 	if (! AsnWriteChoice(aip, atp, (Int2)anp->choice, &av)) goto erret;
724     choice = anp->choice;              /* type of set */
725     switch (choice)
726     {
727         case 1:
728             settype = PUB_SET_pub;
729             elementtype = PUB_SET_pub_E;
730             func = (AsnWriteFunc) PubAsnWrite;
731             break;
732         case 3:
733             settype = PUB_SET_medline;
734             elementtype = PUB_SET_medline_E;
735             func = (AsnWriteFunc) MedlineEntryAsnWrite;
736             break;
737         case 5:
738             settype = PUB_SET_article;
739             elementtype = PUB_SET_article_E;
740             func = (AsnWriteFunc) CitArtAsnWrite;
741             break;
742         case 6:
743             settype = PUB_SET_journal;
744             elementtype = PUB_SET_journal_E;
745             func = (AsnWriteFunc) CitJourAsnWrite;
746             break;
747         case 7:
748             settype = PUB_SET_book;
749             elementtype = PUB_SET_book_E;
750             func = (AsnWriteFunc) CitBookAsnWrite;
751             break;
752         case 8:
753             settype = PUB_SET_proc;
754             elementtype = PUB_SET_proc_E;
755             func = (AsnWriteFunc) CitBookAsnWrite;
756             break;
757         case 9:
758             settype = PUB_SET_patent;
759             elementtype = PUB_SET_patent_E;
760             func = (AsnWriteFunc) CitPatAsnWrite;
761             break;
762     }
763 
764 	oldanp = anp;
765     if (! AsnOpenStruct(aip, settype, oldanp->data.ptrvalue))   /* start SET OF */
766         goto erret;
767 
768     anp = (ValNodePtr)anp->data.ptrvalue;
769 
770     while (anp != NULL)
771     {
772         if (choice == 1)
773             pnt = (Pointer)anp;
774         else
775             pnt = anp->data.ptrvalue;
776         if (func != NULL) {
777           if (! (*func)(pnt, aip, elementtype)) goto erret;
778         }
779         anp = anp->next;
780     }
781 
782     if (! AsnCloseStruct(aip, settype, oldanp->data.ptrvalue))  /* end SET OF */
783         goto erret;
784     retval = TRUE;
785 erret:
786 	AsnUnlinkType(orig);       /* unlink local tree */
787 	return retval;
788 }
789 
790 /*****************************************************************************
791 *
792 *   PubSetAsnRead(aip, atp)
793 *   	atp is the current type (if identifier of a parent struct)
794 *            assumption is readIdent has occurred
795 *       if atp == NULL, then assumes it stands alone and read ident
796 *            has not occurred.
797 *
798 *****************************************************************************/
PubSetAsnRead(AsnIoPtr aip,AsnTypePtr orig)799 NLM_EXTERN ValNodePtr LIBCALL PubSetAsnRead (AsnIoPtr aip, AsnTypePtr orig)
800 {
801 	DataVal av;
802 	AsnTypePtr atp, settype;
803     Pointer pnt;
804     ValNodePtr anp=NULL, cit, curr;
805     Uint1 choice;
806     AsnReadFunc func;
807     Boolean first;
808 
809 	if (! loaded)
810 	{
811 		if (! PubAsnLoad())
812 			return anp;
813 	}
814 
815 	if (aip == NULL)
816 		return anp;
817 
818 	if (orig == NULL)           /* PubSet ::= (self contained) */
819 		atp = AsnReadId(aip, amp, PUB_SET);
820 	else
821 		atp = AsnLinkType(orig, PUB_SET);    /* link in local tree */
822     if (atp == NULL) return anp;
823 
824 	anp = ValNodeNew(NULL);
825     if (anp == NULL) goto erret;
826 
827 	if (AsnReadVal(aip, atp, &av) <= 0)    /* read the CHOICE value (nothing) */
828         goto erret;
829 	settype = AsnReadId(aip, amp, atp);  /* find the choice */
830     if (settype == NULL) goto erret;
831     if (AsnReadVal(aip, settype, &av) <= 0)    /* read START_STRUCT */
832         goto erret;
833 
834 	if (settype == PUB_SET_pub)
835     {
836         choice = 1;
837         func = (AsnReadFunc) PubAsnRead;
838     }
839     else if (settype == PUB_SET_medline)
840     {
841         choice = 3;
842         func = (AsnReadFunc) MedlineEntryAsnRead;
843     }
844     else if (settype == PUB_SET_article)
845     {
846         choice = 5;
847         func = (AsnReadFunc) CitArtAsnRead;
848     }
849     else if (settype == PUB_SET_journal)
850     {
851         choice = 6;
852         func = (AsnReadFunc) CitJourAsnRead;
853     }
854     else if (settype == PUB_SET_book)
855     {
856         choice = 7;
857         func = (AsnReadFunc) CitBookAsnRead;
858     }
859     else if (settype == PUB_SET_proc)
860     {
861         choice = 8;
862         func = (AsnReadFunc) CitBookAsnRead;
863     }
864     else if (settype == PUB_SET_patent)
865     {
866         choice = 9;
867         func = (AsnReadFunc) CitPatAsnRead;
868     }
869 
870     anp->choice = choice;
871     first = TRUE;
872     curr = NULL;
873     while ((atp = AsnReadId(aip, amp, settype)) != settype)
874     {
875         if (atp == NULL) goto erret;
876         pnt = (* func)(aip, atp);
877         if (pnt == NULL) goto erret;
878         if (settype == PUB_SET_pub)   /* already a Pub */
879         {
880             cit = (ValNodePtr)pnt;
881         }
882         else                          /* make into a Pub */
883         {
884             cit = ValNodeNew(NULL);
885             if (cit == NULL) goto erret;
886             cit->data.ptrvalue = pnt;
887             cit->choice = choice;
888         }
889 
890         if (first)
891         {
892             anp->data.ptrvalue = (Pointer)cit;
893             first = FALSE;
894         }
895         else
896         {
897             curr->next = cit;
898         }
899         curr = cit;
900     }
901     if (AsnReadVal(aip, settype, &av) <= 0)   /* read END_STRUCT for SET OF */
902         goto erret;
903 	if (anp == NULL)
904 		ErrPost(CTX_NCBIOBJ, 1, "Empty SET OF Pub.  line %ld", aip->linenumber);
905 ret:
906 	AsnUnlinkType(orig);       /* unlink local tree */
907 	return anp;
908 erret:
909     anp = PubSetFree(anp);
910     goto ret;
911 }
912 
913 /*****************************************************************************
914 *
915 *   PubEquiv is just a chain of Pubs (ValNodes)
916 *
917 *****************************************************************************/
918 /*****************************************************************************
919 *
920 *   PubEquivFree(anp)
921 *       Frees a chain of Pubs
922 *
923 *****************************************************************************/
PubEquivFree(ValNodePtr anp)924 NLM_EXTERN ValNodePtr LIBCALL PubEquivFree (ValNodePtr anp)
925 {
926     ValNodePtr next;
927 
928     while (anp != NULL)
929     {
930         next = anp->next;
931         PubFree(anp);  /* each node individually coded as Pub anyway */
932         anp = next;
933     }
934 	return anp;
935 }
936 
937 /*****************************************************************************
938 *
939 *   PubEquivAsnWrite(anp, aip, atp)
940 *   	atp is the current type (if identifier of a parent struct)
941 *       if atp == NULL, then assumes it stands alone (PubEquiv ::=)
942 *
943 *****************************************************************************/
PubEquivAsnWrite(ValNodePtr anp,AsnIoPtr aip,AsnTypePtr orig)944 NLM_EXTERN Boolean LIBCALL PubEquivAsnWrite (ValNodePtr anp, AsnIoPtr aip, AsnTypePtr orig)
945 {
946 	AsnTypePtr atp;
947 	ValNodePtr oldanp;
948     Boolean retval = FALSE;
949 
950 	if (! loaded)
951 	{
952 		if (! PubAsnLoad())
953 			return FALSE;
954 	}
955 
956 	if (aip == NULL)
957 		return FALSE;
958 
959 	atp = AsnLinkType(orig, PUB_EQUIV);   /* link local tree */
960     if (atp == NULL) return FALSE;
961 
962 	if (anp == NULL) { AsnNullValueMsg(aip, atp); goto erret; }
963 
964 	oldanp = anp;
965     if (! AsnOpenStruct(aip, atp, (Pointer)oldanp))   /* start SET OF */
966         goto erret;
967 
968     while (anp != NULL)
969     {
970         if (! PubAsnWrite(anp, aip, PUB_EQUIV_E)) goto erret;
971         anp = anp->next;
972     }
973 
974     if (! AsnCloseStruct(aip, atp, (Pointer)oldanp))     /* end SET OF */
975         goto erret;
976     retval = TRUE;
977 erret:
978 	AsnUnlinkType(orig);       /* unlink local tree */
979 	return retval;
980 }
981 
982 /*****************************************************************************
983 *
984 *   PubEquivAsnRead(aip, atp)
985 *   	atp is the current type (if identifier of a parent struct)
986 *            assumption is readIdent has occurred
987 *       if atp == NULL, then assumes it stands alone and read ident
988 *            has not occurred.
989 *
990 *****************************************************************************/
PubEquivAsnRead(AsnIoPtr aip,AsnTypePtr orig)991 NLM_EXTERN ValNodePtr LIBCALL PubEquivAsnRead (AsnIoPtr aip, AsnTypePtr orig)
992 {
993 	DataVal av;
994 	AsnTypePtr atp, oldtype;
995     ValNodePtr anp=NULL, cit, curr;
996     Boolean first;
997 
998 	if (! loaded)
999 	{
1000 		if (! PubAsnLoad())
1001 			return anp;
1002 	}
1003 
1004 	if (aip == NULL)
1005 		return anp;
1006 
1007 	first = TRUE;
1008 
1009 	if (orig == NULL)           /* PubEquiv ::= (self contained) */
1010 		oldtype = AsnReadId(aip, amp, PUB_EQUIV);
1011 	else
1012 		oldtype = AsnLinkType(orig, PUB_EQUIV);    /* link in local tree */
1013     if (oldtype == NULL) return anp;
1014 
1015     if (AsnReadVal(aip, oldtype, &av) <= 0)    /* read START_STRUCT */
1016         goto erret;
1017     atp = oldtype;
1018 
1019     curr = NULL;
1020     anp = NULL;
1021     while ((atp = AsnReadId(aip, amp, atp)) != oldtype)
1022     {
1023         if (atp == NULL) goto erret;
1024 
1025         cit = PubAsnRead(aip, atp);
1026         if (cit == NULL) goto erret;
1027 
1028         if (first)
1029         {
1030             anp = cit;
1031             first = FALSE;
1032         }
1033         else
1034         {
1035             curr->next = cit;
1036         }
1037         curr = cit;
1038     }
1039     if (AsnReadVal(aip, oldtype, &av) <= 0)   /* read END_STRUCT for SET OF */
1040         goto erret;
1041 ret:
1042 	AsnUnlinkType(orig);       /* unlink local tree */
1043 	return anp;
1044 erret:
1045     anp = PubEquivFree(anp);
1046     goto ret;
1047 }
1048 
1049 /*****************************************************************************
1050 *
1051 *   Int2 PubMatch(a, b)
1052 *   	returns 0 if can determine pubs POINT TO SAME CITATION (not that
1053 *   		they are identical)
1054 *   	returns positive or negative number if not the same,
1055 *   		for arbitrary ordering
1056 *       -2, +2  = different types
1057 *       -1, +1  = different values, same type
1058 *
1059 *****************************************************************************/
PubMatch(ValNodePtr a,ValNodePtr b)1060 NLM_EXTERN Int2 LIBCALL PubMatch (ValNodePtr a, ValNodePtr b)
1061 {
1062 	ValNode vn1;
1063 	ValNodePtr ap, bp, tp, vnp[2];
1064 	Int2 retval, i;
1065 	Int4 muid[2];
1066 	Int4 pmid[2];
1067 	CitArtPtr cap[2];
1068 	CharPtr country[2],   /* for patents */
1069 		number[2],
1070 		app_number[2];
1071 
1072 	if (a == NULL) return 2;
1073 	if (b == NULL) return -2;
1074 
1075 	                        /* default return for different pub types */
1076 	if (a->choice > b->choice)
1077 		retval = 2;
1078 	else
1079 		retval = -2;
1080 
1081 							/* if either is a Pub-equiv, treat as both */
1082 	if ((a->choice == PUB_Equiv) || (b->choice == PUB_Equiv))
1083 	{
1084 		ap = (ValNodePtr)(a->data.ptrvalue);
1085 		bp = (ValNodePtr)(b->data.ptrvalue);
1086 		tp = NULL;
1087 		if (a->choice != PUB_Equiv)
1088 		{
1089 			tp = a;
1090 			ap = NULL;
1091 		}
1092 		else if (b->choice != PUB_Equiv)
1093 		{
1094 			tp = b;
1095 			bp = NULL;
1096 		}
1097 		if (tp != NULL)   /* convert one */
1098 		{
1099 			MemCopy((Pointer)&vn1, tp, sizeof(ValNode));  /* make a copy of the Pub */
1100 			vn1.next = NULL;                   /* remove from any chain */
1101 			tp = (ValNodePtr)&vn1;
1102 			if (ap == NULL)
1103 				ap = tp;
1104 			else
1105 				bp = tp;
1106 		}
1107 		return PubEquivMatch(ap, bp);   /* use the PubEquivMatch() */
1108 	}
1109                                    /** here we are just matching two pubs */
1110 							/* handle Medline/CitArt combinations */
1111 	                        /* handle CitPat, IdPat combinations */
1112 	vnp[0] = a;
1113 	vnp[1] = b;
1114 	for (i = 0; i < 2; i++)
1115 	{
1116 		cap[i] = NULL;
1117 		muid[i] = 0;
1118 		pmid[i] = 0;
1119 		country[i] = NULL;
1120 		number[i] = NULL;
1121 		app_number[i] = NULL;
1122 
1123 		switch (vnp[i]->choice)
1124 		{
1125 			case PUB_Medline:
1126 				muid[i] = ((MedlineEntryPtr)(vnp[i]->data.ptrvalue))->uid;
1127 				cap[i] = ((MedlineEntryPtr)(vnp[i]->data.ptrvalue))->cit;
1128 				pmid[i] = ((MedlineEntryPtr)(vnp[i]->data.ptrvalue))->pmid;
1129 				break;
1130 			case PUB_Muid:
1131 				muid[i] = vnp[i]->data.intvalue;
1132 				break;
1133 			case PUB_Article:
1134 				cap[i] = (CitArtPtr)(vnp[i]->data.ptrvalue);
1135 				break;
1136 			case PUB_Patent:
1137 				country[i] = ((CitPatPtr)(vnp[i]->data.ptrvalue))->country;
1138 				number[i] = ((CitPatPtr)(vnp[i]->data.ptrvalue))->number;
1139 				app_number[i] = ((CitPatPtr)(vnp[i]->data.ptrvalue))->app_number;
1140 				break;
1141 			case PUB_Pat_id:
1142 				country[i] = ((IdPatPtr)(vnp[i]->data.ptrvalue))->country;
1143 				number[i] = ((IdPatPtr)(vnp[i]->data.ptrvalue))->number;
1144 				app_number[i] = ((IdPatPtr)(vnp[i]->data.ptrvalue))->app_number;
1145 				break;
1146 			case PUB_PMid:
1147 				pmid[i] = vnp[i]->data.intvalue;
1148 				break;
1149 		}
1150 	}
1151 
1152 	if ((pmid[0] > 0) && (pmid[1] > 0))   /* got 2 muids */
1153 	{
1154 		if (pmid[0] == pmid[1])
1155 			return (Int2)0;
1156 		else if (pmid[0] < pmid[1])
1157 			return (Int2)-1;
1158 		else
1159 			return (Int2) 1;
1160 	}
1161 
1162 	if ((muid[0] > 0) && (muid[1] > 0))   /* got 2 muids */
1163 	{
1164 		if (muid[0] == muid[1])
1165 			return (Int2)0;
1166 		else if (muid[0] < muid[1])
1167 			return (Int2)-1;
1168 		else
1169 			return (Int2) 1;
1170 	}
1171 
1172 	if ((cap[0] != NULL) && (cap[1] != NULL))  /* 2 articles */
1173 	{
1174 		return CitArtMatch(cap[0], cap[1]);
1175 	}
1176 
1177 	if ((country[0] != NULL) && (country[1] != NULL))  /* 2 patents */
1178 	{
1179 		retval = (Int2)StringICmp(country[0], country[1]);
1180 		if (retval < 0)   /* different countries */
1181 			return (Int2) -1;
1182 		else if (retval > 0)
1183 			return (Int2) 1;
1184 
1185 		if ((number[0] != NULL) && (number[1] != NULL))
1186 		{
1187 			retval = (Int2)StringICmp(number[0], number[1]);
1188 			if (retval < 0)   /* different number */
1189 				return (Int2) -1;
1190 			else if (retval > 0)
1191 				return (Int2) 1;
1192 			else
1193 				return retval;
1194 		}
1195 		if ((app_number[0] != NULL) && (app_number[1] != NULL))
1196 		{
1197 			retval = (Int2)StringICmp(app_number[0], app_number[1]);
1198 			if (retval < 0)   /* different appl number */
1199 				return (Int2) -1;
1200 			else if (retval > 0)
1201 				return (Int2) 1;
1202 			else
1203 				return retval;
1204 		}
1205 		if (number[0] != NULL)
1206 			return (Int2) -1;
1207 		return (Int2) 1;
1208 	}
1209 
1210 	if (a->choice != b->choice)    /* all others must be same type */
1211 	{
1212 		return retval;
1213 	}
1214 							/* compare other types */
1215 	switch (a->choice)
1216 	{
1217 		case PUB_Gen:        /* generic */
1218 			return CitGenMatch((CitGenPtr)a->data.ptrvalue,
1219 					(CitGenPtr)b->data.ptrvalue, TRUE);
1220 		case PUB_Sub:        /* Submission */
1221 		 	return CitSubMatch((CitSubPtr)a->data.ptrvalue,
1222 					(CitSubPtr)b->data.ptrvalue);
1223 		case PUB_Journal:
1224 			return CitJourMatch((CitJourPtr)a->data.ptrvalue,
1225 					(CitJourPtr)b->data.ptrvalue);
1226 		case PUB_Book:
1227 		case PUB_Proc:
1228 		case PUB_Man:
1229 			return CitBookMatch((CitBookPtr)a->data.ptrvalue,
1230 					(CitBookPtr)b->data.ptrvalue);
1231 	}
1232 
1233 	return retval;
1234 }
1235 
1236 /*****************************************************************************
1237 *
1238 *   Int2 PubEquivMatch(a, b)
1239 *   	returns 0 if can determine pubs POINT TO SAME CITATION (not that
1240 *   		they are identical)
1241 *   	returns +1 or -1 if not the same,
1242 *   		for arbitrary ordering
1243 *
1244 *****************************************************************************/
PubEquivMatch(ValNodePtr a,ValNodePtr b)1245 NLM_EXTERN Int2 LIBCALL PubEquivMatch (ValNodePtr a, ValNodePtr b)
1246 {
1247 	Int2 retval = 0, tmp;
1248 	ValNodePtr vnp;
1249 
1250 	while (a != NULL)
1251 	{
1252 		vnp = b;
1253 		while (vnp != NULL)
1254 		{
1255 			tmp = PubMatch(a, vnp);
1256 			if (! tmp)	   /* a match */
1257 			{
1258 				return tmp;
1259 			}
1260 			if (! retval)   /* first one */
1261 				retval = tmp;
1262 			else if ((retval == 2) || (retval == -2))  /* type diffs only */
1263 				retval = tmp;
1264 
1265 			vnp = vnp->next;
1266 		}
1267 		a = a->next;
1268 	}
1269 	if (retval < 0)
1270 		retval = -1;
1271 	else
1272 		retval = 1;
1273 	return retval;
1274 }
1275 
1276 
1277 /*****************************************************************************
1278 *
1279 *   PubdescContentMatch(pub1, pub2)
1280 *
1281 *   returns TRUE if content of pub1 matches content of pub2, FALSE otherwise
1282 *****************************************************************************/
PubdescContentMatch(PubdescPtr pdp1,PubdescPtr pdp2)1283 NLM_EXTERN Boolean LIBCALL PubdescContentMatch (PubdescPtr pdp1, PubdescPtr pdp2)
1284 {
1285     if (pdp1 == NULL && pdp2 == NULL)
1286     {
1287         return TRUE;
1288     }
1289     else if (pdp1 == NULL || pdp2 == NULL)
1290     {
1291         return FALSE;
1292     }
1293     else if (pdp1->reftype != pdp2->reftype)
1294     {
1295         return FALSE;
1296     }
1297     else if (StringCmp (pdp1->name, pdp2->name) != 0
1298              || StringCmp (pdp1->fig, pdp2->fig) != 0
1299              || StringCmp (pdp1->maploc, pdp2->maploc) != 0
1300              || StringCmp (pdp1->seq_raw, pdp2->seq_raw) != 0
1301              || StringCmp (pdp1->comment, pdp2->comment) != 0)
1302     {
1303         return FALSE;
1304     }
1305     else if (PubMatch (pdp1->pub, pdp2->pub) != 0)
1306     {
1307         return FALSE;
1308     }
1309     else
1310     {
1311         return TRUE;
1312     }
1313 }
1314 
1315 
1316 /*****************************************************************************
1317 *
1318 *   PubLabel(pubptr, buf, buflen, content)
1319 *   	makes a short label for any Pub in buf, up to buflen size
1320 *   	content follows objmgr OM_LABEL_
1321 *
1322 *****************************************************************************/
PubLabel(ValNodePtr pub,CharPtr buf,Int2 buflen,Uint1 content)1323 NLM_EXTERN Int2 LIBCALL PubLabel (ValNodePtr pub, CharPtr buf, Int2 buflen, Uint1 content)
1324 {
1325 	return PubLabelUnique (pub, buf, buflen, content, FALSE);
1326 }
1327 
1328 /*****************************************************************************
1329 *
1330 *   PubLabelUnique(pubptr, buf, buflen, content, unique)
1331 *   	makes a short label for any Pub in buf, up to buflen size
1332 *   	content follows objmgr OM_LABEL_
1333 *       if (unique is TRUE, appends a string based on title words to make
1334 *           unique key base on ANSI std Z39.56-1991
1335 *
1336 *****************************************************************************/
PubLabelUnique(ValNodePtr pub,CharPtr buf,Int2 buflen,Uint1 content,Boolean unique)1337 NLM_EXTERN Int2 LIBCALL PubLabelUnique (ValNodePtr pub, CharPtr buf, Int2 buflen, Uint1 content, Boolean unique)
1338 {
1339 	CharPtr typelabel = NULL;
1340 	static CharPtr pubtypes [14] = {
1341 		"Unknown",
1342 		"Generic",
1343 		"Submit",
1344 		"Medline",
1345 		"MUID",
1346 		"Article",
1347 		"Journal",
1348 		"Book",
1349 		"Proceedings",
1350 		"Patent",
1351 		"PatID",
1352 		"Manuscript",
1353 		"Equiv" ,
1354 		"PMID" };
1355 	ValNodePtr vnp2=NULL, title=NULL;
1356 	Int2 len, diff;
1357 	Char tbuf[41];
1358 	Boolean first = TRUE;
1359 
1360 	Int4 muid = 0, pmid = 0;
1361 	AuthListPtr alp=NULL;
1362 	AuthorPtr ap;
1363 	ImprintPtr imp = NULL;
1364 	CharPtr year = NULL,
1365 			volume = NULL,
1366 			issue = NULL,
1367 			pages = NULL,
1368 			title1=NULL,
1369 			title2=NULL,
1370 			titleunique = NULL,
1371 			part_sup = NULL,
1372 			part_supi = NULL;
1373 	CitArtPtr cap;
1374 	CitJourPtr cjp;
1375 	CitBookPtr cbp=NULL;
1376 	CitSubPtr csp;
1377 	CitPatPtr cpp;
1378 	IdPatPtr ipp;
1379 	CitGenPtr cgp;
1380 	MedlineEntryPtr mep;
1381 	DatePtr dp = NULL;
1382 	Boolean unpublished = FALSE, done;
1383 	ValNodePtr eq[5];
1384 	Int2 i;
1385 	CharPtr s, cit;
1386 
1387 
1388 
1389 	if ((buf == NULL) || (buflen < 1)) return 0;
1390 
1391 	buf[0] = '?';
1392 	buf[1] = '\0';
1393 
1394 	if (pub == NULL) return 0;
1395 
1396 	if (pub->choice > 13)
1397 		typelabel = pubtypes[0];
1398 	else
1399 		typelabel = pubtypes[pub->choice];
1400 
1401 	len = buflen;
1402 
1403 	if (content == OM_LABEL_TYPE)
1404 		return LabelCopy(buf, typelabel, buflen);
1405 
1406 	if (content == OM_LABEL_BOTH)
1407 	{
1408 		diff = LabelCopyExtra(buf, typelabel, buflen, NULL, ": ");
1409 		buflen -= diff; buf += diff;
1410 	}
1411 
1412 	switch (pub->choice)
1413 	{
1414 		case PUB_Muid:
1415 			sprintf(tbuf, "NLM%ld", (long)(pub->data.intvalue));
1416 			diff = LabelCopy(buf, tbuf, buflen);
1417 			buflen -= diff;
1418 			return (len - buflen); /* already unique */
1419 			break;
1420 		case PUB_PMid:
1421 			sprintf(tbuf, "PM%ld", (long)(pub->data.intvalue));
1422 			diff = LabelCopy(buf, tbuf, buflen);
1423 			buflen -= diff;
1424 			return (len - buflen); /* already unique */
1425 			break;
1426 		case PUB_Equiv:
1427 			for (i = 0; i < 5; i++)
1428 				eq[i] = NULL;
1429 			i = 0;
1430 			for (vnp2 = (ValNodePtr)(pub->data.ptrvalue);
1431 			              ((vnp2 != NULL) && (buflen)); vnp2 = vnp2->next)
1432 			{
1433 				switch (vnp2->choice)
1434 				{
1435 					case PUB_Muid:
1436 						eq[3] = vnp2;
1437 						break;
1438 					case PUB_Gen:
1439 						cgp = (CitGenPtr)(vnp2->data.ptrvalue);
1440 						if (cgp->serial_number > 0)
1441 						{
1442 							eq[4] = vnp2;
1443 							break;
1444 						}
1445 					default:
1446 						if (i < 5)
1447 							eq[i] = vnp2;
1448 						i++;
1449 						break;
1450 				}
1451 			}
1452 			for (i = 0; i < 5; i++)
1453 			{
1454 				if (eq[i] != NULL)
1455 				{
1456 					if (! first)
1457 					{
1458 						diff = LabelCopy(buf, " ", buflen);
1459 						buflen -= diff; buf += diff;
1460 					}
1461 					else
1462 						first = FALSE;
1463 
1464 					diff = PubLabelUnique (eq[i], buf, buflen, OM_LABEL_CONTENT, unique);
1465 					buflen -= diff; buf += diff;
1466 				}
1467 			}
1468 			break;
1469 		case PUB_Medline:
1470 			mep = (MedlineEntryPtr)(pub->data.ptrvalue);
1471 			if (mep->pmid > 0)
1472 				sprintf(tbuf, "PM%ld", (long)(mep->pmid));
1473 			else
1474 				sprintf(tbuf, "NLM%ld", (long)(mep->uid));
1475 			diff = LabelCopyExtra(buf, tbuf, buflen, NULL, " ");
1476 		  buflen -= diff; buf += diff;
1477 			cap = mep->cit;
1478 			goto cit_art;
1479 		case PUB_Article:
1480 			cap = (CitArtPtr)(pub->data.ptrvalue);
1481 cit_art:	alp = cap->authors;
1482 			if (cap->title != NULL)
1483 				titleunique = (CharPtr)(cap->title->data.ptrvalue);
1484 			switch (cap->from)
1485 			{
1486 				case 1:
1487 					cjp = (CitJourPtr)(cap->fromptr);
1488 					goto cit_jour;
1489 				case 2:
1490 				case 3:
1491 					cbp = (CitBookPtr)(cap->fromptr);
1492 					goto cit_book;
1493 			}
1494 			break;
1495 		case PUB_Journal:
1496 			cjp = (CitJourPtr)(pub->data.ptrvalue);
1497 cit_jour:	imp = cjp->imp;
1498 			title = cjp->title;
1499 			break;
1500 		case PUB_Book:
1501 		case PUB_Proc:
1502 		case PUB_Man:
1503 			cbp = (CitBookPtr)(pub->data.ptrvalue);
1504 			title = cbp->title;
1505 cit_book:   imp = cbp->imp;
1506 			if (alp == NULL)
1507 				alp = cbp->authors;
1508 			break;
1509 		case PUB_Sub:
1510 			csp = (CitSubPtr)(pub->data.ptrvalue);
1511 			alp = csp->authors;
1512 			imp = csp->imp;
1513 			dp = csp->date;
1514 			break;
1515 		case PUB_Patent:
1516 			cpp = (CitPatPtr)(pub->data.ptrvalue);
1517 			alp = cpp->authors;
1518 			dp = cpp->date_issue;
1519 			if (dp == NULL)
1520 				dp = cpp->app_date;
1521 			title1 = cpp->country;
1522 			title2 = cpp->number;
1523 			if (title2 == NULL)
1524 				title2 = cpp->app_number;
1525 			break;
1526 		case PUB_Pat_id:
1527 			ipp = (IdPatPtr)(pub->data.ptrvalue);
1528 			title1 = ipp->country;
1529 			title2 = ipp->number;
1530 			if (title2 == NULL)
1531 				title2 = ipp->app_number;
1532 			break;
1533 		case PUB_Gen:
1534 			cgp = (CitGenPtr)(pub->data.ptrvalue);
1535 			if (cgp->serial_number > 0)
1536 			{
1537 				sprintf(tbuf, "[%d]", (int)(cgp->serial_number));
1538 				diff = LabelCopy(buf, tbuf, buflen);
1539 				buflen -= diff; buf += diff;
1540 			}
1541 			if (cgp->muid > 0)
1542 			{
1543 				sprintf(tbuf, "NLM%ld", (long)(cgp->muid));
1544 				diff = LabelCopy(buf, tbuf, buflen);
1545 				buflen -= diff; buf += diff;
1546 
1547 			}
1548 			dp = cgp->date;
1549 			title = cgp->journal;
1550 			alp = cgp->authors;
1551 			if (cgp->cit != NULL)
1552 			{
1553 				if (! StringICmp("Unpublished", cgp->cit))
1554 					unpublished = TRUE;
1555 				else if (title == NULL)
1556 					title2 = cgp->cit;
1557 			}
1558 			volume = cgp->volume;
1559 			issue=cgp->issue;
1560 			pages=cgp->pages;
1561             if (cgp->title != NULL)
1562 				titleunique = cgp->title;
1563 			else if (title2 != NULL)
1564 				titleunique = title2;
1565 			else if (title == NULL)
1566 				titleunique = cgp->cit;
1567 			if (title == NULL && alp == NULL && cgp->title == NULL &&
1568 				volume == NULL && pages == NULL && issue == NULL) {
1569 				titleunique = NULL;
1570 				if ((cit = StringSave(cgp->cit)) != NULL) {
1571 					if (!unique) {
1572 						for (s = cit + StringLen(cit) -1;
1573 									s > cit && *s !='|';   s--) continue;
1574 						if (*s == '|' ) {
1575 							*s = '\0';
1576 						}
1577 					}
1578 					diff = LabelCopy(buf, cit, buflen);
1579 					MemFree(cit);
1580 				}
1581 				return 0;
1582 			}
1583 			break;
1584 		default:
1585 			sprintf(tbuf,"Unknown pub[%d]", (int)(pub->choice));
1586 			title2 = tbuf;
1587 			break;
1588 
1589 	}
1590 
1591 	if (imp != NULL)
1592 	{
1593 		if (dp == NULL)
1594 			dp = imp->date;
1595 		if (volume == NULL)
1596 			volume = imp->volume;
1597 		if (issue == NULL)
1598 			issue = imp->issue;
1599 		if (pages == NULL)
1600 			pages = imp->pages;
1601 		part_sup = imp->part_sup;
1602 		part_supi = imp->part_supi;
1603 	}
1604 
1605 	if (alp != NULL)
1606 	{
1607 		vnp2 = alp->names;
1608 		if (vnp2 != NULL)
1609 		{
1610 			if (alp->choice == 1)   /* std name */
1611 			{
1612 				ap = (AuthorPtr)(vnp2->data.ptrvalue);
1613 				diff = PersonIdLabel(ap->name, buf, buflen, PIDLABEL_GENBANK);
1614 			}
1615 			else
1616 				diff = LabelCopy(buf, (CharPtr)(vnp2->data.ptrvalue), buflen);
1617 		buflen -= diff;
1618 		buf += diff;
1619 		}
1620 	}
1621 
1622 	if (dp != NULL)
1623 	{
1624 		if (dp->data[0])
1625 		{
1626 			if (pub->choice == PUB_Sub && dp->data[2] != 0 && dp->data[3] != 0){
1627 				sprintf(tbuf, "%d-%d-%d", (int)(dp->data[2]),
1628 						(int)(dp->data[3]), (int)(dp->data[1])+1900);
1629 				year = tbuf;
1630 			} else {
1631 				sprintf(tbuf, "%d", (int)(dp->data[1])+1900);
1632 				year = tbuf;
1633 			}
1634 		}
1635 		else
1636 			year = dp->str;
1637 		diff = LabelCopyExtra(buf, year, buflen, " (", ") ");
1638 		buflen -= diff; buf += diff;
1639 	}
1640 
1641 	if ((title != NULL) && (titleunique == NULL))
1642 		titleunique = (CharPtr)(title->data.ptrvalue);
1643 
1644 	if (title2 == NULL)
1645 	{
1646 		if (title != NULL)
1647 			title2 = (CharPtr)(title->data.ptrvalue);
1648 
1649 	}
1650 
1651 	if (title2 != NULL)
1652 	{
1653 		if (cbp != NULL)
1654 			title1 = "(in) ";
1655 
1656 		diff = LabelCopyExtra(buf, title2, buflen, title1, " ");
1657 		buflen -= diff; buf += diff;
1658 	}
1659 
1660 	if (volume != NULL)
1661 	{
1662 		if (part_sup != NULL)
1663 			title1 = part_sup;
1664 		else
1665 			title1 = ":";
1666 
1667 		diff = LabelCopyExtra(buf, volume, buflen, NULL, title1);
1668 		buflen -= diff; buf += diff;
1669 		if (part_sup != NULL)
1670 		{
1671 			diff = LabelCopyExtra(buf, ":", buflen, NULL, NULL);
1672 			buflen -= diff; buf += diff;
1673 		}
1674 	}
1675 
1676 	if (issue != NULL)
1677 	{
1678 		if (part_supi != NULL)
1679 			title1 = part_supi;
1680 		else
1681 			title1 = ")";
1682 
1683 		diff = LabelCopyExtra(buf, issue, buflen, "(" , title1);
1684 		buflen -= diff; buf += diff;
1685 		if (part_supi != NULL)
1686 		{
1687 			diff = LabelCopyExtra(buf, ")", buflen, NULL, NULL);
1688 			buflen -= diff; buf += diff;
1689 		}
1690 	}
1691 
1692 	if (pages != NULL)
1693 	{
1694 		diff = LabelCopy(buf, pages, buflen);
1695 		buflen -= diff; buf += diff;
1696 	}
1697 
1698     if (unpublished)
1699     {
1700     	diff = LabelCopy(buf, "Unpublished", buflen);
1701     	buflen -= diff; buf += diff;
1702     }
1703 
1704 	if (unique)  /* put on unique tag made from title */
1705 	{
1706 		done = FALSE;
1707 		i=0;
1708 		if (titleunique != NULL && *titleunique != '\0')
1709 		{
1710 			while ((! done) && (i < 40))
1711 			{
1712 				tbuf[i] = *titleunique;
1713 				i++;
1714 				while (! IS_WHITESP(*titleunique))
1715 				{
1716 					titleunique++;
1717 					if (*titleunique == '\0')
1718 					{
1719 						done = TRUE;
1720 						break;
1721 					}
1722 				}
1723 				while (IS_WHITESP(*titleunique))
1724 				{
1725 					titleunique++;
1726 					if (*titleunique == '\0')
1727 					{
1728 						done = TRUE;
1729 						break;
1730 					}
1731 				}
1732 			}
1733 		}
1734 		tbuf[i] = '\0';
1735 		diff = LabelCopyExtra(buf, tbuf, buflen, "|" , NULL);
1736 		buflen -= diff; buf += diff;
1737 	}
1738 
1739 
1740 	return (len - buflen);
1741 }
1742 
1743