1 /***************************************************************************
2 *   gbfeat.c:
3 *   -- all routines for checking genbank feature table
4 *   -- all extern variables are in gbftglob.c
5 *                                                                  10-11-93
6 $Revision: 6.11 $
7 *
8 ****************************************************************************/
9 
10 #include <utilpars.h>
11 #include "gbftdef.h"
12 #include <gbfeat.h>
13 #include <errdefn.h>
14 
15 #define ParFlat_SPLIT_IGNORE 4
16 CharPtr GBQual_names_split_ignore[ParFlat_SPLIT_IGNORE] = {
17 "citation", "EC_number", "rpt_type", "usedin"};
18 
19 /*------------------------- GBQualNameValid() ------------------------*/
20 /****************************************************************************
21 *  GBQualNameValid:
22 *  -- return index of the ParFlat_GBQual_names array if it is a valid
23 *     qualifier (ignore case), qual; otherwise return (-1)
24 *                                                                   10-12-93
25 *	-- ignore case changed to case sensitive      10-08-95
26 *****************************************************************************/
GBQualNameValid(CharPtr qual)27 NLM_EXTERN Int2 GBQualNameValid(CharPtr qual)
28 {
29    Int2  i;
30 
31    for (i = 0; i < ParFlat_TOTAL_GBQUAL && qual != NULL; i++) {
32        if (StringCmp(qual, ParFlat_GBQual_names[i].name) == 0)
33           return (i);
34    }
35 
36    return (-1);
37 
38 } /* GBQualNameValid */
39 
40 /*------------------------- GBQualSplit() ------------------------*/
41 /****************************************************************************
42 *  GBQualSplit:
43 *  -- return index of the GBQual_names_split_ignore array if it is a valid
44 *     qualifier (ignore case), qual; otherwise return (-1)
45 *                                                                   10-12-93
46 *****************************************************************************/
GBQualSplit(CharPtr qual)47 NLM_EXTERN Int2 GBQualSplit(CharPtr qual)
48 {
49    Int2  i;
50 
51    for (i = 0; i < ParFlat_SPLIT_IGNORE && qual != NULL; i++) {
52        if (StringICmp(qual, GBQual_names_split_ignore[i]) == 0)
53           return (i);
54    }
55 
56    return (-1);
57 
58 } /* GBQualSplit */
59 
60 /*-------------------------- GBFeatKeyNameValid() -------------------------*/
61 /****************************************************************************
62 *  GBFeatKeyNameValid:
63 *  -- return "index" of the ParFlat_GBFeat array if it is a valid feature key (
64 *     ignore case), keystr; otherwise, return (-1), UnknownFeatKey
65 *                                                                  10-11-93
66 *	-- ignore case changed to case sensitive      10-08-95
67 ****************************************************************************/
GBFeatKeyNameValid(CharPtr PNTR keystr,Boolean error_msgs)68 NLM_EXTERN Int2 GBFeatKeyNameValid(CharPtr PNTR keystr, Boolean error_msgs)
69 {
70    Int2    j;
71 
72    if (StringCmp(*keystr, "-") == 0)
73    {
74 	if (error_msgs)
75 	{
76             ErrPostStr(SEV_WARNING, ERR_FEATURE_FeatureKeyReplaced,
77            	"Featkey '-' is replaced by 'misc_feature'");
78 	}
79    	*keystr = StringSave("misc_feature");
80    }
81 
82    for (j = 0; j < ParFlat_TOTAL_GBFEAT; j++)
83    {
84        if (StringCmp(ParFlat_GBFeat[j].key, *keystr) == 0)
85           return (j);
86    }
87 
88    return (-1);
89 
90 } /* GBFeatKeyNameValid */
91 
GBQualValidToAdd(Int2 keyindx,CharPtr curr)92 NLM_EXTERN Boolean GBQualValidToAdd(Int2 keyindx, CharPtr curr)
93 {
94    Int2            i, qual, val;
95 
96 	if (keyindx == -1)
97 		return FALSE;
98 	val = GBQualNameValid(curr);
99 	for (i = 0; i < ParFlat_GBFeat[keyindx].opt_num; i++) {
100 		qual = ParFlat_GBFeat[keyindx].opt_qual[i];
101 		if (qual == val) {
102 			return TRUE;
103 		}
104 	}
105 	for (i = 0; i < ParFlat_GBFeat[keyindx].mand_num; i++) {
106 		qual = ParFlat_GBFeat[keyindx].mand_qual[i];
107 		if (qual == val) {
108 			return TRUE;
109 		}
110 	}
111 	return FALSE;
112 }
113 
114 /*--------------------------- GBFeatKeyQualValid() -----------------------*/
115 /***************************************************************************
116 *  GBFeatKeyQualValid:
117 *  -- returns error severity level.
118 *    error dealt with here.  Messages output if parameter 'error_msgs' set,
119 *    repair done if 'perform_corrections' set
120 *                                                                   10-11-93
121 *****************************************************************************/
GBFeatKeyQualValid(ValNodePtr cit,Int2 keyindx,GBQualPtr PNTR gbqp,Boolean error_msgs,Boolean perform_corrections)122 NLM_EXTERN int GBFeatKeyQualValid(ValNodePtr cit, Int2 keyindx, GBQualPtr PNTR gbqp,
123    Boolean error_msgs, Boolean perform_corrections)
124 {
125    Int2            i, qual, val;
126    Boolean         fqual=FALSE;
127    GBQualPtr       curq, preq = NULL, next_q, first_q;
128    int retval = GB_FEAT_ERR_NONE;
129 
130                               /* unknown qual will be drop after the routine */
131    retval = SplitMultiValQual(gbqp, error_msgs, perform_corrections);
132    retval = GBQualSemanticValid(gbqp, error_msgs, perform_corrections);
133 /*----------------------------------------
134      if the Semnatic QUALIFIER validator says drop, then
135      at the feature level, it is repairable by dropping the
136      qualifier.  The only DROP for a feature is lack of
137      a manditory qualifier which is handled later in this function.
138              -Karl 2/7/94
139 -----------------------------*/
140    if (retval == GB_FEAT_ERR_DROP){
141       retval = GB_FEAT_ERR_REPAIRABLE;
142    }
143 
144    for (first_q = curq = *gbqp; curq != NULL; curq=next_q) {
145    		if (StringCmp(curq->qual, "gsdb_id") == 0) {
146        		next_q = curq -> next;
147    			continue;
148    		}
149        next_q = curq -> next;
150 
151        fqual = FALSE;
152        val = GBQualNameValid(curq->qual);
153 
154        for (i = 0; i < ParFlat_GBFeat[keyindx].opt_num; i++) {
155            qual = ParFlat_GBFeat[keyindx].opt_qual[i];
156 
157            if (qual == val) {
158               fqual = TRUE;
159               break;
160            }
161        }
162 
163        if (!fqual) {
164           /* go back to check, is this a mandatory qualifier ? */
165 
166           for (i = 0; i < ParFlat_GBFeat[keyindx].mand_num; i++) {
167               qual = ParFlat_GBFeat[keyindx].mand_qual[i];
168               if (qual == val) {
169                  fqual = TRUE;
170                  break;
171               }
172           }
173 
174           if (!fqual) {
175              if (retval < GB_FEAT_ERR_REPAIRABLE){
176                 retval = GB_FEAT_ERR_REPAIRABLE;
177              }
178              if (error_msgs){
179                ErrPostStr(SEV_ERROR, ERR_FEATURE_QualWrongThisFeat,
180                  curq -> qual?curq -> qual:"");
181 
182              }
183              if (perform_corrections) {
184                 DeleteGBQualFromList(gbqp, curq, preq);
185              }
186 
187           }
188        }
189        if (preq){
190   /*---- we have retained a qualifier, previously ----*/
191           if (preq -> next != next_q){
192    /*-- did not delete curq ----*/
193               preq = curq;
194           }
195        }else {
196     /* ---- no qualifier previously retained, is there a new head pointer? */
197           if (first_q == *gbqp){
198       /* ---- we have kept our first qualifier  */
199              preq = curq;
200           }else{
201       /*--- we deleted the head of the queue, record current first qualifier */
202              first_q = *gbqp;
203           }
204        }
205        if (*gbqp == NULL){
206           break;  /* was one, is gone */
207        }
208    }
209    if (ParFlat_GBFeat[keyindx].mand_num > 0) {
210                         /* do they contain all the mandatory qualifiers? */
211       for (i = 0; i < ParFlat_GBFeat[keyindx].mand_num; i++) {
212           qual = ParFlat_GBFeat[keyindx].mand_qual[i];
213 
214           for (curq = *gbqp; curq != NULL; curq = curq->next) {
215               fqual = FALSE;
216               val = GBQualNameValid(curq->qual);
217 
218               if (qual == val) {
219                  fqual = TRUE;
220                  break;
221               }
222           }
223 
224           if (!fqual) {
225             if (error_msgs){
226             	if (qual == 7 && cit != NULL) {
227             	/* don't do anything */
228             	} else {
229                		ErrPostEx(SEV_ERROR, ERR_FEATURE_MissManQual,
230                  	ParFlat_GBQual_names[qual].name );
231              	}
232              }
233              if (perform_corrections) {
234             		if (qual == 7 && cit != NULL) {
235             	/* don't do anything */
236             		} else {
237              			retval = GB_FEAT_ERR_DROP;
238              		}
239              }
240          }
241       }
242    }
243                                            /* check optional qualifiers */
244 
245    return retval;
246 
247 } /* GBFeatKeyQualValid */
248 
249 /*-------------------------- SplitMultiValQual() ------------------------*/
250 /***************************************************************************
251 *  SplitMultiValQual:
252 *
253 *
254 ****************************************************************************/
SplitMultiValQual(GBQualPtr PNTR gbqp,Boolean error_msgs,Boolean perform_corrections)255 NLM_EXTERN int SplitMultiValQual(GBQualPtr PNTR gbqp,
256      Boolean error_msgs, Boolean perform_corrections)
257 {
258    Int2        val/*, len -- UNUSED */;
259    GBQualPtr   next_q, curq, preq = NULL, first_q, tmp;
260    int retval = GB_FEAT_ERR_NONE;
261    CharPtr	bptr, ptr, buf;
262 
263    for (first_q = curq = *gbqp; curq != NULL; curq = next_q) {
264         next_q = curq -> next;  /* in case deleted */
265 
266        val = GBQualSplit(curq->qual);
267 /*       len = StringLen(curq->qual); -- NO EFFECT */
268 
269        if (val == -1) {
270        		preq = curq;
271        		continue;
272        }
273        bptr = curq->val;
274        if (bptr == NULL) {
275        		preq = curq;
276        		continue;
277        }
278        if (*bptr != '(') {
279        		preq = curq;
280        		continue;
281        }
282        if (*(bptr+StringLen(bptr)-1) != ')') {
283        		preq = curq;
284        		continue;
285        }
286  	   *(bptr+StringLen(bptr)-1) = '\0';
287       if ((ptr = StringChr(bptr, ',')) == NULL) {
288       		StringCpy(bptr, bptr+1);
289        		preq = curq;
290        		continue;
291         }
292 
293 		ErrPostEx(SEV_WARNING, ERR_QUALIFIER_MultiValue,
294 		   "Splited qualifier %s", curq->qual);
295 		buf = bptr;
296 		bptr++;
297 		curq->val = TextSave(bptr, ptr-bptr);
298 		bptr = ptr + 1;
299 		curq->next = NULL;
300 		while ((ptr = StringChr(bptr, ',')) != NULL) {
301 			tmp = GBQualNew();
302 			tmp->qual = StringSave(curq->qual);
303 			tmp->val = TextSave(bptr, ptr-bptr);
304 			curq = tie_qual(curq, tmp);
305 			bptr = ptr + 1;
306 		}
307 		tmp = GBQualNew();
308 		tmp->qual = StringSave(curq->qual);
309 		tmp->val = StringSave(bptr);
310 		curq = tie_qual(curq, tmp);
311 		tmp->next = next_q;
312 		curq = tmp;
313 		MemFree(buf);
314 
315        if (preq){
316   /*---- we have retained a qualifier, previously ----*/
317           if (preq -> next != next_q){
318    /*-- did not delete curq ----*/
319               preq = curq;
320           }
321        }else {
322     /* ---- no qualifier previously retained, is there a new head pointer? */
323           if (first_q == *gbqp){
324       /* ---- we have kept our first qualifier  */
325              preq = curq;
326           }else{
327       /*--- we deleted the head of the queue, record current first qualifier */
328              first_q = *gbqp;
329           }
330        }
331       if (*gbqp == NULL){
332           break;  /* was one, is gone */
333        }
334    }
335 
336    return retval;
337 
338 } /* SplitMultiValQual */
339 
340 
341 /*-------------------------- GBQualSemanticValid() ------------------------*/
342 /***************************************************************************
343 *  GBQualSemanticValid:
344 *  -- returns GB_ERR level, outputs error messages if
345 *      'error_msgs', set
346 *
347 *  -- routine also drop out any unknown qualifier, if
348 *      'perform_corrections' is set  10-11-93
349 *
350 ****************************************************************************/
GBQualSemanticValid(GBQualPtr PNTR gbqp,Boolean error_msgs,Boolean perform_corrections)351 NLM_EXTERN int GBQualSemanticValid(GBQualPtr PNTR gbqp,
352      Boolean error_msgs, Boolean perform_corrections)
353 {
354    Int2        val;
355    GBQualPtr   next_q, curq, preq = NULL, first_q;
356    int retval = GB_FEAT_ERR_NONE, ret;
357 
358    for (first_q = curq = *gbqp; curq != NULL; curq = next_q) {
359    		if (StringCmp(curq->qual, "gsdb_id") == 0) {
360         	next_q = curq -> next;
361    			continue;
362    		}
363         next_q = curq -> next;  /* in case deleted */
364 
365        val = GBQualNameValid(curq->qual);
366 
367        if (val == -1) {
368           if (retval < GB_FEAT_ERR_REPAIRABLE){
369              retval = GB_FEAT_ERR_REPAIRABLE;
370           }
371              if (error_msgs){
372                ErrPostEx(SEV_ERROR, ERR_QUALIFIER_UnknownSpelling,
373                   curq -> qual);
374              }
375           if (perform_corrections){
376             DeleteGBQualFromList(gbqp, curq, preq);
377           }
378        } else {
379           switch (ParFlat_GBQual_names[val].gbclass) {
380                 case Class_pos_aa:
381                      ret = CkQualPosaa(gbqp, curq, preq,
382                            error_msgs, perform_corrections);
383                      if (ret > retval){
384                         retval = ret;
385                      }
386                      break;
387                 case Class_note:
388                      ret = CkQualNote(gbqp, curq, preq,
389                            error_msgs, perform_corrections);
390                      if (ret > retval){
391                         retval = ret;
392                      }
393                      break;
394                 case Class_text:
395                      ret = CkQualText( gbqp, curq, preq, NULL,
396                          FALSE, error_msgs, perform_corrections);
397                      if (ret > retval){
398                         retval = ret;
399                      }
400                      break;
401                 case Class_bracket_int:
402                      ret = CkQualTokenType(gbqp, curq, preq, error_msgs,
403                          perform_corrections, ParFlat_BracketInt_type);
404                      if (ret > retval){
405                         retval = ret;
406                      }
407                      break;
408                 case Class_seq_aa:
409                      ret = CkQualSeqaa(gbqp, curq, preq,
410                              error_msgs, perform_corrections);
411                      if (ret > retval){
412                         retval = ret;
413                      }
414                      break;
415                 case Class_int_or:
416                      ret = CkQualMatchToken(gbqp, curq, preq, error_msgs,
417                            perform_corrections,
418                            ParFlat_IntOrString, ParFlat_TOTAL_IntOr);
419                      if (ret > retval){
420                         retval = ret;
421                      }
422                      break;
423                 case Class_site:
424                      ret = CkQualSite(gbqp, curq, preq, error_msgs,
425                         perform_corrections);
426                      if (ret > retval){
427                         retval = ret;
428                      }
429                      break;
430                 case Class_L_R_B:
431                      ret =  CkQualMatchToken(gbqp, curq, preq, error_msgs,
432                                 perform_corrections,
433                                 ParFlat_LRBString, ParFlat_TOTAL_LRB);
434                      if (ret > retval){
435                         retval = ret;
436                      }
437                      break;
438                 case Class_ecnum:
439                      ret =  CkQualEcnum(gbqp, curq, preq, error_msgs,
440                          perform_corrections);
441                      if (ret > retval){
442                         retval = ret;
443                      }
444                      break;
445                 case Class_exper:
446                      ret =  CkQualMatchToken(gbqp, curq, preq, error_msgs,
447                             perform_corrections,
448                             ParFlat_ExpString, ParFlat_TOTAL_Exp);
449                      if (ret > retval){
450                         retval = ret;
451                      }
452                      break;
453                 case Class_token:
454                      ret = CkQualTokenType(gbqp, curq, preq, error_msgs,
455                                perform_corrections, ParFlat_Stoken_type);
456                      if (ret > retval){
457                         retval = ret;
458                      }
459                      break;
460                 case Class_int:
461                      ret = CkQualTokenType(gbqp, curq, preq, error_msgs,
462                            perform_corrections, ParFlat_Integer_type);
463                      if (ret > retval){
464                         retval = ret;
465                      }
466                      break;
467                 case Class_number:
468                      ret = CkQualTokenType(gbqp, curq, preq, error_msgs,
469                            perform_corrections, ParFlat_Number_type);
470                      if (ret > retval){
471                         retval = ret;
472                      }
473                      break;
474                 case Class_rpt:
475                      ret = CkQualMatchToken(gbqp, curq, preq, error_msgs,
476                                perform_corrections,
477                                 ParFlat_RptString, ParFlat_TOTAL_Rpt);
478                      if (ret > retval){
479                         retval = ret;
480                      }
481                      break;
482                 case Class_flabel_base:
483                      ret = CkQualTokenType(gbqp, curq, preq, error_msgs,
484                         perform_corrections, ParFlat_Stoken_type);
485                      if (ret > retval){
486                         retval = ret;
487                      }
488                      break;
489                 case Class_flabel_dbname:
490                      ret = CkQualTokenType(gbqp, curq, preq, error_msgs,
491                          perform_corrections, ParFlat_Stoken_type);
492                      if (ret > retval){
493                         retval = ret;
494                      }
495                      break;
496                 case Class_none:
497                      if (curq->val != NULL && *(curq->val)) {
498                         if (error_msgs){
499                            ErrPostEx(SEV_ERROR, ERR_QUALIFIER_Xtratext,
500                              "/%s=%s",curq->qual,curq->val);
501                          }
502                          retval = GB_FEAT_ERR_REPAIRABLE;
503                          if (perform_corrections){
504                            MemFree(curq->val);
505                            curq->val = NULL;
506                          }
507                      }
508                 default:
509                      break;
510           } /* switch */
511 
512 
513        } /* check qual's value */
514        if (preq){
515   /*---- we have retained a qualifier, previously ----*/
516           if (preq -> next != next_q){
517    /*-- did not delete curq ----*/
518               preq = curq;
519           }
520        }else {
521     /* ---- no qualifier previously retained, is there a new head pointer? */
522           if (first_q == *gbqp){
523       /* ---- we have kept our first qualifier  */
524              preq = curq;
525           }else{
526       /*--- we deleted the head of the queue, record current first qualifier */
527              first_q = *gbqp;
528           }
529        }
530       if (*gbqp == NULL){
531           break;  /* was one, is gone */
532        }
533    }
534 
535    return retval;
536 
537 } /* GBQualSemanticValid */
538 
539 
540 /*------------------------------ CkQualPosSeqaa() -------------------------*/
541 /***************************************************************************
542 *  CkQualPosSeqaa:  (called by CkQaulPosaa and ChQualSeqaa)
543 *
544 *  -- format       (...aa:amino_acid)
545 *  -- example     aa:Phe)
546 *                                          -Karl 1/28/94
547 ****************************************************************************/
548 
CkQualPosSeqaa(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean error_msgs,Boolean perform_corrections,CharPtr aa,CharPtr eptr)549 NLM_EXTERN int CkQualPosSeqaa(GBQualPtr PNTR head_gbqp, GBQualPtr gbqp,
550    GBQualPtr preq,
551    Boolean error_msgs, Boolean perform_corrections, CharPtr aa, CharPtr eptr)
552 {
553    CharPtr  str;
554    int retval = GB_FEAT_ERR_NONE;
555 
556       DelTailBlank(aa);
557 
558       if (ValidAminoAcid(aa) != 255) {
559          str = eptr;
560 
561          while (*str != '\0' && (*str == ' ' || *str == ')'))
562              str++;
563 
564          if (*str == '\0') {
565             MemFree(aa);
566             return retval;  /* successful, format ok return */
567          }
568          else {
569             MemFree(aa);
570             if (error_msgs){
571               ErrPostEx(SEV_ERROR, ERR_QUALIFIER_AA,
572                 "Extra text after end /%s=%s",gbqp->qual,gbqp->val);
573              }
574              retval = GB_FEAT_ERR_DROP;
575              if (perform_corrections){
576                DeleteGBQualFromList(head_gbqp, gbqp, preq);
577              }
578 
579          }
580       }
581       else {
582             if (error_msgs){
583               ErrPostEx(SEV_ERROR, ERR_QUALIFIER_AA,
584                 "Bad aa abbreviation<%s>, /%s=%s",
585                 aa, gbqp->qual,gbqp->val);
586              }
587              retval = GB_FEAT_ERR_DROP;
588              if (perform_corrections){
589                DeleteGBQualFromList(head_gbqp, gbqp, preq);
590              }
591       }
592 
593       return retval;
594 
595 }
596 
597 
598 
599 
600 /*------------------------------ CkQualPosaa() -------------------------*/
601 /***************************************************************************
602 *  CkQualPosaa:
603 *
604 *  -- format       (pos:base_range, aa:amino_acid)
605 *  -- example      /anticodon=(pos:34..36,aa:Phe)
606 *                  /anticodon=(pos: 34..36, aa: Phe)
607 *                                                                 10-12-93
608 ****************************************************************************/
CkQualPosaa(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean error_msgs,Boolean perform_corrections)609 NLM_EXTERN int CkQualPosaa(GBQualPtr PNTR head_gbqp, GBQualPtr gbqp,
610    GBQualPtr preq,
611    Boolean error_msgs, Boolean perform_corrections)
612 {
613    CharPtr  eptr, str, aa = NULL;
614    int retval = GB_FEAT_ERR_NONE;
615 
616    str = gbqp->val;
617 
618    if (StringNICmp(str, "(pos:", 5) == 0) {
619       str += 5;
620 
621       while (*str == ' ')
622           ++str;
623 
624 /*---I expect that we maight need to allow blanks here,
625             but not now... -Karl 1/28/94 */
626       if ((eptr = StringChr(str, ',')) != NULL) {
627          while (str != eptr  && (IS_DIGIT(*str) || *str == '.'))
628              str++;
629 
630          if (str == eptr) {
631             while (*str != '\0' && (*str == ',' || *str == ' '))
632                 str++;
633 
634             if (StringNICmp(str, "aa:", 3) == 0) {
635                str += 3;
636 
637                while (*str == ' ')
638                    ++str;
639 
640                if ((eptr = StringChr(str, ')')) != NULL) {
641                   aa = TextSave(str, eptr-str);
642 
643 
644                  retval = CkQualPosSeqaa(head_gbqp,  gbqp, preq,
645                     error_msgs, perform_corrections,  aa, eptr);
646                }
647             } /* if, aa: */ else{
648                if (error_msgs){
649                 ErrPostEx(SEV_ERROR, ERR_QUALIFIER_AA,
650                    "Missing aa: /%s=%s",gbqp->qual,gbqp->val);
651                }
652                retval = GB_FEAT_ERR_DROP;
653                if (perform_corrections){
654                   DeleteGBQualFromList(head_gbqp, gbqp, preq);
655                }
656             }
657          }
658       }else{
659          if (error_msgs){
660             ErrPostEx(SEV_ERROR, ERR_QUALIFIER_SeqPosComma,
661                "Missing \',\' /%s=%s",gbqp->qual,gbqp->val);
662    /* ) match */
663          }
664          retval = GB_FEAT_ERR_DROP;
665         if (perform_corrections){
666              DeleteGBQualFromList(head_gbqp, gbqp, preq);
667          }
668       }
669    } /* if, (pos: */  else{
670       if (error_msgs){
671          ErrPostEx(SEV_ERROR, ERR_QUALIFIER_Pos,
672             "Missing (pos: /%s=%s",gbqp->qual,gbqp->val);
673 /* ) match */
674       }
675       retval = GB_FEAT_ERR_DROP;
676      if (perform_corrections){
677           DeleteGBQualFromList(head_gbqp, gbqp, preq);
678       }
679    }
680 
681       return retval;
682 
683 } /* CkQualPosaa */
684 
685 /*------------------------------ CkQualNote() --------------------------*/
686 /***************************************************************************
687 *  CkQualNote:
688 *  -- example: testfile  gbp63.seq gbp88.seq, gbp76.seq
689 *     /bound_moiety="repressor"
690 *     /note="Dinucleotide repeat, polymorphic among these rat
691       strains:LOU/N>F344/N=BUF/N=MNR/N=WBB1/N=WBB2/N=MR/N=LER/N=ACI/N=SR/Jr=
692       SHR/N=WKY/N>BN/SsN=LEW/N (the size of the allelesindicated)."
693 *     /note="guanine nucleotide-binding protein /hgml-locus_uid='LJ0088P'"
694 *     /note=" /map='6p21.3' /hgml_locus_uid='LU0011B'"
695 *
696 *  -- embedded qualifer
697 *     -- convert all double quotes to single qutoes
698 *        (this is unnecessary for the flat2asn parser program, because
699 *        it only grep first close double quote when "ParseQualifiers" routine
700 *        build GBQualPtr link list, but it would have post out message if
701 *        any data was truncated) (I add the conversion because someone may
702 *        use the routine which parsing the string different from the way I did)
703 *     -- convert the '/' characters at the start of the embedded-qualifier
704 *        token to '_'
705 *                                                                 12-20-93
706 ****************************************************************************/
CkQualNote(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean error_msgs,Boolean perform_corrections)707 NLM_EXTERN int CkQualNote(GBQualPtr PNTR head_gbqp, GBQualPtr gbqp,
708    GBQualPtr preq,
709    Boolean error_msgs, Boolean perform_corrections)
710 {
711 
712    CharPtr  str;
713    Boolean has_embedded;
714    int retval;
715 
716    retval = CkQualText( head_gbqp, gbqp, preq,
717          & has_embedded, TRUE, error_msgs,
718          perform_corrections);
719       if (has_embedded) {
720 
721          str = gbqp->val;
722          for (; *str != '\0'; str++)
723              if (*str == '\"')
724                 *str = '\'';
725          /*
726          ConvertEmbedQual(gbqp->val);
727          */
728       }
729 
730    return retval;
731 
732 } /* CkQualNote */
733 
734 /*----------------------- ConvertEmbedQual() ----------------------------*/
735 /****************************************************************************
736 *   ConvertEmbedQual:
737 *   -- convert the '/' characters at the start of the embedded-qualifier
738 *      token to '_'
739 *                                                                 12-20-93
740 *****************************************************************************/
ConvertEmbedQual(CharPtr value)741 NLM_EXTERN void ConvertEmbedQual(CharPtr value)
742 {
743    CharPtr  bptr, ptr, qualname, slash;
744    Int2     val;
745 
746    if (value != NULL) {
747 
748       for (bptr = value; *bptr != '\0';) {
749 
750           for (;*bptr != '/' && *bptr != '\0'; bptr++)
751               continue;
752 
753           if (*bptr == '/') {
754              for (slash = bptr, ++bptr, ptr = bptr; *bptr != '=' && *bptr != ' '
755                                                    && *bptr != '\0'; bptr++)
756                  continue;
757 
758              qualname = TextSave(ptr, bptr-ptr);
759 
760              val = GBQualNameValid(qualname);
761              if (val >= 0)
762                 *slash = '_';
763 
764              MemFree(qualname);
765           }
766 
767       } /* for */
768    }
769 
770 } /* ConvertEmbedQual */
771 
772 /*----------------------- ScanEmbedQual() -----------------------------*/
773 /****************************************************************************
774 *  ScanEmbedQual:
775 *  -- retun NULL if no embedded qualifiers found; otherwise, return the
776 *     embedded qualifier.
777 *  -- scan embedded valid qualifier
778 *                                                                  6-29-93
779 *****************************************************************************/
ScanEmbedQual(CharPtr value)780 NLM_EXTERN CharPtr ScanEmbedQual(CharPtr value)
781 {
782    CharPtr  bptr, ptr, qual;
783    Int2     val;
784 
785    if (value != NULL) {
786       for (bptr = value; *bptr != '\0';) {
787           for (;*bptr != '/' && *bptr != '\0'; bptr++)
788               continue;
789 
790           if (*bptr == '/') {
791              for (++bptr, ptr = bptr; *bptr != '=' && *bptr != ' '
792                                                    && *bptr != '\0'; bptr++)
793                  continue;
794 
795              qual = TextSave(ptr, bptr-ptr);
796 
797              val = GBQualNameValid(qual);
798 
799              if (val >= 0)
800                 return (qual);
801 
802              MemFree(qual);
803           }
804       } /* for */
805    }
806 
807    return (NULL);
808 
809 } /* ScanEmbedQual */
810 
811 /*------------------------------ CkQualText() -------------------------*/
812 /***************************************************************************
813 *  CkQualText:
814 *  -- return error severity
815 *  -- also check if embedded qualifier
816 *  -- format      "text"
817 *  if called from /note, ="" will cause qualifier to be dropped.
818 *  all others no error, all other, if no qualifier, will add "" value
819 ****************************************************************************/
CkQualText(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean PNTR has_embedded,Boolean from_note,Boolean error_msgs,Boolean perform_corrections)820 NLM_EXTERN int CkQualText (GBQualPtr PNTR head_gbqp,  GBQualPtr gbqp,
821    GBQualPtr preq,
822    Boolean PNTR has_embedded, Boolean from_note, Boolean error_msgs,
823    Boolean perform_corrections)
824 {
825    CharPtr  value=NULL, bptr, eptr, str;
826    int retval = GB_FEAT_ERR_NONE;
827 
828    if (has_embedded != NULL){
829      *has_embedded = FALSE;
830    }
831    if (gbqp->val == NULL) {
832        if (from_note){
833                if (error_msgs){
834                 ErrPostEx(SEV_ERROR, ERR_QUALIFIER_EmptyNote,
835                    "/note with no text ");
836                }
837                retval = GB_FEAT_ERR_DROP;
838                if (perform_corrections){
839                   DeleteGBQualFromList(head_gbqp, gbqp, preq);
840                }
841                return retval;
842        } else {
843            retval = GB_FEAT_ERR_SILENT;
844            if (perform_corrections){
845                gbqp ->val = StringSave("\"\"");  /* yup, a "" string is legal */
846            } else {
847            		return retval;
848            }
849        }
850    }
851    str = gbqp->val;
852    while (*str != '\0' && (*str == ' ' || *str == '\"')){
853     /* open double quote */
854        str++;
855        if (*(str-1) == '\"'){
856          break;  /* so does not continue through a "" string */
857        }
858     }
859    /* find first close double quote */
860    for (bptr = str; *str != '\0' && *str != '\"'; str++)
861        continue;
862    eptr = str;
863 
864    while (*str != '\0' && (*str == ' ' || *str == '\"'))
865        str++;
866 
867    if (*str != '\0'){
868 /*   extra stuff is already rm in ParseQualifiers(). Tatiana*/
869 /* extra stuff, if perform corrections, remove it */
870 /* ERROR  here  sets retval*/
871    }
872 
873       value = TextSave(bptr, eptr-bptr);
874 /* Some check must be done for illegal characters in gbpq->val
875       for (s = value; *s != '\0'; s++) {
876       	if (!IS_WHITESP(*s) && !IS_ALPHANUM(*s) && *s != '\"') {
877             if (error_msgs){
878                 ErrPostEx(SEV_WARNING, ERR_QUALIFIER_IllegalCharacter,
879                    "illegal char [%c] used in qualifier %s", s, gbqp ->qual);
880              }
881              return (retval > GB_FEAT_ERR_REPAIRABLE) ? retval :
882             								GB_FEAT_ERR_REPAIRABLE;
883       	}
884       }
885 */
886  /* only finds first embedded qualifier */
887       if (value != NULL && ((bptr = ScanEmbedQual(value)) != NULL)) {
888 
889          if (has_embedded != NULL) {
890             *has_embedded = TRUE;
891          }
892          MemFree(value);
893          MemFree(bptr);
894          if (from_note){
895             if (error_msgs){
896                 ErrPostEx(SEV_WARNING, ERR_QUALIFIER_NoteEmbeddedQual,
897                    "/note with embedded qualifiers %s", gbqp ->val);
898             }
899             return (retval > GB_FEAT_ERR_REPAIRABLE) ? retval :
900             								GB_FEAT_ERR_REPAIRABLE;
901          }else{
902             if (error_msgs){
903                 ErrPostEx(SEV_WARNING, ERR_QUALIFIER_EmbeddedQual,
904                    "/%s with embedded qualifiers %s",
905                    gbqp -> qual, gbqp ->val);
906             }
907             return retval;
908          }
909 
910 /*  This needs to be discussed some!, not sure -Karl 1/28/94 */
911       }
912 
913       MemFree(value);
914 
915       return retval;
916 } /* CkQualText */
917 
918 /*------------------------- CkQualSeqaa() --------------------------*/
919 /***************************************************************************
920 *  CkQualSeqaa:
921 *  -- format       (seq:"codon-sequence", aa:amino_acid)
922 *  -- example      /codon=(seq:"ttt",aa:Leu)
923 *                  /codon=(seq: "ttt", aa: Leu )
924 *                                                                  6-29-93
925 ***************************************************************************/
CkQualSeqaa(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean error_msgs,Boolean perform_corrections)926 NLM_EXTERN int CkQualSeqaa (GBQualPtr PNTR head_gbqp, GBQualPtr gbqp,
927    GBQualPtr preq,
928    Boolean error_msgs, Boolean perform_corrections)
929 {
930    CharPtr  eptr, str, aa;
931    int retval = GB_FEAT_ERR_NONE;
932 
933    str = gbqp->val;
934 
935    if (StringNICmp(str, "(seq:", 5) == 0) {
936       str += 5;
937 
938       while (*str == ' ')
939           ++str;
940 
941       if ((eptr = StringChr(str, ',')) != NULL) {
942          while (str != eptr)
943              str++;
944 
945          while (*str != '\0' && (*str == ',' || *str == ' '))
946              str++;
947 
948          if (StringNICmp(str, "aa:", 3) == 0) {
949             str += 3;
950 
951             while (*str == ' ')
952                 ++str;
953 
954             if ((eptr = StringChr(str, ')')) != NULL) {
955                aa = TextSave(str, eptr-str);
956 
957                  retval = CkQualPosSeqaa(head_gbqp,  gbqp, preq,
958                     error_msgs, perform_corrections,  aa, eptr);
959 
960              }
961            } /* if, aa: */ else{
962             if (error_msgs){
963                ErrPostEx(SEV_ERROR, ERR_QUALIFIER_AA,
964                  "Missing aa: /%s=%s",gbqp->qual,gbqp->val);
965              }
966              retval = GB_FEAT_ERR_DROP;
967              if (perform_corrections){
968                 DeleteGBQualFromList(head_gbqp, gbqp, preq);
969              }
970 
971          }
972       }else{
973          if (error_msgs){
974             ErrPostEx(SEV_ERROR, ERR_QUALIFIER_SeqPosComma,
975                "Missing \',\' /%s=%s",gbqp->qual,gbqp->val);
976    /* ) match */
977          }
978          retval = GB_FEAT_ERR_DROP;
979         if (perform_corrections){
980              DeleteGBQualFromList(head_gbqp, gbqp, preq);
981          }
982       }
983    } /* if, (seq: */ else {
984 
985 
986         if (error_msgs){
987            ErrPostEx(SEV_ERROR, ERR_QUALIFIER_Seq,
988               "Missing (seq: /%s=%s",gbqp->qual,gbqp->val);
989 /* ) match */
990         }
991         retval = GB_FEAT_ERR_DROP;
992        if (perform_corrections){
993             DeleteGBQualFromList(head_gbqp, gbqp, preq);
994         }
995       }
996 
997       return retval;
998 
999 } /* CkQualSeqaa */
1000 
1001 /*------------------------- () -------------------------*/
1002 /*****************************************************************************
1003 *  CkQualMatchToken:
1004 *                                                                6-29-93
1005 *****************************************************************************/
CkQualMatchToken(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean error_msgs,Boolean perform_corrections,CharPtr array_string[],Int2 totalstr)1006 NLM_EXTERN int CkQualMatchToken
1007 (GBQualPtr PNTR head_gbqp, GBQualPtr gbqp,
1008    GBQualPtr preq,
1009    Boolean error_msgs, Boolean perform_corrections, CharPtr array_string[],
1010    Int2 totalstr)
1011 {
1012    CharPtr  msg=NULL, bptr, eptr, str;
1013    int retval = GB_FEAT_ERR_NONE;
1014 
1015 	if(gbqp->val == NULL) {
1016         if (error_msgs){
1017            ErrPostEx(SEV_ERROR, ERR_QUALIFIER_InvalidDataFormat,
1018              "NULL value for (%s)", gbqp->qual);
1019          }
1020          retval = GB_FEAT_ERR_DROP;
1021          if (perform_corrections){
1022             DeleteGBQualFromList(head_gbqp, gbqp, preq);
1023          }
1024    		return retval;
1025 	}
1026    str = gbqp->val;
1027 
1028    for (bptr = str; *str != '\0' && *str != ' '; str++)
1029        continue;
1030    eptr = str;
1031 
1032    while (*str != '\0' && *str == ' ')
1033        str++;
1034 
1035    if (*str == '\0') {
1036       msg = TextSave(bptr, eptr-bptr);
1037 
1038       if (MatchArrayStringIcase(array_string, totalstr, msg) == -1) {
1039         if (error_msgs){
1040            ErrPostEx(SEV_ERROR, ERR_QUALIFIER_InvalidDataFormat,
1041              "Value not in list of legal values /%s=%s",
1042             gbqp->qual,gbqp->val);
1043          }
1044          retval = GB_FEAT_ERR_DROP;
1045          if (perform_corrections){
1046             DeleteGBQualFromList(head_gbqp, gbqp, preq);
1047          }
1048   	  }
1049    } else {
1050          if (error_msgs){
1051            ErrPostEx(SEV_ERROR, ERR_QUALIFIER_Too_many_tokens,
1052              "/%s=%s", gbqp->qual,gbqp->val);
1053          }
1054          retval = GB_FEAT_ERR_DROP;
1055          if (perform_corrections){
1056             DeleteGBQualFromList(head_gbqp, gbqp, preq);
1057          }
1058    }
1059 
1060    MemFree(msg);
1061    return retval;
1062 
1063 } /* CkQualMatchToken */
1064 
1065 /*------------------------- CkQualEcnum() ---------------------------*/
1066 /***************************************************************************
1067 *   CkQualEcnum:
1068 *   -- Ec_num has text format,
1069 *      but the text only allow digits, period, and hyphen (-)
1070 *                                                                12-10-93
1071 ****************************************************************************/
CkQualEcnum(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean error_msgs,Boolean perform_corrections)1072 NLM_EXTERN int CkQualEcnum( GBQualPtr PNTR head_gbqp, GBQualPtr gbqp,
1073    GBQualPtr preq,
1074    Boolean error_msgs, Boolean perform_corrections )
1075 {
1076    CharPtr  str;
1077    int retval = GB_FEAT_ERR_NONE;
1078 
1079 
1080    retval = CkQualText(head_gbqp, gbqp, preq, NULL, FALSE,
1081         error_msgs, perform_corrections);
1082 		if (retval == GB_FEAT_ERR_NONE){
1083 
1084       str = gbqp->val;
1085                                                        /* open double quote */
1086       while (*str != '\0' && (*str == ' ' || *str == '\"'))
1087           str++;
1088 
1089       for (; *str != '\0' && *str != '\"'; str++)
1090           if (!IS_DIGIT(*str) && *str != '.' && *str != '-' && *str != 'n') {
1091             if (error_msgs){
1092                ErrPostEx(SEV_ERROR, ERR_QUALIFIER_BadECnum,
1093                  "At <%c>(%d) /%s=%s",
1094                  *str, (int) *str, gbqp->qual,gbqp->val);
1095              }
1096              retval = GB_FEAT_ERR_DROP;
1097              if (perform_corrections){
1098                 DeleteGBQualFromList(head_gbqp, gbqp, preq);
1099              }
1100            break;
1101       }
1102    }
1103 
1104    return retval;
1105 
1106 } /* CkQualEcnum */
1107 
1108 /*------------------------- CkQualSite() --------------------------*/
1109 /***************************************************************************
1110 *  CkQualSite:
1111 *  -- format       (5'site:boolean, 3'site:boolean)
1112 *  -- example      /cons_splice=(5'site:YES, 3'site:NO)
1113 *                                                                  6-29-93
1114 ***************************************************************************/
CkQualSite(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean error_msgs,Boolean perform_corrections)1115 NLM_EXTERN int CkQualSite ( GBQualPtr PNTR head_gbqp, GBQualPtr gbqp,
1116    GBQualPtr preq,
1117    Boolean error_msgs, Boolean perform_corrections )
1118 {
1119    int retval = GB_FEAT_ERR_NONE;
1120    CharPtr  bptr, str;
1121    Boolean ok=FALSE;
1122    CharPtr yes_or_no = "not \'YES\', \'NO\' or \'ABSENT\'";
1123 
1124    str = gbqp->val;
1125    if (StringNICmp(str, "(5'site:", 8) == 0) {
1126       bptr = str;
1127       str += 8;
1128 
1129       if (StringNICmp(str, "YES", 3) == 0 || StringNICmp(str, "NO", 2) == 0 ||
1130           StringNICmp(str, "ABSENT", 6) == 0) {
1131 
1132          if (StringNICmp(str, "YES", 3) == 0)
1133             str += 3;
1134          else if (StringNICmp(str, "NO", 2) == 0)
1135             str += 2;
1136          else
1137             str += 6;
1138 
1139          for (; *str == ' '; str++);
1140          for (; *str == ','; str++);
1141          for (; *str == ' '; str++);
1142 
1143 
1144          if (StringNICmp(str, "3'site:", 7) == 0) {
1145             str += 7;
1146 
1147             if (StringNICmp(str, "YES", 3) == 0 ||
1148                 StringNICmp(str, "NO", 2) == 0 ||
1149                 StringNICmp(str, "ABSENT", 6) == 0) {
1150                if (StringNICmp(str, "YES", 3) == 0)
1151                   str += 3;
1152                else if (StringNICmp(str, "NO", 2) == 0)
1153                   str += 2;
1154                else
1155                   str += 6;
1156 
1157                if (*str == ')') {
1158 
1159                   while (*str != '\0' && (*str == ' ' || *str == ')'))
1160                       str++;
1161 
1162                   if (*str == '\0')
1163                     ok=TRUE;
1164                   else {
1165                      bptr = "extra characters";
1166                   }
1167 
1168                } /* if, ")" */ else{
1169                }
1170             } /* if, yes or no */ else{
1171                bptr = yes_or_no;
1172             }
1173          } /* if, 3'site */ else{
1174             bptr="3\' site";
1175          }
1176       } /* if, yes or no */else {
1177          bptr = yes_or_no;
1178       }
1179    } /* if, 5'site */else {
1180      bptr="5\' site";
1181    }
1182 
1183   if (! ok){
1184       if (error_msgs){
1185          ErrPostEx(SEV_ERROR, ERR_QUALIFIER_Cons_splice,
1186            "%s /%s=%s", bptr, gbqp->qual,gbqp->val);
1187        }
1188        retval = GB_FEAT_ERR_DROP;
1189        if (perform_corrections){
1190           DeleteGBQualFromList(head_gbqp, gbqp, preq);
1191        }
1192   }
1193   return retval;
1194 
1195 } /* CkQualSite */
1196 
1197 /*------------------------- CkQualTokenType() --------------------------*/
1198 /***************************************************************************
1199 *  CkQualTokenType:
1200 *  -- format   single token
1201 *  -- example  ParFlat_Stoken_type        /label=Albl_exonl  /mod_base=m5c
1202 *              ParFlat_BracketInt_type    /citation=[3] or /citation= ([1],[3])
1203 *              ParFlat_Integer_type           /transl_table=4
1204 *				ParFlat_Number_type			/number=4b
1205 *  -- not implemented yet, treat as ParFlat_Stoken_type:
1206 *     -- feature_label or base_range
1207 *                 /rpt_unit=Alu_rpt1   /rpt_unit=202..245
1208 *     -- Accession-number:feature-name or
1209 *                            Database_name:Acc_number:feature_label
1210 *        /usedin=X10087:proteinx
1211 *                                                                 10-12-93
1212 ***************************************************************************/
CkQualTokenType(GBQualPtr PNTR head_gbqp,GBQualPtr gbqp,GBQualPtr preq,Boolean error_msgs,Boolean perform_corrections,Uint1 type)1213 NLM_EXTERN int CkQualTokenType (GBQualPtr PNTR head_gbqp,  GBQualPtr gbqp,
1214    GBQualPtr preq,
1215    Boolean error_msgs, Boolean perform_corrections, Uint1 type)
1216 {
1217    CharPtr  token = NULL, bptr, eptr, str;
1218    Boolean token_there = FALSE;
1219    int retval = GB_FEAT_ERR_NONE;
1220 
1221    str = gbqp->val;
1222 
1223    if (str != NULL)
1224     if (*str != '\0'){
1225 			token_there = TRUE;
1226     }
1227    if (! token_there) {
1228      if (error_msgs){
1229         ErrPostEx(SEV_ERROR, ERR_QUALIFIER_InvalidDataFormat,
1230           "Missing value /%s=...",gbqp->qual);
1231       }
1232       retval = GB_FEAT_ERR_DROP;
1233       if (perform_corrections){
1234          DeleteGBQualFromList(head_gbqp, gbqp, preq);
1235       }
1236    }else{
1237 /*  token there */
1238    for (bptr = str; *str != '\0' && *str != ' '; str++)
1239        continue;
1240    eptr = str;
1241 
1242    while (*str != '\0' && *str == ' ')
1243        str++;
1244 
1245    if (*str == '\0') {
1246 /*------single token found ----*/
1247       token = TextSave(bptr, eptr-bptr);
1248 
1249       bptr = token;
1250 
1251       switch (type) {
1252          case ParFlat_BracketInt_type:
1253 /*-------this can be made to be much more rigorous --Karl ---*/
1254 			  str = CkBracketType(token);
1255                break;
1256          case ParFlat_Integer_type:
1257               for (str = token; *str != '\0' && IS_DIGIT(*str); str++)
1258               		continue;
1259               if (*str == '\0') {
1260               	str = NULL;
1261               }
1262               break;
1263          case ParFlat_Stoken_type:
1264          		str = CkLabelType(token);
1265                break;
1266          case ParFlat_Number_type:
1267          		str = CkNumberType(token);
1268                break;
1269         default:
1270               str = NULL;
1271               break;
1272       }
1273 
1274       if (str != NULL) {
1275          switch (type) {
1276             case ParFlat_BracketInt_type:
1277                          bptr = "Invalid [integer] format";
1278                          break;
1279             case ParFlat_Integer_type:
1280                          bptr = "Not an integer number";
1281                          break;
1282             case ParFlat_Stoken_type:
1283                          bptr = "Invalid format";
1284                          break;
1285 /*-- logically can not happen, as coded now -Karl  1/31/94 --*/
1286             default:     bptr = "Bad qualifier value";
1287                          break;
1288          }
1289         if (error_msgs){
1290            ErrPostEx(SEV_ERROR, ERR_QUALIFIER_InvalidDataFormat,
1291              "%s=%s, at %s", gbqp->qual,gbqp->val, str);
1292          }
1293          retval = GB_FEAT_ERR_DROP;
1294          if (perform_corrections){
1295             DeleteGBQualFromList(head_gbqp, gbqp, preq);
1296          }
1297       }
1298    } else{
1299 /*-- more than a single token found ---*/
1300      if (error_msgs){
1301         ErrPostEx(SEV_ERROR, ERR_QUALIFIER_Xtratext,
1302           "extra text found /%s=%s, at %s",gbqp->qual,gbqp->val, str);
1303       }
1304       retval = GB_FEAT_ERR_DROP;
1305       if (perform_corrections){
1306          DeleteGBQualFromList(head_gbqp, gbqp, preq);
1307       }
1308    }
1309  } /* token there */
1310 
1311       MemFree(token);
1312       return retval;
1313 
1314 } /* CkQualTokenType */
1315 
1316 /*--------------------------- GBFeatErrSpec() ------------------*/
1317 /***************************************************************************
1318 *   GBFeatErrSpec:
1319 *   -- return a err_specific string by a given index
1320 *   -- GenBank feature table semantic checking is return a link list of
1321 *      ValNodePtr, where
1322 *      vnp->choice points to "err_specific", start from 1
1323 *      vnp->data.prtvalue points to "err_msg" string, a short message to
1324 *      describe the "err_specific"
1325 *                                                                10-14-93
1326 ****************************************************************************/
GBFeatErrSpec(Uint1 indx)1327 NLM_EXTERN CharPtr GBFeatErrSpec(Uint1 indx)
1328 {
1329    switch (indx) {
1330      case  1: return("MissMandQual");
1331      case  2: return("QualNotFound");
1332      case  3: return("UnkQual");
1333      case  4: return("BadQualValPosaa");
1334      case  5: return("BadQualValText");
1335      case  6: return("BadQualValBracketInt");
1336      case  7: return("BadQualValSeqaa");
1337      case  8: return("BadQualValNot1or2or3");
1338      case  9: return("BadQualValSite");
1339      case 10: return("BadQualValNotLorRorB");
1340      case 11: return("BadQualValBadEcnum");
1341      case 12: return("BadQualValExporNotexp");
1342      case 13: return("BadQualValFeatLabel");
1343      case 14: return("BadQualValNotInteger");
1344      case 15: return("BadQualValNotInStringList");
1345      case 16: return("BadQualValFlabelBase");
1346      case 17: return("BadQualValFlabelDbname");
1347      case 18: return("NoValueQualHasVal");
1348      case 19: return("EmbeddedQual");
1349      case 20: return("EmbeddedQualInNote");
1350      default: return("AddMoreInGBFeatErrSpec");
1351    }
1352 
1353 } /* GBFeatErrSpec */
1354 
1355 /*------------------------ DeleteGBQualFromList() --------------------*/
1356 /*****************************************************************************
1357 *   DeleteGBQualFromList:
1358 *     all deletes of GBQuals done here
1359 *                                                          -Karl 1/28/94
1360 ******************************************************************************/
DeleteGBQualFromList(GBQualPtr PNTR gbqp,GBQualPtr curq,GBQualPtr preq)1361 NLM_EXTERN void DeleteGBQualFromList (GBQualPtr PNTR gbqp, GBQualPtr curq,
1362      GBQualPtr preq)
1363 {
1364     GBQualPtr   temp;
1365 
1366           if (preq == NULL)
1367              *gbqp = curq->next;  /* will change first_q in calling function */
1368           else
1369              preq->next = curq->next;  /* will cause next_q == preq -> next */
1370 
1371           temp = curq;
1372           temp->next = NULL;
1373           GBQualFree(temp);
1374 }
1375 
1376 /*------------------------ CkBracketType() --------------------*/
1377 /*****************************************************************************
1378 *   CkBracketType:
1379 *	checks /citation=([1],[3])
1380 *     May be we should check for only single value here like
1381 *	/citation=[digit]
1382 *                                                          -Tatiana 1/28/95
1383 ******************************************************************************/
CkBracketType(CharPtr str)1384 NLM_EXTERN CharPtr CkBracketType(CharPtr str)
1385 {
1386 	if (str == NULL)
1387 		return "NULL value";
1388 	if (*str == '[') {
1389 		str++;
1390 		if (!IS_DIGIT(*str)) {
1391 			return str;
1392 		} else {
1393 			while (IS_DIGIT(*str)) {
1394 				str++;
1395 			}
1396 			if (*str != ']') {
1397 				return str;
1398 			}
1399 			str++;
1400 			if (*str != '\0') {
1401 				return str;
1402 			}
1403 			return NULL;
1404 		}
1405 	} else {
1406 		return str;
1407 	}
1408 }
1409 
1410 /*------------------------ CkNumberType() --------------------*/
1411 /*****************************************************************************
1412 *   CkNumberType:
1413 *	checks /number=single_token  - numbers and letters
1414 *	/number=4 or /number=6b
1415 *                                                          -Tatiana 2/1/00
1416 ******************************************************************************/
CkNumberType(CharPtr str)1417 NLM_EXTERN CharPtr CkNumberType(CharPtr str)
1418 {
1419 		for (;  *str != '\0' && !IS_ALPHANUM(*str); str++)
1420 			continue;
1421 		if (*str != '\0') {
1422 			return NULL;
1423 		}
1424 		return str;
1425 }
1426 
1427 /*------------------------ CkLabelType() --------------------*/
1428 /*****************************************************************************
1429 *   CkLabelType:
1430 *	checks /label=,feature_label> or /label=<base_range>
1431 *                                                          -Tatiana 1/28/95
1432 ******************************************************************************/
CkLabelType(CharPtr str)1433 NLM_EXTERN CharPtr CkLabelType(CharPtr str)
1434 {
1435 	Boolean range = TRUE, label = TRUE;
1436 	CharPtr		bptr;
1437 
1438 	if (IS_DIGIT(*str)) {
1439 		for (; IS_DIGIT(*str); str++)
1440 			continue;
1441 		if (*str == '.' && *(str+1) == '.') {
1442 			str += 2;
1443 			if (!IS_DIGIT(*str)) {
1444 				range = FALSE;
1445 			} else {
1446 				while (IS_DIGIT(*str)) {
1447 					str++;
1448 				}
1449 			}
1450 			if (*str != '\0') {
1451 				range = FALSE;
1452 			}
1453 		} else {
1454 			range = FALSE;
1455 		}
1456 
1457 	}
1458 	if (!range) {
1459 		bptr = str;
1460 		for (;  *str != '\0' && !IS_ALPHA(*str); str++)
1461 			continue;
1462 		if (*str == '\0') {
1463 			label = FALSE;    /* must be at least one letter */
1464 		}
1465 		for (str = bptr; *str != '\0' && IS_ALPHA(*str) || IS_DIGIT(*str)
1466 			|| *str == '-' || *str == '_' || *str == '\'' || *str == '*';
1467 			str++)
1468 			continue;
1469 		if (*str != '\0') {
1470 			label = FALSE;
1471 		}
1472 	}
1473 	if (range || label) {
1474 		return NULL;
1475 	} else {
1476 		return str;
1477 	}
1478 }
1479 
1480 /*--------------------------- tie_qual() ---------------------------*/
1481 /****************************************************************************
1482 *  tie_qual:
1483 *  -- ties next ValNode to the end of the chain
1484 *                                                                    08-4-93
1485 ****************************************************************************/
tie_qual(GBQualPtr head,GBQualPtr next)1486 NLM_EXTERN GBQualPtr tie_qual(GBQualPtr head, GBQualPtr next)
1487 {
1488 	GBQualPtr v;
1489 
1490 	if (head == NULL) {
1491 		return next;
1492 	}
1493 	for (v = head; v->next != NULL; v = v->next) {
1494 		v = v;
1495 	}
1496 	v->next = next;
1497 	return head;
1498 }
1499