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