~ubuntu-branches/ubuntu/saucy/ncbi-tools6/saucy-proposed

« back to all changes in this revision

Viewing changes to api/valid.c

Tags: upstream-6.1.20080302
ImportĀ upstreamĀ versionĀ 6.1.20080302

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
*   
30
30
* Version Creation Date: 1/1/94
31
31
*
32
 
* $Revision: 6.970 $
 
32
* $Revision: 6.1032 $
33
33
*
34
34
* File Description:  Sequence editing utilities
35
35
*
101
101
static void     CdConflictCheck (ValidStructPtr vsp, SeqFeatPtr sfp);
102
102
static void     SpliceCheckEx (ValidStructPtr vsp, SeqFeatPtr sfp, Boolean checkAll);
103
103
static void     CdsProductIdCheck (ValidStructPtr vsp, SeqFeatPtr sfp);
104
 
static void     ValidateBioSource (ValidStructPtr vsp, GatherContextPtr gcp, BioSourcePtr biop, SeqFeatPtr sfp);
 
104
static void     ValidateBioSource (ValidStructPtr vsp, GatherContextPtr gcp, BioSourcePtr biop, SeqFeatPtr sfp, ValNodePtr sdp);
105
105
static void     ValidatePubdesc (ValidStructPtr vsp, GatherContextPtr gcp, PubdescPtr pdp);
106
106
static void     LookForMultiplePubs (ValidStructPtr vsp, GatherContextPtr gcp, SeqDescrPtr sdp);
107
107
static void     ValidateSfpCit (ValidStructPtr vsp, GatherContextPtr gcp, SeqFeatPtr sfp);
573
573
  "LatLonRange",
574
574
  "LatLonValue",
575
575
  "LatLonCountry",
576
 
  "LatLonState"
 
576
  "LatLonState",
 
577
  "BadSpecificHost",
 
578
  "RefGeneTrackingIllegalStatus"
577
579
};
578
580
 
579
581
static CharPtr err3Label [] = {
760
762
  "BadAuthorSuffix",
761
763
  "BadAnticodonAA",
762
764
  "BadAnticodonCodon",
763
 
  "BadAnticodonStrand"
 
765
  "BadAnticodonStrand",
 
766
  "UndesiredGeneSynonym",
 
767
  "UndesiredProteinName",
 
768
  "FeatureBeginsOrEndsInGap",
 
769
  "GeneOntologyTermMissingGOID"
764
770
};
765
771
 
766
772
static CharPtr err6Label [] = {
1471
1477
        if (sfp != NULL) {
1472
1478
          if (sfp->data.choice == SEQFEAT_BIOSRC) {
1473
1479
            biop = (BioSourcePtr) sfp->data.value.ptrvalue;
1474
 
            ValidateBioSource (vsp, gcp, biop, sfp);
 
1480
            ValidateBioSource (vsp, gcp, biop, sfp, NULL);
1475
1481
          }
1476
1482
          if (sfp->data.choice == SEQFEAT_PUB) {
1477
1483
            pdp = (PubdescPtr) sfp->data.value.ptrvalue;
1545
1551
      if (sdp != NULL) {
1546
1552
        if (sdp->choice == Seq_descr_source) {
1547
1553
          biop = (BioSourcePtr) sdp->data.ptrvalue;
1548
 
          ValidateBioSource (vsp, gcp, biop, NULL);
 
1554
          ValidateBioSource (vsp, gcp, biop, NULL, sdp);
1549
1555
        }
1550
1556
        if (sdp->choice == Seq_descr_pub) {
1551
1557
          pdp = (PubdescPtr) sdp->data.ptrvalue;
2256
2262
  ValNodePtr      tailid;
2257
2263
} VsicData, PNTR VsicDataPtr;
2258
2264
 
 
2265
static Boolean IsNCBIFileID (SeqIdPtr sip)
 
2266
{
 
2267
  DbtagPtr dbt;
 
2268
 
 
2269
  if (sip == NULL || sip->choice != SEQID_GENERAL) return FALSE;
 
2270
  dbt = (DbtagPtr) sip->data.ptrvalue;
 
2271
  if (dbt == NULL) return FALSE;
 
2272
  if (StringCmp (dbt->db, "NCBIFILE") == 0) {
 
2273
    return TRUE;
 
2274
  } else {
 
2275
    return FALSE;
 
2276
  }
 
2277
}
 
2278
 
 
2279
 
2259
2280
static void CaptureTextSeqIDs (BioseqPtr bsp, Pointer userdata)
2260
2281
 
2261
2282
{
2269
2290
 
2270
2291
  for (sip = bsp->id; sip != NULL; sip = sip->next) {
2271
2292
    if (sip->choice == SEQID_GI || sip->choice == SEQID_GIBBSQ || sip->choice == SEQID_GIBBMT) continue;
 
2293
    if (IsNCBIFileID (sip)) continue;
2272
2294
    SeqIdWrite (sip, buf, PRINTID_FASTA_SHORT, sizeof (buf) - 1);
2273
2295
    vnp = ValNodeCopyStr (&(vdp->tailid), 0, buf);
2274
2296
    if (vdp->headid == NULL) {
2593
2615
  Boolean     accounted_for;
2594
2616
  Boolean     products_unique;
2595
2617
  Boolean     featid_matched;
 
2618
  Boolean     feat_touches_gap;
2596
2619
  SeqFeatPtr  nearbygene;
2597
2620
  SeqFeatPtr  nearbycds;
2598
2621
  SeqFeatPtr  nearbymrna;
3575
3598
  return TRUE;
3576
3599
}
3577
3600
 
 
3601
static Boolean CheckForInconsistentMolInfos (SeqEntryPtr sep, ValidStructPtr vsp, MolInfoPtr PNTR mipp, BioseqSetPtr top)
 
3602
 
 
3603
{
 
3604
  BioseqPtr          bsp;
 
3605
  BioseqSetPtr       bssp;
 
3606
  SeqMgrDescContext  dcontext;
 
3607
  Uint2              entityID = 0, oldEntityID;
 
3608
  MolInfoPtr         firstmip;
 
3609
  GatherContextPtr   gcp;
 
3610
  Uint4              itemID = 0, oldItemID;
 
3611
  Uint2              itemtype = 0, oldItemtype;
 
3612
  MolInfoPtr         mip;
 
3613
  ValNodePtr         sdp;
 
3614
  SeqEntryPtr        tmp;
 
3615
 
 
3616
  if (sep == NULL || vsp == NULL || mipp == NULL)
 
3617
    return FALSE;
 
3618
  gcp = vsp->gcp;
 
3619
 
 
3620
  if (IS_Bioseq_set (sep)) {
 
3621
    bssp = (BioseqSetPtr) sep->data.ptrvalue;
 
3622
    if (bssp == NULL)
 
3623
      return FALSE;
 
3624
    for (tmp = bssp->seq_set; tmp != NULL; tmp = tmp->next) {
 
3625
      if (CheckForInconsistentMolInfos (tmp, vsp, mipp, top))
 
3626
        return TRUE;
 
3627
    }
 
3628
    return FALSE;
 
3629
  }
 
3630
 
 
3631
  if (!IS_Bioseq (sep))
 
3632
    return FALSE;
 
3633
  bsp = (BioseqPtr) sep->data.ptrvalue;
 
3634
  if (bsp == NULL)
 
3635
    return FALSE;
 
3636
 
 
3637
  sdp = SeqMgrGetNextDescriptor (bsp, NULL, Seq_descr_molinfo, &dcontext);
 
3638
  if (sdp == NULL) return FALSE;
 
3639
  mip = (MolInfoPtr) sdp->data.ptrvalue;
 
3640
  if (mip == NULL || mip->biomol == MOLECULE_TYPE_PEPTIDE) return FALSE;
 
3641
 
 
3642
  firstmip = *mipp;
 
3643
  if (firstmip == NULL) {
 
3644
    *mipp = mip;
 
3645
    return FALSE;
 
3646
  }
 
3647
 
 
3648
  if (mip->biomol == firstmip->biomol) return FALSE;
 
3649
 
 
3650
  oldEntityID = gcp->entityID;
 
3651
  oldItemID = gcp->itemID;
 
3652
  oldItemtype = gcp->thistype;
 
3653
 
 
3654
  gcp->entityID = entityID;
 
3655
  gcp->itemID = itemID;
 
3656
  gcp->thistype = itemtype;
 
3657
 
 
3658
  if (top != NULL) {
 
3659
    gcp->entityID = top->idx.entityID;
 
3660
    gcp->itemID = top->idx.itemID;
 
3661
    gcp->thistype = OBJ_BIOSEQSET;
 
3662
  }
 
3663
 
 
3664
  /* only report the first one that doesn't match */
 
3665
 
 
3666
  ValidErr (vsp, SEV_WARNING, ERR_SEQ_PKG_InconsistentMolInfoBiomols, "Pop/phy/mut/eco set contains inconsistent MolInfo biomols");
 
3667
 
 
3668
  gcp->entityID = oldEntityID;
 
3669
  gcp->itemID = oldItemID;
 
3670
  gcp->thistype = oldItemtype;
 
3671
 
 
3672
  return TRUE;
 
3673
}
 
3674
 
 
3675
static void LookForMolInfoInconsistency (BioseqSetPtr bssp, ValidStructPtr vsp)
 
3676
 
 
3677
{
 
3678
  MolInfoPtr    mip = NULL;
 
3679
  SeqEntryPtr   sep;
 
3680
 
 
3681
  if (bssp == NULL) return;
 
3682
 
 
3683
  for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
 
3684
    if (CheckForInconsistentMolInfos (sep, vsp, &mip, bssp))
 
3685
      return;
 
3686
  }
 
3687
}
 
3688
 
3578
3689
static void ValidatePopSet (BioseqSetPtr bssp, ValidStructPtr vsp)
3579
3690
 
3580
3691
{
3596
3707
    }
3597
3708
  }
3598
3709
 
 
3710
  LookForMolInfoInconsistency (bssp, vsp);
 
3711
 
3599
3712
  for (sep = bssp->seq_set; sep != NULL; sep = sep->next) {
3600
3713
    if (CheckForInconsistentBiosources (sep, vsp, &orp, bssp))
3601
3714
      return;
3636
3749
                "Bioseq-set contains internal GenBank Bioseq-set");
3637
3750
    }
3638
3751
  }
 
3752
 
 
3753
  LookForMolInfoInconsistency (bssp, vsp);
3639
3754
}
3640
3755
 
3641
3756
static void ValidateGenProdSet (BioseqSetPtr bssp, ValidStructPtr vsp)
4405
4520
  ValNodeFreeData (head);
4406
4521
}
4407
4522
 
 
4523
static CharPtr legal_refgene_status_strings [] = {
 
4524
  "Inferred",
 
4525
  "Provisional",
 
4526
  "Predicted",
 
4527
  "Validated",
 
4528
  "Reviewed",
 
4529
  "Model",
 
4530
  "WGS",
 
4531
  "Pipeline",
 
4532
  NULL
 
4533
};
 
4534
 
4408
4535
static void ValidateBioseqInst (GatherContextPtr gcp)
4409
4536
{
4410
4537
  Boolean         retval = TRUE;
4459
4586
  Boolean         in_N;
4460
4587
  Boolean         isActiveFin = FALSE;
4461
4588
  Boolean         isDraft = FALSE;
 
4589
  Boolean         isFullTop = FALSE;
4462
4590
  Boolean         isGB = FALSE;
4463
4591
  Boolean         isPatent = FALSE;
4464
4592
  Boolean         isPDB = FALSE;
 
4593
  Boolean         isPreFin = FALSE;
4465
4594
  Boolean         isNC = FALSE;
4466
4595
  Boolean         isNTorNC = FALSE;
4467
4596
  Boolean         isNZ;
4468
4597
  Boolean         is_gps = FALSE;
4469
4598
  Boolean         isRefSeq = FALSE;
 
4599
  Boolean         isSwissProt = FALSE;
4470
4600
  Boolean         last_is_gap;
4471
4601
  Boolean         non_interspersed_gaps;
4472
4602
  Int2            num_adjacent_gaps;
4497
4627
  ObjectIdPtr     oip;
4498
4628
  Boolean         hasRefGeneTracking = FALSE;
4499
4629
  Boolean         hasRefTrackStatus;
 
4630
  Boolean         hasLegalStatus;
4500
4631
  Int2            accn_count = 0;
4501
4632
  Int2            gi_count = 0;
4502
4633
  Int4            runsofn;
4548
4679
      hasGi = TRUE;
4549
4680
    } else if (sip1->choice == SEQID_GENBANK) {
4550
4681
      isGB = TRUE;
 
4682
    } else if (sip1->choice == SEQID_SWISSPROT) {
 
4683
      isSwissProt = TRUE;
4551
4684
    }
4552
4685
 
4553
4686
    for (sip2 = sip1->next; sip2 != NULL; sip2 = sip2->next) {
4774
4907
        } else if (oip != NULL && StringICmp (oip->str, "RefGeneTracking") == 0) {
4775
4908
          hasRefGeneTracking = TRUE;
4776
4909
          hasRefTrackStatus = FALSE;
 
4910
          hasLegalStatus = FALSE;
4777
4911
          for (ufp = uop->data; ufp != NULL; ufp = ufp->next) {
4778
4912
            oip = ufp->label;
4779
4913
            if (oip != NULL && StringCmp (oip->str, "Status") == 0) {
4780
4914
              hasRefTrackStatus = TRUE;
 
4915
              str = (CharPtr) ufp->data.ptrvalue;
 
4916
              if (StringHasNoText (str)) {
 
4917
                str = "?";
 
4918
              }
 
4919
              for (i = 0; legal_refgene_status_strings [i] != NULL; i++) {
 
4920
                if (StringICmp (str, legal_refgene_status_strings [i]) == 0) {
 
4921
                  hasLegalStatus = TRUE;
 
4922
                  break;
 
4923
                }
 
4924
              }
 
4925
              if (! hasLegalStatus) {
 
4926
                olditemid = gcp->itemID;
 
4927
                olditemtype = gcp->thistype;
 
4928
                gcp->itemID = context.itemID;
 
4929
                gcp->thistype = OBJ_SEQDESC;
 
4930
                ValidErr (vsp, SEV_ERROR, ERR_SEQ_DESCR_RefGeneTrackingIllegalStatus, "RefGeneTracking object has illegal Status '%s'", str);
 
4931
                gcp->itemID = olditemid;
 
4932
                gcp->thistype = olditemtype;
 
4933
              }
4781
4934
            }
4782
4935
          }
4783
4936
          if (! hasRefTrackStatus) {
5346
5499
            isActiveFin = TRUE;
5347
5500
          } else if (StringICmp (str, "HTGS_DRAFT") == 0) {
5348
5501
            isDraft = TRUE;
 
5502
          } else if (StringICmp (str, "HTGS_FULLTOP") == 0) {
 
5503
            isFullTop = TRUE;
 
5504
          } else if (StringICmp (str, "HTGS_PREFIN") == 0) {
 
5505
            isPreFin = TRUE;
5349
5506
          }
5350
5507
        }
5351
5508
      }
5473
5630
              }
5474
5631
            }
5475
5632
          } else if (slitp->length == 0) {
 
5633
            if (isSwissProt) {
 
5634
              sev = SEV_WARNING;
 
5635
            } else {
 
5636
              sev = SEV_ERROR;
 
5637
            }
5476
5638
            ifp = slitp->fuzz;
5477
5639
            if (ifp == NULL || ifp->choice != 4 || ifp->a != 0) {
5478
 
              ValidErr (vsp, SEV_ERROR, ERR_SEQ_INST_SeqLitGapLength0, "Gap of length 0 in delta chain");
 
5640
              ValidErr (vsp, sev, ERR_SEQ_INST_SeqLitGapLength0, "Gap of length 0 in delta chain");
5479
5641
            } else {
5480
 
              ValidErr (vsp, SEV_ERROR, ERR_SEQ_INST_SeqLitGapLength0, "Gap of length 0 with unknown fuzz in delta chain");
 
5642
              ValidErr (vsp, sev, ERR_SEQ_INST_SeqLitGapLength0, "Gap of length 0 with unknown fuzz in delta chain");
5481
5643
            }
5482
5644
          }
5483
5645
          len += slitp->length;
5628
5790
    }
5629
5791
  }
5630
5792
 
5631
 
  if (mip != NULL) {
5632
 
    if (isDraft && mip->tech == MI_TECH_htgs_3) {
5633
 
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_INST_BadHTGSeq, "HTGS 3 sequence should not have HTGS_DRAFT keyword");
 
5793
  if (mip != NULL && mip->tech == MI_TECH_htgs_3) {
 
5794
    if (isDraft) {
 
5795
      ValidErr (vsp, SEV_ERROR, ERR_SEQ_INST_BadHTGSeq, "HTGS 3 sequence should not have HTGS_DRAFT keyword");
 
5796
    }
 
5797
    if (isPreFin) {
 
5798
      ValidErr (vsp, SEV_ERROR, ERR_SEQ_INST_BadHTGSeq, "HTGS 3 sequence should not have HTGS_PREFIN keyword");
 
5799
    }
 
5800
    if (isActiveFin) {
 
5801
      ValidErr (vsp, SEV_ERROR, ERR_SEQ_INST_BadHTGSeq, "HTGS 3 sequence should not have HTGS_ACTIVEFIN keyword");
 
5802
    }
 
5803
    if (isFullTop) {
 
5804
      ValidErr (vsp, SEV_ERROR, ERR_SEQ_INST_BadHTGSeq, "HTGS 3 sequence should not have HTGS_FULLTOP keyword");
5634
5805
    }
5635
5806
  }
5636
5807
 
5783
5954
          /* check generated protein defline with first prp->name - new convention */
5784
5955
          if (buf != NULL && CreateDefLineExEx (&ii, bsp, buf, buflen, tech, NULL, NULL, TRUE, FALSE)) {
5785
5956
            if (StringICmp (buf, title) != 0) {
 
5957
              /* okay if instantiated title has single trailing period */
 
5958
              len2 = StringLen (buf);
 
5959
              len3 = StringLen (title);
 
5960
              if (len3 == len2 + 1 && title [len3 - 1] == '.' && len3 > 3 && title [len3 - 2] != '.') {
 
5961
                StringCat (buf, ".");
 
5962
              }
 
5963
            }
 
5964
            if (StringICmp (buf, title) != 0) {
5786
5965
              /* also check generated protein defline with all prp->names - old convention */
5787
5966
              if (CreateDefLineExEx (&ii, bsp, buf, buflen, tech, NULL, NULL, TRUE, TRUE)) {
5788
5967
                if (StringICmp (buf, title) != 0) {
6561
6740
            if (imp->pubstatus == PUBSTATUS_aheadofprint && imp->prepub != 2) {
6562
6741
              ValidErr (vsp, SEV_WARNING, ERR_GENERIC_PublicationInconsistency, "Ahead-of-print without in-press");
6563
6742
            }
 
6743
            if (imp->pubstatus == PUBSTATUS_epublish && imp->prepub == 2) {
 
6744
              ValidErr (vsp, SEV_WARNING, ERR_GENERIC_PublicationInconsistency, "Electronic-only publication should not also be in-press");
 
6745
            }
6564
6746
          }
6565
6747
        }
6566
6748
        break;
7270
7452
  "Saudi Arabia",
7271
7453
  "Senegal",
7272
7454
  "Serbia",
7273
 
  "Serbia and Montenegro",
7274
7455
  "Seychelles",
7275
7456
  "Sierra Leone",
7276
7457
  "Singapore",
7321
7502
  "West Bank",
7322
7503
  "Western Sahara",
7323
7504
  "Yemen",
7324
 
  "Yugoslavia",
7325
7505
  "Zambia",
7326
7506
  "Zimbabwe",
7327
7507
  NULL
7328
7508
};
7329
7509
 
 
7510
static CharPtr  Nlm_formerly_valid_country_codes [] = {
 
7511
  "British Guiana",
 
7512
  "Burma",
 
7513
  "Czechoslovakia",
 
7514
  "Ivory Coast",
 
7515
  "Serbia and Montenegro",
 
7516
  "Siam",
 
7517
  "USSR",
 
7518
  "Yugoslavia",
 
7519
  "Zaire",
 
7520
  NULL
 
7521
};
 
7522
 
7330
7523
NLM_EXTERN CharPtr PNTR GetValidCountryList (void)
7331
7524
 
7332
7525
{
7333
7526
  return (CharPtr PNTR) Nlm_valid_country_codes;
7334
7527
}
7335
7528
 
7336
 
static Boolean CountryIsValid (CharPtr name)
 
7529
NLM_EXTERN Boolean CountryIsValid (CharPtr name, BoolPtr old_countryP)
7337
7530
{
7338
7531
  Int2            L, R, mid;
7339
7532
  CharPtr         ptr;
7363
7556
    return TRUE;
7364
7557
  }
7365
7558
 
 
7559
  L = 0;
 
7560
  R = sizeof (Nlm_formerly_valid_country_codes) / sizeof (Nlm_formerly_valid_country_codes[0]) - 1; /* -1 because now NULL terminated */
 
7561
 
 
7562
  while (L < R) {
 
7563
    mid = (L + R) / 2;
 
7564
    if (StringICmp (Nlm_formerly_valid_country_codes[mid], str) < 0) {
 
7565
      L = mid + 1;
 
7566
    } else {
 
7567
      R = mid;
 
7568
    }
 
7569
  }
 
7570
 
 
7571
  if (StringICmp (Nlm_formerly_valid_country_codes[R], str) == 0) {
 
7572
    if (old_countryP != NULL) {
 
7573
      *old_countryP = TRUE;
 
7574
    }
 
7575
    return FALSE;
 
7576
  }
 
7577
 
7366
7578
  return FALSE;
7367
7579
}
7368
7580
 
7439
7651
  "Central African Republic\tCT\t14.4\t2.2\t27.5\t11.0",
7440
7652
  "Chad\tCD\t13.4\t7.4\t24.0\t23.5",
7441
7653
  "Chile\tCI\t-75.8\t-56.0\t-66.4\t-17.5",
7442
 
  "China\tCH\t73.5\t20.2\t134.8\t53.6",
 
7654
  "China\tCH\t73.5\t20.2\t134.8\t53.6\t108.6\t18.1\t111.1\t20.2",
 
7655
  "China: Hainan\tXX\t108.6\t18.1\t111.1\t20.2",
7443
7656
  "Christmas Island\tKT\t105.5\t-10.6\t105.7\t-10.4",
7444
7657
  "Clipperton Island\tIP\t-109.3\t10.2\t-109.2\t10.3",
7445
7658
  "Cocos Islands\tCK\t96.8\t-12.2\t96.9\t-11.8",
7609
7822
  "Saudi Arabia\tSA\t34.4\t15.6\t55.7\t32.2",
7610
7823
  "Senegal\tSG\t-17.6\t12.3\t-11.4\t16.7",
7611
7824
  "Serbia\tRB\t18.8\t41.8\t23.1\t46.2",
7612
 
  "Serbia and Montenegro\tYI\t",
7613
7825
  "Seychelles\tSE\t50.7\t-9.6\t51.1\t-9.2\t52.7\t-7.2\t52.8\t-7.0\t53.0\t-6.3\t53.7\t-5.1\t55.2\t-5.9\t56.0\t-3.7\t56.2\t-7.2\t56.3\t-7.1",
7614
7826
  "Sierra Leone\tSL\t-13.4\t6.9\t-10.3\t10.0",
7615
7827
  "Singapore\tSN\t103.6\t1.1\t104.1\t1.5",
7712
7924
  "West Bank\tWE\t34.8\t31.3\t35.6\t32.6",
7713
7925
  "Western Sahara\tWI\t-17.2\t20.7\t-8.7\t27.7",
7714
7926
  "Yemen\tYM\t41.8\t11.7\t54.5\t19.0",
7715
 
  "Yugoslavia\tXX\t13.3\t40.8\t23.0\t46.9",
7716
7927
  "Zambia\tZA\t21.9\t-18.1\t33.7\t-8.2",
7717
7928
  "Zimbabwe\tZI\t25.2\t-22.5\t33.1\t-15.6",
7718
7929
  NULL
7719
7930
};
7720
7931
 
7721
 
typedef struct ctdata {
7722
 
  CharPtr  country;
 
7932
 
 
7933
/* one CtBlock for each discontiguous area per country */
 
7934
 
 
7935
typedef struct ctblock {
 
7936
  CharPtr  country;       /* points to instance in countries list */
7723
7937
  FloatHi  minx;
7724
7938
  FloatHi  miny;
7725
7939
  FloatHi  maxx;
7726
7940
  FloatHi  maxy;
7727
 
} CtData, PNTR CtDataPtr;
7728
 
 
7729
 
typedef struct ctlist {
7730
 
  ValNodePtr      countries;
7731
 
  ValNodePtr      boundaries;
7732
 
  CtDataPtr PNTR  ctarray;
7733
 
  CtDataPtr PNTR  bdarray;
7734
 
  Int2            num;
7735
 
} CtList, PNTR CtListPtr;
7736
 
 
7737
 
static int LIBCALLBACK SortCdpByCountry (VoidPtr ptr1, VoidPtr ptr2)
7738
 
 
7739
 
{
7740
 
  int        compare;
7741
 
  CtDataPtr  cdp1, cdp2;
7742
 
 
7743
 
  if (ptr1 == NULL || ptr2 == NULL) return 0;
7744
 
  cdp1 = *((CtDataPtr PNTR) ptr1);
7745
 
  cdp2 = *((CtDataPtr PNTR) ptr2);
7746
 
  if (cdp1 == NULL || cdp2 == NULL) return 0;
7747
 
 
7748
 
  compare = StringICmp (cdp1->country, cdp2->country);
7749
 
  if (compare > 0) {
7750
 
    return 1;
7751
 
  } else if (compare < 0) {
7752
 
    return -1;
7753
 
  }
7754
 
 
7755
 
  return 0;
7756
 
}
7757
 
 
7758
 
static int LIBCALLBACK SortCdpByBounds (VoidPtr ptr1, VoidPtr ptr2)
7759
 
 
7760
 
{
7761
 
  CtDataPtr  cdp1, cdp2;
7762
 
 
7763
 
  if (ptr1 == NULL || ptr2 == NULL) return 0;
7764
 
  cdp1 = *((CtDataPtr PNTR) ptr1);
7765
 
  cdp2 = *((CtDataPtr PNTR) ptr2);
7766
 
  if (cdp1 == NULL || cdp2 == NULL) return 0;
7767
 
 
7768
 
  if (cdp1->minx > cdp2->minx) {
7769
 
    return 1;
7770
 
  } else if (cdp1->minx < cdp2->minx) {
7771
 
    return -1;
7772
 
  }
7773
 
 
7774
 
  if (cdp1->maxx > cdp2->maxx) {
7775
 
    return -1;
7776
 
  } else if (cdp1->maxx < cdp2->maxx) {
7777
 
    return 1;
7778
 
  }
7779
 
 
7780
 
  if (cdp1->miny > cdp2->miny) {
7781
 
    return 1;
7782
 
  } else if (cdp1->miny < cdp2->miny) {
7783
 
    return -1;
7784
 
  }
7785
 
 
7786
 
  if (cdp1->maxy > cdp2->maxy) {
7787
 
    return -1;
7788
 
  } else if (cdp1->maxy < cdp2->maxy) {
7789
 
    return 1;
7790
 
  }
7791
 
 
7792
 
  return 0;
7793
 
}
7794
 
 
7795
 
static CtListPtr CtLatLonDataFree (
7796
 
  CtListPtr clp
7797
 
)
7798
 
 
7799
 
{
7800
 
  if (clp == NULL) return NULL;
7801
 
 
7802
 
  ValNodeFreeData (clp->countries);
7803
 
  ValNodeFreeData (clp->boundaries);
7804
 
 
7805
 
  MemFree (clp->ctarray);
7806
 
  MemFree (clp->bdarray);
7807
 
 
7808
 
  MemFree (clp);
 
7941
} CtBlock, PNTR CtBlockPtr;
 
7942
 
 
7943
/* one CtGrid for each 10-degree-by-10-degree area touched by a CtBlock */
 
7944
 
 
7945
typedef struct ctgrid {
 
7946
  CtBlockPtr  cbp;
 
7947
  Int2        xindex;
 
7948
  Int2        yindex;
 
7949
} CtGrid, PNTR CtGridPtr;
 
7950
 
 
7951
/* main structure for country/lat-lon lookup */
 
7952
 
 
7953
typedef struct ctset {
 
7954
  ValNodePtr       countries;
 
7955
  ValNodePtr       blocks;
 
7956
  ValNodePtr       grids;
 
7957
  CtBlockPtr PNTR  bkarray;     /* sorted by country name */
 
7958
  CtGridPtr PNTR   gdarray;     /* sorted by geographic index */
 
7959
  Int4             num_blocks;
 
7960
  Int4             num_grids;
 
7961
} CtSet, PNTR CtSetPtr;
 
7962
 
 
7963
static int LIBCALLBACK SortCbpByCountry (
 
7964
  VoidPtr ptr1,
 
7965
  VoidPtr ptr2
 
7966
)
 
7967
 
 
7968
{
 
7969
  int         compare;
 
7970
  CtBlockPtr  cbp1, cbp2;
 
7971
 
 
7972
  if (ptr1 == NULL || ptr2 == NULL) return 0;
 
7973
  cbp1 = *((CtBlockPtr PNTR) ptr1);
 
7974
  cbp2 = *((CtBlockPtr PNTR) ptr2);
 
7975
  if (cbp1 == NULL || cbp2 == NULL) return 0;
 
7976
 
 
7977
  compare = StringICmp (cbp1->country, cbp2->country);
 
7978
  if (compare > 0) {
 
7979
    return 1;
 
7980
  } else if (compare < 0) {
 
7981
    return -1;
 
7982
  }
 
7983
 
 
7984
  return 0;
 
7985
}
 
7986
 
 
7987
static int CgpGridComp (
 
7988
  CtGridPtr cgp1,
 
7989
  Int2 xindex,
 
7990
  Int2 yindex
 
7991
)
 
7992
 
 
7993
{
 
7994
  if (cgp1 == NULL) return 0;
 
7995
 
 
7996
  if (cgp1->xindex > xindex) {
 
7997
    return 1;
 
7998
  } else if (cgp1->xindex < xindex) {
 
7999
    return -1;
 
8000
  }
 
8001
 
 
8002
  if (cgp1->yindex > yindex) {
 
8003
    return 1;
 
8004
  } else if (cgp1->yindex < yindex) {
 
8005
    return -1;
 
8006
  }
 
8007
 
 
8008
  return 0;
 
8009
}
 
8010
 
 
8011
static int LIBCALLBACK SortCgpByGrid (
 
8012
  VoidPtr ptr1,
 
8013
  VoidPtr ptr2
 
8014
)
 
8015
 
 
8016
{
 
8017
  CtBlockPtr  cbp1, cbp2;
 
8018
  CtGridPtr   cgp1, cgp2;
 
8019
  int         compare;
 
8020
 
 
8021
  if (ptr1 == NULL || ptr2 == NULL) return 0;
 
8022
  cgp1 = *((CtGridPtr PNTR) ptr1);
 
8023
  cgp2 = *((CtGridPtr PNTR) ptr2);
 
8024
  if (cgp1 == NULL || cgp2 == NULL) return 0;
 
8025
 
 
8026
  compare = CgpGridComp (cgp1, cgp2->xindex, cgp2->yindex);
 
8027
  if (compare > 0) {
 
8028
    return 1;
 
8029
  } else if (compare < 0) {
 
8030
    return -1;
 
8031
  }
 
8032
 
 
8033
  cbp1 = cgp1->cbp;
 
8034
  cbp2 = cgp2->cbp;
 
8035
  if (cbp1 == NULL || cbp2 == NULL) return 0;
 
8036
 
 
8037
  if (cbp1->minx > cbp2->minx) {
 
8038
    return 1;
 
8039
  } else if (cbp1->minx < cbp2->minx) {
 
8040
    return -1;
 
8041
  }
 
8042
 
 
8043
  if (cbp1->maxx > cbp2->maxx) {
 
8044
    return -1;
 
8045
  } else if (cbp1->maxx < cbp2->maxx) {
 
8046
    return 1;
 
8047
  }
 
8048
 
 
8049
  if (cbp1->miny > cbp2->miny) {
 
8050
    return 1;
 
8051
  } else if (cbp1->miny < cbp2->miny) {
 
8052
    return -1;
 
8053
  }
 
8054
 
 
8055
  if (cbp1->maxy > cbp2->maxy) {
 
8056
    return -1;
 
8057
  } else if (cbp1->maxy < cbp2->maxy) {
 
8058
    return 1;
 
8059
  }
 
8060
 
 
8061
  compare = StringICmp (cbp1->country, cbp2->country);
 
8062
  if (compare > 0) {
 
8063
    return 1;
 
8064
  } else if (compare < 0) {
 
8065
    return -1;
 
8066
  }
 
8067
 
 
8068
  return 0;
 
8069
}
 
8070
 
 
8071
static Int2 LatLonDegreeToIndex (
 
8072
  FloatHi coord
 
8073
)
 
8074
 
 
8075
{
 
8076
  double  fval;
 
8077
  long    ival;
 
8078
 
 
8079
  fval = coord;
 
8080
  fval += 200.0;
 
8081
  fval /= 10.0;
 
8082
  ival = (long) fval;
 
8083
  ival -= 20;
 
8084
 
 
8085
  return ival;
 
8086
}
 
8087
 
 
8088
static CtSetPtr CtSetDataFree (
 
8089
  CtSetPtr csp
 
8090
)
 
8091
 
 
8092
{
 
8093
  if (csp == NULL) return NULL;
 
8094
 
 
8095
  ValNodeFreeData (csp->countries);
 
8096
  ValNodeFreeData (csp->blocks);
 
8097
  ValNodeFreeData (csp->grids);
 
8098
 
 
8099
  MemFree (csp->bkarray);
 
8100
  MemFree (csp->gdarray);
 
8101
 
 
8102
  MemFree (csp);
7809
8103
 
7810
8104
  return NULL;
7811
8105
}
7812
8106
 
7813
 
static Boolean ct_list_not_found = FALSE;
 
8107
static Boolean ct_set_not_found = FALSE;
7814
8108
 
7815
 
static CtListPtr GetCtLatLonDataInt (
 
8109
static CtSetPtr GetCtSetLatLonDataInt (
7816
8110
  CharPtr prop,
7817
8111
  CharPtr file,
7818
8112
  CharPtr PNTR local
7819
8113
)
7820
8114
 
7821
8115
{
7822
 
  ValNodePtr      boundaries = NULL;
7823
 
  FloatHi         bounds [4];
7824
 
  CtDataPtr       cdp;
7825
 
  CtDataPtr PNTR  ctarray;
7826
 
  CtDataPtr PNTR  bdarray;
7827
 
  CtListPtr       clp;
7828
 
  ValNodePtr      countries = NULL;
7829
 
  CharPtr         country;
7830
 
  FileCache       fc;
7831
 
  FILE            *fp = NULL;
7832
 
  Int2            i;
7833
 
  Int2            j = 0;
7834
 
  ValNodePtr      lastbdry = NULL;
7835
 
  ValNodePtr      lastctry = NULL;
7836
 
  Char            line [1024];
7837
 
  Int4            num;
7838
 
  Char            path [PATH_MAX];
7839
 
  CharPtr         ptr;
7840
 
  ErrSev          sev;
7841
 
  CharPtr         str = NULL;
7842
 
  double          val;
7843
 
  ValNodePtr      vnp;
7844
 
  CharPtr         wrk;
7845
 
 
7846
 
  clp = (CtListPtr) GetAppProperty (prop);
7847
 
  if (clp != NULL) return clp;
7848
 
 
7849
 
  if (ct_list_not_found) return NULL;
 
8116
  CtBlockPtr PNTR  bkarray;
 
8117
  ValNodePtr       blocks = NULL;
 
8118
  FloatHi          bounds [4];
 
8119
  CtBlockPtr       cbp;
 
8120
  CtGridPtr        cgp;
 
8121
  ValNodePtr       countries = NULL;
 
8122
  CharPtr          country;
 
8123
  CtSetPtr         csp;
 
8124
  FileCache        fc;
 
8125
  FILE             *fp = NULL;
 
8126
  CtGridPtr PNTR   gdarray;
 
8127
  ValNodePtr       grids = NULL;
 
8128
  Int2             hix;
 
8129
  Int2             hiy;
 
8130
  Int2             i;
 
8131
  Int2             j = 0;
 
8132
  ValNodePtr       lastblk = NULL;
 
8133
  ValNodePtr       lastctry = NULL;
 
8134
  ValNodePtr       lastgrd = NULL;
 
8135
  Char             line [1024];
 
8136
  Int2             lox;
 
8137
  Int2             loy;
 
8138
  Int4             num;
 
8139
  Char             path [PATH_MAX];
 
8140
  CharPtr          ptr;
 
8141
  ErrSev           sev;
 
8142
  CharPtr          str = NULL;
 
8143
  double           val;
 
8144
  ValNodePtr       vnp;
 
8145
  CharPtr          wrk;
 
8146
  Int2             x;
 
8147
  Int2             y;
 
8148
 
 
8149
  csp = (CtSetPtr) GetAppProperty (prop);
 
8150
  if (csp != NULL) return csp;
 
8151
 
 
8152
  if (ct_set_not_found) return NULL;
7850
8153
 
7851
8154
  if (FindPath ("ncbi", "ncbi", "data", path, sizeof (path))) {
7852
8155
    FileBuildPath (path, NULL, file);
7888
8191
            wrk = StringSave (ptr);
7889
8192
            str = wrk;
7890
8193
            i = 0;
 
8194
 
7891
8195
            while (StringDoesHaveText (str)) {
7892
8196
              ptr = StringChr (str, '\t');
7893
8197
              if (ptr != NULL) {
7894
8198
                *ptr = '\0';
7895
8199
                ptr++;
7896
8200
              }
 
8201
 
7897
8202
              if (sscanf (str, "%lf", &val) == 1) {
7898
8203
                bounds [i] = (FloatHi) val;
7899
8204
                i++;
7900
8205
                if (i > 3) {
7901
8206
 
7902
 
                  cdp = (CtDataPtr) MemNew (sizeof (CtData));
7903
 
                  if (cdp != NULL) {
7904
 
                    cdp->country = country;
7905
 
                    cdp->minx = bounds [0];
7906
 
                    cdp->miny = bounds [1];
7907
 
                    cdp->maxx = bounds [2];
7908
 
                    cdp->maxy = bounds [3];
7909
 
 
7910
 
                    vnp = ValNodeAddPointer (&lastbdry, 0, (Pointer) cdp);
7911
 
                    if (boundaries == NULL) {
7912
 
                      boundaries = vnp;
7913
 
                    }
7914
 
                    lastbdry = vnp;
 
8207
                  cbp = (CtBlockPtr) MemNew (sizeof (CtBlock));
 
8208
                  if (cbp != NULL) {
 
8209
                    cbp->country = country;
 
8210
                    cbp->minx = bounds [0];
 
8211
                    cbp->miny = bounds [1];
 
8212
                    cbp->maxx = bounds [2];
 
8213
                    cbp->maxy = bounds [3];
 
8214
 
 
8215
                    vnp = ValNodeAddPointer (&lastblk, 0, (Pointer) cbp);
 
8216
                    if (blocks == NULL) {
 
8217
                      blocks = vnp;
 
8218
                    }
 
8219
                    lastblk = vnp;
 
8220
 
 
8221
                    lox = LatLonDegreeToIndex (cbp->minx);
 
8222
                    loy = LatLonDegreeToIndex (cbp->miny);
 
8223
                    hix = LatLonDegreeToIndex (cbp->maxx);
 
8224
                    hiy = LatLonDegreeToIndex (cbp->maxy);
 
8225
 
 
8226
                    for (x = lox; x <= hix; x++) {
 
8227
                      for (y = loy; y <= hiy; y++) {
 
8228
                        cgp = (CtGridPtr) MemNew (sizeof (CtGrid));
 
8229
                        if (cgp != NULL) {
 
8230
                          cgp->cbp = cbp;
 
8231
                          cgp->xindex = x;
 
8232
                          cgp->yindex = y;
 
8233
 
 
8234
                          vnp = ValNodeAddPointer (&lastgrd, 0, (Pointer) cgp);
 
8235
                          if (grids == NULL) {
 
8236
                            grids = vnp;
 
8237
                          }
 
8238
                          lastgrd = vnp;
 
8239
                        }
 
8240
                      }
 
8241
                    }
7915
8242
                  }
7916
8243
 
7917
8244
                  i = 0;
7918
8245
                }
7919
8246
              }
 
8247
 
7920
8248
              str = ptr;
7921
8249
            }
 
8250
 
7922
8251
            MemFree (wrk);
7923
8252
          }
7924
8253
        }
7925
8254
      }
7926
8255
    }
 
8256
 
7927
8257
    if (fp != NULL) {
7928
8258
      str = FileCacheReadLine (&fc, line, sizeof (line), NULL);
7929
8259
    } else {
7940
8270
    FileClose (fp);
7941
8271
  }
7942
8272
 
7943
 
  if (countries == NULL || boundaries == NULL) {
7944
 
    ct_list_not_found = TRUE;
 
8273
  if (countries == NULL || blocks == NULL || grids == NULL) {
 
8274
    ct_set_not_found = TRUE;
7945
8275
    return NULL;
7946
8276
  }
7947
8277
 
7948
 
  clp = (CtListPtr) MemNew (sizeof (CtList));
7949
 
  if (clp == NULL) return NULL;
 
8278
  csp = (CtSetPtr) MemNew (sizeof (CtSet));
 
8279
  if (csp == NULL) return NULL;
7950
8280
 
7951
8281
  /* now populate, heap sort arrays */
7952
8282
 
7953
 
  num = ValNodeLen (boundaries);
7954
 
 
7955
 
  clp->countries = countries;
7956
 
  clp->boundaries = boundaries;
7957
 
  clp->num = (Int2) num;
7958
 
 
7959
 
  ctarray = (CtDataPtr PNTR) MemNew (sizeof (CtDataPtr) * (num + 1));
7960
 
  if (ctarray != NULL) {
7961
 
    for (vnp = boundaries, i = 0; vnp != NULL; vnp = vnp->next, i++) {
7962
 
      cdp = (CtDataPtr) vnp->data.ptrvalue;
7963
 
      ctarray [i] = cdp;
7964
 
    }
7965
 
 
7966
 
    HeapSort (ctarray, (size_t) num, sizeof (CtDataPtr), SortCdpByCountry);
7967
 
    clp->ctarray = ctarray;
7968
 
  }
7969
 
 
7970
 
  bdarray = (CtDataPtr PNTR) MemNew (sizeof (CtDataPtr) * (num + 1));
7971
 
  if (bdarray != NULL) {
7972
 
    for (vnp = boundaries, i = 0; vnp != NULL; vnp = vnp->next, i++) {
7973
 
      cdp = (CtDataPtr) vnp->data.ptrvalue;
7974
 
      bdarray [i] = cdp;
7975
 
    }
7976
 
 
7977
 
    HeapSort (bdarray, (size_t) num, sizeof (CtDataPtr), SortCdpByBounds);
7978
 
    clp->bdarray = bdarray;
7979
 
  }
7980
 
 
7981
 
  SetAppProperty (prop, (Pointer) clp);
7982
 
 
7983
 
  return clp;
 
8283
  num = ValNodeLen (blocks);
 
8284
 
 
8285
  csp->countries = countries;
 
8286
  csp->blocks = blocks;
 
8287
  csp->num_blocks = (Int2) num;
 
8288
 
 
8289
  bkarray = (CtBlockPtr PNTR) MemNew (sizeof (CtBlockPtr) * (num + 1));
 
8290
  if (bkarray != NULL) {
 
8291
    for (vnp = blocks, i = 0; vnp != NULL; vnp = vnp->next, i++) {
 
8292
      cbp = (CtBlockPtr) vnp->data.ptrvalue;
 
8293
      bkarray [i] = cbp;
 
8294
    }
 
8295
 
 
8296
    HeapSort (bkarray, (size_t) num, sizeof (CtBlockPtr), SortCbpByCountry);
 
8297
    csp->bkarray = bkarray;
 
8298
  }
 
8299
 
 
8300
  num = ValNodeLen (grids);
 
8301
 
 
8302
  csp->num_grids = (Int2) num;
 
8303
 
 
8304
  gdarray = (CtGridPtr PNTR) MemNew (sizeof (CtGridPtr) * (num + 1));
 
8305
  if (gdarray != NULL) {
 
8306
    for (vnp = grids, i = 0; vnp != NULL; vnp = vnp->next, i++) {
 
8307
      cgp = (CtGridPtr) vnp->data.ptrvalue;
 
8308
      gdarray [i] = cgp;
 
8309
    }
 
8310
 
 
8311
    HeapSort (gdarray, (size_t) num, sizeof (CtGridPtr), SortCgpByGrid);
 
8312
    csp->gdarray = gdarray;
 
8313
  }
 
8314
 
 
8315
  SetAppProperty (prop, (Pointer) csp);
 
8316
 
 
8317
  return csp;
7984
8318
}
7985
8319
 
7986
 
static CtListPtr GetCtLatLonData (
 
8320
static CtSetPtr GetCtSetLatLonData (
7987
8321
  void
7988
8322
)
7989
8323
 
7990
8324
{
7991
 
  return GetCtLatLonDataInt ("CountryLatLonList", "country_lat_lon.txt", ctry_lat_lon);
 
8325
  return GetCtSetLatLonDataInt ("CountryLatLonList", "country_lat_lon.txt", ctry_lat_lon);
7992
8326
}
7993
8327
 
7994
8328
NLM_EXTERN Boolean IsCountryInLatLonList (
7996
8330
)
7997
8331
 
7998
8332
{
7999
 
  CtDataPtr       cdp;
8000
 
  CtDataPtr PNTR  ctarray;
8001
 
  CtListPtr       clp;
8002
 
  Int2            L, R, mid;
 
8333
  CtBlockPtr       cbp;
 
8334
  CtBlockPtr PNTR  bkarray;
 
8335
  CtSetPtr         csp;
 
8336
  Int2             L, R, mid;
8003
8337
 
8004
8338
  if (StringHasNoText (country)) return FALSE;
8005
8339
 
8006
 
  clp = GetCtLatLonData ();
8007
 
  if (clp == NULL) return FALSE;
 
8340
  csp = GetCtSetLatLonData ();
 
8341
  if (csp == NULL) return FALSE;
8008
8342
 
8009
 
  ctarray = clp->ctarray;
8010
 
  if (ctarray == NULL) return FALSE;
 
8343
  bkarray = csp->bkarray;
 
8344
  if (bkarray == NULL) return FALSE;
8011
8345
 
8012
8346
  L = 0;
8013
 
  R = clp->num - 1;
 
8347
  R = csp->num_blocks - 1;
8014
8348
 
8015
8349
  while (L < R) {
8016
8350
    mid = (L + R) / 2;
8017
 
    cdp = ctarray [mid];
8018
 
    if (cdp != NULL && StringICmp (cdp->country, country) < 0) {
 
8351
    cbp = bkarray [mid];
 
8352
    if (cbp != NULL && StringICmp (cbp->country, country) < 0) {
8019
8353
      L = mid + 1;
8020
8354
    } else {
8021
8355
      R = mid;
8022
8356
    }
8023
8357
  }
8024
8358
 
8025
 
  cdp = ctarray [R];
8026
 
  if (cdp != NULL && StringICmp (cdp->country, country) == 0) return TRUE;
 
8359
  cbp = bkarray [R];
 
8360
  if (cbp != NULL && StringICmp (cbp->country, country) == 0) return TRUE;
8027
8361
 
8028
8362
  return FALSE;
8029
8363
}
8035
8369
)
8036
8370
 
8037
8371
{
8038
 
  CtDataPtr       cdp;
8039
 
  CtDataPtr PNTR  ctarray;
8040
 
  CtListPtr       clp;
8041
 
  Int2            L, R, mid;
 
8372
  CtBlockPtr       cbp;
 
8373
  CtBlockPtr PNTR  bkarray;
 
8374
  CtSetPtr         csp;
 
8375
  Int2             L, R, mid;
8042
8376
 
8043
8377
  if (StringHasNoText (country)) return FALSE;
8044
8378
 
8045
 
  clp = GetCtLatLonData ();
8046
 
  if (clp == NULL) return FALSE;
 
8379
  csp = GetCtSetLatLonData ();
 
8380
  if (csp == NULL) return FALSE;
8047
8381
 
8048
 
  ctarray = clp->ctarray;
8049
 
  if (ctarray == NULL) return FALSE;
 
8382
  bkarray = csp->bkarray;
 
8383
  if (bkarray == NULL) return FALSE;
8050
8384
 
8051
8385
  L = 0;
8052
 
  R = clp->num - 1;
 
8386
  R = csp->num_blocks - 1;
8053
8387
 
8054
8388
  while (L < R) {
8055
8389
    mid = (L + R) / 2;
8056
 
    cdp = ctarray [mid];
8057
 
    if (cdp != NULL && StringICmp (cdp->country, country) < 0) {
 
8390
    cbp = bkarray [mid];
 
8391
    if (cbp != NULL && StringICmp (cbp->country, country) < 0) {
8058
8392
      L = mid + 1;
8059
8393
    } else {
8060
8394
      R = mid;
8061
8395
    }
8062
8396
  }
8063
8397
 
8064
 
  while (R < clp->num) {
8065
 
    cdp = ctarray [R];
8066
 
    if (cdp == NULL) return FALSE;
8067
 
    if (StringICmp (cdp->country, country) != 0) return FALSE;
8068
 
    if (lon >= cdp->minx && lat >= cdp->miny && lon <= cdp->maxx && lat <= cdp->maxy) return TRUE;
 
8398
  while (R < csp->num_blocks) {
 
8399
    cbp = bkarray [R];
 
8400
    if (cbp == NULL) return FALSE;
 
8401
    if (StringICmp (cbp->country, country) != 0) return FALSE;
 
8402
    if (lon >= cbp->minx && lat >= cbp->miny && lon <= cbp->maxx && lat <= cbp->maxy) return TRUE;
8069
8403
    R++;
8070
8404
  }
8071
8405
 
8078
8412
)
8079
8413
 
8080
8414
{
8081
 
  CtDataPtr PNTR  bdarray;
8082
 
  CtDataPtr       cdp;
8083
 
  CtListPtr       clp;
 
8415
  CtBlockPtr      cbp;
 
8416
  CtGridPtr       cgp;
8084
8417
  CharPtr         country = NULL;
 
8418
  CtSetPtr        csp;
 
8419
  CtGridPtr PNTR  gdarray;
8085
8420
  Int2            L, R, mid;
8086
 
 
8087
 
  clp = GetCtLatLonData ();
8088
 
  if (clp == NULL) return NULL;
8089
 
 
8090
 
  bdarray = clp->bdarray;
8091
 
  if (bdarray == NULL) return NULL;
 
8421
  Int2            x;
 
8422
  Int2            y;
 
8423
 
 
8424
  csp = GetCtSetLatLonData ();
 
8425
  if (csp == NULL) return NULL;
 
8426
 
 
8427
  gdarray = csp->gdarray;
 
8428
  if (gdarray == NULL) return NULL;
8092
8429
 
8093
8430
  L = 0;
8094
 
  R = clp->num - 1;
 
8431
  R = csp->num_grids - 1;
 
8432
 
 
8433
  x = LatLonDegreeToIndex (lon);
 
8434
  y = LatLonDegreeToIndex (lat);
8095
8435
 
8096
8436
  while (L < R) {
8097
8437
    mid = (L + R) / 2;
8098
 
    cdp = bdarray [mid];
8099
 
    if (cdp != NULL && cdp->maxx < lon) {
 
8438
    cgp = gdarray [mid];
 
8439
    if (cgp != NULL && CgpGridComp (cgp, x, y) < 0) {
8100
8440
      L = mid + 1;
8101
8441
    } else {
8102
8442
      R = mid;
8103
8443
    }
8104
8444
  }
8105
8445
 
8106
 
  while (mid < clp->num) {
8107
 
    cdp = bdarray [mid];
8108
 
    if (cdp == NULL) return country;
8109
 
    if (cdp->minx > lon) return country;
8110
 
    if (lon >= cdp->minx && lat >= cdp->miny && lon <= cdp->maxx && lat <= cdp->maxy) {
8111
 
      country = cdp->country;
 
8446
  while (R < csp->num_grids) {
 
8447
    cgp = gdarray [R];
 
8448
    if (cgp == NULL) return country;
 
8449
    if (cgp->xindex != x || cgp->yindex != y) return country;
 
8450
    cbp = cgp->cbp;
 
8451
    if (cbp == NULL) return country;
 
8452
    if (lon >= cbp->minx && lat >= cbp->miny && lon <= cbp->maxx && lat <= cbp->maxy) {
 
8453
      country = cbp->country;
8112
8454
    }
8113
 
    mid++;
 
8455
    R++;
8114
8456
  }
8115
8457
 
8116
8458
  return country;
8117
8459
}
8118
8460
 
 
8461
 
8119
8462
static CharPtr bodiesOfWater [] = {
8120
8463
  "Bay",
8121
8464
  "Canal",
8166
8509
  return fsa;
8167
8510
}
8168
8511
 
8169
 
static Boolean StringContainsBodyOfWater (CharPtr str)
 
8512
NLM_EXTERN Boolean StringContainsBodyOfWater (CharPtr str)
8170
8513
 
8171
8514
{
8172
8515
  Char        ch;
8200
8543
 
8201
8544
 
8202
8545
 
8203
 
NLM_EXTERN Boolean ParseLatLon (
8204
 
  CharPtr lat_lon,
8205
 
  FloatHi PNTR latP,
8206
 
  FloatHi PNTR lonP
8207
 
)
8208
 
 
8209
 
{
8210
 
  char    ew;
8211
 
  double  lat;
8212
 
  double  lon;
8213
 
  char    ns;
8214
 
 
8215
 
  if (latP != NULL) {
8216
 
    *latP = 0.0;
8217
 
  }
8218
 
  if (lonP != NULL) {
8219
 
    *lonP = 0.0;
8220
 
  }
8221
 
 
8222
 
  if (StringHasNoText (lat_lon)) return FALSE;
8223
 
 
8224
 
  if (sscanf (lat_lon, "%lf %c %lf %c", &lat, &ns, &lon, &ew) == 4) {
8225
 
    if (lon < -180.0) {
8226
 
      lon = -180.0;
8227
 
    }
8228
 
    if (lat < -90.0) {
8229
 
      lat = -90.0;
8230
 
    }
8231
 
    if (lon > 180.0) {
8232
 
      lon = 180.0;
8233
 
    }
8234
 
    if (lat > 90.0) {
8235
 
      lat = 90.0;
8236
 
    }
8237
 
    if (ew == 'W') {
8238
 
      lon = -lon;
8239
 
    }
8240
 
    if (ns == 'S') {
8241
 
      lat = -lat;
8242
 
    }
8243
 
 
8244
 
    if (latP != NULL) {
8245
 
      *latP = (FloatHi) lat;
8246
 
    }
8247
 
    if (lonP != NULL) {
8248
 
      *lonP = (FloatHi) lon;
8249
 
    }
8250
 
 
8251
 
    return TRUE;
8252
 
  }
8253
 
 
8254
 
  return FALSE;
8255
 
}
8256
 
 
8257
 
 
8258
8546
 
8259
8547
static CharPtr GetDash (CharPtr str)
8260
8548
 
9049
9337
*      Gather callback helper function for validating context on a Bioseq
9050
9338
*
9051
9339
*****************************************************************************/
9052
 
static void ValidateBioSource (ValidStructPtr vsp, GatherContextPtr gcp, BioSourcePtr biop, SeqFeatPtr sfp)
 
9340
static void ValidateBioSource (ValidStructPtr vsp, GatherContextPtr gcp, BioSourcePtr biop, SeqFeatPtr sfp, ValNodePtr sdp)
9053
9341
{
9054
9342
  Char            badch;
9055
9343
  Boolean         bad_frequency;
 
9344
  BioseqPtr       bsp;
 
9345
  BioseqSetPtr    bssp;
9056
9346
  Char            buf [256];
9057
 
  CharPtr         casecounts;
9058
9347
  Char            ch;
9059
9348
  Boolean         chromconf = FALSE;
9060
9349
  Int2            chromcount = 0;
9063
9352
  ValNodePtr      db;
9064
9353
  DbtagPtr        dbt;
9065
9354
  Boolean         format_ok;
 
9355
  CharPtr         gb_synonym = NULL;
9066
9356
  Boolean         germline = FALSE;
9067
9357
  CharPtr         guess = NULL;
9068
9358
  Boolean         has_strain = FALSE;
9069
9359
  Boolean         has_fwd_pcr_seq = FALSE;
9070
9360
  Boolean         has_rev_pcr_seq = FALSE;
9071
9361
  Boolean         has_pcr_name = FALSE;
9072
 
  Int2            i;
 
9362
  Boolean         has_metagenome_source = FALSE;
9073
9363
  Int4            id;
9074
9364
  Boolean         is_env_sample = FALSE;
9075
9365
  Boolean         is_iso_source = FALSE;
9076
9366
  Boolean         is_metagenomic = FALSE;
9077
9367
  Boolean         is_specific_host = FALSE;
9078
9368
  Boolean         is_transgenic = FALSE;
 
9369
  Boolean         isViral = FALSE;
9079
9370
  CharPtr         last_db = NULL;
9080
9371
  FloatHi         lat = 0.0;
9081
9372
  FloatHi         lon = 0.0;
9082
9373
  CharPtr         lat_lon = NULL;
9083
9374
  Boolean         lat_in_range;
9084
9375
  Boolean         lon_in_range;
 
9376
  Boolean         old_country = FALSE;
9085
9377
  OrgNamePtr      onp;
9086
9378
  OrgModPtr       omp;
9087
9379
  OrgRefPtr       orp;
 
9380
  ObjValNodePtr   ovp;
9088
9381
  Int4            primer_len_before;
9089
9382
  Int4            primer_len_after;
9090
9383
  ValNodePtr      pset;
9091
9384
  CharPtr         ptr;
9092
9385
  Boolean         rearranged = FALSE;
 
9386
  SeqEntryPtr     sep;
9093
9387
  ErrSev          sev;
9094
9388
  SubSourcePtr    ssp;
9095
9389
  CharPtr         str;
9096
9390
  Boolean         strict = TRUE;
 
9391
  CharPtr         synonym = NULL;
9097
9392
  Char            tmp [128];
 
9393
  Int4            dbvalid;
 
9394
  CharPtr         dbxerr;
9098
9395
 
9099
9396
  if (vsp->sourceQualTags == NULL) {
9100
9397
    InitializeSourceQualTags (vsp);
9105
9402
    ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_ObsoleteSourceLocation,
9106
9403
              "Transposon and insertion sequence are no longer legal locations");
9107
9404
  }
 
9405
 
 
9406
  orp = biop->org;
 
9407
  if (orp != NULL) {
 
9408
    onp = orp->orgname;
 
9409
    if (onp != NULL) {
 
9410
      if (StringNICmp (onp->lineage, "Viruses; ", 9) == 0) {
 
9411
        isViral = TRUE;
 
9412
      }
 
9413
    }
 
9414
  }
 
9415
 
9108
9416
  ssp = biop->subtype;
9109
9417
  while (ssp != NULL) {
9110
9418
    if (ssp->subtype == SUBSRC_country) {
9112
9420
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BadCountryCode, "Multiple country names on BioSource");
9113
9421
      }
9114
9422
      countryname = ssp->name;
9115
 
      if (! CountryIsValid (countryname)) {
 
9423
      if (! CountryIsValid (countryname, &old_country)) {
9116
9424
        if (StringHasNoText (countryname)) {
9117
9425
          countryname = "?";
9118
9426
        }
9119
 
        ValidErr (vsp, SEV_ERROR, ERR_SEQ_DESCR_BadCountryCode, "Bad country name [%s]", countryname);
 
9427
        if (old_country) {
 
9428
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BadCountryCode, "Replaced country name [%s]", countryname);
 
9429
        } else {
 
9430
          ValidErr (vsp, SEV_ERROR, ERR_SEQ_DESCR_BadCountryCode, "Bad country name [%s]", countryname);
 
9431
        }
9120
9432
      }
9121
9433
    } else if (ssp->subtype == SUBSRC_chromosome) {
9122
9434
      chromcount++;
9166
9478
      }
9167
9479
    } else if (ssp->subtype == SUBSRC_isolation_source) {
9168
9480
      is_iso_source = TRUE;
9169
 
     } else if (ssp->subtype == SUBSRC_plasmid_name) {
 
9481
    } else if (ssp->subtype == SUBSRC_plasmid_name) {
9170
9482
      if (biop->genome != GENOME_plasmid) {
9171
9483
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plasmid subsource but not plasmid location");
9172
9484
      }
 
9485
    } else if (ssp->subtype == SUBSRC_plastid_name) {
 
9486
      if (StringCmp (ssp->name, "chloroplast") == 0) {
 
9487
        if (biop->genome != GENOME_chloroplast) {
 
9488
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plastid name subsource chloroplast but not chloroplast location");
 
9489
        }
 
9490
      } else if (StringCmp (ssp->name, "chromoplast") == 0) {
 
9491
        if (biop->genome != GENOME_chromoplast) {
 
9492
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plastid name subsource chromoplast but not chromoplast location");
 
9493
        }
 
9494
      } else if (StringCmp (ssp->name, "kinetoplast") == 0) {
 
9495
        if (biop->genome != GENOME_kinetoplast) {
 
9496
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plastid name subsource kinetoplast but not kinetoplast location");
 
9497
        }
 
9498
      } else if (StringCmp (ssp->name, "plastid") == 0) {    
 
9499
        if (biop->genome != GENOME_plastid) {
 
9500
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plastid name subsource plastid but not plastid location");
 
9501
        }
 
9502
      } else if (StringCmp (ssp->name, "apicoplast") == 0) {  
 
9503
        if (biop->genome != GENOME_apicoplast) {
 
9504
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plastid name subsource apicoplast but not apicoplast location");
 
9505
        }
 
9506
      } else if (StringCmp (ssp->name, "leucoplast") == 0) {  
 
9507
        if (biop->genome != GENOME_leucoplast) {
 
9508
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plastid name subsource leucoplast but not leucoplast location");
 
9509
        }
 
9510
      } else if (StringCmp (ssp->name, "proplastid") == 0) {  
 
9511
        if (biop->genome != GENOME_proplastid) {
 
9512
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plastid name subsource proplastid but not proplastid location");
 
9513
        }
 
9514
      } else {
 
9515
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Plastid name subsource contains unrecognized value");
 
9516
      }  
9173
9517
    } else if (ssp->subtype == SUBSRC_collection_date) {
9174
9518
      if (! CollectionDateIsValid (ssp->name)) {
9175
9519
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BadCollectionDate, "Collection_date format is not in DD-Mmm-YYYY format");
9258
9602
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "bad frequency qualifier value %s", ssp->name);
9259
9603
        }
9260
9604
      }
 
9605
    } else if (ssp->subtype == SUBSRC_sex && isViral) {
 
9606
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Virus has unexpected sex qualifier");
 
9607
    } else if (ssp->subtype == SUBSRC_cell_line && isViral) {
 
9608
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Virus has unexpected cell_line qualifier");
 
9609
    } else if (ssp->subtype == SUBSRC_cell_type && isViral) {
 
9610
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Virus has unexpected cell_type qualifier");
 
9611
    } else if (ssp->subtype == SUBSRC_tissue_type && isViral) {
 
9612
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Virus has unexpected tissue_type qualifier");
9261
9613
    }
9262
9614
    ssp = ssp->next;
9263
9615
  }
9330
9682
        */
9331
9683
        } else if (TestLatLonForCountry (buf, lon, lat)) {
9332
9684
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_LatLonValue, "Latitude and longitude values appear to be exchanged");
 
9685
        /*
9333
9686
        } else if (strict) {
9334
 
          /* single unqualified country name, report at info level for now */
9335
9687
          ValidErr (vsp, SEV_INFO, ERR_SEQ_DESCR_LatLonCountry, "Lat_lon '%s' does not map to '%s'", lat_lon, buf);
 
9688
        */
9336
9689
        } else {
9337
9690
          if (vsp->strictLatLonCountry || (! StringContainsBodyOfWater (countryname))) {
9338
9691
            guess = GuessCountryForLatLon (lat, lon);
9398
9751
      if (biop->genome != GENOME_proviral && biop->genome != GENOME_virion) {
9399
9752
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "HIV should be proviral or virion");
9400
9753
      }
 
9754
    } else if (StringICmp (orp->taxname, "uncultured bacterium") == 0) {
 
9755
      bsp = NULL;
 
9756
      if (sfp != NULL) {
 
9757
        bsp = BioseqFindFromSeqLoc (sfp->location);
 
9758
      } else if (sdp != NULL && sdp->extended != 0) {
 
9759
        ovp = (ObjValNodePtr) sdp;
 
9760
        if (ovp->idx.parenttype == OBJ_BIOSEQ) {
 
9761
          bsp = (BioseqPtr) ovp->idx.parentptr;
 
9762
        } else if (ovp->idx.parenttype == OBJ_BIOSEQSET) {
 
9763
          bssp = (BioseqSetPtr) ovp->idx.parentptr;
 
9764
          if (bssp != NULL) {
 
9765
            sep = bssp->seqentry;
 
9766
            if (sep != NULL) {
 
9767
              sep = FindNthBioseq (sep, 1);
 
9768
              if (sep != NULL && IS_Bioseq (sep)) {
 
9769
                bsp = (BioseqPtr) sep->data.ptrvalue;
 
9770
              }
 
9771
            }
 
9772
          }
 
9773
        }
 
9774
      }
 
9775
      if (bsp != NULL && bsp->length >= 10000) {
 
9776
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Uncultured bacterium sequence length is suspiciously high");
 
9777
      }
 
9778
    }
 
9779
    if (StringNICmp (orp->taxname, "uncultured ", 11) == 0) {
 
9780
      if (! is_env_sample) {
 
9781
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Uncultured should also have /environmental_sample");
 
9782
      }
9401
9783
    }
9402
9784
  }
9403
9785
  if (orp == NULL || (StringHasNoText (orp->taxname) && StringHasNoText (orp->common))) {
9435
9817
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BadOrganelle, "Only Chlorarachniophyceae and Cryptophyta have nucleomorphs");
9436
9818
      }
9437
9819
    }
 
9820
 
 
9821
    /* warn if bacteria has organelle location */
 
9822
    if (StringCmp (onp->div, "BCT") == 0 
 
9823
        && biop->genome != GENOME_unknown 
 
9824
        && biop->genome != GENOME_genomic
 
9825
        && biop->genome != GENOME_plasmid) {
 
9826
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Bacterial source should not have organelle location");
 
9827
    }
9438
9828
  }
9439
9829
  for (db = orp->db; db != NULL; db = db->next) {
9440
9830
    dbt = (DbtagPtr) db->data.ptrvalue;
9458
9848
        }
9459
9849
        has_strain = TRUE;
9460
9850
      } else if (omp->subtype == ORGMOD_variety) {
9461
 
        if ((! StringHasNoText (onp->div)) && StringICmp (onp->div, "PLN") != 0) {
9462
 
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BadOrgMod, "Orgmod variety should only be in plants or fungi");
 
9851
        if ((! StringHasNoText (onp->div)) && StringICmp (onp->div, "PLN") != 0 && StringStr (onp->lineage, "Cyanobacteria") == 0) {
 
9852
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BadOrgMod, "Orgmod variety should only be in plants, fungi, or cyanobacteria");
9463
9853
        }
9464
9854
        ValidateOrgModInTaxName (vsp, omp, orp->taxname);
9465
9855
      } else if (omp->subtype == ORGMOD_nat_host) {
9466
9856
        is_specific_host = TRUE;
 
9857
        if (StringICmp (omp->subname, orp->taxname) == 0) {
 
9858
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BadOrgMod, "Specific host is identical to taxname");
 
9859
        }
9467
9860
      } else if (omp->subtype == ORGMOD_other) {
9468
9861
        ValidateSourceQualTags (vsp, gcp, biop, omp->subname);
9469
9862
      } else if (omp->subtype == ORGMOD_biovar
9472
9865
                 || omp->subtype == ORGMOD_sub_species
9473
9866
                 || omp->subtype == ORGMOD_pathovar) {         
9474
9867
        ValidateOrgModInTaxName (vsp, omp, orp->taxname);
 
9868
      } else if (omp->subtype == ORGMOD_metagenome_source) {
 
9869
        has_metagenome_source = TRUE;
 
9870
      } else if (omp->subtype == ORGMOD_common) {
 
9871
        if (StringICmp (omp->subname, orp->common) == 0) {
 
9872
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BadOrgMod, "OrgMod common is identical to Org-ref common");
 
9873
        }
 
9874
      } else if (omp->subtype == ORGMOD_synonym) {
 
9875
        synonym = omp->subname;
 
9876
      } else if (omp->subtype == ORGMOD_gb_synonym) {
 
9877
        gb_synonym = omp->subname;
9475
9878
      }
9476
9879
      omp = omp->next;
9477
9880
    }
9482
9885
  if (is_env_sample && (! is_iso_source) && (! is_specific_host)) {
9483
9886
    ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Environmental sample should also have isolation source or specific host annotated");
9484
9887
  }
 
9888
  if (has_metagenome_source && (! is_metagenomic)) {
 
9889
    ValidErr (vsp, SEV_ERROR, ERR_SEQ_DESCR_BioSourceInconsistency, "Metagenome source should also have metagenomic qualifier");
 
9890
  }
 
9891
  if (StringDoesHaveText (synonym) && StringDoesHaveText (gb_synonym)) {
 
9892
    if (StringICmp (synonym, gb_synonym) == 0) {
 
9893
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "OrgMod synonym is identical to OrgMod gb_synonym");
 
9894
    }
 
9895
  }
9485
9896
 
9486
9897
  for (db = orp->db; db != NULL; db = db->next) {
9487
9898
    id = -1;
9488
9899
    dbt = (DbtagPtr) db->data.ptrvalue;
9489
9900
    if (dbt != NULL && dbt->db != NULL) {
9490
 
      casecounts = NULL;
9491
 
      for (i = 0; legalDbXrefs [i] != NULL; i++) {
9492
 
        if (StringCmp (dbt->db, legalDbXrefs [i]) == 0) {
9493
 
          id = i;
9494
 
          break;
9495
 
        } else if (StringICmp (dbt->db, legalDbXrefs [i]) == 0) {
9496
 
          casecounts = legalDbXrefs [i];
9497
 
        }
9498
 
      }
9499
 
      if (id == -1 || id < 4) {
9500
 
        if (StringDoesHaveText (casecounts)) {
9501
 
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_IllegalDbXref, "Illegal db_xref type %s, legal capitalization is %s", dbt->db, casecounts);
9502
 
        } else {
9503
 
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_IllegalDbXref, "Illegal db_xref type %s", dbt->db);
9504
 
        }
9505
 
      }
9506
 
    }
9507
 
  }
9508
 
 
9509
 
  if (sfp != NULL) {
9510
 
    for (db = sfp->dbxref; db != NULL; db = db->next) {
9511
 
      dbt = (DbtagPtr) db->data.ptrvalue;
9512
 
      if (dbt != NULL) {
9513
 
        if (StringICmp (dbt->db, "taxon") == 0) {
9514
 
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_TaxonDbxrefOnFeature, "BioSource feature has taxon xref in common feature db_xref list");
9515
 
        }
9516
 
      }
 
9901
      dbxerr = NULL;
 
9902
      dbvalid = IsDbxrefValid (dbt->db, NULL, orp, FALSE, &dbxerr);
 
9903
      if (dbxerr != NULL) {
 
9904
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_IllegalDbXref, dbxerr);
 
9905
        dbxerr = MemFree (dbxerr);
 
9906
      } 
9517
9907
    }
9518
9908
  }
9519
9909
 
9861
10251
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_InvalidForType, "Molinfo-biomol other should be used if Biosource-location is synthetic");
9862
10252
      }
9863
10253
    }
9864
 
    /* ValidateBioSource (vsp, gcp, biop, NULL); */
 
10254
    /* ValidateBioSource (vsp, gcp, biop, NULL, vnp); */
9865
10255
    this_org = biop->org;
9866
10256
    /* fall into Seq_descr_org */
9867
10257
  case Seq_descr_org:
10205
10595
  return FALSE;
10206
10596
}
10207
10597
 
 
10598
static Boolean IsEMBLAccn (SeqEntryPtr sep, SeqLocPtr location)
 
10599
{
 
10600
  BioseqPtr  bsp;
 
10601
  SeqIdPtr   sip;
 
10602
 
 
10603
  bsp = BioseqFindFromSeqLoc (location);
 
10604
  if (bsp != NULL) {
 
10605
    for (sip = bsp->id; sip != NULL; sip = sip->next) {
 
10606
      if (sip->choice == SEQID_EMBL) return TRUE;
 
10607
    }
 
10608
  }
 
10609
  return FALSE;
 
10610
}
 
10611
 
10208
10612
static Boolean IsGeneralAccn (SeqEntryPtr sep, SeqLocPtr location)
10209
10613
{
10210
10614
  BioseqPtr  bsp;
10836
11240
 
10837
11241
{
10838
11242
  BioSourcePtr       biop;
 
11243
  ValNodePtr         cdshead = NULL;
 
11244
  ValNodePtr         cdstail = NULL;
10839
11245
  SeqMgrDescContext  dcontext;
10840
11246
  SeqMgrFeatContext  fcontext, rcontext;
10841
11247
  GatherContextPtr   gcp;
10846
11252
  Int2               i, j, k, numfeats, tmpnumcds, tmpnummrna, count;
10847
11253
  Boolean            is_genbank = FALSE;
10848
11254
  LpData             ld;
 
11255
  Int2               num_no_mrna = 0;
10849
11256
  Int4               num_repeat_regions;
10850
11257
  Uint2              olditemtype = 0;
10851
11258
  Uint4              olditemid = 0;
10859
11266
  SeqFeatPtr         sfp;
10860
11267
  SeqIdPtr           sip;
10861
11268
  VvmDataPtr         vdp;
 
11269
  ValNodePtr         vnp;
10862
11270
 
10863
11271
  if (vsp == NULL || bsp == NULL) return;
10864
11272
  if (! ISA_na (bsp->mol)) return;
11078
11486
          rpt_region = SeqMgrGetOverlappingFeature (sfp->location, 0, repeat_region_array, num_repeat_regions,
11079
11487
                                                    NULL, CONTAINED_WITHIN, &rcontext);
11080
11488
          if (rpt_region == NULL) {
 
11489
            /*
11081
11490
            if (gcp != NULL) {
11082
11491
              gcp->itemID = sfp->idx.itemID;
11083
11492
              gcp->thistype = OBJ_SEQFEAT;
11085
11494
            vsp->descr = NULL;
11086
11495
            vsp->sfp = sfp;
11087
11496
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_CDSwithNoMRNAOverlap, "CDS overlapped by 0 mRNAs");
 
11497
            */
 
11498
            vnp = ValNodeAddPointer (&cdstail, 0, (Pointer) sfp);
 
11499
            if (cdshead == NULL) {
 
11500
              cdshead = vnp;
 
11501
            }
 
11502
            cdstail = vnp;
 
11503
            num_no_mrna++;
11088
11504
          }
11089
11505
        }
11090
11506
      }
11094
11510
 
11095
11511
  MemFree (repeat_region_array);
11096
11512
 
 
11513
  if (num_no_mrna > 0) {
 
11514
    if (num_no_mrna >= 10) {
 
11515
      if (gcp != NULL) {
 
11516
        gcp->itemID = olditemid;
 
11517
        gcp->thistype = olditemtype;
 
11518
      }
 
11519
      vsp->descr = NULL;
 
11520
      vsp->sfp = NULL;
 
11521
      vsp->bsp = bsp;
 
11522
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_CDSwithNoMRNAOverlap,
 
11523
                "%d out of %d CDSs overlapped by 0 mRNAs", (int) num_no_mrna, (int) numcds);
 
11524
    } else {
 
11525
      for (vnp = cdshead; vnp != NULL; vnp = vnp->next) {
 
11526
        sfp = (SeqFeatPtr) vnp->data.ptrvalue;
 
11527
        if (sfp == NULL) continue;
 
11528
        if (gcp != NULL) {
 
11529
          gcp->itemID = sfp->idx.itemID;
 
11530
          gcp->thistype = OBJ_SEQFEAT;
 
11531
        }
 
11532
        vsp->descr = NULL;
 
11533
        vsp->sfp = sfp;
 
11534
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_CDSwithNoMRNAOverlap, "CDS overlapped by 0 mRNAs");
 
11535
      }
 
11536
    }
 
11537
  }
 
11538
 
 
11539
  ValNodeFree (cdshead);
 
11540
 
11097
11541
  if (gcp != NULL) {
11098
11542
    gcp->itemID = olditemid;
11099
11543
    gcp->thistype = olditemtype;
11138
11582
static Int2 WhichRNA (SeqFeatPtr sfp)
11139
11583
 
11140
11584
{
 
11585
  GBQualPtr  gbq;
11141
11586
  RnaRefPtr  rrp;
11142
11587
  CharPtr    str;
11143
11588
 
11168
11613
    if (StringNICmp (str, "23 ", 3) == 0) return RIGHT_RIBOSOMAL_SUBUNIT;
11169
11614
  }
11170
11615
  if (rrp->type == 255) {
 
11616
    if (StringICmp (str, "misc_RNA") == 0) {
 
11617
      for (gbq = sfp->qual; gbq != NULL; gbq = gbq->next) {
 
11618
        if (StringICmp (gbq->qual, "product") != 0) continue;
 
11619
        if (StringHasNoText (gbq->val)) continue;
 
11620
        str = gbq->val;
 
11621
      }
 
11622
    }
11171
11623
    if (StringICmp (str, "internal transcribed spacer 1") == 0) return INTERNAL_SPACER_1;
11172
11624
    if (StringICmp (str, "internal transcribed spacer 2") == 0) return INTERNAL_SPACER_2;
11173
11625
    /* variant spellings */
11285
11737
)
11286
11738
 
11287
11739
{
 
11740
  BioseqPtr         bsp;
11288
11741
  Int4              dashes;
11289
11742
  Int2              first = 0;
11290
11743
  GatherContextPtr  gcp;
11291
11744
  Int2              last = 0;
 
11745
  Int4              len;
 
11746
  SeqLocPtr         loc;
 
11747
  Boolean           needToStream = TRUE;
11292
11748
  Int4              Ns;
11293
11749
  Uint2             olditemtype = 0;
11294
11750
  Uint4             olditemid = 0;
11295
11751
  Int4              plusses;
 
11752
  Int2              prefix = 0;
 
11753
  Int2              suffix = 0;
11296
11754
  Int4              realBases;
11297
11755
  Int2              res;
11298
11756
  StreamCache       sc;
 
11757
  SeqIntPtr         sintp;
11299
11758
  ValidStructPtr    vsp;
11300
11759
 
11301
11760
  if (sfp == NULL || fcontext == NULL) return FALSE;
11305
11764
  if (gcp == NULL) return FALSE;
11306
11765
 
11307
11766
  if (sfp->idx.subtype == FEATDEF_gap) return TRUE;
 
11767
  loc = sfp->location;
 
11768
  if (loc == NULL) return TRUE;
11308
11769
 
11309
11770
  olditemid = gcp->itemID;
11310
11771
  olditemtype = gcp->thistype;
11319
11780
  Ns = 0;
11320
11781
  realBases = 0;
11321
11782
 
11322
 
  if (StreamCacheSetup (NULL, sfp->location, EXPAND_GAPS_TO_DASHES | KNOWN_GAP_AS_PLUS, &sc)) {
 
11783
  /* special check for single interval misc_features that may exactly cover a gap */
 
11784
  if (loc->choice == SEQLOC_INT && sfp->idx.subtype == FEATDEF_misc_feature) {
 
11785
    sintp = (SeqIntPtr) loc->data.ptrvalue;
 
11786
    if (sintp != NULL) {
 
11787
      bsp = BioseqFind (sintp->id);
 
11788
      if (bsp != NULL && sintp->from > 0 && sintp->to < bsp->length - 1) {
 
11789
        len = SeqLocLen (loc);
 
11790
        if (StreamCacheSetup (bsp, NULL, EXPAND_GAPS_TO_DASHES | KNOWN_GAP_AS_PLUS, &sc)) {
 
11791
          StreamCacheSetPosition (&sc, sintp->from - 1);
 
11792
          prefix = StreamCacheGetResidue (&sc);
 
11793
          while ((res = StreamCacheGetResidue (&sc)) != '\0' && len > 0) {
 
11794
            if (IS_LOWER (res)) {
 
11795
              res = TO_UPPER (res);
 
11796
            }
 
11797
            if (first == 0) {
 
11798
              first = res;
 
11799
            }
 
11800
            last = res;
 
11801
            if (res == '-') {
 
11802
              dashes++;
 
11803
            } else if (res == '+') {
 
11804
              plusses++;
 
11805
            } else if (res == 'N') {
 
11806
              Ns++;
 
11807
            } else if (res != 0) {
 
11808
              realBases++;
 
11809
            }
 
11810
            len--;
 
11811
          }
 
11812
          suffix = StreamCacheGetResidue (&sc);
 
11813
          needToStream = FALSE;
 
11814
        }
 
11815
      }
 
11816
    }
 
11817
  }
 
11818
 
 
11819
  if (needToStream && StreamCacheSetup (NULL, loc, EXPAND_GAPS_TO_DASHES | KNOWN_GAP_AS_PLUS, &sc)) {
11323
11820
    while ((res = StreamCacheGetResidue (&sc)) != '\0') {
11324
11821
      if (IS_LOWER (res)) {
11325
11822
        res = TO_UPPER (res);
11334
11831
        plusses++;
11335
11832
      } else if (res == 'N') {
11336
11833
        Ns++;
11337
 
      } else {
 
11834
      } else if (res != 0) {
11338
11835
        realBases++;
11339
11836
      }
11340
11837
    }
11344
11841
    /* ignore features that do not cover any gap characters */
11345
11842
  } else if (first == '-' || first == '+' || last == '-' || last == '+') {
11346
11843
    if (realBases > 0) {
11347
 
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureCrossesGap, "Feature crosses sequence gap");
 
11844
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureBeginsOrEndsInGap, "Feature begins or ends in gap");
 
11845
    } else if (IS_ALPHA (prefix) && IS_ALPHA (suffix)) {
 
11846
      /* ignore (misc_) features that exactly cover the gap */
11348
11847
    } else {
11349
11848
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureInsideGap, "Feature inside sequence gap");
11350
11849
    }
11352
11851
    /* ignore genes, unless they start or stop in a gap */
11353
11852
  } else if (dashes == 0 && plusses == 0 && Ns > 0) {
11354
11853
    if (realBases > 0) {
 
11854
      /*
11355
11855
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureCrossesGap, "Feature crosses gap of Ns");
 
11856
      */
11356
11857
    } else {
11357
11858
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureInsideGap, "Feature inside gap of Ns");
11358
11859
    }
11359
11860
  } else if (dashes > 0) {
11360
11861
    if (realBases > 0) {
11361
11862
      if (sfp->idx.subtype == FEATDEF_CDS || sfp->idx.subtype == FEATDEF_mRNA) {
11362
 
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureCrossesGap, "Feature crosses sequence gap");
 
11863
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureCrossesGap, "Feature crosses gap of unknown length");
11363
11864
      }
11364
11865
    } else {
11365
 
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureInsideGap, "Feature inside sequence gap");
 
11866
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_FeatureInsideGap, "Feature inside gap of unknown length");
11366
11867
    }
11367
11868
  } else if (plusses > 0) {
11368
11869
    if (realBases > 0) {
11381
11882
  return TRUE;
11382
11883
}
11383
11884
 
 
11885
static Boolean LIBCALLBACK MarkFeatsInGaps (
 
11886
  SeqFeatPtr sfp,
 
11887
  SeqMgrFeatContextPtr fcontext
 
11888
)
 
11889
 
 
11890
{
 
11891
  VvmDataPtr         vdp;
 
11892
 
 
11893
  if (sfp == NULL) return TRUE;
 
11894
  vdp = (VvmDataPtr) sfp->idx.scratch;
 
11895
  if (vdp == NULL) return TRUE;
 
11896
 
 
11897
  vdp->feat_touches_gap = TRUE;
 
11898
 
 
11899
  return TRUE;
 
11900
}
 
11901
 
11384
11902
static void CheckBioseqForFeatsInGap (
11385
11903
  BioseqPtr bsp,
11386
11904
  ValidStructPtr vsp
11387
11905
)
11388
11906
 
11389
11907
{
11390
 
  Int4         currpos = 0;
11391
 
  SeqLitPtr    litp;
11392
 
  SeqInt       si;
11393
 
  SeqIdPtr     sip;
11394
 
  SeqLoc       sl;
11395
 
  SeqLocPtr    slp;
11396
 
  ValNodePtr   vnp;
 
11908
  Int4               currpos = 0;
 
11909
  SeqMgrFeatContext  fcontext;
 
11910
  SeqLitPtr          litp;
 
11911
  SeqFeatPtr         sfp;
 
11912
  SeqInt             si;
 
11913
  SeqIdPtr           sip;
 
11914
  SeqLoc             sl;
 
11915
  SeqLocPtr          slp;
 
11916
  VvmDataPtr         vdp;
 
11917
  ValNodePtr         vnp;
11397
11918
 
11398
11919
  if (bsp == NULL || bsp->repr != Seq_repr_delta || ISA_aa (bsp->mol)) return;
11399
11920
  sip = SeqIdFindBest (bsp->id, 0);
11417
11938
        si.id = sip;
11418
11939
        sl.choice = SEQLOC_INT;
11419
11940
        sl.data.ptrvalue = (Pointer) &si;
11420
 
        SeqMgrExploreFeatures (bsp, (Pointer) vsp, GetFeatsInGaps, &sl, NULL, NULL);
 
11941
        SeqMgrExploreFeatures (bsp, (Pointer) vsp, MarkFeatsInGaps, &sl, NULL, NULL);
 
11942
        /* SeqMgrExploreFeatures (bsp, (Pointer) vsp, GetFeatsInGaps, &sl, NULL, NULL); */
11421
11943
      }
11422
11944
      currpos += litp->length;
11423
11945
    }
11424
11946
  }
 
11947
 
 
11948
  sfp = SeqMgrGetNextFeature (bsp, NULL, 0, 0, &fcontext);
 
11949
  while (sfp != NULL) {
 
11950
    vdp = (VvmDataPtr) sfp->idx.scratch;
 
11951
    if (vdp != NULL && vdp->feat_touches_gap) {
 
11952
      fcontext.userdata = (Pointer) vsp;
 
11953
      GetFeatsInGaps (sfp, &fcontext);
 
11954
    }
 
11955
    sfp = SeqMgrGetNextFeature (bsp, sfp, 0, 0, &fcontext);
 
11956
  }
11425
11957
}
11426
11958
 
11427
11959
static Boolean ValidateBioseqContextIndexed (BioseqPtr bsp, BioseqValidStrPtr bvsp)
11872
12404
                if (suppress_duplicate_messages && (featdeftype == FEATDEF_CDS || featdeftype == FEATDEF_mRNA) && HaveUniqueFeatIDXrefs (xref, sfp->xref)) {
11873
12405
                  /* do not report CDS or mRNA if every one has a unique product and unique featID xrefs */
11874
12406
                } else {
11875
 
                  ValidErr (vsp, severity, ERR_SEQ_FEAT_DuplicateFeat, "Features have identical intervals, but labels differ (packaged in different feature table)");
 
12407
                  ValidErr (vsp, /* severity */ SEV_WARNING, ERR_SEQ_FEAT_DuplicateFeat, "Features have identical intervals, but labels differ (packaged in different feature table)");
11876
12408
                }
11877
12409
              }
11878
12410
            }
12642
13174
  Boolean         is_neg_strand_virus = FALSE;
12643
13175
  Boolean         is_ambisense_virus = FALSE;
12644
13176
  Boolean         is_transgenic = FALSE;
 
13177
  Boolean         has_cds = FALSE;
12645
13178
  ErrSev          sev;
12646
13179
  SubSourcePtr    ssp;
12647
13180
  CharPtr         str;
12804
13337
 
12805
13338
    sfp = SeqMgrGetNextFeature (bsp, NULL, SEQFEAT_CDREGION, 0, &fcontext);
12806
13339
    while (sfp != NULL) {
 
13340
      has_cds = TRUE;
12807
13341
      if (SeqLocStrand (sfp->location) == Seq_strand_minus) {
12808
13342
        if (mip->biomol != MOLECULE_TYPE_GENOMIC) {
12809
13343
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Negative-strand virus with minus strand CDS should be genomic");
12815
13349
      }
12816
13350
      sfp = SeqMgrGetNextFeature (bsp, sfp, SEQFEAT_CDREGION, 0, &fcontext);
12817
13351
    }
 
13352
    if (! has_cds) {
 
13353
      sfp = SeqMgrGetNextFeature (bsp, NULL, 0, FEATDEF_misc_feature, &fcontext);
 
13354
      while (sfp != NULL) {
 
13355
        if (StringISearch (sfp->comment, "nonfunctional") != NULL) {
 
13356
          if (SeqLocStrand (sfp->location) == Seq_strand_minus) {
 
13357
            if (mip->biomol != MOLECULE_TYPE_GENOMIC) {
 
13358
              ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Negative-strand virus with nonfunctional minus strand misc_feature should be mRNA or cRNA");
 
13359
            }
 
13360
          } else {
 
13361
            if (mip->biomol != MOLECULE_TYPE_MRNA && mip->biomol != MOLECULE_TYPE_CRNA && (! is_ambisense_virus)) {
 
13362
              ValidErr (vsp, SEV_WARNING, ERR_SEQ_DESCR_BioSourceInconsistency, "Negative-strand virus with nonfunctional plus strand misc_feature should be mRNA or cRNA");
 
13363
            }
 
13364
          }
 
13365
        }
 
13366
        sfp = SeqMgrGetNextFeature (bsp, sfp, 0, FEATDEF_misc_feature, &fcontext);
 
13367
      }
 
13368
    }
12818
13369
 
12819
13370
    gcp->entityID = oldEntityID;
12820
13371
    gcp->itemID = oldItemID;
14120
14671
NLM_EXTERN void ECNumberFSAFreeAll (void)
14121
14672
 
14122
14673
{
14123
 
  CtListPtr   clp;
 
14674
  CtSetPtr    csp;
14124
14675
  TextFsaPtr  fsa;
14125
14676
 
14126
14677
  fsa = (TextFsaPtr) GetAppProperty ("SpecificECNumberFSA");
14153
14704
    TextFsaFree (fsa);
14154
14705
  }
14155
14706
 
14156
 
  clp = (CtListPtr) GetAppProperty ("CountryLatLonList");
14157
 
  if (clp != NULL) {
 
14707
  csp = (CtSetPtr) GetAppProperty ("CountryLatLonList");
 
14708
  if (csp != NULL) {
14158
14709
    SetAppProperty ("CountryLatLonList", NULL);
14159
 
    CtLatLonDataFree (clp);
 
14710
    CtSetDataFree (csp);
14160
14711
  }
14161
14712
}
14162
14713
 
14723
15274
          if (!found) {
14724
15275
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_InvalidQualifierValue, "%s is not a legal value for qualifier %s", gbqual->val, gbqual->qual);
14725
15276
          }
 
15277
        } else if (val == GBQUAL_frequency) {
 
15278
          if (StringCmp (gbqual->val, "1") == 0 || StringCmp (gbqual->val, "1.0") == 0 || StringCmp (gbqual->val, "1.00") == 0) {
 
15279
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_InvalidQualifierValue, "%s is a suspicious value for qualifier %s", gbqual->val, gbqual->qual);
 
15280
          }
14726
15281
        } else if (val == GBQUAL_compare) {
14727
15282
          multi_compare = FALSE;
14728
15283
          ptr = gbqual->val;
15157
15712
  return rsult;
15158
15713
}
15159
15714
 
 
15715
 
 
15716
static void 
 
15717
ValidateIntronEndsAtSpliceSiteOrGap 
 
15718
(ValidStructPtr vsp, 
 
15719
 SeqLocPtr slp)
 
15720
{
 
15721
  BioseqPtr       bsp;
 
15722
  SeqIdPtr        sip;
 
15723
  Uint1           strand;
 
15724
  Int4            strt, stop, pos;
 
15725
  Boolean         partial5, partial3;
 
15726
  Char            buf[3];
 
15727
  Char            id_buf[150];
 
15728
 
 
15729
  if (slp == NULL) return;
 
15730
  CheckSeqLocForPartial (slp, &partial5, &partial3);
 
15731
  if (partial5 && partial3) return;
 
15732
 
 
15733
  sip = SeqLocId (slp);
 
15734
  if (sip == NULL)
 
15735
    return;
 
15736
  
 
15737
  bsp = NULL;
 
15738
  if (sip != NULL && (sip->choice != SEQID_GI || sip->data.intvalue > 0)) {
 
15739
    bsp = BioseqLockById (sip);
 
15740
  }
 
15741
  if (bsp == NULL)
 
15742
    return;
 
15743
 
 
15744
  BioseqLabel (bsp, id_buf, sizeof (id_buf) - 1, OM_LABEL_CONTENT);
 
15745
 
 
15746
  strt = SeqLocStart (slp);
 
15747
  stop = SeqLocStop (slp);
 
15748
 
 
15749
  strand = SeqLocStrand (slp);
 
15750
 
 
15751
  if (!partial5) {
 
15752
    if (strand == Seq_strand_minus) {
 
15753
      SeqPortStreamInt (bsp, stop - 1, stop, Seq_strand_minus, EXPAND_GAPS_TO_DASHES, (Pointer) buf, NULL);
 
15754
      pos = stop;
 
15755
    } else {
 
15756
      SeqPortStreamInt (bsp, strt, strt + 1, Seq_strand_plus, EXPAND_GAPS_TO_DASHES, (Pointer) buf, NULL);
 
15757
      pos = strt;
 
15758
    }
 
15759
    if ((buf[0] == '-' && buf[1] == '-')
 
15760
        || (buf[0] == 'G' && buf[1] == 'T')
 
15761
        || (buf[0] == 'G' && buf[1] == 'C')) {
 
15762
      /* location is ok */
 
15763
    } else if (pos == 0 || pos == bsp->length - 1) {
 
15764
      ValidErr (vsp, SEV_INFO, ERR_SEQ_FEAT_NotSpliceConsensusDonor,
 
15765
                "Splice donor consensus (GT) not found at start of terminal intron, position %ld of %s", (long) (pos + 1), id_buf);
 
15766
    } else {
 
15767
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_NotSpliceConsensusDonor,
 
15768
                "Splice donor consensus (GT) not found at start of intron, position %ld of %s", (long) (pos + 1), id_buf);
 
15769
    }
 
15770
  }
 
15771
  if (!partial3) {
 
15772
    if (strand == Seq_strand_minus) {
 
15773
      SeqPortStreamInt (bsp, strt, strt + 1, Seq_strand_minus, EXPAND_GAPS_TO_DASHES, (Pointer) buf, NULL);
 
15774
      pos = strt;
 
15775
    } else {
 
15776
      SeqPortStreamInt (bsp, stop - 1, stop, Seq_strand_plus, EXPAND_GAPS_TO_DASHES, (Pointer) buf, NULL);
 
15777
      pos = stop;
 
15778
    }
 
15779
    if ((buf[0] == '-' && buf[1] == '-')
 
15780
        || (buf[0] == 'A' && buf[1] == 'G')) {
 
15781
      /* location is ok */
 
15782
    } else if (pos == 0 || pos == bsp->length - 1) {
 
15783
      ValidErr (vsp, SEV_INFO, ERR_SEQ_FEAT_NotSpliceConsensusAcceptor,
 
15784
                "Splice acceptor consensus (AG) not found at end of terminal intron, position %ld of %s, but at end of sequence", (long) (pos + 1), id_buf);
 
15785
    } else {
 
15786
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_NotSpliceConsensusAcceptor,
 
15787
                "Splice acceptor consensus (AG) not found at end of intron, position %ld of %s", (long) (pos + 1), id_buf);
 
15788
    }
 
15789
  }
 
15790
  BioseqUnlock (bsp);  
 
15791
}
 
15792
 
 
15793
 
15160
15794
#if 0
15161
15795
static void CheckTrnaCodons (ValidStructPtr vsp, GatherContextPtr gcp, SeqFeatPtr sfp, tRNAPtr trp)
15162
15796
{
16129
16763
  return FALSE;
16130
16764
}
16131
16765
 
16132
 
static CharPtr legalDbXrefOnRefSeq [] = {
16133
 
  "GenBank",
16134
 
  "EMBL",
16135
 
  "DDBJ",
16136
 
  NULL
16137
 
};
16138
 
 
16139
 
static CharPtr badDbXref [] = {
16140
 
  "PIDe",
16141
 
  "PIDd",
16142
 
  "PIDg",
16143
 
  "PID",
16144
 
  "NID",
16145
 
  "GI",
16146
 
  NULL
16147
 
};
16148
 
 
16149
16766
static void CheckForIllegalDbxref (ValidStructPtr vsp, GatherContextPtr gcp, SeqFeatPtr sfp, ValNodePtr dbxref)
16150
16767
 
16151
16768
{
16152
 
  CharPtr     casecounts;            
 
16769
  CharPtr     dbxerr;          
16153
16770
  DbtagPtr    db;
16154
 
  Int2        i;
16155
16771
  Int4        id;
16156
16772
  ValNodePtr  vnp;
 
16773
  Boolean     valid;
16157
16774
 
16158
16775
  for (vnp = dbxref; vnp != NULL; vnp = vnp->next) {
16159
16776
    id = -1;
16160
16777
    db = (DbtagPtr) vnp->data.ptrvalue;
16161
16778
    if (db != NULL && db->db != NULL) {
16162
 
      casecounts = NULL;
16163
 
      for (i = 0; legalDbXrefs [i] != NULL; i++) {
16164
 
        if (StringCmp (db->db, legalDbXrefs [i]) == 0) {
16165
 
          id = i;
16166
 
          break;
16167
 
        } else if (StringICmp (db->db, legalDbXrefs [i]) == 0) {
16168
 
          casecounts = legalDbXrefs [i];
16169
 
        }
16170
 
      }
16171
 
      if (id == -1 && GPSorRefSeq (vsp->sep, sfp->location)) {
16172
 
        for (i = 0; legalDbXrefOnRefSeq [i] != NULL; i++) {
16173
 
          if (StringCmp (db->db, legalDbXrefOnRefSeq [i]) == 0) return;
16174
 
        }
16175
 
        for (i = 0; legalRefSeqDbXrefs [i] != NULL; i++) {
16176
 
          if (StringCmp (db->db, legalRefSeqDbXrefs [i]) == 0) return;
16177
 
        }
16178
 
      }
16179
 
      if (id == -1 || (sfp->data.choice != SEQFEAT_CDREGION && id < 4)) {
16180
 
        if (StringDoesHaveText (casecounts)) {
16181
 
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_IllegalDbXref, "Illegal db_xref type %s, legal capitalization is %s", db->db, casecounts);
16182
 
        } else {
16183
 
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_IllegalDbXref, "Illegal db_xref type %s", db->db);
16184
 
        }
16185
 
      } else {
16186
 
        for (i = 0; badDbXref [i] != NULL; i++) {
16187
 
          if (StringICmp (db->db, badDbXref [i]) == 0) {
16188
 
            ValidErr (vsp, SEV_ERROR, ERR_SEQ_FEAT_IllegalDbXref,
16189
 
                      "db_xref type %s is only created by the flatfile generator, and should not be in the record as a separate xref", db->db);
16190
 
          }
16191
 
        }
16192
 
      }
 
16779
      dbxerr = NULL;
 
16780
      valid = IsDbxrefValid (db->db, sfp, NULL,
 
16781
                             GPSorRefSeq (vsp->sep, sfp->location),
 
16782
                             &dbxerr);
 
16783
      if (dbxerr != NULL) {
 
16784
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_IllegalDbXref, dbxerr);
 
16785
        dbxerr = MemFree (dbxerr);
 
16786
      }                 
16193
16787
    }
16194
16788
  }
16195
16789
}
17133
17727
  for (vnp = head; vnp != NULL; vnp = vnp->next) {
17134
17728
    gsp = (GovStrucPtr) vnp->data.ptrvalue;
17135
17729
    if (gsp == NULL) continue;
 
17730
    if (StringHasNoText (gsp->goid)) {
 
17731
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_GeneOntologyTermMissingGOID, "GO term does not have GO identifier");
 
17732
    }
17136
17733
    if (lastgsp != NULL) {
17137
17734
      if (StringICmp (gsp->term, lastgsp->term) == 0 || StringICmp (gsp->goid, lastgsp->goid) == 0) {
17138
17735
        if (gsp->pmid == lastgsp->pmid && StringICmp (gsp->evidence, lastgsp->evidence) == 0) {
17333
17930
  return FALSE;
17334
17931
}
17335
17932
 
 
17933
static CharPtr badGeneSyn [] = {
 
17934
  "alpha",
 
17935
  "alternative",
 
17936
  "beta",
 
17937
  "cellular",
 
17938
  "cytokine",
 
17939
  "drosophila",
 
17940
  "gamma",
 
17941
  "HLA",
 
17942
  "homolog",
 
17943
  "mouse",
 
17944
  "orf",
 
17945
  "partial",
 
17946
  "plasma",
 
17947
  "precursor",
 
17948
  "pseudogene",
 
17949
  "putative",
 
17950
  "rearranged",
 
17951
  "small",
 
17952
  "trna",
 
17953
  "unknown function",
 
17954
  "unknown protein",
 
17955
  "unknown",
 
17956
  "unnamed",
 
17957
  NULL
 
17958
};
 
17959
 
 
17960
static CharPtr badProtName [] = {
 
17961
  "'hypothetical protein",
 
17962
  "alpha",
 
17963
  "alternative",
 
17964
  "alternatively spliced",
 
17965
  "bacteriophage hypothetical protein",
 
17966
  "beta",
 
17967
  "cellular",
 
17968
  "cnserved hypothetical protein",
 
17969
  "conesrved hypothetical protein",
 
17970
  "conserevd hypothetical protein",
 
17971
  "conserved archaeal protein",
 
17972
  "conserved domain protein",
 
17973
  "conserved hypohetical protein",
 
17974
  "conserved hypotehtical protein",
 
17975
  "conserved hypotheical protein",
 
17976
  "conserved hypothertical protein",
 
17977
  "conserved hypothetcial protein",
 
17978
  "conserved hypothetical exported protein",
 
17979
  "conserved hypothetical integral membrane protein",
 
17980
  "conserved hypothetical membrane protein",
 
17981
  "conserved hypothetical phage protein",
 
17982
  "conserved hypothetical prophage protein",
 
17983
  "conserved hypothetical protein - phage associated",
 
17984
  "conserved hypothetical protein fragment 3",
 
17985
  "conserved hypothetical protein, fragment",
 
17986
  "conserved hypothetical protein, putative",
 
17987
  "conserved hypothetical protein, truncated",
 
17988
  "conserved hypothetical protein, truncation",
 
17989
  "conserved hypothetical protein; possible membrane protein",
 
17990
  "conserved hypothetical protein; putative membrane protein",
 
17991
  "conserved hypothetical protein.",
 
17992
  "conserved hypothetical protein",
 
17993
  "conserved hypothetical proteins",
 
17994
  "conserved hypothetical protien",
 
17995
  "conserved hypothetical transmembrane protein",
 
17996
  "conserved hypothetical",
 
17997
  "conserved hypotheticcal protein",
 
17998
  "conserved hypthetical protein",
 
17999
  "conserved in bacteria",
 
18000
  "conserved membrane protein",
 
18001
  "conserved protein of unknown function ; putative membrane protein",
 
18002
  "conserved protein of unknown function",
 
18003
  "conserved protein",
 
18004
  "conserved unknown protein",
 
18005
  "conservedhypothetical protein",
 
18006
  "conserverd hypothetical protein",
 
18007
  "conservered hypothetical protein",
 
18008
  "consrved hypothetical protein",
 
18009
  "converved hypothetical protein",
 
18010
  "cytokine",
 
18011
  "drosophila",
 
18012
  "duplicated hypothetical protein",
 
18013
  "gamma",
 
18014
  "HLA",
 
18015
  "homeodomain protein",
 
18016
  "homeodomain",
 
18017
  "homolog",
 
18018
  "hyopthetical protein",
 
18019
  "hypotethical",
 
18020
  "hypotheical protein",
 
18021
  "hypothertical protein",
 
18022
  "hypothetcical protein",
 
18023
  "hypothetical  protein",
 
18024
  "hypothetical conserved protein",
 
18025
  "hypothetical exported protein",
 
18026
  "hypothetical novel protein",
 
18027
  "hypothetical orf",
 
18028
  "hypothetical phage protein",
 
18029
  "hypothetical prophage protein",
 
18030
  "hypothetical protein - phage associated",
 
18031
  "hypothetical protein (fragment)",
 
18032
  "hypothetical protein (multi-domain)",
 
18033
  "hypothetical protein (phage associated)",
 
18034
  "hypothetical protein fragment ",
 
18035
  "hypothetical protein fragment 1",
 
18036
  "hypothetical protein predicted by genemark",
 
18037
  "hypothetical protein predicted by glimmer",
 
18038
  "hypothetical protein predicted by glimmer/critica",
 
18039
  "hypothetical protein-putative conserved hypothetical protein",
 
18040
  "hypothetical protein, conserved",
 
18041
  "hypothetical protein, phage associated",
 
18042
  "hypothetical protein, truncated",
 
18043
  "hypothetical protein.",
 
18044
  "hypothetical protein",
 
18045
  "hypothetical proteins",
 
18046
  "hypothetical protien",
 
18047
  "hypothetical transmembrane protein",
 
18048
  "hypothetical",
 
18049
  "hypothetoical protein",
 
18050
  "hypothteical protein",
 
18051
  "identified by sequence similarity; putative; ORF located\nusing Blastx/FrameD",
 
18052
  "identified by sequence similarity; putative; ORF located\nusing Blastx/Glimmer/Genemark",
 
18053
  "ion channel",
 
18054
  "membrane protein, putative",
 
18055
  "mouse",
 
18056
  "narrowly conserved hypothetical protein ",
 
18057
  "novel protein",
 
18058
  "orf, conserved hypothetical protein",
 
18059
  "orf, hypothetical protein",
 
18060
  "orf, hypothetical, fragment",
 
18061
  "orf, hypothetical",
 
18062
  "orf, partial conserved hypothetical protein",
 
18063
  "orf; hypothetical protein",
 
18064
  "orf; unknown function",
 
18065
  "orf",
 
18066
  "partial cds, hypothetical",
 
18067
  "partial",
 
18068
  "partially conserved hypothetical protein",
 
18069
  "phage hypothetical protein",
 
18070
  "phage-related conserved hypothetical protein",
 
18071
  "phage-related protein",
 
18072
  "plasma",
 
18073
  "possible hypothetical protein",
 
18074
  "precursor",
 
18075
  "predicted coding region",
 
18076
  "predicted protein (pseudogene)",
 
18077
  "predicted protein family",
 
18078
  "predicted protein",
 
18079
  "product uncharacterised protein family",
 
18080
  "protein family",
 
18081
  "protein of unknown function",
 
18082
  "pseudogene",
 
18083
  "putative conserved protein",
 
18084
  "putative exported protein",
 
18085
  "putative hypothetical protein",
 
18086
  "putative membrane protein",
 
18087
  "putative orf; unknown function",
 
18088
  "putative phage protein",
 
18089
  "putative protein",
 
18090
  "putative",
 
18091
  "putative",
 
18092
  "rearranged",
 
18093
  "repeats containing protein",
 
18094
  "reserved",
 
18095
  "ribosomal protein",
 
18096
  "similar to",
 
18097
  "small hypothetical protein",
 
18098
  "small",
 
18099
  "transmembrane protein",
 
18100
  "trna",
 
18101
  "trp repeat",
 
18102
  "trp-repeat protein",
 
18103
  "truncated conserved hypothetical protein",
 
18104
  "truncated hypothetical protein",
 
18105
  "uncharacterized conserved membrane protein",
 
18106
  "uncharacterized conserved protein",
 
18107
  "uncharacterized conserved secreted protein",
 
18108
  "uncharacterized protein conserved in archaea",
 
18109
  "uncharacterized protein conserved in bacteria",
 
18110
  "uncharacterized protein",
 
18111
  "unique hypothetical protein",
 
18112
  "unique hypothetical",
 
18113
  "unknown CDS",
 
18114
  "unknown function",
 
18115
  "unknown gene",
 
18116
  "unknown protein",
 
18117
  "unknown protein",
 
18118
  "unknown-related protein",
 
18119
  "unknown, conserved protein",
 
18120
  "unknown, hypothetical",
 
18121
  "unknown; predicted coding region",
 
18122
  "unknown",
 
18123
  "unknown",
 
18124
  "unnamed protein product",
 
18125
  "unnamed",
 
18126
  "very hypothetical protein",
 
18127
  NULL
 
18128
};
 
18129
 
 
18130
static Boolean NameInList (CharPtr name, CharPtr PNTR list, size_t numelements)
 
18131
 
 
18132
{
 
18133
  Int2  L, R, mid;
 
18134
 
 
18135
  if (StringHasNoText (name) || list == NULL || numelements < 1) return FALSE;
 
18136
 
 
18137
  L = 0;
 
18138
  R = numelements - 1; /* -1 because now NULL terminated */
 
18139
 
 
18140
  while (L < R) {
 
18141
    mid = (L + R) / 2;
 
18142
    if (StringICmp (list [mid], name) < 0) {
 
18143
      L = mid + 1;
 
18144
    } else {
 
18145
      R = mid;
 
18146
    }
 
18147
  }
 
18148
 
 
18149
  if (StringICmp (list [R], name) == 0) return TRUE;
 
18150
 
 
18151
  return FALSE;
 
18152
}
 
18153
 
17336
18154
NLM_EXTERN void ValidateSeqFeat (GatherContextPtr gcp)
17337
18155
{
17338
18156
  Int2            type, i, j;
17403
18221
  Boolean         isgap;
17404
18222
  Boolean         badseq;
17405
18223
  Boolean         is_seqloc_bond;
 
18224
  SeqBondPtr      sbp;
17406
18225
  SeqFeatXrefPtr  xref, matchxref;
17407
18226
  SeqFeatPtr      matchsfp, origsfp;
17408
18227
  Boolean         hasxref;
17420
18239
  Boolean         farFetchProd;
17421
18240
  Boolean         skip;
17422
18241
  Boolean         is_nc = FALSE;
 
18242
  Boolean         no_nonconsensus_except = TRUE;
17423
18243
 
17424
18244
 
17425
18245
  vsp = (ValidStructPtr) (gcp->userdata);
17458
18278
  partials[0] = SeqLocPartialCheckEx (sfp->product, farFetchProd);
17459
18279
  partials[1] = SeqLocPartialCheck (sfp->location);
17460
18280
 
 
18281
  if (sfp->excpt) {
 
18282
    if (StringISearch (sfp->except_text, "nonconsensus splice site") != NULL) {
 
18283
      no_nonconsensus_except = FALSE;
 
18284
    }
 
18285
  }
 
18286
 
 
18287
  if (sfp->idx.subtype == FEATDEF_intron && no_nonconsensus_except) {
 
18288
    ValidateIntronEndsAtSpliceSiteOrGap (vsp, sfp->location);
 
18289
  }
 
18290
 
17461
18291
  if ((partials[0] != SLP_COMPLETE) || (partials[1] != SLP_COMPLETE) || (sfp->partial)) {       /* partialness */
17462
18292
    /* a feature on a partial sequence should be partial -- if often isn't */
17463
18293
    if ((!sfp->partial) && (partials[1] != SLP_COMPLETE) && (sfp->location->choice == SEQLOC_WHOLE)) {
17588
18418
          } else if (sfp->data.choice == SEQFEAT_CDREGION && sfp->excpt &&
17589
18419
                     StringStr (sfp->except_text, "rearrangement required for product") != NULL) {
17590
18420
          } else if (sfp->data.choice == SEQFEAT_CDREGION && j == 0) {
17591
 
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_PartialProblem,
17592
 
              "%s: %s", parterr[i], "5' partial is not at start AND"
17593
 
              " is not at consensus splice site");
 
18421
            if (no_nonconsensus_except) {
 
18422
              ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_PartialProblem,
 
18423
                "%s: %s", parterr[i], "5' partial is not at start AND"
 
18424
                " is not at consensus splice site");
 
18425
            }
17594
18426
          } else if (sfp->data.choice == SEQFEAT_CDREGION && j == 1) {
17595
 
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_PartialProblem,
17596
 
              "%s: %s", parterr[i], "3' partial is not at stop AND"
17597
 
              " is not at consensus splice site");
 
18427
            if (no_nonconsensus_except) {
 
18428
              ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_PartialProblem,
 
18429
                "%s: %s", parterr[i], "3' partial is not at stop AND"
 
18430
                " is not at consensus splice site");
 
18431
            }
17598
18432
          } else {
17599
18433
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_PartialProblem,
17600
18434
              "%s: %s", parterr[i], parterrs[j]);
17700
18534
          }
17701
18535
        }
17702
18536
      }
 
18537
      if (grp->syn != NULL && vsp->is_refseq_in_sep) {
 
18538
        for (vnp = grp->syn; vnp != NULL; vnp = vnp->next) {
 
18539
          str = (CharPtr) vnp->data.ptrvalue;
 
18540
          if (StringHasNoText (str)) continue;
 
18541
          if (NameInList (str, badGeneSyn, sizeof (badGeneSyn) / sizeof (badGeneSyn [0]))) {
 
18542
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_UndesiredGeneSynonym, "Uninformative gene synonym '%s", str);
 
18543
          }
 
18544
          if (StringDoesHaveText (grp->locus) && StringCmp (grp->locus, str) == 0) {
 
18545
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_UndesiredGeneSynonym, "gene synonym has same value as gene locus");
 
18546
          }
 
18547
        }
 
18548
      }
 
18549
      if (StringDoesHaveText (grp->locus) && StringDoesHaveText (grp->desc) && StringCmp (grp->locus, grp->desc) == 0) {
 
18550
        ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_UndesiredGeneSynonym, "gene description has same value as gene locus");
 
18551
      }
17703
18552
      /* - need to ignore if curated drosophila - add to vsp internal flags for efficiency?
17704
18553
      if (StringDoesHaveText (grp->locus)) {
17705
18554
        for (gbq = sfp->qual; gbq != NULL; gbq = gbq->next) {
17802
18651
        }
17803
18652
      }
17804
18653
      if (pseudo && SeqMgrGetProtXref (sfp) != NULL) {
17805
 
        if (NGorNT (vsp->sep, sfp->location, &is_nc)) {
 
18654
        if (NGorNT (vsp->sep, sfp->location, &is_nc) || IsEMBLAccn (vsp->sep, sfp->location)) {
17806
18655
          sev = SEV_WARNING;
17807
18656
        } else {
17808
18657
          sev = SEV_ERROR;
17992
18841
            if (ECnumberWasDeleted (str)) {
17993
18842
              ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_BadEcNumberValue, "EC_number %s was deleted", str);
17994
18843
            } else if (ECnumberWasReplaced (str)) {
17995
 
              ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_BadEcNumberValue, "EC_number %s was replaced", str);
 
18844
              ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_BadEcNumberValue, "EC_number %s was transferred and is no longer valid", str);
17996
18845
            } else {
17997
18846
              ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_BadEcNumberValue, "%s is not a legal value for qualifier EC_number", str);
17998
18847
            }
18002
18851
        }
18003
18852
      }
18004
18853
    }
 
18854
    if (prp->name != NULL && vsp->is_refseq_in_sep) {
 
18855
      for (vnp = prp->name; vnp != NULL; vnp = vnp->next) {
 
18856
        str = (CharPtr) vnp->data.ptrvalue;
 
18857
        if (StringHasNoText (str)) continue;
 
18858
          if (NameInList (str, badProtName, sizeof (badProtName) / sizeof (badProtName [0]))) {
 
18859
            ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_UndesiredProteinName, "Uninformative protein name '%s'", str);
 
18860
          }
 
18861
        }
 
18862
      }
18005
18863
    break;
18006
18864
  case 5:                      /* RNA-ref */
18007
18865
    rrp = (RnaRefPtr) (sfp->data.value.ptrvalue);
18101
18959
        }
18102
18960
      }
18103
18961
    }
 
18962
    if (rrp->type == 255 && rrp->ext.choice == 1) {
 
18963
      str = (CharPtr) rrp->ext.value.ptrvalue;
 
18964
      if (StringICmp (str, "ncRNA") == 0) {
 
18965
        for (gbq = sfp->qual; gbq != NULL; gbq = gbq->next) {
 
18966
          if (StringICmp (gbq->qual, "ncRNA_class") != 0) continue;
 
18967
          if (StringHasNoText (gbq->val)) continue;
 
18968
          if (IsStringInNcRNAClassList (gbq->val)) continue;
 
18969
          ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_InvalidQualifierValue, "Illegal ncRNA_class value '%s'", gbq->val);
 
18970
        }
 
18971
      }
 
18972
    }
18104
18973
    if (sfp->product != NULL) {
18105
18974
      CheckRnaProductType (vsp, gcp, sfp, rrp);
18106
18975
    }
18197
19066
      }
18198
19067
    }
18199
19068
    /*
18200
 
       ValidateBioSource (vsp, gcp, biop, sfp);
 
19069
       ValidateBioSource (vsp, gcp, biop, sfp, NULL);
18201
19070
     */
18202
19071
    break;
18203
19072
  default:
18204
19073
    ValidErr (vsp, SEV_ERROR, ERR_SEQ_FEAT_InvalidType, "Invalid SeqFeat type [%d]", (int) (type));
18205
19074
    break;
18206
19075
  }
18207
 
  if (type != SEQFEAT_BOND) {
 
19076
  if (type == SEQFEAT_HET) {
 
19077
    /* heterogen can have mix of bonds with just "a" point specified */
 
19078
    is_seqloc_bond = FALSE;
 
19079
    slp = SeqLocFindNext (sfp->location, NULL);
 
19080
    while (slp != NULL) {
 
19081
      if (slp->choice == SEQLOC_BOND) {
 
19082
        sbp = (SeqBondPtr) slp->data.ptrvalue;
 
19083
        if (sbp != NULL) {
 
19084
          if (sbp->a == NULL || sbp->b != NULL) {
 
19085
            is_seqloc_bond = TRUE;
 
19086
          }
 
19087
        }
 
19088
      }
 
19089
      slp = SeqLocFindNext (sfp->location, slp);
 
19090
    }
 
19091
    if (is_seqloc_bond) {
 
19092
      ValidErr (vsp, SEV_WARNING, ERR_SEQ_FEAT_ImproperBondLocation, "Bond location should only be on bond features");
 
19093
    }
 
19094
  } else if (type != SEQFEAT_BOND) {
18208
19095
    is_seqloc_bond = FALSE;
18209
19096
    slp = SeqLocFindNext (sfp->location, NULL);
18210
19097
    while (slp != NULL) {
19882
20769
      residue2 = SeqPortGetResidue (spp);
19883
20770
      */
19884
20771
      if (residue1 == '-' && residue2 == '-') {
19885
 
        /* ignore gap */
 
20772
        /* ignore gap, and suppress UnnecessaryException message */
 
20773
        has_errors = TRUE;
19886
20774
      } else if (IS_residue (residue1) && IS_residue (residue2)) {
19887
20775
        if (residue1 != 'G' || residue2 != 'T') {        /* not T */
19888
20776
          if (residue1 == 'G' && residue2 == 'C') {       /* GC minor splice site */
19947
20835
      residue2 = SeqPortGetResidue (spp);
19948
20836
      */
19949
20837
      if (residue1 == '-' && residue2 == '-') {
19950
 
        /* ignore gap */
 
20838
        /* ignore gap, and suppress UnnecessaryException message */
 
20839
        has_errors = TRUE;
19951
20840
      } else if (IS_residue (residue1) && IS_residue (residue2)) {
19952
20841
        if (residue1 != 'A' || residue2 != 'G') {
19953
20842
          if (gpsOrRefSeq) {