NCBI C Toolkit Cross Reference

C/api/asn2ff5.c


  1 /*   asn2ff5.c
  2 * ===========================================================================
  3 *
  4 *                            PUBLIC DOMAIN NOTICE
  5 *            National Center for Biotechnology Information (NCBI)
  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 do not place any restriction on its use or reproduction.
 13 *  We would, however, appreciate having the NCBI and the author cited in
 14 *  any work or product based on this material
 15 *
 16 *  Although all reasonable efforts have been taken to ensure the accuracy
 17 *  and reliability of the software and data, the NLM and the U.S.
 18 *  Government do not and cannot warrant the performance or results that
 19 *  may be obtained by using this software or data. The NLM and the U.S.
 20 *  Government disclaim all warranties, express or implied, including
 21 *  warranties of performance, merchantability or fitness for any particular
 22 *  purpose.
 23 *
 24 * ===========================================================================
 25 *
 26 * File Name:  asn2ff5.c
 27 *
 28 * Author:  Karl Sirotkin, Tom Madden, Tatiana Tatusov
 29 *
 30 * Version Creation Date:   7/15/95
 31 *
 32 * $Revision: 6.13 $
 33 *
 34 * File Description: 
 35 *
 36 * Modifications:  
 37 * --------------------------------------------------------------------------
 38 * Date     Name        Description of modification
 39 * -------  ----------  -----------------------------------------------------
 40 *
 41 *
 42 * ==========================================================================
 43 */
 44 
 45 /*************************************
 46 *
 47  * $Log: asn2ff5.c,v $
 48  * Revision 6.13  2002/01/29 12:37:21  kans
 49  * restored year for unpublished records to minimize QA diffs
 50  *
 51  * Revision 6.12  2002/01/10 15:19:16  kans
 52  * suppress year in unpublished citgen - this is new policy, and suppresses diffs against asn2gb
 53  *
 54  * Revision 6.11  2001/06/25 22:39:05  kans
 55  * format_patent puts patent seqid in GenPept format
 56  *
 57  * Revision 6.10  2000/05/15 23:13:35  kans
 58  * format_thesis forgot to add space for afp->affil
 59  *
 60  * Revision 6.9  1998/12/09 18:45:09  tatiana
 61  * a bug fixed in GetAuthors()
 62  *
 63  * Revision 6.8  1998/06/17 21:41:24  tatiana
 64  * Null pointer protection added to ValidatePub()
 65  *
 66  * Revision 6.7  1998/06/15 14:58:53  tatiana
 67  * UNIX compiler warnings fixed
 68  *
 69  * Revision 6.6  1998/04/30 21:49:03  tatiana
 70  * *** empty log message ***
 71  *
 72  * Revision 6.5  1998/03/09 21:45:04  tatiana
 73  * changed format_book to skip empty authors
 74  *
 75  * Revision 6.4  1998/02/06 16:19:25  tatiana
 76  * added std affiliation to format_thesis()
 77  *
 78  * Revision 6.3  1997/12/15 15:53:26  tatiana
 79  * features processing has been changed
 80  *
 81  * Revision 6.1  1997/11/13 19:26:41  tatiana
 82  * fixed Array bounds Write error in format_book()
 83  *
 84  * Revision 6.0  1997/08/25 18:05:02  madden
 85  * Revision changed to 6.0
 86  *
 87  * Revision 5.20  1997/07/22 19:26:35  tatiana
 88  * SeqIdFindBest(bsp->id, SEQID_GENBANK) added in CheckAndGetNAFeatLoc
 89  *
 90  * Revision 5.19  1997/07/16 21:55:43  vakatov
 91  * Removed extraneous and DLL-harmful "extern NCBI_months[]" declaration
 92  *
 93  * Revision 5.18  1997/06/19 18:37:12  vakatov
 94  * [WIN32,MSVC++]  Adopted for the "NCBIOBJ.LIB" DLL'ization
 95  *
 96  * Revision 5.17  1997/06/06 20:27:12  tatiana
 97  * doSup changed
 98  *
 99  * Revision 5.16  1997/04/22  18:07:31  tatiana
100  * added a space between part and suppl in doSup()
101  *
102  * Revision 5.15  1997/02/25  23:45:41  tatiana
103  * line 1121: debugging printf removed
104  *
105  * Revision 5.14  1997/02/10  22:14:24  tatiana
106  * *** empty log message ***
107  *
108  * Revision 5.13  1997/01/27  19:15:10  tatiana
109  * *** empty log message ***
110  *
111  * Revision 5.12  1997/01/06  21:52:53  tatiana
112  * added check for zero patent_seqid in format_patent()
113  *
114  * Revision 5.11  1996/08/27  17:35:01  tatiana
115  * changes in FlatIgnoreThisPatentPub to allow patent pub without SeqId
116  *
117  * Revision 5.10  1996/08/16  20:33:30  tatiana
118  * feat key changed in GetNAFeatKey()
119  *
120  * Revision 5.8  1996/08/12  16:56:40  tatiana
121  * change ErrPostEx to ErrPostStr
122  *
123  * Revision 5.7  1996/07/30  16:33:32  tatiana
124  * add Boolean arg in CheckNAFeat()
125  *
126  * Revision 5.6  1996/07/11  14:58:50  tatiana
127  * title in Thesis
128  *
129  * Revision 5.5  1996/06/14  18:04:30  tatiana
130  * GetNAFeatKey change
131  *
132  * Revision 5.3  1996/06/12  22:34:56  tatiana
133  * turn off aouthor name in format_sub
134  *
135  * Revision 5.2  1996/06/06  14:49:23  tatiana
136  * *** empty log message ***
137  *
138  * Revision 5.1  1996/06/05  18:18:42  tatiana
139  * format_article, format_bookarticle, format_jourarticle are not static any more
140  *
141  * Revision 4.18  1996/04/29  18:51:17  tatiana
142  * whole_book format added
143  *
144  * Revision 4.17  1996/01/29  22:36:57  tatiana
145  * a2ferrdf.h included for error posting MODULE
146  *
147  * Revision 4.16  1995/12/13  16:33:04  tatiana
148  * a bug fixed (check for NULL pointer)
149  *
150  * Revision 4.15  1995/11/17  21:28:35  kans
151  * asn2ff now uses gather (Tatiana)
152  *
153  * Revision 4.4  1995/08/18  21:47:30  tatiana
154  * *** empty log message ***
155  *
156  * Revision 4.3  1995/08/16  15:34:19  tatiana
157  * *** empty log message ***
158  *
159  * Revision 4.2  1995/08/04  15:24:31  tatiana
160  * CheckPubs in debug mode added
161  *
162  * Revision 4.1  1995/08/01  14:52:36  tatiana
163  * change SeqIdPrint to SeqIdWrite
164  *
165  * Revision 1.55  1995/07/17  19:33:20  kans
166  * parameters combined into Asn2ffJobPtr structure
167  *
168 *
169 **************************************/
170 
171 /*************************************************************************
172 *
173 *       "pub.c" which contains files relating to publications.
174 *
175 **************************************************************************/
176 
177 #include <asn2ffp.h>
178 #include <a2ferrdf.h>
179 #include <utilpub.h>
180 #include <parsegb.h>
181 
182 #define CTX_2GB_NOT_IMPLEMENTED 1
183 /***************************************************************************
184 *
185 *       PROTOTYPES, mostly for functions from Karl Sirotkin's code.
186 *
187 *************************************************************************/
188 static CharPtr /*UNUSED*/GetSubmitterName PROTO ((Uint1 format, ValNodePtr pub));
189 NLM_EXTERN CharPtr FlatStringGroupTerm PROTO ((Boolean embl_format, CharPtr start, ValNodePtr head, CharPtr delimit, CharPtr period, CharPtr term));
190 NLM_EXTERN Int2 fix_pages PROTO ((CharPtr out_pages, CharPtr in_pages));
191 NLM_EXTERN CharPtr FlatDateFromCreate PROTO ((CharPtr default_date, NCBI_DatePtr flat_date));
192 NLM_EXTERN ValNodePtr GBGetAuthNames PROTO ((Uint1 format, AuthListPtr ap));
193 NLM_EXTERN CharPtr GetAffiliation PROTO ((AffilPtr afp));
194 NLM_EXTERN Int2 ValidatePub PROTO ((BioseqPtr bsp, ValNodePtr the_pub));
195 static CharPtr format_cit_sub PROTO ((Uint1 format, ValNodePtr the_pub, Boolean PNTR submit, Boolean make_index));
196 static CharPtr format_general PROTO ((Asn2ffJobPtr ajp, BioseqPtr bsp, ValNodePtr the_pub, Boolean make_index));
197 static CharPtr format_patent PROTO ((Uint1 format, ValNodePtr the_pub, Int4 pat_seqid, Boolean make_index));
198 static CharPtr format_thesis PROTO ((Uint1 format, ValNodePtr the_pub, Boolean make_index));
199 void PostARefErrMessage PROTO ((Asn2ffJobPtr ajp, BioseqPtr bsp, PubStructPtr psp, ValNodePtr ext_pub, Int2 status, CharPtr string));
200 static GBQualPtr GBQualCopy PROTO ((GBQualPtr old_qual));
201 static CharPtr StripParanthesis PROTO ((CharPtr ptr_in, Boolean PNTR paranthesis));
202 static CharPtr makeaffil PROTO ((AffilPtr afp, CharPtr temp, Boolean PNTR first_std));
203 static CharPtr doSup PROTO ((CharPtr temp, CharPtr issue, CharPtr part_sup, CharPtr part_supi));
204 NLM_EXTERN CharPtr format_book PROTO ((Uint1 format, ValNodePtr the_pub, Boolean make_index));
205 
206 /*****************************************************************************
207 *GetAuthors
208 *
209 *
210 *****************************************************************************/
211 
212 /*----------- GetAuthors ()------*/
213 NLM_EXTERN ValNodePtr GetAuthors (Asn2ffJobPtr ajp, ValNodePtr the_pub)
214 {
215 
216         AuthListPtr ap = NULL;
217         CharPtr tmp;
218         CitArtPtr ca;
219         CitBookPtr cb;
220         CitGenPtr cg;   
221         CitSubPtr cs;
222         CitPatPtr cp;
223         MedlineEntryPtr ml;
224         ValNodePtr spare, this_name, namehead=NULL;
225 
226         if (the_pub == NULL)
227                 return NULL;
228         switch ( the_pub -> choice) {
229 
230         case PUB_Patent:
231                 cp = (CitPatPtr) the_pub -> data.ptrvalue;
232                 ap = cp  -> authors;
233                 break;
234         case PUB_Man:
235         case PUB_Book:
236                 cb = (CitBookPtr) the_pub -> data.ptrvalue;
237                 ap = cb -> authors;
238                 break;
239         case PUB_Article:
240         case PUB_Medline:
241                 if ( the_pub -> choice == PUB_Medline){
242                         ml = (MedlineEntryPtr) the_pub -> data.ptrvalue;
243                         ca = (CitArtPtr) ml -> cit;
244                 } else{
245                         ca = (CitArtPtr) the_pub -> data.ptrvalue;
246                 }
247                 ap = ca -> authors;
248                 break;
249         case PUB_Gen: 
250                 cg = (CitGenPtr) the_pub -> data.ptrvalue;
251                 ap = cg -> authors;
252                 break;
253         case PUB_Sub:
254                 cs = (CitSubPtr)  the_pub -> data.ptrvalue;
255                 ap = cs -> authors;
256                 break;
257         default:
258                 if (ajp->error_msgs == TRUE)
259                         ErrPostEx(SEV_WARNING, ERR_REFERENCE_Illegalreference,
260                         "FlatAuthor: Unimplemented pub type=%d\n", 
261                         (int) the_pub -> choice);
262                 break;
263         }
264 
265         if (ap) {
266                 if (ap->choice != 1){   /* just strings */
267                         for (spare = ap->names, namehead = NULL; 
268                                         spare; spare = spare -> next) {
269                                 this_name = ValNodeNew(namehead);
270                                 if (namehead == NULL)
271                                         namehead = this_name;
272                                 this_name -> data.ptrvalue = StringSave(spare -> data.ptrvalue);
273                                 if (ajp->format == EMBL_FMT || ajp->format == PSEUDOEMBL_FMT ||
274                                         ajp->format == EMBLPEPT_FMT) {
275                                         for (tmp=(CharPtr) this_name->data.ptrvalue; 
276                                                 *tmp != '\0'; tmp++) {
277                                                 if (*tmp == ',') {
278                                                         *tmp = ' ';
279                                                         break;
280                                                 }
281                                         }
282                                 }
283                         }
284                 }  else {               /* structured names */
285                         namehead = GBGetAuthNames(ajp->format, ap);
286                 }
287         }
288 
289         return namehead;
290 
291 }       /* GetAuthors */
292 
293 /*----------- FlatAuthor ()------*/
294 NLM_EXTERN CharPtr FlatAuthor (Asn2ffJobPtr ajp, ValNodePtr the_pub)
295 {
296         CharPtr ret_save, temp, retval=NULL;
297         int len;
298         ValNodePtr namehead;
299 
300         namehead = GetAuthors(ajp, the_pub);
301 
302         if (ajp->format == EMBL_FMT || ajp->format == PSEUDOEMBL_FMT || 
303                 ajp->format == EMBLPEPT_FMT)
304                 retval = FlatStringGroupTerm(TRUE, NULL, namehead, ", ", NULL, ", ");
305         else
306                 retval = FlatStringGroupTerm(FALSE, NULL, namehead, ", ", NULL, " and ");
307 
308         ValNodeFreeData(namehead);     /* remove name list */
309 
310         if (retval) {
311                 len = StringLen(retval);
312                 if (len > 0){
313                         if ( retval[len-1] != '.') {
314                                 ret_save = retval;
315                                 temp = retval = MemNew(len+2);
316                                 temp = StringMove(temp,ret_save);
317                                 temp = StringMove(temp,".");
318                                 MemFree (ret_save);
319                         }
320                 }
321         }
322 
323         return FlatCleanEquals(retval);
324 
325 }       /* FlatAuthor */
326 
327 
328 /*****************************************************************************
329 *FlatCleanEquals
330 *
331 *       taken (with minor modifications) from Karl Sirotkin's code 
332 *       by Tom Madden.
333 *
334 *****************************************************************************/
335 
336         /*--------FlatCleanEquals()----------*/
337 
338 NLM_EXTERN CharPtr FlatCleanEquals
339 (CharPtr retval)
340 {
341         CharPtr p=retval;
342 
343         if (p){
344                 for (;*p; p++){
345                         if (*p == '\"')
346                                 *p = '\'';
347                 }
348         }
349 
350 return retval;
351 }
352 
353 /*****************************************************************************
354 *FlatStringGroupTerm
355 *
356 *       taken (with minor modifications) from Karl Sirotkin's code 
357 *       by Tom Madden.
358 *
359 *****************************************************************************/
360 
361 /*----------- FlatStringGroupTerm  ()------*/
362 NLM_EXTERN CharPtr FlatStringGroupTerm 
363 (Boolean embl_format, CharPtr start, ValNodePtr head, CharPtr delimit, CharPtr period, CharPtr term)
364 {
365         CharPtr retval = NULL, p, ptr;
366         Int4 lenmax, len = 0, lenstart = 0, lende = 0, lente=0, lenper=0;
367         ValNodePtr an;
368 
369         if (head == NULL)
370                 return NULL;
371 
372         if (delimit) {
373                 lende = StringLen(delimit);
374         }
375         if (term) {
376                 lente = StringLen(term);
377         }
378         lenmax = lende;
379         if (lente > lende) {
380                 lenmax = lente;
381         }
382         if (period) {
383                 lenper=StringLen(period);
384         }
385         len =  lenmax + lenper;
386         if (start) {
387                 len += (lenstart = StringLen(start))  ;
388         }
389         for (an = head; an; an = an -> next) {
390                 if (an -> data.ptrvalue) {
391                         len += lenmax + StringLen( (CharPtr) ( an -> data.ptrvalue));
392                 }
393         }
394 
395 /*--will be lende too long - who cares --- */
396         p = retval = MemNew ((size_t)(len+1));
397         if (start) {
398                 StringCpy (p, start);
399                 p += lenstart;
400                 StringCpy(p, delimit);
401                 p += lende;
402         }
403         for (an = head; an; an = an -> next) {
404                 if (an -> data.ptrvalue == NULL) {
405                         continue;
406                 }
407                 StringCpy(p, (CharPtr) (an -> data.ptrvalue) );
408                 p += StringLen( (CharPtr) (an->data.ptrvalue));
409                 if (an->next) {
410                         if ( an -> next -> next) {
411                                 StringCpy(p, delimit);
412                                 p += lende;
413                         } else {
414                                 ptr = (CharPtr) an->next->data.ptrvalue;
415                                 if ((StringCmp("et al.", ptr)) == 0 ||
416                                                 (StringCmp("et,al.", ptr)) == 0) {
417                                         if (embl_format) {
418                                                 StringCpy(p, term);
419                                                 p += lente;
420                                         } else {
421                                                 StringCpy(p, " ");
422                                                 p++;
423                                         }
424                                 } else {
425                                         StringCpy(p, term);
426                                         p += lente;
427                                 }
428                         }
429                 }
430         }
431         if (period){
432                 StringCpy(p, period);
433                 p += lenper;
434         }
435         return retval;
436 }       
437 
438 /*****************************************************************************
439 *
440 *   GBGetAuthNames(Uint1 format, AuthListPtr)
441 *       Allocates a linked list of ValNode
442 *       Each ->data.ptrvalue will have a string containing a formatted name
443 *       Processes only AuthList of type "std"
444 *               Returns NULL on any other type
445 *       Caller must free returned linked list (call ValNodeFreeData())
446 *
447 *****************************************************************************/
448 NLM_EXTERN ValNodePtr GBGetAuthNames (Uint1 format, AuthListPtr ap)
449 {
450         ValNodePtr namehead, cur, spare;
451         CharPtr tmp;
452         AuthorPtr authptr;
453         PersonIdPtr pid;
454         NameStdPtr nsp;
455         Boolean embl_format = FALSE;
456 
457         if (ap == NULL)
458                 return NULL;
459 
460         if (format == EMBL_FMT || format == PSEUDOEMBL_FMT ||
461                                         format == EMBLPEPT_FMT) {
462                 embl_format = TRUE;
463         }
464         namehead = NULL;   /* convert to strings */
465         if (ap->choice != 1)
466                 return NULL;
467 
468         cur = NULL;
469         for (spare = ap->names; spare; spare = spare->next)
470         {
471                 cur = ValNodeNew(cur);
472                 if (namehead == NULL)
473                         namehead = cur;
474                 authptr = (AuthorPtr) spare->data.ptrvalue;
475                 pid = authptr->name;
476                 if (pid->choice == 2)  /* structured name */
477                 {
478                         nsp = (NameStdPtr) pid->data;
479                         if (nsp->names[0] != NULL)   /* last name */
480                         {
481                                 tmp = MemNew((size_t)(StringLen(nsp->names[0]) + StringLen(nsp->names[4]) + StringLen(nsp->names[5]) + 3));
482                                 cur->data.ptrvalue = tmp;
483                                 tmp = StringMove(tmp, nsp->names[0]);
484                                 if (nsp->names[4] && *nsp->names[4] != '\0')
485                                 {
486                                 if (embl_format)
487                                                 tmp = StringMove(tmp, " ");
488                                         else
489                                                 tmp = StringMove(tmp, ",");
490                                         tmp = StringMove(tmp, nsp->names[4]);
491                                 }
492                                 if (nsp->names[5] && *nsp->names[5] != '\0') /* suffix */
493                                 {
494                                         tmp = StringMove(tmp, " ");
495                                         tmp = StringMove(tmp, nsp->names[5]);
496                                 }
497                         }
498                         else if (nsp->names[3] && *nsp->names[3] != '\0') /* full name */
499                         {
500                                 cur->data.ptrvalue = (Pointer)StringSave(nsp->names[3]);
501                         }
502                 }
503                 else if ((pid->choice == 3) || (pid->choice == 4)){
504                         cur->data.ptrvalue = (Pointer)StringSave((CharPtr)pid->data);
505                                 if (embl_format)
506                                 for (tmp = (CharPtr) cur->data.ptrvalue; 
507                                         *tmp != '\0'; tmp ++)
508                                 {
509                                         if (*tmp == ','){
510                                                 *tmp = ' ';
511                                                 break;
512                                         }
513                                 }
514                 }
515         }
516         return namehead;
517 }
518 /*****************************************************************************
519 *
520 *   GetSubmitterName (Uint1 format, ValNodePtr pub)
521 *
522 *       Returns one author name for the submitter line on the flat file.
523 *       The pub should be a cit-sub.
524 *
525 *****************************************************************************/
526 
527 /*______________________________________________________________________
528 **
529 **      This code is not currently used.
530 **      I do not remove this piece of code, just comment it out.
531 **      -- Dmitri Lukyanov
532 */
533 #if 0
534 
535 static CharPtr GetSubmitterName (Uint1 format, ValNodePtr pub)
536 
537 {
538         AuthListPtr ap;
539         AuthorPtr authptr;
540         CharPtr first, initials=NULL, last, middle, start, tmp, submitter_name=NULL;
541         CitSubPtr cs;
542         Int2 length;
543         NameStdPtr nsp;
544         PersonIdPtr pid;
545         ValNodePtr spare;
546 
547         if (pub->choice != 2)
548                 return NULL;
549 
550         cs = (CitSubPtr) pub->data.ptrvalue;
551         ap = cs->authors;
552 
553         if (ap && ap->choice != 1)
554         {
555                 spare = ap->names;      /* take first name in list */
556                 if (spare)
557                 {
558                         submitter_name = StringSave(spare -> data.ptrvalue);
559                                 if (format == EMBL_FMT || format == PSEUDOEMBL_FMT ||
560                                         format == EMBLPEPT_FMT)
561                         {
562                                 for (tmp=(CharPtr) submitter_name; 
563                                         *tmp != '\0'; tmp++)
564                                 {
565                                         if (*tmp == ',')
566                                         {
567                                                 *tmp = ' ';
568                                                 break;
569                                         }
570                                 }
571                         }
572                 }
573         } 
574         else
575         {
576                 spare = ap->names;
577                 if (spare)
578                 {
579                         authptr = (AuthorPtr) spare->data.ptrvalue;
580                         pid = authptr->name;
581                         if (pid->choice == 2)  /* structured name */
582                         {
583                                 nsp = (NameStdPtr) pid->data;
584                                 if (nsp->names[3]) /* full name */
585                                 {
586                                         submitter_name = StringSave(nsp->names[3]);
587                                 }
588                                 else
589                                 {
590                                         if (nsp->names[0] != NULL)   /* last name */
591                                                 last = nsp->names[0];
592                                         else
593                                                 last = NULL;
594                                         if (nsp->names[1] != NULL)   /* first name */
595                                                 first = nsp->names[1];
596                                         else
597                                                 first = NULL;
598                                         if (nsp->names[4] != NULL)   /* initials*/
599                                         {
600                                             tmp = nsp->names[4];
601                                             while (*tmp == ' ') 
602                                                 tmp++;     /* no white space */
603                                             if (first)
604                                             {
605                                                while (*tmp != '\0')
606                                                {
607                                                   if (*tmp == *first)
608                                                   {
609                                                         tmp++;
610                                                         if (*tmp == '.')
611                                                            tmp++;
612                                                         break;
613                                                    }
614                                                    else
615                                                         tmp++;
616                                                }
617                                             }
618                                             length = StringLen(tmp);
619                                             if (length > 0)
620                                             {
621                                                  if (tmp[length-1] != '.')
622                                                  {
623                                                         start = initials = MemNew((length+2)*sizeof(Char));
624                                                         initials = StringMove(initials, tmp);
625                                                         initials = StringMove(initials, ".");
626                                                         initials = start;
627                                                  }
628                                                  else
629                                                         initials = StringSave(tmp);
630                                             }
631                                             else
632                                                  initials = NULL;
633                                         }
634                                         if (initials == NULL && 
635                                                 nsp->names[2] != NULL)   /* middle name */
636                                         {
637                                              middle = nsp->names[2];
638                                              start = initials = MemNew(3*sizeof(Char));
639                                              *initials = middle[0]; initials++;
640                                              *initials = '.'; 
641                                              initials = start;
642                                         }
643                                         length = StringLen(last) + 
644                                                 StringLen(initials) + StringLen(first);
645                                         if (last)
646                                         {
647                                                 start = submitter_name = 
648                                                         MemNew((length+3)*sizeof(Char));
649                                                 if (first)
650                                                 {
651                                                    start = StringMove(start, first);
652                                                    start = StringMove(start, " ");
653                                                 }
654                                                 if (initials)
655                                                 {
656                                                    start = StringMove(start, initials);
657                                                    start = StringMove(start, " ");
658                                                    initials = MemFree(initials);
659                                                 }
660                                                 start = StringMove(start, last);
661                                         }
662                                 }
663                         }
664                         else if ((pid->choice == 3) || (pid->choice == 4))
665                         {
666                                 submitter_name = StringSave((CharPtr)pid->data);
667                                 if (format == EMBL_FMT || format == PSEUDOEMBL_FMT ||
668                                         format == EMBLPEPT_FMT)
669                                         for (tmp = (CharPtr) submitter_name; 
670                                                 *tmp != '\0'; tmp ++)
671                                         {
672                                                 if (*tmp == ','){
673                                                         *tmp = ' ';
674                                                         break;
675                                                 }
676                                         }
677                         }
678                 }
679         }
680         return submitter_name;
681 }
682 
683 #endif
684 /*______________________________________________________________________
685 */
686 
687 static Boolean all_caps(CharPtr p)
688 {
689         for ( p++; p != NULL && *p != '\0'; p++){
690                 if (IS_LOWER(*p)) {
691                         return FALSE;
692                 }
693         }
694         return TRUE;
695 }
696 
697 /*****************************************************************************
698 *FlatPubTitle
699 *
700 *       taken (with minor modifications) from Karl Sirotkin's code 
701 *       creates a title string from ValNode pub
702 *****************************************************************************/
703 
704 /*----------- FlatPubTitle ()------*/
705 NLM_EXTERN CharPtr FlatPubTitle 
706 (ValNodePtr the_pub)
707 {
708         CharPtr retval = NULL;
709         CitArtPtr ca;
710         CitBookPtr book;
711         CitGenPtr cg;
712         CharPtr str_ret, p;
713         MedlineEntryPtr ml;
714         CitPatPtr cp;
715 
716         switch ( the_pub -> choice){
717 
718         case PUB_Patent:
719                 cp = (CitPatPtr) the_pub -> data.ptrvalue;
720                 retval = StringSave(cp -> title);
721                 break;
722         case PUB_Man:
723         case PUB_Book:
724                 book = (CitBookPtr) the_pub -> data.ptrvalue;
725                 if (book ->  title && book -> title -> data.ptrvalue) {
726                         p = book -> title -> data.ptrvalue;
727                         if (StringLen(p) > 3) {
728                                 if (IS_LOWER(*p)) {
729                                         *p = TO_UPPER(*p);
730                                 }
731                                 if (all_caps(p)) {
732                                         for ( p++; p != NULL && *p != '\0'; p++){
733                                                 *p = TO_LOWER(*p);
734                                         }
735                                 }
736                         }
737                         retval = StringSave(book -> title -> data.ptrvalue);
738                 }
739                 break;
740 
741         case PUB_Medline:
742         case PUB_Article:
743                 if ( the_pub -> choice == PUB_Medline){
744                         ml = (MedlineEntryPtr) the_pub -> data.ptrvalue;
745                         ca = (CitArtPtr) ml -> cit;
746                 }else{
747                         ca = (CitArtPtr) the_pub -> data.ptrvalue;
748                 }
749                 if (ca -> title )
750                         if (ca -> title -> data.ptrvalue)
751                                 retval = StringSave(ca -> title -> data.ptrvalue);
752                 break;
753         case PUB_Gen: 
754                 cg = (CitGenPtr) the_pub -> data.ptrvalue;
755                 if (cg->title)
756                         retval = StringSave(cg->title);
757                 else
758                 {
759                         str_ret = NULL;
760                         if (cg -> cit)
761                                 str_ret = StrStr(cg -> cit ,"Title=\"");
762                         if (str_ret){
763                                 retval = StringSave(str_ret + 7);
764                                 for (p=retval; *p; p++)
765                                         if (*p == '"'){
766                                                 *p = '\0';
767                                                 break;
768                                         }
769                         } 
770                         /* Finish off for unparsed direct subs. */
771                         /* else {
772                                 if (StringNICmp("submitted, cg->cit, 8) == 0)
773                                         retval = StringSave("Direct Submission");
774                                         */
775                 }
776                 break;
777         case PUB_Sub:
778                 retval = StringSave("Direct Submission");
779                 break;
780         default:
781                 break;
782 
783         }
784                 
785         retval =  FlatCleanEquals(retval);
786         if(retval) if (*retval)
787         for (p=retval + StringLen(retval)-1 ; p> retval+2; p--){
788                 if (*p == ' '){
789                         *p = '\0';
790                 }else if (*p == '.'){
791                         Boolean remove_it = FALSE;
792                         if ( p > retval +5){
793                                 if ( *(p -1 ) != '.' || * (p-2) != '.')
794                                         remove_it = TRUE;
795                         }
796                         if (remove_it)
797                                 *p = '\0';
798                         break;
799                 }else{
800                         break;
801                 }
802         }
803         return (retval);
804 }
805 
806 /*****************************************************************************
807 *FlatJournal
808 *
809 *       creates 'JOURNAL' line from different ASN.1 pubs
810 *
811 *****************************************************************************/
812 
813 /*----------- FlatJournal ()------*/
814 NLM_EXTERN CharPtr FlatJournal 
815 (Asn2ffJobPtr ajp, GBEntryPtr gbp, ValNodePtr the_pub, Int4 pat_seqid, Boolean PNTR submit, Boolean make_index)
816 {
817         CharPtr retval=NULL;
818 
819         if (the_pub)
820         {
821                 switch ( the_pub -> choice){
822                 case PUB_Sub:
823                         retval = format_cit_sub(ajp->format, the_pub, submit, make_index);
824                         break;
825         
826                 case PUB_Patent:
827                         retval = format_patent(ajp->format, the_pub, pat_seqid, make_index);
828                         break;
829         
830                 case PUB_Man: 
831                         retval = format_thesis(ajp->format, the_pub, make_index);
832                         break;
833         
834                 case PUB_Article:
835                 case PUB_Medline:
836                         retval = format_article(ajp, gbp->bsp, the_pub, make_index);
837                         break;
838         
839                 case PUB_Book: 
840                         retval = format_book(ajp->format, the_pub, make_index);
841                         break;
842                         
843                 case PUB_Gen: 
844                         retval = format_general(ajp, gbp->bsp, the_pub, make_index);
845                         break;
846         
847                 default:
848                 if (ASN2FF_SHOW_ERROR_MSG == TRUE)
849                         ErrPostEx(SEV_WARNING, ERR_REFERENCE_Illegalreference,
850                         "FlatJournal: Unimplemented pub type=%d\n", 
851                         (int) the_pub -> choice);
852                 }
853         }
854 
855         if (retval){
856                 CharPtr hold, p , q;
857 
858                 retval = FlatCleanEquals(retval);
859                 hold = p = MemNew(StringLen(retval)+1);
860 
861                 for (q=retval; *q; q++){
862                         if (*q != '\n' && *q != '\r'){
863                                 *p = *q;
864                         }else{
865                                 *p = ' ';
866                         }
867                         p ++;
868                 }
869                 *p = '\0';
870                 MemFree(hold);
871         }
872 
873         return retval;
874 
875 }       /* FlatJournal */
876 
877 
878 static size_t fmt_cit_sub_1 (AffilPtr afp, size_t aflen)
879 
880 {
881   if (afp) {
882     if (afp -> choice == 1) {
883       if (afp -> affil) {
884         aflen += StringLen (afp -> affil);
885       }
886     } else if (afp -> choice == 2) {
887       aflen += 15 +
888       StringLen (afp -> affil) + 
889       StringLen (afp -> div) + 
890       StringLen (afp -> city) + 
891       StringLen (afp -> sub) + 
892       StringLen (afp -> street) + 
893       StringLen (afp -> country);
894     }
895   }
896   return aflen;
897 }
898 
899 static CharPtr fmt_cit_sub_2 (CharPtr start, CharPtr date_std, Uint1 format)
900 
901 {
902   CharPtr temp;
903 
904   temp = StringMove (start, "Submitted");
905   temp = StringMove (temp, " (");
906   temp = StringMove (temp, date_std);
907   if (format == EMBL_FMT || format == PSEUDOEMBL_FMT || format == EMBLPEPT_FMT)
908   {
909     temp = StringMove (temp, ")");
910   } else {
911     temp = StringMove (temp, ")");
912   }
913   return temp;
914 }
915 
916 /*************************************************************************
917 *static CharPtr format_cit_sub(Uint1 format, ValNodePtr the_pub, Boolean PNTR submit, Boolean make_index)
918 *
919 *format pubs of type CitSub for GenBank and EMBL flat file.
920 **************************************************************************/
921 
922 static CharPtr format_cit_sub (Uint1 format, ValNodePtr the_pub, Boolean PNTR submit, Boolean make_index)
923 {
924   AffilPtr afp = NULL;
925   AuthListPtr alp;
926   Boolean need_comma = FALSE, /*UNUSED*/need_space = TRUE;
927   Char ch;
928   CitSubPtr cs;
929   CharPtr affil=NULL, start, retval = NULL, temp, dup_pages = NULL;
930   CharPtr date_std = NULL, ptr;
931   DatePtr dp = NULL;
932   ImprintPtr ip = NULL;
933   size_t aflen = 0;
934   Int2 l_str;
935   Boolean no_to = FALSE;
936 
937   cs = (CitSubPtr) the_pub -> data.ptrvalue;
938   dp = cs->date;
939   if (dp) {
940         date_std = FlatDateFromCreate (NULL, (NCBI_DatePtr) dp);
941   }
942   if (cs->imp) {
943     ip = cs -> imp;
944     if (dp  == NULL && ip -> date) {
945         dp = ip -> date;
946         date_std = FlatDateFromCreate (NULL, (NCBI_DatePtr) dp);
947     }
948     if (ip -> pub) {
949       afp = ip -> pub;
950       aflen = 10;   /* "Submitted " */
951     }
952   }
953 
954   if (afp == NULL) {
955     alp = cs -> authors;
956     if (alp && alp -> affil) {
957       afp = alp -> affil;
958     }
959   }
960 
961   aflen = fmt_cit_sub_1 (afp, aflen);
962   
963 /* stop printing authors  06-12-96 */
964 /*
965   if (afp) {
966         if (afp->choice == 1) { 
967                 authors = NULL;
968         } else {
969                 authors = GetSubmitterName (format, the_pub);
970         }
971   } else {
972         authors = GetSubmitterName (format, the_pub);
973   }
974   retval = MemNew ((size_t) (60 + 2 + StringLen (authors) +
975                    StringLen (date_std) + aflen));
976 */
977   retval = MemNew ((size_t) (60 + 2 + StringLen (date_std) + aflen));
978   temp = fmt_cit_sub_2 (retval, date_std, format);
979 
980   if (afp) {
981         affil = GetAffiliation (afp);
982   }
983   if (format == EMBL_FMT || format == PSEUDOEMBL_FMT || format == EMBLPEPT_FMT)
984   {
985         if (affil) {
986            l_str = StringLen(" to the EMBL/GenBank/DDBJ databases.");
987            if (StringNCmp(affil, " to the EMBL/GenBank/DDBJ databases.", 
988                         l_str) != 0){
989                         no_to = TRUE;
990                 }
991         }
992         if (no_to) {    
993                 temp = StringMove (temp, " to the EMBL/GenBank/DDBJ databases.");
994             *temp = NEWLINE;
995             need_space = FALSE;
996             temp++;
997     } else {
998         *temp = ' '; temp++;
999     }
1000   }
1001 /* stop printing authors  06-12-96 */
1002 /*
1003   if (authors) {
1004       if (need_space)
1005       {
1006         *temp = ' '; temp++;
1007       }
1008       temp = StringMove (temp, authors);
1009       authors = MemFree (authors);
1010       need_comma = TRUE;
1011   }
1012 */
1013   *submit = TRUE;
1014 
1015         if (afp) {
1016   /*  affil = GetAffiliation (afp); */ /*already got it */
1017                 if (need_comma) {
1018                         *temp = ','; temp++;
1019                 }
1020         if (affil) {
1021                     start = affil;
1022                     if (format == EMBL_FMT || format == PSEUDOEMBL_FMT || 
1023                                                       format == EMBLPEPT_FMT && afp->choice == 1)
1024                             affil++;
1025                     ptr = affil;
1026                     ch = *affil;
1027                     while (ch != '\0') {
1028                             *temp = ch;
1029                     temp++;
1030                     affil++;
1031                     ch = *affil;
1032                   }
1033                     affil = ptr;
1034                     start = MemFree (start);
1035             }
1036         }
1037 
1038   if (date_std) {
1039     MemFree (date_std);
1040   }
1041   if (dup_pages) {
1042     MemFree (dup_pages);
1043   }
1044 
1045   return retval;
1046 }       /* format_cit_sub */
1047 
1048 static CharPtr format_patent (Uint1 format, ValNodePtr the_pub, Int4 pat_seqid, Boolean make_index)
1049 
1050 {
1051         AffilPtr afp;
1052         AuthListPtr ap=NULL;
1053         CitPatPtr cp;
1054         CharPtr retval = NULL, temp, pat_date = NULL;
1055         char buf[10];
1056         int patlen;
1057         Boolean embl_format = FALSE;
1058 
1059         if (format == EMBL_FMT || format == PSEUDOEMBL_FMT ||
1060                                         format == EMBLPEPT_FMT) {
1061                 embl_format = TRUE;
1062         }
1063         cp = (CitPatPtr) the_pub -> data.ptrvalue;
1064         if (cp == NULL) {
1065                 return retval;
1066         }
1067         patlen = 50;
1068         patlen += StringLen(cp -> country) ;
1069         if (cp -> number){
1070                 patlen += StringLen(cp -> number);
1071         } else if (cp -> app_number){
1072                 patlen += StringLen(cp -> app_number);
1073         }
1074         if (cp -> doc_type){
1075                 patlen += StringLen(cp -> doc_type);
1076         }
1077         ap = cp -> authors;
1078         if (ap) {
1079                 afp = ap -> affil;
1080                 if (afp){
1081                         patlen += StringLen(afp -> affil);
1082                         if (afp -> choice == 2){
1083                                 patlen += StringLen(afp -> div);
1084                                 patlen += StringLen(afp -> city);
1085                                 patlen += StringLen(afp -> sub );
1086                                 patlen += StringLen(afp -> country);
1087                                 patlen += StringLen(afp -> street);
1088                         }
1089                 }
1090         }
1091         temp = retval = MemNew(patlen);
1092         if (embl_format) {
1093                 temp = StringMove(temp,"Patent number ");
1094         } else {
1095                 temp = StringMove(temp,"Patent: ");
1096         }
1097         if (cp -> country) {
1098                 temp = StringMove(temp,cp -> country);
1099                 if (!embl_format)
1100                         temp = StringMove(temp," ");
1101         }
1102         if (cp -> number) {
1103                 temp = StringMove(temp, cp -> number);
1104         } else if (cp -> app_number) {
1105                 temp = StringMove(temp,"(");
1106                 temp = StringMove(temp, cp -> app_number);
1107                 temp = StringMove(temp,")");
1108         }
1109         if (cp -> doc_type) if ( *(cp -> doc_type)){
1110                 temp = StringMove(temp,"-");
1111                 temp = StringMove(temp, cp -> doc_type);
1112         }
1113         if (pat_seqid > 0) {
1114                 if (embl_format) {
1115                         sprintf(buf,"%s%ld%s", "/", (long) pat_seqid, ", ");
1116                 /*
1117                 } else if (format == GENPEPT_FMT) {
1118                         sprintf(buf,"%s", " ? ");
1119                 */
1120                 } else {
1121                         sprintf(buf,"%s%ld ", " ", (long) pat_seqid);
1122                 }
1123                 temp = StringMove(temp,buf);
1124         } else {
1125                 temp = StringMove(temp, " ");
1126         }
1127         if (cp -> date_issue){
1128                 pat_date = FlatDateFromCreate(NULL, cp -> date_issue);
1129         } else if (cp -> app_date) {
1130                 pat_date = FlatDateFromCreate(NULL, cp -> app_date);
1131         }
1132         if (pat_date){
1133                 temp = StringMove(temp,pat_date);
1134         }
1135         if (embl_format)
1136                 temp = StringMove(temp, ".");
1137         else
1138                 temp = StringMove(temp, ";");
1139         ap = cp -> authors;
1140         if (ap == NULL || afp == NULL) {
1141                 if (pat_date)
1142                         MemFree(pat_date);
1143                 return retval;
1144         }
1145         if (make_index != TRUE)
1146                 *temp = NEWLINE;
1147         else
1148                 *temp = ' ';
1149         temp++;
1150         temp = StringMove(temp,afp -> affil);
1151         if (afp -> choice == 2){
1152                 if (afp -> affil) {
1153                         temp = StringMove(temp,";");
1154                 }
1155                 if (afp -> street){
1156                         if (make_index != TRUE) {
1157                                 *temp = NEWLINE;
1158                         } else {
1159                                 *temp = ' ';
1160                         }
1161                         temp++;
1162                         temp = StringMove(temp,afp -> street);
1163                         temp = StringMove(temp,";");
1164                 }
1165                 if (afp -> div){
1166                         if (make_index != TRUE)
1167                                 *temp = NEWLINE;
1168                         else
1169                                 *temp = ' ';
1170                         temp++;
1171                         temp = StringMove(temp,afp -> div);
1172                         temp = StringMove(temp,";");
1173                 }
1174                 if (afp -> city){
1175                         if (make_index != TRUE)
1176                                 *temp = NEWLINE;
1177                         else
1178                                 *temp = ' ';
1179                         temp++;
1180                         temp = StringMove(temp,afp -> city);
1181                         temp = StringMove(temp,", ");
1182                 }
1183                 if (afp -> sub){
1184                         temp = StringMove(temp, afp -> sub );
1185                 }
1186                 if (afp ->country){
1187                                 temp = StringMove(temp,";");
1188                                 if (make_index != TRUE)
1189                                         *temp = NEWLINE;
1190                                 else
1191                                         *temp = ' ';
1192                                 temp++;
1193                         temp = StringMove(temp,afp -> country);
1194                         temp = StringMove(temp,";");
1195                 }
1196                 MemFree(pat_date);
1197         }
1198 
1199         return retval;
1200 
1201 }       /* format_patent */
1202 
1203 static CharPtr format_thesis (Uint1 format, ValNodePtr the_pub, Boolean make_index)
1204 
1205 {
1206         AffilPtr afp;
1207         char year[5];
1208         CitBookPtr cb;
1209         CharPtr retval = NULL, temp;
1210         DatePtr dp;
1211         ImprintPtr ip;
1212         int aflen=0;
1213         Boolean /*UNUSED*/embl_format = FALSE;
1214         Boolean first_std=TRUE;
1215 
1216         if (format == EMBL_FMT || format == PSEUDOEMBL_FMT ||
1217                                         format == EMBLPEPT_FMT) {
1218                 embl_format = TRUE;
1219         }
1220         year[0] = '\0';
1221 
1222         cb = (CitBookPtr) the_pub -> data.ptrvalue;
1223         if (cb -> othertype == 2 && cb -> let_type == 3){ /* match thesis */
1224                 ip = cb -> imp;
1225                 dp = ip -> date;
1226                 if ( dp -> data[0] == 1){
1227                         sprintf(year,"%ld",(long) ( 1900+dp -> data[1]));
1228                 } else {
1229                         StringNCpy( (CharPtr) year, (CharPtr) dp -> str, (size_t) 4);
1230                         year[4] = '\0';
1231                 }
1232                 if ( ip -> pub){
1233                         afp = ip->pub;
1234                         aflen = 7;
1235                         if (afp->choice == 1) {
1236                                 if (afp -> affil){
1237                                         aflen += StringLen(afp -> affil) + 6;
1238                                 }
1239 
1240                         } else if (afp->choice == 2){
1241                                 aflen += 3 + StringLen(afp -> affil);
1242                                 aflen += 3 + StringLen(afp -> div);
1243                                 aflen += 3 + StringLen(afp -> street);
1244                                 aflen += 3 + StringLen(afp -> city);
1245                                 aflen += 3 + StringLen(afp -> sub);
1246                                 aflen += 3 + StringLen(afp -> country);
1247                         } else {
1248                                 aflen = 22;
1249                         }
1250                 }
1251                 if (ip->prepub == 2)   /* In press */
1252                         aflen += 10;
1253 
1254                 temp = retval = MemNew((size_t) (60 + StringLen(year) + aflen));
1255                 temp = StringMove(temp,"Thesis");
1256                 temp = StringMove(temp," (");
1257                 temp = StringMove(temp, year);
1258                 temp = StringMove(temp,")");
1259 
1260                 if ( ip -> pub){
1261                         afp = ip->pub;
1262                         if ( afp->choice == 1){
1263                                 if (afp->affil){
1264                                         if (StringLen( afp -> affil) > 7){
1265                                                 temp = StringMove(temp, " ");
1266                                                 temp = StringMove(temp, afp -> affil);
1267                                                 if (ip->prepub == 2)   /* In press */
1268                                                         temp = StringMove(temp, ", In press");
1269                                         }
1270                                 }
1271                         } else if (afp->choice == 2) {
1272                                 *temp = ' ';
1273                                 temp++;
1274                                 temp = makeaffil(afp, temp, &first_std);
1275                                 if (ip->prepub == 2) {
1276                                         temp = StringMove(temp, ", In press");
1277                                 }
1278                         }
1279                 }
1280         }
1281         return retval;
1282 
1283 }       /* format_thesis */
1284 
1285 NLM_EXTERN CharPtr format_book (Uint1 format, ValNodePtr the_pub, Boolean make_index)
1286 
1287 {
1288         AffilPtr afp;
1289         char year[5];
1290         CharPtr book_tit=NULL;
1291         CitBookPtr cb;
1292         CharPtr retval = NULL, temp;
1293         DatePtr dp;
1294         ImprintPtr ip;
1295         int aflen=0;
1296         Boolean embl_format = FALSE;
1297         CharPtr p;
1298         Boolean first_std=TRUE;
1299         
1300         if (format == EMBL_FMT || format == PSEUDOEMBL_FMT ||
1301                                         format == EMBLPEPT_FMT) {
1302                 embl_format = TRUE;
1303         }
1304         year[0] = '\0';
1305         if (the_pub == NULL)
1306                 return NULL;
1307         cb = (CitBookPtr) the_pub -> data.ptrvalue;
1308         if (cb == NULL)
1309                 return NULL;
1310         if ( cb -> othertype != 0){ /* match book */
1311                 return NULL;
1312         }
1313         ip = cb -> imp;
1314         dp = ip -> date;
1315         if ( dp -> data[0] == 1) {
1316                 sprintf(year,"%ld",(long) ( 1900+dp -> data[1]));
1317         } else {
1318                 StringNCpy( (CharPtr) year, (CharPtr) dp -> str, (size_t) 4);
1319                 year[4] = '\0';
1320         }
1321         if (cb->title)
1322                 book_tit = StringSave(cb -> title -> data.ptrvalue);
1323         if ( ip -> pub){
1324                 afp = ip -> pub;
1325                 aflen = StringLen(afp -> affil)+ 5;
1326                 if ( afp -> choice == 2){
1327                         aflen += 3 + StringLen(afp -> div);
1328                         aflen += 3 + StringLen(afp -> street);
1329                         aflen += 3 + StringLen(afp -> city);
1330                         aflen += 3 + StringLen(afp -> sub);
1331                         aflen += 3 + StringLen(afp -> country);
1332                 }
1333         } else{
1334                 aflen = 22;
1335         }
1336         if (ip->prepub == 2)   /* In press */
1337                 aflen += 10;
1338 
1339         temp = retval = MemNew( (size_t) (30+StringLen( book_tit)+StringLen( year) + aflen) );
1340                 
1341 /*--make book title all caps */
1342         for ( p = book_tit; *p; p++){
1343                 *p = TO_UPPER(*p);
1344         }
1345         temp = StringMove(temp, "Book: ");
1346         temp = StringMove(temp, book_tit);
1347                         temp = StringMove(temp, ".");
1348         if ( ip -> pub){
1349                 afp = ip -> pub;
1350                 *temp = ' ';
1351                 temp++;
1352                 temp = makeaffil(afp, temp, &first_std);
1353         }
1354         if (year[0] != '\0') {
1355                 if (! first_std)
1356                         temp = StringMove(temp," (");
1357                 else
1358                         temp = StringMove(temp, "(");
1359                 temp = StringMove(temp, year);
1360                 temp = StringMove(temp, ")");
1361         }
1362         if (ip->prepub == 2) { /* In press */
1363                 temp = StringMove(temp, ", In press");
1364         }
1365         if (book_tit)
1366                 MemFree(book_tit);
1367 
1368         return retval;
1369 
1370 }       /* format_book */
1371 
1372 
1373 NLM_EXTERN CharPtr format_article (Asn2ffJobPtr ajp, BioseqPtr bsp, ValNodePtr the_pub, Boolean make_index)
1374 {
1375         CharPtr retval=NULL;
1376         CitArtPtr ca = NULL;
1377         MedlineEntryPtr ml;
1378 
1379         if ( the_pub -> choice == PUB_Medline) {
1380                 ml = (MedlineEntryPtr) the_pub -> data.ptrvalue;
1381                 ca = (CitArtPtr) ml -> cit;
1382         } else if (the_pub->choice == PUB_Article) {
1383                 ca = (CitArtPtr) the_pub -> data.ptrvalue;
1384         }
1385         if (ca == NULL) {
1386                 return NULL;
1387         }
1388 
1389         if ( ca -> from != 1) {
1390                 retval = format_bookarticle(ajp, bsp, the_pub, make_index);
1391         } else {
1392                 retval = format_jourarticle(ajp, bsp, the_pub, make_index);
1393         }
1394 
1395         return retval;
1396 
1397 }       /* format_article */
1398 
1399 NLM_EXTERN CharPtr format_bookarticle(Asn2ffJobPtr ajp, BioseqPtr bsp, ValNodePtr the_pub, Boolean make_index)
1400 
1401 {
1402         AffilPtr afp;
1403         AuthListPtr ap = NULL;
1404         Boolean first_std=TRUE, found_paran=FALSE;
1405         CharPtr temp, dup_pages=NULL, retval=NULL, volume=NULL;
1406         CharPtr issue=NULL, part_sup=NULL, part_supi=NULL;
1407         CharPtr p;
1408         CharPtr book_authors=NULL, book_tit=NULL;
1409         Char year[5];
1410         CitArtPtr ca = NULL;
1411         CitBookPtr book;
1412         DatePtr dp;
1413         ImprintPtr ip;
1414         Int2 aflen=0, length;
1415         Int2 fix_p_ret;
1416         MedlineEntryPtr ml;
1417         ValNodePtr namehead;
1418         size_t len_page = 0;
1419         Boolean embl_format = FALSE;
1420 
1421         if (ajp && (ajp->format == EMBL_FMT || ajp->format == PSEUDOEMBL_FMT ||
1422                                         ajp->format == EMBLPEPT_FMT)) {
1423                 embl_format = TRUE;
1424         }
1425         if ( the_pub -> choice == PUB_Medline) {
1426                 ml = (MedlineEntryPtr) the_pub -> data.ptrvalue;
1427                 ca = (CitArtPtr) ml -> cit;
1428         } else if (the_pub->choice == PUB_Article) {
1429                 ca = (CitArtPtr) the_pub -> data.ptrvalue;
1430         }
1431         if (ca == NULL) {
1432                 return NULL;
1433         }
1434         book = (CitBookPtr) ca->fromptr;
1435         ap = book -> authors;
1436         if (ap->choice != 1)   /* just strings */
1437                 namehead = ap->names;
1438         else                  /* structured names */
1439                         namehead = GBGetAuthNames(ajp->format, ap);
1440         book_authors = FlatStringGroupTerm(embl_format, NULL, namehead, ", ", NULL, " and ");
1441                                 
1442         book_tit = StringSave(book -> title -> data.ptrvalue);
1443         ip = book -> imp;
1444         if (ip -> pages){
1445                 len_page = StringLen( ip -> pages);
1446                 dup_pages = MemNew ( 2*len_page );
1447                 fix_p_ret = fix_pages(dup_pages, ip ->pages);
1448                 if (ajp && fix_p_ret == -1 && ajp->error_msgs == TRUE) {
1449                         PostARefErrMessage (ajp, bsp, NULL, the_pub, 1, dup_pages);
1450                 }
1451         }else if (ajp && !ip->prepub && ajp->error_msgs == TRUE) {
1452                 PostARefErrMessage (ajp, bsp, NULL, the_pub, 2, NULL);
1453         }
1454         dp = ip -> date;
1455         year[0] = '\0';
1456         if ( dp -> data[0] == 1) {
1457                 sprintf(year,"%ld",(long) ( 1900+dp -> data[1]));
1458         } else {
1459                 StringNCpy( (CharPtr) year, (CharPtr) dp -> str, (size_t) 4);
1460                 year[4] = '\0';
1461         }
1462         
1463         if (ip -> pub){
1464                 afp = ip -> pub;
1465                 aflen = StringLen(afp -> affil)+ 5;
1466                 if ( afp -> choice == 2) {
1467                         aflen += 3 + StringLen(afp -> div);
1468                         aflen += 3 + StringLen(afp -> street);
1469                         aflen += 3 + StringLen(afp -> city);
1470                         aflen += 3 + StringLen(afp -> sub);
1471                         aflen += 3 + StringLen(afp -> country);
1472                 }
1473         } else {
1474                 aflen = 22;
1475         }
1476         if (ip->volume) {
1477                 volume = StringSave(ip->volume);
1478         }
1479         if (embl_format) { /* Don't do this for EMBL! */
1480            if (ip->part_sup) {
1481                         part_sup = StringSave(ip->part_sup);
1482            }
1483            if (ip->issue) {
1484                         issue = StripParanthesis(ip->issue, &found_paran);
1485                 if (ajp && ajp->error_msgs == TRUE && found_paran == TRUE) 
1486                     PostARefErrMessage (ajp, bsp, NULL, the_pub, 5, NULL);
1487            }
1488            if (ip->part_supi) {
1489                         part_supi = StripParanthesis(ip->part_supi, &found_paran);
1490                 if (ajp->error_msgs == TRUE && found_paran == TRUE) 
1491                     PostARefErrMessage (ajp, bsp, NULL, the_pub, 5, NULL);
1492            }
1493         }
1494 
1495         length = 80;
1496         length += StringLen (book_tit)+ StringLen(book_authors);
1497         length += StringLen(volume);
1498         length += StringLen(issue);
1499         length += StringLen(part_sup);
1500         length += StringLen(part_supi);
1501         length += 2*len_page;
1502         length += StringLen( year) + aflen;
1503 
1504         temp = retval = MemNew( (size_t) length);
1505 
1506 /*--make book title all caps */
1507         for ( p = book_tit; *p; p++){
1508                 *p = TO_UPPER(*p);
1509         }
1510 
1511         temp = StringMove(temp,"(in) ");
1512         if (make_index == FALSE && book_authors)
1513         {
1514                 temp = StringMove(temp,book_authors);
1515                 if (namehead != NULL) {
1516                         temp = StringMove(temp,namehead -> next? " (Eds.);":" (Ed.);");
1517                 } 
1518                 *temp = NEWLINE;
1519                 temp++;
1520         }
1521 
1522         if (ap->choice == 1)    /* std names */
1523                 ValNodeFreeData(namehead);
1524 
1525         temp = StringMove(temp,book_tit);
1526         if (volume && StringCmp(volume, "0") != 0)
1527         {
1528                 temp = StringMove(temp,", ");
1529                 temp = StringMove(temp, "Vol. ");
1530                 temp = StringMove(temp, volume);
1531                 temp = doSup(temp, issue, part_sup, part_supi);
1532         }
1533         if (ip->pages != NULL)
1534         {
1535                 temp = StringMove(temp,": ");
1536                 temp = StringMove(temp,dup_pages);
1537         }
1538         if (book_tit)
1539         {
1540                 *temp = ';'; 
1541                 temp++;
1542         }
1543         if ( ip -> pub){
1544                 afp = ip -> pub;
1545                 if (make_index != TRUE)
1546                         *temp = NEWLINE;
1547                 else
1548                         *temp = ' ';
1549                 temp++;
1550                 temp = makeaffil(afp, temp, &first_std);
1551         }
1552         if (! first_std)
1553                 temp = StringMove(temp," (");
1554         else
1555                 temp = StringMove(temp,"(");
1556         temp = StringMove(temp,year);
1557         temp = StringMove(temp,")");
1558         if (ip->prepub == 2 && !embl_format)
1559                 temp = StringMove(temp, " In press");
1560 
1561         if (volume)
1562                 volume = MemFree(volume);
1563         if (book_authors)
1564                 MemFree(book_authors);
1565         if (book_tit)
1566                 MemFree(book_tit);
1567         if (issue)
1568                 issue = MemFree(issue);
1569         if (part_sup)
1570                 part_sup = MemFree(part_sup);
1571         if (part_supi)
1572                 part_supi = MemFree(part_supi);
1573         if (dup_pages)
1574                 MemFree(dup_pages);
1575 
1576         return retval;
1577 }
1578 
1579 /***********************************************************************
1580 *CharPtr format_jourarticle(Asn2ffJobPtr ajp, BioseqPtr bsp, ValNodePtr the_pub, Boolean make_index)
1581 *
1582 *       format a journal article
1583 *       The caller must deallocate the space allocated.
1584 **********************************************************************/
1585 
1586 NLM_EXTERN CharPtr format_jourarticle(Asn2ffJobPtr ajp, BioseqPtr bsp, ValNodePtr the_pub, Boolean make_index)
1587 
1588 
1589 {
1590         Boolean found_paran=FALSE;
1591         char year[5];
1592         CharPtr temp, dup_pages=NULL, retval=NULL, volume=NULL;
1593         CharPtr issue=NULL, part_sup=NULL, part_supi=NULL;
1594         CitArtPtr ca = NULL;
1595         CitJourPtr jp;
1596         DatePtr dp;
1597         ImprintPtr ip;
1598         Int2 fix_p_ret, length;
1599         MedlineEntryPtr ml;
1600         size_t len_page = 0;
1601         Boolean embl_format = FALSE;
1602 
1603         if (ajp) {
1604                 if (ajp->format == EMBL_FMT || ajp->format == PSEUDOEMBL_FMT ||
1605                                         ajp->format == EMBLPEPT_FMT) {
1606                         embl_format = TRUE;
1607                 }
1608         }
1609         if ( the_pub -> choice == PUB_Medline) {
1610                 ml = (MedlineEntryPtr) the_pub -> data.ptrvalue;
1611                 ca = (CitArtPtr) ml -> cit;
1612         } else if (the_pub->choice == PUB_Article) {
1613                 ca = (CitArtPtr) the_pub -> data.ptrvalue;
1614         }
1615         if (ca == NULL) {
1616                 return NULL;
1617         }
1618         jp = (CitJourPtr) ca -> fromptr;
1619         ip = jp -> imp;
1620         dp = ip -> date;
1621         year[0] = '\0';
1622         if ( dp -> data[0] == 1) {
1623                 if (dp->data[1] != '\0') {
1624                         sprintf(year,"%ld",(long) ( 1900+dp -> data[1]));
1625                 }
1626         } else {
1627                 StringNCpy( (CharPtr) year, (CharPtr) dp -> str, (size_t) 4);
1628                 year[4] = '\0';
1629         }
1630         if (ip -> pages){
1631                 len_page = StringLen( ip -> pages);
1632                 dup_pages = MemNew ( 2*len_page );
1633                 fix_p_ret = fix_pages(dup_pages, ip ->pages);
1634                 if (ajp && fix_p_ret == -1 && ajp->error_msgs == TRUE) {
1635                         PostARefErrMessage (ajp, bsp, NULL, the_pub, 1, dup_pages);
1636                 }
1637         } else if (ajp && !ip->prepub && ajp->error_msgs == TRUE) {
1638                 PostARefErrMessage (ajp, bsp, NULL, the_pub, 2, NULL);
1639         }
1640         if (ip->prepub != 1 && ip->prepub != 255) {
1641                 if (ip->volume) {
1642                     volume = StringSave(ip->volume);
1643                 }
1644                 if (!embl_format) { /* Don't do this for EMBL! */
1645                    if (ip->part_sup)
1646                         part_sup = StringSave(ip->part_sup);
1647                    if (ip->issue) {
1648                         issue = StripParanthesis(ip->issue, &found_paran);
1649                         if (ajp->error_msgs == TRUE && found_paran == TRUE) 
1650                             PostARefErrMessage (ajp, bsp, NULL, the_pub, 5, NULL);
1651                    }
1652                    if (ip->part_supi) {
1653                         part_supi = StripParanthesis(ip->part_supi, &found_paran);
1654                         if (ajp && ajp->error_msgs == TRUE && found_paran == TRUE) 
1655                             PostARefErrMessage (ajp, bsp, NULL, the_pub, 5, NULL);
1656                    }
1657                 }
1658 
1659                 length = 25;
1660                 length += StringLen ((CharPtr) (jp -> title -> data.ptrvalue));
1661                 length += StringLen(volume);
1662                 length += StringLen(issue);
1663                 length += StringLen(part_sup);
1664                 length += StringLen(part_supi);
1665                 length += 2*len_page + StringLen( year);
1666 
1667 
1668                 /* Does the journal have a title? */
1669                 if (jp -> title -> data.ptrvalue != NULL &&
1670                         StringLen(jp -> title -> data.ptrvalue) > 2)
1671                 {
1672                    temp = retval = MemNew( (size_t) length);
1673                    temp = StringMove(temp, (CharPtr) (jp -> title -> data.ptrvalue));
1674                    if ((volume != NULL) || (ip->pages != NULL))
1675                    {
1676                         temp = StringMove(temp," ");
1677                         if (volume != NULL)
1678                                 temp = StringMove(temp, volume);
1679                         temp = doSup(temp, issue, part_sup, part_supi);
1680                         if (ip->pages != NULL)
1681                                 if (embl_format)
1682                                         temp = StringMove(temp,":");
1683                                 else
1684                                         temp = StringMove(temp,", ");
1685                    }
1686                    if (ip->pages != NULL)
1687                         temp = StringMove(temp, dup_pages);
1688                    else if (ip->prepub == 2 && embl_format)
1689                         temp = StringMove(temp, " 0:0-0");
1690                    else if (embl_format  && ip->pages == NULL 
1691                         && volume == NULL)
1692                         temp = StringMove(temp, " 0:0-0");
1693                    if (embl_format)
1694                         temp = StringMove(temp," (");
1695                    else
1696                         temp = StringMove(temp," (");
1697                    temp = StringMove(temp, year);
1698                    temp = StringMove(temp,")");
1699                    if (ip->prepub == 2 && !embl_format)
1700                         temp = StringMove(temp, " In press");
1701                 }
1702                 else
1703                 {
1704                    length = 2;
1705                    temp = retval = MemNew( (size_t) length);
1706                    temp = StringMove(temp,".");
1707                 }
1708                 
1709         }
1710         else
1711         {
1712                       temp = retval = MemNew(21*sizeof(Char));
1713                       temp = StringMove(temp, "Unpublished ");
1714                       if (year[0] != NULLB)
1715                       {
1716                               temp = StringMove(temp,"(");
1717                               temp = StringMove(temp, year);
1718                               temp = StringMove(temp,")");
1719                       }
1720         }
1721 
1722         if (volume)
1723                 volume = MemFree(volume);
1724         if (issue)
1725                 issue = MemFree(issue);
1726         if (part_sup)
1727                 part_sup = MemFree(part_sup);
1728         if (part_supi)
1729                 part_supi = MemFree(part_supi);
1730         if (dup_pages)
1731                 MemFree(dup_pages);
1732 
1733         return retval;
1734 }       /* format_jourarticle */
1735 
1736 
1737 
1738 
1739 
1740 /************************************************************************
1741 *static CharPtr makeaffil(AffilPtr afp, CharPtr temp, Boolean PNTR first_std)
1742 *
1743 *       formats the affiliation into temp, which should already be 
1744 *       allocated to hold this stuff.
1745 ***********************************************************************/
1746 
1747 static CharPtr makeaffil(AffilPtr afp, CharPtr temp, Boolean PNTR first_std)
1748 
1749 {
1750         *first_std = TRUE;
1751 
1752         if (afp -> affil && StringLen(afp->affil) > 0)
1753         {
1754                 temp = StringMove(temp, afp -> affil);
1755                 *first_std = FALSE;
1756         }
1757         if ( afp -> choice == 2){
1758                 if (afp -> div){
1759                         if ( ! *first_std)
1760                                 temp = StringMove(temp,", ");
1761                         temp =  StringMove(temp,afp -> div);
1762                         *first_std = FALSE;
1763                 }
1764                 if (afp -> street){
1765                         if ( ! *first_std)
1766                                 temp = StringMove(temp,", ");
1767                         temp =  StringMove(temp,afp -> street);
1768                         *first_std = FALSE;
1769                 }
1770                 if (afp -> city){
1771                         if ( ! *first_std)
1772                                 temp = StringMove(temp,", ");
1773                         temp =  StringMove(temp,afp -> city);
1774                         *first_std = FALSE;
1775                 }
1776                 if (afp -> sub){
1777                         if ( ! *first_std)
1778                                 temp = StringMove(temp,", ");
1779                         temp =  StringMove(temp,afp -> sub);
1780                         *first_std = FALSE;
1781                 }
1782                 if (afp -> country){
1783                         if ( ! *first_std)
1784                                 temp = StringMove(temp,", ");
1785                         temp =  StringMove(temp,afp -> country);
1786                         *first_std = FALSE;
1787                 }
1788         }
1789         return temp;
1790 }
1791 
1792 static Boolean IsStringEmpty(CharPtr str)
1793 {
1794         if (str == NULL)
1795                 return TRUE;
1796         if (*str == '\0')
1797                 return TRUE;
1798     while (*str)
1799         if (!isspace(*str))
1800             /* The string contains something other then whitespace
1801              */
1802             return FALSE;
1803         else
1804             str++;
1805 
1806     return TRUE;
1807 }
1808 /************************************************************************
1809 *static CharPtr doSup(CharPtr temp, CharPtr issue, CharPtr part_sup, CharPtr part_supi)
1810 *
1811 *       copies the characters onto temp.
1812 *
1813 **************************************************************************/
1814 static CharPtr doSup(CharPtr temp, CharPtr issue, CharPtr part_sup, CharPtr part_supi)
1815 
1816 {
1817         if (!IsStringEmpty(part_sup)) {
1818                 *temp = ' ';
1819                 temp++;
1820                 temp = StringMove(temp, part_sup);
1821         }
1822         if (IsStringEmpty(issue) && IsStringEmpty(part_supi)) {
1823                 return temp;
1824         }
1825         *temp = ' ';
1826         temp++;
1827         *temp = '(';
1828         temp++;
1829         if (!IsStringEmpty(issue)) {
1830                 temp = StringMove(temp, issue);
1831         }
1832         if (!IsStringEmpty(part_supi)) {
1833                 *temp = ' ';
1834                 temp++;
1835                 temp = StringMove(temp, part_supi);
1836         }
1837         *temp = ')';
1838         temp++;
1839         return temp;
1840 }
1841 
1842 /*************************************************************************
1843 *static CharPtr format_general(BiotablePtr btp, ValNodePtr the_pub, Boolean make_index)
1844 *
1845 *format pubs of type CitSub for GenBank and EMBL flat file.
1846 **************************************************************************/
1847 
1848 static CharPtr fmt_gen_1 (ValNodePtr the_pub, CharPtr unp, CharPtr affil, CitGenPtr cg, Boolean used_cit, Boolean found_journal,
1849 CharPtr year, CharPtr unp_long, CharPtr p, size_t len_page)
1850 
1851 {
1852   CharPtr  retval;
1853   Int2 volume=0, cit = 0;
1854 
1855   retval = NULL;
1856   /* use cit or journal */
1857   if (cg->cit) {
1858         cit = StringLen(cg->cit);
1859   }
1860    if (cg->volume) {
1861         volume = StringLen(cg->volume);
1862   }
1863   if (unp) {
1864     retval = MemNew ((size_t) (9+
1865       StringLen (unp) +
1866       StringLen (affil) +
1867       volume + 2*len_page + StringLen( year)) );
1868   } else if (cg -> cit && ! used_cit && found_journal ) {
1869     retval = MemNew ((size_t) (9 +
1870       11 + volume + 1+ cit + 2*len_page + 
1871       StringLen( year) + StringLen (unp_long)) + StringLen(p));
1872   } else { /* tack extra unpub entry to end of year */
1873     retval = MemNew ((size_t) (9+
1874       11 + volume + StringLen(p) + 
1875       2*len_page + StringLen( year) + StringLen (unp_long)) );
1876   }
1877 
1878   return retval;
1879 }
1880 
1881 static CharPtr fmt_gen_2 (Boolean embl_format, ValNodePtr the_pub, 
1882                 CharPtr start, CharPtr ptr, CharPtr unp, CharPtr unp_long, 
1883                 CitGenPtr cg, Uint1 format, CharPtr dup_pages, CharPtr year)
1884 
1885 {
1886   CharPtr  temp, volume=NULL;
1887 
1888         temp = start;
1889         if (ptr) {
1890                 temp = StringMove (temp, ptr);
1891         } else if (unp_long) {
1892                 temp = StringMove (temp, "Unpublished");
1893         } else if (unp) { 
1894                 if (!ASN2FF_SHOW_ALL_PUBS) {
1895                         temp = StringMove (temp, "Unpublished");
1896                 } else { 
1897                         temp = StringMove (temp, unp);
1898                 }
1899         }
1900         if (cg->volume)
1901         {
1902            volume = StringSave(cg->volume);
1903         }
1904 
1905         if (volume) 
1906         {
1907                 temp = StringMove (temp," ");
1908                 temp = StringMove (temp, volume);
1909         }
1910 
1911         if (dup_pages != NULL) 
1912         {
1913                 if (embl_format) 
1914                         temp = StringMove (temp,":");
1915                 else 
1916                         temp = StringMove (temp,", ");
1917                 temp = StringMove (temp, dup_pages);
1918         }
1919 
1920         if (year[0] != '\0') 
1921         {
1922                 /* this removes the year from unpublished records
1923                 if (unp == NULL) {
1924                         temp = StringMove (temp," (");
1925                         temp = StringMove (temp, year);
1926                         temp = StringMove (temp,")");
1927                 }
1928                 */
1929                 temp = StringMove (temp," (");
1930                 temp = StringMove (temp, year);
1931                 temp = StringMove (temp,")");
1932         }
1933 
1934   if (volume)
1935         volume = MemFree(volume);
1936   return temp;
1937 }
1938 
1939 static CharPtr format_general (Asn2ffJobPtr ajp, BioseqPtr bsp, ValNodePtr the_pub, Boolean make_index)
1940 
1941 {
1942   AuthListPtr ap = NULL;
1943   Char ch;
1944   Boolean used_cit=FALSE, found_journal=FALSE;
1945   Char year[5];
1946   CharPtr affil=NULL, temp, dup_pages=NULL, retval=NULL;
1947   CharPtr str_ret, ptr, unp=NULL, unp_long=NULL, misc_unp=NULL;
1948   CitGenPtr cg;
1949   DatePtr dp;
1950   Int2 fix_p_ret;
1951   size_t len_page = 0;
1952   Uint1 format=ajp->format;
1953   Boolean embl_format = FALSE;
1954 
1955         if (format == EMBL_FMT || format == PSEUDOEMBL_FMT ||
1956                                         format == EMBLPEPT_FMT) {
1957                 embl_format = TRUE;
1958         }
1959         cg = (CitGenPtr) the_pub -> data.ptrvalue;
1960         year[0] = '\0';
1961         if (cg->date) {
1962                 dp = cg -> date;
1963                 if (dp -> data[0] == 1) {
1964                         sprintf (year,"%ld", (long) (1900 + dp -> data[1]));
1965                 } else {
1966                         StringNCpy ((CharPtr) year, (CharPtr) dp -> str, (size_t) 4);
1967                         year[4] = '\0';
1968                 }
1969         }
1970         if (cg->pages) {
1971                 len_page = StringLen (cg -> pages);
1972                 dup_pages = MemNew (2 * len_page);
1973                 fix_p_ret = fix_pages (dup_pages, cg ->pages);
1974                 if (fix_p_ret == -1) {
1975                         if (ajp->error_msgs == TRUE)
1976                                 PostARefErrMessage (ajp, bsp, NULL, the_pub, 1, dup_pages);
1977                         }
1978                 } else if (StringNICmp ("unpublished", cg->cit, 11) != 0 &&
1979              StringNICmp ("submitted", cg->cit, 8) != 0 &&
1980                 StringNICmp ("in press", cg->cit, 8) != 0 &&
1981                         StringNICmp ("to be published", cg->cit, 15) != 0) {
1982                         if (ajp->error_msgs == TRUE)
1983                                 PostARefErrMessage (ajp, bsp, NULL, the_pub, 2, NULL);
1984                 }
1985                 if (cg->journal) {
1986                         ptr = (CharPtr) (cg->journal->data.ptrvalue);
1987                         found_journal = TRUE;
1988                 } else {
1989                 ptr = NULL;
1990         }
1991 
1992         str_ret = NULL;
1993         if (cg -> cit) {
1994                 ap=cg->authors;
1995                 str_ret = StrStr (cg -> cit ,"Journal=\"");
1996                 if (str_ret) {
1997                         retval = StringSave (str_ret + 9);
1998                         found_journal =used_cit = TRUE;
1999                         for (ptr=retval; *ptr; ptr++) {
2000                                 if (*ptr == '=' || *ptr == '\"') {
2001                                         *ptr = '\0';
2002                                 }
2003                         }
2004                 } else if (ptr == NULL) {   /* no journal field, use cit */
2005                         used_cit = TRUE;
2006                         if (strncmp ("Unpublished ", cg->cit, (unsigned) 12) == 0) {
2007                                 if (strlen (cg->cit) > (size_t) 12) { /* rest of Unpub entry */
2008                                         unp_long = cg->cit;
2009                                         unp_long += 11;
2010                                 } else {
2011                                         unp = cg->cit;
2012                                         if ((ap=cg->authors) != NULL) {
2013                                                 if (ASN2FF_SHOW_ALL_PUBS)
2014                                                         affil = GetAffiliation (ap->affil);
2015                                         }
2016                                 }
2017                         } else if (strncmp ("Unpublished; ", cg->cit, (unsigned) 13) == 0) {
2018                         if (strlen (cg->cit) > (size_t) 13) { /* rest of Unpub entry */
2019                                         unp_long = cg->cit;
2020                                         unp_long += 12;
2021                         } else {
2022                                         unp = cg->cit;
2023                                 if ((ap=cg->authors) != NULL) {
2024                                         if (ASN2FF_SHOW_ALL_PUBS)
2025                                                 affil = GetAffiliation (ap->affil);
2026                                 }
2027                         }
2028                 } else if (StringNICmp ("unpublished", cg->cit, 11) == 0 ||
2029                         StringNICmp ("submitted", cg->cit, 8) == 0 ||
2030                         StringNICmp ("in press", cg->cit, 8) == 0 ||
2031                                 StringNICmp ("to be published", cg->cit, 15) == 0) {
2032                                 if (ASN2FF_SHOW_ALL_PUBS) {
2033                                         misc_unp = StringSave(cg->cit);
2034                                 if ((ap=cg->authors) != NULL) 
2035                                         affil = GetAffiliation (ap->affil);
2036                                 } else {
2037                                         misc_unp = StringSave("Unpublished");
2038                                 }
2039                                 unp = misc_unp;
2040                         } else if (ASN2FF_SHOW_ALL_PUBS) {
2041                                 unp = StringSave(cg->cit);
2042                         if ((ap=cg->authors) != NULL) 
2043                         affil = GetAffiliation (ap->affil);
2044                         }
2045                 }
2046         }
2047 
2048   if ((retval == NULL) && ( (ptr != NULL) || unp != NULL || unp_long))   {
2049     /* use cit or journal */
2050     retval = fmt_gen_1 (the_pub, unp, affil, cg, used_cit, found_journal,
2051                         year, unp_long, ptr, len_page);
2052 
2053     temp = fmt_gen_2 (embl_format, the_pub, retval, ptr, unp, unp_long,
2054                       cg, format, dup_pages, year);
2055   }
2056   if (unp_long && ASN2FF_SHOW_ALL_PUBS) {
2057     temp = StringMove (temp, unp_long);
2058   } else if (unp ) {
2059     if (affil) {
2060       ptr = affil;
2061       ch = *affil;
2062       while (ch != '\0') {
2063         *temp = ch;
2064         temp++;
2065         affil++;
2066         ch = *affil;
2067       }
2068       affil = ptr;
2069       affil = MemFree (affil);
2070     }
2071   }
2072   if (cg -> cit && ! used_cit && found_journal) {
2073     temp = StringMove (temp," ");
2074     temp = StringMove (temp, cg -> cit);
2075   }
2076 
2077   if (dup_pages) {
2078     MemFree (dup_pages);
2079   }
2080 
2081   if (misc_unp != NULL)
2082         misc_unp = MemFree(misc_unp);
2083 
2084   return retval;
2085 
2086 }  /* format_general */
2087 
2088 
2089 /*************************************************************************
2090 *CharPtr StripParanthesis(CharPtr ptr_in, Boolean PNTR paranthesis)
2091 *
2092 *       This function strips spaces and '(' from the front of
2093 *       ptr_in, copies the rest of the string, up to a possible
2094 *       ')'.
2095 *
2096 *       The caller is responsible for deallocating "retval".
2097 *       do not strip spaces!   add by Tatiana 06.01.95
2098 ************************************************************************/
2099 
2100 static CharPtr 
2101 StripParanthesis(CharPtr ptr_in, Boolean PNTR paranthesis)
2102 {
2103         CharPtr temp, retval;
2104         Int2 length;
2105 
2106         *paranthesis=FALSE;
2107 
2108         while (*ptr_in == '(' )
2109         {
2110                 if (*ptr_in == '(')
2111                         *paranthesis = TRUE;
2112                 ptr_in++;
2113         }
2114 
2115         if (*ptr_in == NULLB)
2116                 retval = NULL;
2117         else
2118         {
2119                 length = StringLen(ptr_in);
2120                 retval = temp = MemNew((length+1)*sizeof(Char));
2121                 while (*ptr_in != ')'  && *ptr_in != NULLB)
2122                 {
2123                         *temp = *ptr_in;
2124                         temp++; *ptr_in++;
2125                 }
2126                 if (*ptr_in == ')')
2127                         *paranthesis = TRUE;
2128                 temp = '\0';
2129         }
2130         return retval;
2131 }
2132 
2133 #define MAX_PAGE_DIGITS 12
2134 
2135 /*************************************************************************
2136 *
2137 *        || (CharPtr out_pages, CharPtr in_pages)
2138 *
2139 *       in_pages: input page numbering. 
2140 *       out_pages: output page numbering; "out_pages" should already
2141 *       have allocated space when fix_pages is called (twice as many 
2142 *       characters as "in_pages").
2143 *
2144 *       medline type page numbering is expanded (e.g., 125-35 -> 125-135,
2145 *       F124-34 -> F124-F134, 12a-c -> 12a-12c).
2146 *       If only one page is given, this is output without a dash.
2147 *       Expanded numbering is validated to ensure that the
2148 *       first number is smaller than or equal to the second and
2149 *       that the first letter is less than or identical to the second
2150 *       (i.e., a < c).  If the input is all letters (i.e., roman numerals)
2151 *       this is not validated.
2152 *
2153 *       Return values:
2154 *        0 : valid page numbering.
2155 *       -1 : invalid page numbering.
2156 ************************************************************************/
2157 NLM_EXTERN Int2 fix_pages (CharPtr out_pages, CharPtr in_pages)
2158 
2159 {
2160         Boolean dash=TRUE, first_alpha;
2161         Char firstbegin[MAX_PAGE_DIGITS];
2162         Char secondbegin[MAX_PAGE_DIGITS];
2163         Char firstend[MAX_PAGE_DIGITS];
2164         Char secondend[MAX_PAGE_DIGITS];
2165         Char temp[MAX_PAGE_DIGITS];
2166         CharPtr alphabegin, numbegin, alphaend, numend, ptr, in=in_pages;
2167         Int2 diff, index, retval=0;
2168         Int2 length_nb, length_ab, length_ne, length_ae;
2169         Int4 num1=0, num2=0;
2170 
2171         while (*in != '\0')
2172         {                       /* Check for digits in input*/
2173                 if (IS_DIGIT(*in))
2174                         break;
2175                 in++;
2176         }
2177 
2178         if (*in == '\0' || (in != in_pages && *(in-1) == ' '))
2179         {               /* if all letters (i.e. roman numerals), put out. */
2180                 out_pages = StringCpy(out_pages, in_pages);
2181                 return retval;
2182         }
2183 
2184         in = in_pages;
2185         if (IS_DIGIT(*in))
2186         {                       /* Do digits come first? */
2187                 first_alpha = FALSE;
2188                 index=0;
2189                 while (IS_DIGIT(*in) || *in == ' ')
2190                 {
2191                         firstbegin[index] = *in;
2192                         if (*in != ' ')
2193                                 index++;
2194                         in++;
2195                         if (*in == '-')
2196                                 break;
2197 
2198                 }
2199                 firstbegin[index] = '\0';
2200                 index=0;
2201                 if (*in != '-')
2202                 {               /* After digits look for letters. */
2203                         while (IS_ALPHA(*in)  || *in == ' ')
2204                         {
2205                                 secondbegin[index] = *in;
2206                                 index++;
2207                                 in++;
2208                                 if (*in == '-')
2209                                         break;
2210                         }
2211                 }
2212                 secondbegin[index] = '\0';
2213                 if (*in == '-')         /* if dash is not present, note */
2214                         in++;
2215                 else
2216                         dash=FALSE;
2217                 index=0;
2218                 while (IS_DIGIT(*in) || *in == ' ')
2219                 {                       /* Look for digits.     */
2220                         firstend[index] = *in;
2221                         if (*in != ' ')
2222                                 index++;
2223                         in++;
2224                 }
2225                 firstend[index] = '\0';
2226                 index=0;
2227                 if (*in != '\0')
2228                 {                       /* Look for letters again. */
2229                         while (IS_ALPHA(*in)  || *in == ' ')
2230                         {
2231                                 secondend[index] = *in;
2232                                 index++;
2233                                 in++;
2234                         }
2235                 }
2236                 secondend[index] = '\0';
2237         }
2238         else
2239         {                       /* Do letters come first? */
2240                 first_alpha = TRUE;
2241                 index=0;
2242                 while (IS_ALPHA(*in) || *in == ' ')
2243                 {
2244                         firstbegin[index] = *in;
2245                         index++;
2246                         in++;
2247                         if (*in == '-')
2248                                 break;
2249                 }
2250                 firstbegin[index] = '\0';
2251                 index=0;
2252                 if (*in != '-')
2253                 {               /* After letters look for digits.       */
2254                         while (IS_DIGIT(*in)  || *in == ' ')
2255                         {
2256                                 secondbegin[index] = *in;
2257                                 if (*in != ' ')
2258                                         index++;
2259                                 in++;
2260                                 if (*in == '-')
2261                                         break;
2262                         }
2263                 }
2264                 secondbegin[index] = '\0';
2265                 if (*in == '-')         /* Note if dash is missing. */
2266                         in++;
2267                 else
2268                         dash=FALSE;
2269                 index=0;
2270                 while (IS_ALPHA(*in) || *in == ' ')
2271                 {               /* Look for letters again. */
2272                         firstend[index] = *in;
2273                         index++;
2274                         in++;
2275                 }
2276                 firstend[index] = '\0';
2277                 index=0;
2278                 if (*in != '\0')
2279                 {               /* Any digits here? */
2280                         while (IS_DIGIT(*in)  || *in == ' ')
2281                         {
2282                                 secondend[index] = *in;
2283                                 if (*in != ' ')
2284                                         index++;
2285                                 in++;
2286                         }
2287                 }
2288                 secondend[index] = '\0';
2289         }
2290 
2291         if (first_alpha)
2292         {
2293                 alphabegin = firstbegin;
2294                 numbegin = secondbegin;
2295                 alphaend = firstend;
2296                 numend = secondend;
2297         }
2298         else
2299         {
2300                 numbegin = firstbegin;
2301                 alphabegin = secondbegin;
2302                 numend = firstend;
2303                 alphaend = secondend;
2304         }
2305 
2306         length_nb = StringLen(numbegin);
2307         length_ab = StringLen(alphabegin);
2308         length_ne = StringLen(numend);
2309         length_ae = StringLen(alphaend);
2310 
2311         /* If no dash, but second letters or numbers present, reject. */
2312         if (dash == FALSE)
2313         {
2314                 if (length_ne != 0 || length_ae != 0)
2315                         retval = -1;
2316         }
2317         /* Check for situations like "AAA-123" or "222-ABC". */
2318         if (dash == TRUE)
2319         {
2320                 if (length_ne == 0 && length_ab == 0)
2321                         retval = -1;
2322                 else if (length_ae == 0 && length_nb == 0)
2323                         retval = -1;
2324         }
2325 
2326         /* The following expands "F502-512" into "F502-F512" and
2327         checks, for entries like "12a-12c" that a > c.  "12aa-12ab",
2328         "125G-137A", "125-G137" would be rejected. */
2329         if (retval == 0)
2330         {
2331                 if (length_ab > 0)
2332                 {
2333                         if (length_ae > 0)      
2334                         { 
2335                                 if (StringCmp(alphabegin, alphaend) != 0)
2336                                 {
2337                                         if (length_ab != 1 || length_ae != 1)
2338                                                 retval = -1;
2339                                         else if (*alphabegin > *alphaend)
2340                                                 retval = -1;
2341                                 }
2342                         }
2343                         else
2344                         {
2345                                 alphaend = alphabegin;
2346                                 length_ae = length_ab;
2347                         }
2348                 } 
2349                 else if (length_ae > 0) 
2350                         retval = -1;
2351         }
2352 
2353 /* The following expands "125-37" into "125-137".       */
2354         if (retval == 0)
2355         {
2356                 if (length_nb > 0)
2357                 {
2358                         if (length_ne > 0)
2359                         {
2360                                 diff = length_nb - length_ne;
2361                                 if (diff > 0)
2362                                 {
2363                                         index=0;
2364                                         while (numend[index] != '\0')
2365                                         {
2366                                                 temp[index+diff] = numend[index];
2367                                                 index++;
2368                                         }
2369                                         temp[index+diff] = numend[index];
2370                                         for (index=0; index<diff; index++)
2371                                                 temp[index] = numbegin[index];
2372                                         index=0;
2373                                         while (temp[index] != '\0')
2374                                         {
2375                                                 numend[index] = temp[index];
2376                                                 index++;
2377                                         }
2378                                         numend[index] = temp[index];
2379                                 }
2380                         }
2381                         else
2382                         {
2383                                 numend = numbegin;
2384                                 length_ne = length_nb;
2385                         }
2386                 
2387                 }
2388                 else if (length_ne > 0)
2389                         retval = -1;
2390         /* Check that the first number is <= the second (expanded) number. */
2391                 if (retval == 0)
2392                 {
2393         /*              sscanf(numbegin, "%ld", &num_type);
2394                         num1 = (Int4) num_type;
2395                         sscanf( numend, "%ld", &num_type);
2396                         num2 = (Int4) num_type;
2397         */
2398                         num1 = (Int4) atol(numbegin);
2399                         num2 = (Int4) atol(numend);
2400                         if (num2 < num1)
2401                                 retval = -1;
2402                 }
2403         }
2404 
2405         if (retval == -1)
2406         {
2407                 out_pages = StringCpy(out_pages, in_pages);
2408         }
2409         else
2410         {
2411                 ptr = out_pages;
2412         /* Place expanded and validated page numbers into "out_pages". */
2413                 if (first_alpha)
2414                 {
2415                         while (*alphabegin != '\0')
2416                         {
2417                                 *ptr = *alphabegin;
2418                                 alphabegin++;
2419                                 ptr++;
2420                         }
2421                         while (*numbegin != '\0')
2422                         {
2423                                 *ptr = *numbegin;
2424                                 numbegin++;
2425                                 ptr++;
2426                         }
2427                         if (dash == TRUE)
2428                         {
2429                                 *ptr = '-';
2430                                 ptr++;
2431                                 while (*alphaend != '\0')
2432                                 {
2433                                         *ptr = *alphaend;
2434                                         alphaend++;
2435                                         ptr++;
2436                                 }
2437                                 while (*numend != '\0')
2438                                 {
2439                                         *ptr = *numend;
2440                                         numend++;
2441                                         ptr++;
2442                                 }
2443                         }
2444                         *ptr = '\0';
2445                 }
2446                 else 
2447                 {
2448                         while (*numbegin != '\0')
2449                         {
2450                                 *ptr = *numbegin;
2451                                 numbegin++;
2452                                 ptr++;
2453                         }
2454                         while (*alphabegin != '\0')
2455                         {
2456                                 *ptr = *alphabegin;
2457                                 alphabegin++;
2458                                 ptr++;
2459                         }
2460                         if (dash == TRUE)
2461                         {
2462                                 *ptr = '-';
2463                                 ptr++;
2464                                 while (*numend != '\0')
2465                                 {
2466                                         *ptr = *numend;
2467                                         numend++;
2468                                         ptr++;
2469                                 }
2470                                 while (*alphaend != '\0')
2471                                 {
2472                                         *ptr = *alphaend;
2473                                         alphaend++;
2474                                         ptr++;
2475                                 }
2476                         }
2477                         *ptr = '\0';
2478                 }
2479         }
2480         return retval;
2481 }
2482 
2483 /*****************************************************************************
2484 *FlatDateFromCreate
2485 *
2486 *       taken (with minor modifications) from Karl Sirotkin's code 
2487 *       by Tom Madden.
2488 *
2489 *****************************************************************************/
2490 
2491 NLM_EXTERN CharPtr
2492 FlatDateFromCreate (CharPtr default_date, NCBI_DatePtr flat_date)
2493 {
2494         CharPtr retval = NULL;
2495         char month[4], year[5]  , day[3];
2496         CharPtr daypt = & day[0];
2497         char result[14];
2498         char localbuf[14];
2499 
2500         if ( flat_date -> data[0] == 0){
2501 /*---string---*/
2502                 if (StringICmp(flat_date -> str,"Not given") != 0){
2503                         retval = StringSave(flat_date -> str);
2504                 }
2505         }else{
2506 /*---standard---*/
2507                 if (! default_date  || 
2508                                 (flat_date -> data[1] &&flat_date -> data[2]
2509                                         && flat_date -> data[3])){
2510                         if (flat_date -> data[1]){
2511                                 sprintf(year, "%4ld", (long) (flat_date -> data[1] + 1900));
2512                         }else{
2513                                 sprintf(year, "????");
2514                         }
2515                         if (flat_date -> data[3]){
2516                                 if (flat_date -> data[3] <= 9){
2517                                         *daypt = '0';
2518                                         daypt ++;
2519                                 }
2520                                 sprintf(localbuf, "%ld", (long) (flat_date -> data[3] ));
2521                         }else{
2522                                 sprintf(localbuf, "??");
2523                         }
2524                         StringCpy (daypt, localbuf);
2525                         if ( flat_date -> data[2] ){
2526                                 StringCpy(month, NCBI_months[flat_date -> data[2] -1 ]);
2527                                 month[1] = TO_UPPER(month[1]);
2528                                 month[2] = TO_UPPER(month[2]);
2529                         }else{
2530                                 sprintf(month, "??");
2531                         }
2532                         sprintf(result,"%s-%s-%s",day,month, year);
2533                         retval = StringSave(result);
2534                 }
2535         }
2536         return retval;
2537 }
2538 
2539 /*****************************************************************************
2540 *FlatIgnoreThisPatentPub
2541 *       Compares patent pub with patent seq_id
2542 *       returns TRUE if they don't match
2543 *****************************************************************************/
2544 NLM_EXTERN Boolean FlatIgnoreThisPatentPub (BioseqPtr bsp, ValNodePtr best, Int4Ptr seqidPt)
2545 {
2546         Boolean retval = FALSE;
2547         CitPatPtr cp;
2548         SeqIdPtr sip;
2549         PatentSeqIdPtr psip;
2550         IdPatPtr ip;
2551 
2552         if (best == NULL)
2553                 return FALSE;
2554         if (seqidPt){
2555                 * seqidPt = 0;
2556         }
2557         if (best -> choice != 9){
2558                 return retval;
2559         }
2560         cp = (CitPatPtr) best -> data.ptrvalue;
2561         for ( sip = bsp -> id; sip; sip = sip -> next){
2562                 if (sip -> choice != SEQID_PATENT) {
2563                         continue;
2564                 }
2565                 psip = (PatentSeqIdPtr) sip -> data.ptrvalue;
2566                 ip = psip -> cit;
2567                 if (ip == NULL) {
2568                         continue;
2569                 }
2570                 retval = TRUE;
2571                 if (ip -> number){
2572                         if (StringCmp(ip -> number, cp -> number) == 0){
2573                                 retval = FALSE;
2574                                 if (seqidPt){
2575                                         *seqidPt = psip -> seqid;
2576                                 }
2577                                 break;
2578                         }
2579                 } else if (ip -> app_number){
2580                         if (StringCmp(ip -> app_number, cp -> app_number) == 0){
2581                                 retval = FALSE;
2582                                 if (seqidPt){
2583                                         *seqidPt = (psip -> seqid);
2584                                 }
2585                                 break;
2586                         }
2587                 }
2588         }
2589 
2590         return retval;
2591 }
2592 
2593 NLM_EXTERN CharPtr GetAffiliation (AffilPtr afp)
2594 
2595 {
2596         Boolean need_comma=FALSE;
2597         CharPtr string=NULL, temp, ptr;
2598         Int2 aflen=15;
2599 
2600         if (afp) {
2601                 if (afp -> choice == 1){
2602                         if (afp -> affil){
2603                                 aflen += StringLen(afp -> affil);
2604                         }
2605                 }else if (afp -> choice == 2){
2606                         aflen += StringLen (afp -> affil) + 
2607                         StringLen (afp -> div) + 
2608                         StringLen (afp -> city) + 
2609                         StringLen (afp -> sub) + 
2610                         StringLen (afp -> street) + 
2611                         StringLen (afp -> country) + StringLen(afp->postal_code);
2612                 }
2613 
2614                 temp = string = MemNew(aflen);
2615 
2616                 if ( afp -> choice == 1){
2617                          if (afp -> affil){
2618                                 *temp = ' '; temp++;
2619                                 ptr = afp->affil;
2620                                 while ((*temp = *ptr) != '\0')
2621                                 {
2622                                         temp++; ptr++;
2623                                 }
2624                          }
2625                 }else if (afp -> choice == 2){
2626 
2627                         *temp = ' '; 
2628                         temp++;
2629                         if( afp -> div) { 
2630                                 if (need_comma)
2631                                 {
2632                                         *temp = ','; temp++;
2633                                         *temp = ' '; temp++;
2634                                 }
2635                                 ptr = afp->div;
2636                                 while ((*temp = *ptr) != '\0')
2637                                 {
2638                                         temp++; ptr++;
2639                                 }
2640                                 need_comma = TRUE;
2641                         }
2642 
2643                         if(afp -> affil) { 
2644                                 if (need_comma)
2645                                 {
2646                                         *temp = ','; temp++;
2647                                         *temp = ' '; temp++;
2648                                 }
2649                                 ptr = afp->affil;
2650                                 while ((*temp = *ptr) != '\0')
2651                                 {
2652                                         temp++; ptr++;
2653                                 }
2654                                 need_comma = TRUE;
2655                         }
2656 
2657                         if(afp -> street) { 
2658                                 if (need_comma)
2659                                 {
2660                                         *temp = ','; temp++;
2661                                         *temp = ' '; temp++;
2662                                 }
2663                                 ptr = afp->street;
2664                                 while ((*temp = *ptr) != '\0')
2665                                 {
2666                                         temp++; ptr++;
2667                                 }
2668                                 need_comma = TRUE;
2669                         }
2670 
2671                         if( afp -> city) { 
2672                                 if (need_comma)
2673                                 {
2674                                         *temp = ','; temp++;
2675                                         *temp = ' '; temp++;
2676                                 }
2677                                 ptr = afp->city;
2678                                 while ((*temp = *ptr) != '\0')
2679                                 {
2680                                         temp++; ptr++;
2681                                 }
2682                                 need_comma = TRUE;
2683                         }
2684 
2685                         if( afp -> sub) { 
2686                                 if (need_comma)
2687                                 {
2688                                         *temp = ','; temp++;
2689                                         *temp = ' '; temp++;
2690                                 }
2691                                 ptr = afp->sub;
2692                                 while ((*temp = *ptr) != '\0')
2693                                 {
2694                                         temp++; ptr++;
2695                                 }
2696                                 need_comma = TRUE;
2697                         }
2698 
2699                         if( afp -> postal_code){
2700                                 *temp = ' '; 
2701                                 temp++;
2702                                 ptr = afp->postal_code;
2703                                 while ((*temp = *ptr) != '\0')
2704                                 {
2705                                         temp++; ptr++;
2706                                 }
2707                         }       
2708 
2709                         if( afp -> country){
2710                                 if (need_comma)
2711                                 {
2712                                         *temp = ','; temp++;
2713                                         *temp = ' '; temp++;
2714                                 }
2715                                 ptr = afp->country;
2716                                 while ((*temp = *ptr) != '\0')
2717                                 {
2718                                         temp++; ptr++;
2719                                 }
2720                                 need_comma = TRUE;
2721                         }       
2722                 }
2723                 temp++;
2724                 *temp = '\0';
2725         }
2726         return string;
2727 }       /* GetAffiliation */
2728 
2729 
2730 /*****************************************************************************
2731 *CheckPubs
2732 *
2733 *       Code to check that the pub contains enough info to warrant 
2734 *       printing out.  This is checked out in ValidatePub.
2735 *       If the pub is not valid, it is deleted from the list.
2736 *
2737 *       do not delete in debug mode  (tatiana)
2738 *       Returns the number of valid pubs found.
2739 *
2740 *****************************************************************************/
2741 
2742 NLM_EXTERN Int2 CheckPubs (Asn2ffJobPtr ajp, BioseqPtr bsp, ValNodePtr PNTR vnpp)
2743 
2744 {
2745         Boolean good_one = FALSE;
2746         Int2 retval=0, status;
2747         PubStructPtr psp;
2748         ValNodePtr last, newpub, vnp2, vnp = *vnpp, pub;
2749 
2750         UniquePubs(vnpp);
2751         last=NULL;
2752         vnp = *vnpp;
2753         while (vnp)
2754         {
2755                 psp = vnp->data.ptrvalue;
2756                 if ((psp->pub)->choice == PUB_Equiv)
2757                         newpub = psp->pub->data.ptrvalue;
2758                 else
2759                         newpub = psp->pub;
2760 
2761                 for (vnp2=newpub; vnp2; vnp2=vnp2->next)
2762                         if ((status=ValidatePub(bsp, vnp2)) > 0)
2763                         {
2764                                 retval++;
2765                                 break;
2766                         }
2767 
2768                 if (status < 0)
2769                 {
2770                         vnp->choice = (Uint1) 1;
2771                         if (ajp->error_msgs)
2772                                 PostARefErrMessage (ajp, bsp, psp, NULL, status, NULL);
2773                 }
2774                 else 
2775                 {
2776                         good_one = TRUE;
2777                 }
2778                 vnp = vnp->next;
2779         }
2780 
2781 /* If not one good pub was found, look for something printable and take that. */
2782         vnp = *vnpp;
2783         if (good_one == FALSE)
2784         {
2785                 retval = -1;
2786                 while (vnp)
2787                 {
2788                         psp = vnp->data.ptrvalue;
2789                         pub = FlatRefBest(psp->pub, FALSE, FALSE);
2790 /* If a pub is a patent it probably failed FlatIgnoreThisPatentPub; don't
2791 take it and keep looking. */
2792                         if (pub != NULL && pub->choice != PUB_Patent)
2793                         {
2794                                 vnp->choice = (Uint1) 0;
2795                                 retval = 0;
2796                                 break;
2797                         }
2798                         vnp = vnp->next;
2799                 }
2800         }
2801         if (ASN2FF_SHOW_ALL_PUBS) {
2802                 return retval;
2803         }
2804 /* Drop the bad ones. */
2805         vnp = *vnpp;
2806         last = NULL;
2807         while (vnp)
2808         {
2809                 if (vnp->choice != 0)
2810                 {
2811                     if (last == NULL)
2812                     {   /* If the first pub is bad. */
2813                         *vnpp = vnp->next;
2814                         vnp->next = NULL;
2815                         FreePubStruct(vnp->data.ptrvalue);
2816                         ValNodeFree(vnp);
2817                         vnp = *vnpp;
2818                     }
2819                     else
2820                     {   /* If any but the first pub is bad. */
2821                         last->next = vnp->next;
2822                         vnp->next = NULL;
2823                         FreePubStruct(vnp->data.ptrvalue);
2824                         ValNodeFree(vnp);
2825                         vnp = last->next;
2826                     }
2827                 }
2828                 else
2829                 {
2830                         last = vnp;
2831                         vnp = vnp->next;
2832                 }
2833         }
2834         
2835         return retval;
2836 }               
2837 
2838 /*****************************************************************************
2839 *ValidatePub 
2840 *
2841 *       Checks whether pubs include authors, journal names etc.
2842 *
2843 * At present (2/10/94) this function passes most pubs w/o checks (i.e.,
2844 * status is 0.  This should be tightened up to include more checks 
2845 *(vol. # etc.)???????????
2846 *
2847 *       (8/17/94): adding more specific information on error return:
2848 *       status:
2849 *               -1      not specific, reference is just bad.
2850 *               -2      no valid author names.
2851 *               -3      no valid journal title.
2852 *
2853 *****************************************************************************/
2854 
2855 NLM_EXTERN Int2 ValidatePub (BioseqPtr bsp, ValNodePtr the_pub)
2856 {
2857         AuthListPtr             ap;
2858         AuthorPtr               authptr;
2859         Boolean                 ignore_this=FALSE;
2860         CitBookPtr              cb;
2861         CitSubPtr               cs;
2862         CitGenPtr               cg;     
2863         CitArtPtr               ca;
2864         CitPatPtr               cp;
2865         Int2                    length, status = -1;
2866         Int4                    pat;
2867         MedlineEntryPtr ml;
2868         CitJourPtr              jp;
2869         ImprintPtr              ip;
2870         NameStdPtr              nsp;
2871         PersonIdPtr             pid;
2872 
2873         switch ( the_pub -> choice) {
2874 
2875         case PUB_Sub:
2876                         status = 1;
2877                         cs = (CitSubPtr) the_pub -> data.ptrvalue;
2878                         ap = cs->authors;
2879                 break;
2880                 case PUB_Man:
2881                 case PUB_Book: 
2882                         cb = (CitBookPtr) the_pub -> data.ptrvalue;
2883                         if ( cb -> imp) {
2884                                 ip = cb -> imp;
2885                                 if (ip)
2886                                         status = 1;
2887                         }
2888                         ap = cb->authors;
2889                 break;
2890                 case PUB_Patent:
2891                         ignore_this = FlatIgnoreThisPatentPub(bsp, the_pub, &pat);
2892                         if (ignore_this == FALSE || ISA_aa(bsp->mol))
2893                                 status = 1;
2894                         cp = (CitPatPtr) the_pub -> data.ptrvalue;
2895                         ap = cp->authors;
2896                         break;
2897 
2898                 case PUB_Medline:
2899                 case PUB_Article:
2900                         if ( the_pub -> choice == PUB_Medline) {
2901                                 ml = (MedlineEntryPtr) the_pub -> data.ptrvalue;
2902                                 ca = (CitArtPtr) ml -> cit;
2903                         } else {
2904                                 ca = (CitArtPtr) the_pub -> data.ptrvalue;
2905                         }
2906                 if ( ca -> fromptr) {
2907                         if ( ca -> from ==1) {
2908                                 jp = (CitJourPtr) ca -> fromptr;
2909                                 if (StringLen((CharPtr)jp->title->data.ptrvalue) == 0) {
2910                                         ip = jp->imp;
2911                                         if (ip && ip->prepub == 0) {
2912                                                 status = -3;
2913                                                 break;
2914                                         }
2915                                 }
2916                                 if ( jp -> imp)
2917                                                 status = 1;
2918                         } else {
2919                                 CitBookPtr book = (CitBookPtr) ca -> fromptr;
2920                                         if ( book -> imp)
2921                                                         status = 1;
2922                         }
2923                 }
2924                 ap = ca -> authors;
2925                 break;
2926                 case PUB_Gen: 
2927                         cg = (CitGenPtr) the_pub -> data.ptrvalue;
2928                         if (cg -> cit) {
2929                                 if (StringNICmp("unpublished", cg->cit, 11) == 0)
2930                                         status = 1;
2931                                 if (StringNICmp("submitted", cg->cit, 8) == 0)
2932                                         status = 1;
2933                                 if (StringNICmp("to be published", cg->cit, 15) == 0)
2934                                         status = 1;
2935                                 if (StringNICmp("in press", cg->cit, 8) == 0)
2936                                         status = 1;
2937                                 else if (StrStr(cg->cit, "Journal") != NULL)
2938                                         status = 1;
2939                         } else {
2940                                 if ((cg->journal) && (cg->date))
2941                                         status = 1;
2942                                 else if (cg->journal == NULL)
2943                                         status = -4;
2944                                 else if (cg->date == NULL)
2945                                         status = -5;
2946                         }
2947 
2948                         ap = cg -> authors;
2949                         break;
2950                 default:
2951                         status = -1;
2952                         break;
2953         }
2954 
2955         if (status < 0)
2956                 return status;
2957         else if (ap == NULL)
2958                 return -2;
2959 
2960         if (ap && the_pub -> choice != PUB_Patent) {
2961                 if (ap->choice == 1) {
2962                         if (ap->names == NULL) {
2963                                 return -2;
2964                         }
2965                         authptr = (AuthorPtr) (ap->names)->data.ptrvalue;
2966                         pid = authptr->name;
2967                         if (pid->choice == 2) {
2968                                 nsp = (NameStdPtr) pid->data;
2969                                 length = StringLen(nsp->names[0]);
2970                                 length += StringLen(nsp->names[3]);
2971                                 if (length == 0)
2972                                         status = -2;
2973                         } else if (pid->choice == 3 || pid->choice == 4) {
2974                                 length = StringLen((CharPtr)pid->data);
2975                                 if (length == 0)
2976                                         status = -2;
2977                         }
2978                 } else if (ap->choice == 2 || ap->choice == 3) {
2979                         if (ap->names == NULL)
2980                                 status = -2;
2981                         else if (StringLen((CharPtr)ap->names->data.ptrvalue) == 0)
2982                                 status = -2;
2983                 }
2984         }
2985 
2986         return status;
2987 }
2988 
2989 /*************************************************************************
2990 *void PostARefErrMessage(Asn2ffJobPtr ajp, BioseqPtr bsp, PubStructPtr psp, ValNodePtr pub, Int2 status, CharPtr string)
2991 *
2992 *       Given a pub, by "checkPubs", this function posts an error
2993 *       message about the invalid reference.  
2994 *
2995 *       status has the following meanings:
2996 *
2997 *               -1      not specific, reference is just bad.
2998 *               -2      no valid author names.
2999 *               -3      no valid journal title.
3000 *************************************************************************/
3001 
3002 NLM_EXTERN void PostARefErrMessage (Asn2ffJobPtr ajp, BioseqPtr bsp, PubStructPtr psp, ValNodePtr ext_pub, Int2 status, CharPtr ext_string)
3003 
3004 {
3005         Boolean /*UNUSED*/ignore_this, submit=FALSE, error;
3006         CharPtr authors=NULL, string=NULL, newstring=NULL, title=NULL, journal=NULL, ptr;
3007         Char buffer[30];
3008         Int2 length;
3009         Int4 pat_seqid=0;
3010         ValNodePtr equiv, pub;
3011 
3012 /*      ajp->format = GENBANK_FMT; */
3013 /*      ajp->newline = ' '; */
3014         error = ajp->error_msgs;
3015         ajp->error_msgs = FALSE;
3016 
3017         if (bsp == NULL) {
3018                 flat2asn_delete_locus_user_string();
3019                 flat2asn_install_locus_user_string("SET_UP");
3020                 flat2asn_delete_accession_user_string();
3021                 flat2asn_install_accession_user_string("SET_UP");
3022         } else {
3023                 MakeAnAccession(buffer, bsp->id, 30);
3024                 flat2asn_delete_locus_user_string();
3025                 flat2asn_install_locus_user_string(buffer);
3026                 flat2asn_delete_accession_user_string();
3027                 flat2asn_install_accession_user_string(buffer);
3028         }
3029         if (ext_pub)
3030                 pub = ext_pub;
3031         else if (psp)
3032                 pub = FlatRefBest(psp->pub, TRUE, FALSE);
3033         else    /* Nothing done here, as neither pub nor psp is given! */
3034                 return;
3035 
3036         if (pub == NULL && ext_string == NULL)
3037         {       /* Look for pubs that only have muid of zero! */
3038                 equiv = psp->pub;
3039                 if (equiv->choice == PUB_Equiv)
3040                         pub = equiv->data.ptrvalue;
3041                 else
3042                         pub = equiv;
3043                 if (pub)
3044                 {
3045                         if (pub->choice == 4 && pub->next == NULL)
3046                            if (pub->data.intvalue == 0)
3047                                 status = -9;
3048                 }
3049                 pub = NULL;     /* To avoid problems down below */
3050         }
3051 
3052 
3053 
3054         if (pub != NULL)
3055         {
3056                 ignore_this = FlatIgnoreThisPatentPub(bsp, pub, &pat_seqid);
3057 /* if ext_pub is not NULL, then the call is from FlatJournal, due to 
3058 bad pagination, and calling FlatJournal, with error_msgs set to TRUE, risks 
3059 a loop! */
3060                 if (ext_pub != NULL) 
3061                         ajp->error_msgs = FALSE;
3062                 journal = FlatJournal(ajp, ajp->asn2ffwep->gbp, pub, pat_seqid, &submit, FALSE);
3063                 title = FlatPubTitle(pub);
3064                 authors = FlatAuthor(ajp, pub);
3065         }
3066 
3067         length = StringLen(ext_string) + StringLen(authors) + StringLen(journal) + StringLen(title) + 5;
3068 
3069         string = newstring = MemNew(length*sizeof(Char));
3070 
3071         if (authors)
3072         {
3073                 ptr = authors;
3074                 while (*ptr != '\0')
3075                 {
3076                         *string = *ptr;
3077                         ptr++; string++;
3078                 }
3079                 authors = MemFree(authors);
3080         }
3081         *string = '|';
3082         string++;
3083 
3084         if (journal)
3085         {
3086                 ptr = journal;
3087                 while (*ptr != '\0')
3088                 {
3089                         *string = *ptr;
3090                         ptr++; string++;
3091                 }
3092         }
3093         *string = '|';
3094         string++;
3095         
3096         if (title)
3097         {       /* Also may be needed below. */
3098                 ptr = title;
3099                 while (*ptr != '\0')
3100                 {
3101                         *string = *ptr;
3102                         ptr++; string++;
3103                 }
3104         }
3105         *string = '|';
3106         string++;
3107 
3108         if (ext_string)
3109         {
3110                 ptr = ext_string;
3111                 while (*ptr != '\0')
3112                 {
3113                         *string = *ptr;
3114                         ptr++; string++;
3115                 }
3116         }
3117 
3118 /* Sometimes an error is caused by a Direct Sub in a cit-gen */
3119         if (status > 0 && 
3120                 pub->choice == 1 && 
3121                     title != NULL &&
3122                         StringNCmp(title, "Direct Submission", 17) == 0)
3123                 status = 3;
3124         else if (status > 0 && 
3125                 pub->choice == 1 && 
3126                     journal != NULL &&
3127                         StringNCmp(journal, "Submitted", 9) == 0)
3128                 status = 3;
3129 
3130         if (title)
3131                 title = MemFree(title);
3132         if (journal)
3133                 journal = MemFree(journal);
3134 
3135         if (status == 5)
3136             ErrPostStr(SEV_INFO, ERR_REFERENCE_ParanInSupp, newstring);
3137         if (status == 4)
3138             ErrPostStr(SEV_INFO, ERR_REFERENCE_VolHasSuppl, newstring);
3139         else if (status == 3)
3140             ErrPostStr(SEV_INFO, ERR_REFERENCE_DirSubInCitGen, newstring);
3141         else if (status == 2)
3142             ErrPostStr(SEV_WARNING, ERR_REFERENCE_NoPageNumbering, newstring);
3143         else if (status == 1)
3144             ErrPostStr(SEV_WARNING, ERR_REFERENCE_IllegalPageRange, newstring);
3145         else if (status == -1)
3146             ErrPostStr(SEV_ERROR, ERR_REFERENCE_Illegalreference, newstring);
3147         if (status == -2)
3148             ErrPostStr(SEV_ERROR, ERR_REFERENCE_NoAuthorName, newstring);
3149         else if (status == -3 || status == -4)
3150             ErrPostStr(SEV_ERROR, ERR_REFERENCE_NoJournalName, newstring);
3151         else if (status == -5)
3152             ErrPostStr(SEV_ERROR, ERR_REFERENCE_NoDateOnRef, newstring);
3153         else if (status == -9)
3154             ErrPostStr(SEV_WARNING, ERR_REFERENCE_MuidZeroOnly, newstring);
3155         
3156         newstring = MemFree(newstring);
3157         ajp->error_msgs = error;
3158         return;
3159 }
3160 
3161 /*************************************************************************
3162 *       This function does a check that the NAFeat will be valid at all,
3163 *       i.e., that it has a valid key and all the mandatory qualifiers
3164 *       are present.  ValidateNAImpFeat does a more thorough validation
3165 *       later on.
3166 *       New condition (7/21/94): if the feature is a misc_feature and
3167 *       has no valid qualifiers, it is dropped.
3168 ************************************************************************/
3169 NLM_EXTERN Boolean CheckNAFeat(Boolean is_new, BioseqPtr bsp, SeqFeatPtr sfp)
3170 
3171 {
3172         Boolean allocated=FALSE, found_key, location=FALSE, valid=FALSE;
3173         CharPtr key=NULL;
3174         CharPtr ptr=NULL;
3175         GBQualPtr gbqual;
3176         Int2 index, status;
3177 
3178         found_key = GetNAFeatKey(is_new, &key, sfp, NULL);
3179 
3180         if (found_key)
3181         {
3182                 flat2asn_install_feature_user_string(key, NULL);
3183                 index = GBFeatKeyNameValid(&key, FALSE);
3184                 if (index != -1)
3185                 {
3186                         location = CheckAndGetNAFeatLoc(bsp, &ptr, sfp, TRUE);
3187                         flat2asn_delete_feature_user_string();
3188                         flat2asn_install_feature_user_string(key, ptr);
3189                         gbqual=sfp->qual;
3190                         if (StringCmp(key, "source") == 0) {  /*fake check for Biosource */
3191                                 status = GB_FEAT_ERR_NONE;
3192                                 valid = TRUE;
3193                         } else {
3194                                 status = GBFeatKeyQualValid(sfp->cit, index, &gbqual,
3195                                                                                         ASN2FF_SHOW_ERROR_MSG, FALSE);
3196                                 if (status == GB_FEAT_ERR_NONE)
3197                                         valid = TRUE;
3198                                 else if (status == GB_FEAT_ERR_REPAIRABLE)
3199                                 { /* Check if bad qual is required!! */
3200                                         gbqual = GBQualCopy(sfp->qual);
3201                                         allocated = TRUE;
3202                                         status = GBFeatKeyQualValid(sfp->cit, index, &gbqual,
3203                                                                                                                                  FALSE, TRUE);
3204                                         if (status != GB_FEAT_ERR_DROP)
3205                                                 valid = TRUE;
3206                                 }
3207                         }
3208                         ptr = MemFree(ptr);
3209 
3210                         if (valid == TRUE && 
3211                                 StringCmp(key, "misc_feature") == 0)
3212                         { /* Check for at least one valid qual on misc_feature*/
3213                                 if (gbqual == NULL)
3214                                         if (sfp->data.choice != 1 &&
3215                                                 sfp->comment == NULL)
3216                                         {
3217                                                 valid = FALSE;
3218                                         ErrPostStr(SEV_WARNING, ERR_FEATURE_NoQualOnMiscFeat, " "); 
3219                                         }
3220                         } /* was gbqual allocated, or a copy of sfp->qual?*/
3221                         if (allocated == TRUE && gbqual != NULL)
3222                                         gbqual = GBQualFree(gbqual);
3223                 }
3224                 else if (ASN2FF_SHOW_ERROR_MSG == TRUE)
3225                 {
3226                         ErrPostStr(SEV_WARNING, ERR_FEATURE_UnknownFeatureKey, " "); 
3227                 }
3228                 flat2asn_delete_feature_user_string();
3229         }
3230 
3231         if (location && valid)
3232                 return TRUE;
3233         else
3234                 return FALSE;
3235 }       /* CheckNAFeat */
3236 
3237 /*************************************************************************
3238 *Boolean CheckAndGetNAFeatLoc(BiotablePtr btp, Int2 count, CharPtr PNTR buffer, SeqFeatPtr sfp, Boolean loc_return)
3239 *
3240 *       This function does a check that the feature location is valid.
3241 *       It makes use of parser validation functions.
3242 *       The Boolean "loc_return" specifies whether or not a location should 
3243 *       be returned.
3244 ************************************************************************/
3245 
3246 NLM_EXTERN Boolean CheckAndGetNAFeatLoc(BioseqPtr bsp, CharPtr PNTR buffer, SeqFeatPtr sfp, Boolean loc_return)
3247 
3248 {
3249         Boolean location=FALSE;
3250         CharPtr flatloc_ptr=NULL;
3251         ImpFeatPtr ifp=NULL;
3252         int num_errs;
3253         Boolean keep_rawPt, sitesPt;
3254         SeqIdPtr seq_id;
3255         SeqLocPtr slp;
3256 
3257         if (bsp == NULL)
3258                 return FALSE;
3259         seq_id = SeqIdFindBest(bsp->id, SEQID_GENBANK);
3260         install_gbparse_range_func(NULL, check_range);
3261         if (ASN2FF_SHOW_ERROR_MSG == TRUE) {
3262                 install_gbparse_error_handler(do_loc_errors);
3263         } else {
3264                 install_gbparse_error_handler(do_no_loc_errors);
3265         }
3266         if (sfp->data.choice == SEQFEAT_IMP) {  /* Use ifp->loc if OK */
3267                 ifp = sfp->data.value.ptrvalue;
3268                 if (ifp && ifp->loc) {
3269                         slp = gbparseint(ifp->loc, &keep_rawPt, 
3270                                                         &sitesPt, &num_errs, seq_id);
3271                         if (num_errs == 0) {
3272                                 SeqLocFree(slp);
3273                                 location=TRUE;
3274                         } else if ( ASN2FF_VALIDATE_FEATURES == FALSE && loc_return) {
3275                                 flat2asn_install_feature_user_string(ifp->key, ifp->loc);
3276                                 flat2asn_delete_feature_user_string();
3277                         }
3278                         if (loc_return) {
3279                                 if (*buffer)
3280                                         *buffer = MemFree(*buffer);
3281                                 *buffer = StringSave (ifp->loc);
3282                         }
3283                 }
3284         }
3285 
3286         if (location == FALSE)
3287         {       /* only called if not an ImpFeatPtr and/or ifp->loc bad */
3288                 flatloc_ptr =  FlatLoc(bsp, sfp->location);
3289                 slp = gbparseint(flatloc_ptr, &keep_rawPt, &sitesPt, &num_errs, seq_id);
3290 
3291                 if (num_errs == 0 || ASN2FF_VALIDATE_FEATURES == FALSE)
3292                 {
3293                         SeqLocFree(slp);
3294                         location=TRUE;
3295                 }
3296                 if (loc_return)
3297                 {
3298                         if (*buffer)
3299                                 *buffer = MemFree(*buffer);
3300                         *buffer = flatloc_ptr;
3301                 }
3302                 else
3303                         flatloc_ptr = MemFree(flatloc_ptr);
3304         }
3305 
3306         if (location)
3307                 return TRUE;
3308         else
3309                 return FALSE;
3310 }       /* CheckAndGetNAFeatLoc */
3311 
3312 /*****************************************************************************
3313 *void GetAAFeatLoc(BioseqPtr bsp, CharPtr PNTR buffer, SeqFeatPtr sfp, Boolean use_product)
3314 *
3315 *       "twin" to CheckAndGetNAFeatLoc, except that no checking is done
3316 *       yet for genpept.
3317 ****************************************************************************/
3318 
3319 NLM_EXTERN void GetAAFeatLoc(BioseqPtr bsp, CharPtr PNTR buffer, SeqFeatPtr sfp, Boolean use_product)
3320 {
3321         Boolean location=FALSE;
3322         CharPtr flatloc_ptr=NULL;
3323         ImpFeatPtr ifp=NULL;
3324 
3325         if (sfp->data.choice == SEQFEAT_IMP) {
3326                 ifp = sfp->data.value.ptrvalue;
3327                 if (ifp && ifp->loc) {
3328                         if (*buffer) {
3329                                 *buffer = MemFree(*buffer);
3330                         }
3331                         *buffer = StringSave (ifp->loc);
3332                         location = TRUE;
3333                 }
3334         }
3335 
3336         if (location == FALSE) {
3337                 if (use_product)  /* Used for CDS in genpept. */
3338                         flatloc_ptr =  FlatLoc(bsp, sfp->product);
3339                 else
3340                         flatloc_ptr =  FlatLoc(bsp, sfp->location);
3341 
3342                 if (*buffer)
3343                         *buffer = MemFree(*buffer);
3344                 *buffer = flatloc_ptr;
3345         }
3346 
3347 }       /* GetAAFeatLoc */
3348 
3349 static GBQualPtr GBQualCopy (GBQualPtr old_qual)
3350 {
3351         GBQualPtr curq, new_qual, new_qual_start=NULL;
3352 
3353         if (old_qual)
3354         {
3355                 new_qual_start = new_qual = GBQualNew();
3356                 for (curq=old_qual; curq; curq=curq->next)
3357                 {
3358                         if (curq->val)
3359                                 new_qual->val = StringSave(curq->val);
3360                         if (curq->qual)
3361                                 new_qual->qual = StringSave(curq->qual);
3362                         if (curq->next)
3363                         {
3364                                 new_qual->next = GBQualNew();
3365                                 new_qual = new_qual->next;
3366                         }
3367                         else
3368                                 new_qual->next = NULL;
3369                 }
3370         }
3371         return new_qual_start;
3372 }
3373 
3374 

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.