NCBI C++ ToolKit
xm_index.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: xm_index.cpp 102143 2024-04-09 12:51:41Z stakhovv $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * File Name: xm_index.cpp
27  *
28  * Author: Sergey Bazhin
29  *
30  * File Description:
31  * Parsing flat records to memory blocks in XML format.
32  *
33  */
34 
35 #include <ncbi_pch.hpp>
36 
37 #include "ftacpp.hpp"
38 #include "index.h"
39 
40 #include "ftaerr.hpp"
41 #include "indx_blk.h"
42 #include "indx_def.h"
43 #include "utilfun.h"
44 #include "fta_xml.h"
45 
46 #ifdef THIS_FILE
47 # undef THIS_FILE
48 #endif
49 #define THIS_FILE "xm_index.cpp"
50 
51 #define XML_FAKE_ACC_TAG "AC "
52 
54 
55 struct XmlKwordBlk {
56  const char* str;
59 };
60 using XmlKwordBlkPtr = const XmlKwordBlk*;
61 
62 // clang-format off
64  {"<INSDSeq_locus>", 1, INSDSEQ_LOCUS},
65  {"<INSDSeq_length>", 2, INSDSEQ_LENGTH},
66  {"<INSDSeq_strandedness>", 3, INSDSEQ_STRANDEDNESS},
67  {"<INSDSeq_moltype>", 4, INSDSEQ_MOLTYPE},
68  {"<INSDSeq_topology>", 5, INSDSEQ_TOPOLOGY},
69  {"<INSDSeq_division>", 6, INSDSEQ_DIVISION},
70  {"<INSDSeq_update-date>", 7, INSDSEQ_UPDATE_DATE},
71  {"<INSDSeq_create-date>", 8, INSDSEQ_CREATE_DATE},
72  {"<INSDSeq_update-release>", 9, INSDSEQ_UPDATE_RELEASE},
73  {"<INSDSeq_create-release>", 10, INSDSEQ_CREATE_RELEASE},
74  {"<INSDSeq_definition>", 11, INSDSEQ_DEFINITION},
75  {"<INSDSeq_primary-accession>", 12, INSDSEQ_PRIMARY_ACCESSION},
76  {"<INSDSeq_entry-version>", 13, INSDSEQ_ENTRY_VERSION},
77  {"<INSDSeq_accession-version>", 14, INSDSEQ_ACCESSION_VERSION},
78  {"<INSDSeq_other-seqids>", 15, INSDSEQ_OTHER_SEQIDS},
79  {"<INSDSeq_secondary-accessions>", 16, INSDSEQ_SECONDARY_ACCESSIONS},
80  {"<INSDSeq_keywords>", 17, INSDSEQ_KEYWORDS},
81  {"<INSDSeq_segment>", 18, INSDSEQ_SEGMENT},
82  {"<INSDSeq_source>", 19, INSDSEQ_SOURCE},
83  {"<INSDSeq_organism>", 20, INSDSEQ_ORGANISM},
84  {"<INSDSeq_taxonomy>", 21, INSDSEQ_TAXONOMY},
85  {"<INSDSeq_references>", 22, INSDSEQ_REFERENCES},
86  {"<INSDSeq_comment>", 23, INSDSEQ_COMMENT},
87  {"<INSDSeq_primary>", 24, INSDSEQ_PRIMARY},
88  {"<INSDSeq_source-db>", 25, INSDSEQ_SOURCE_DB},
89  {"<INSDSeq_database-reference>", 26, INSDSEQ_DATABASE_REFERENCE},
90  {"<INSDSeq_feature-table>", 27, INSDSEQ_FEATURE_TABLE},
91  {"<INSDSeq_sequence>", 28, INSDSEQ_SEQUENCE},
92  {"<INSDSeq_contig>", 29, INSDSEQ_CONTIG},
93  {nullptr, -1, -1}
94 };
95 
97  {"<INSDFeature_key>", 1, INSDFEATURE_KEY},
98  {"<INSDFeature_location>", 2, INSDFEATURE_LOCATION},
99  {"<INSDFeature_intervals>", 3, INSDFEATURE_INTERVALS},
100  {"<INSDFeature_quals>", 4, INSDFEATURE_QUALS},
101  {nullptr, -1, -1}
102 };
103 
105  {"<INSDInterval_from>", 1, INSDINTERVAL_FROM},
106  {"<INSDInterval_to>", 2, INSDINTERVAL_TO},
107  {"<INSDInterval_point>", 3, INSDINTERVAL_POINT},
108  {"<INSDInterval_accession>", 4, INSDINTERVAL_ACCESSION},
109  {nullptr, -1, -1}
110 };
111 
113  {"<INSDReference_reference>", 1, INSDREFERENCE_REFERENCE},
114  {"<INSDReference_position>", 2, INSDREFERENCE_POSITION},
115  {"<INSDReference_authors>", 3, INSDREFERENCE_AUTHORS},
116  {"<INSDReference_consortium>", 4, INSDREFERENCE_CONSORTIUM},
117  {"<INSDReference_title>", 5, INSDREFERENCE_TITLE},
118  {"<INSDReference_journal>", 6, INSDREFERENCE_JOURNAL},
119  {"<INSDReference_xref>", 7, INSDREFERENCE_XREF},
120  {"<INSDReference_medline>", 8, INSDREFERENCE_MEDLINE},
121  {"<INSDReference_pubmed>", 9, INSDREFERENCE_PUBMED},
122  {"<INSDReference_remark>", 10, INSDREFERENCE_REMARK},
123  {nullptr, -1, -1}
124 };
125 
127  {"<INSDQualifier_name>", 1, INSDQUALIFIER_NAME},
128  {"<INSDQualifier_value>", 2, INSDQUALIFIER_VALUE},
129  {nullptr, -1, -1}
130 };
131 
133  {"<INSDXref_dbname>", 1, INSDXREF_DBNAME},
134  {"<INSDXref_id>", 2, INSDXREF_ID},
135  {nullptr, -1, -1}
136 };
137 
139  {"<INSDSecondary-accn>", 1, INSDSECONDARY_ACCN},
140  {"<INSDKeyword>", 1, INSDKEYWORD},
141  {"<INSDFeature>", 1, INSDFEATURE},
142  {"<INSDInterval>", 1, INSDINTERVAL},
143  {"<INSDQualifier>", 1, INSDQUALIFIER},
144  {"<INSDReference>", 1, INSDREFERENCE},
145  {"<INSDAuthor>", 1, INSDAUTHOR},
146  {"<INSDXref>", 1, INSDXREF},
147  {nullptr, -1, -1}
148 };
149 // clang-format on
150 
151 /**********************************************************/
153 {
154  XmlIndexPtr xip;
155 
156  xip = new XmlIndex;
157  xip->tag = -1;
158  xip->order = -1;
159  xip->start = 0;
160  xip->end = 0;
161  xip->start_line = -1;
162  xip->end_line = -1;
163  xip->subtags = nullptr;
164  xip->next = nullptr;
165  return (xip);
166 }
167 
168 /**********************************************************/
169 static string XMLRestoreSpecialCharacters(string_view s)
170 {
171  string buf;
172  buf.reserve(s.size());
173 
174  for (size_t i = 0; i < s.size();) {
175  if (s[i] != '&') {
176  buf += s[i++];
177  continue;
178  }
179  if (s.substr(i, 4) == string_view("&lt;", 4)) {
180  buf += '<';
181  i += 4;
182  } else if (s.substr(i, 4) == string_view("&gt;", 4)) {
183  buf += '>';
184  i += 4;
185  } else if (s.substr(i, 5) == string_view("&amp;", 5)) {
186  buf += '&';
187  i += 5;
188  } else if (s.substr(i, 6) == string_view("&apos;", 6)) {
189  buf += '\'';
190  i += 6;
191  } else if (s.substr(i, 6) == string_view("&quot;", 6)) {
192  buf += '\"';
193  i += 6;
194  } else
195  buf += s[i++];
196  }
197 
198  return buf;
199 }
200 
201 /**********************************************************/
202 char* XMLGetTagValue(const char* entry, const XmlIndex* xip)
203 {
204  if (! entry || ! xip || xip->start == 0 || xip->end == 0 ||
205  xip->start >= xip->end)
206  return nullptr;
207 
208  string_view buf(entry + xip->start, xip->end - xip->start);
209 
211 }
212 
213 /**********************************************************/
214 char* XMLFindTagValue(const char* entry, const XmlIndex* xip, Int4 tag)
215 {
216  for (; xip; xip = xip->next)
217  if (xip->tag == tag)
218  break;
219  if (! xip)
220  return nullptr;
221  return (XMLGetTagValue(entry, xip));
222 }
223 
224 /**********************************************************/
225 static bool XMLDelSegnum(IndexblkPtr ibp, const char* segnum, size_t len2)
226 {
227  if (! segnum)
228  return false;
229  size_t len1 = StringLen(segnum);
230  if (len2 < len1)
231  return false;
232 
233  /* check, is there enough digits to delete
234  */
235  size_t tlen = len1;
236  char* str = ibp->blocusname;
237  size_t i = StringLen(str) - 1;
238  for (; tlen > 0 && str[i] >= '0' && str[i] <= '9'; i--)
239  tlen--;
240 
241  if (tlen != 0)
242  return false;
243 
244  if (len2 > len1 && str[i] == '0') {
245  /* check, is there enough "0" appended
246  */
247  for (tlen = len2 - len1; tlen > 0 && str[i] == '0'; i--)
248  tlen--;
249 
250  if (tlen != 0)
251  return false;
252  }
253 
254  char* p;
255  char* q;
256  for (q = &str[i + 1], p = q; *p == '0';)
257  p++;
258 
259  i = atoi(segnum);
260  if (atoi(p) != (int)i) {
261  ErrPostEx(SEV_REJECT, ERR_SEGMENT_BadLocusName, "Segment suffix in locus name \"%s\" does not match number in <INSDSEQ_segment> line = \"%d\". Entry dropped.", str, i);
262  ibp->drop = true;
263  }
264 
265  *q = '\0'; /* strip off "len" characters */
266  return true;
267 }
268 
269 /**********************************************************/
270 static void XMLGetSegment(const char* entry, IndexblkPtr ibp)
271 {
272  TokenStatBlkPtr stoken;
273  XmlIndexPtr xip;
274  char* buf;
275  const char* segnum;
276  const char* segtotal;
277 
278  if (! entry || ! ibp || ! ibp->xip)
279  return;
280 
281  for (xip = ibp->xip; xip; xip = xip->next)
282  if (xip->tag == INSDSEQ_SEGMENT)
283  break;
284  if (! xip)
285  return;
286 
287  buf = XMLGetTagValue(entry, xip);
288  if (! buf)
289  return;
290 
291  stoken = TokenString(buf, ' ');
292 
293  if (stoken->num > 2) {
294  segnum = stoken->list->str;
295  segtotal = stoken->list->next->next->str;
296  ibp->segnum = (Uint2)atoi(segnum);
297 
298  if (! XMLDelSegnum(ibp, segnum, StringLen(segtotal))) {
299  ErrPostEx(SEV_ERROR, ERR_SEGMENT_BadLocusName, "Bad locus name \"%s\".", ibp->blocusname);
300  }
301 
302  ibp->segtotal = (Uint2)atoi(segtotal);
303  } else {
304  ErrPostEx(SEV_ERROR, ERR_SEGMENT_IncompSeg, "Incomplete Segment information at line %d.", xip->start_line);
305  }
306 
307  FreeTokenstatblk(stoken);
308  MemFree(buf);
309 }
310 
311 
312 static bool s_HasInput(const Parser& config)
313 {
314  return (config.ffbuf.start != nullptr);
315 }
316 
317 
319 {
320  if (*config.ffbuf.current == '\0') {
321  return -1;
322  }
323  return *(config.ffbuf.current++);
324 }
325 
327 {
328  config.ffbuf.set_offs(offset);
329 }
330 
331 /**********************************************************/
332 static void XMLPerformIndex(ParserPtr pp)
333 {
334  XmlKwordBlkPtr xkbp;
335  IndBlkNextPtr ibnp;
336  IndBlkNextPtr tibnp;
337  XmlIndexPtr xip;
338  IndexblkPtr ibp;
339  char* p;
340  Char s[60];
341  Char ch;
342  size_t count;
343  Int4 line;
344  Int4 c;
345  Int4 i;
346 
347 
348  if (! pp || ! s_HasInput(*pp)) {
349  return;
350  }
351 
352  c = 0;
353  s[0] = '\0';
354  bool within = false;
355  tibnp = nullptr;
356  ibnp = nullptr;
357  ibp = nullptr;
358  xip = nullptr;
359  pp->indx = 0;
360  size_t start_len = StringLen(INSDSEQ_START);
361  for (count = 0, line = 1;;) {
362  if (c != '<') {
363  c = s_GetCharAndAdvance(*pp);
364  if (c < 0)
365  break;
366  count++;
367  if ((Char)c == '\n')
368  line++;
369  }
370  if (c != '<')
371  continue;
372 
373  s[0] = '<';
374  for (i = 1; i < 50; i++) {
375  c = s_GetCharAndAdvance(*pp);
376  if (c < 0)
377  break;
378  count++;
379  ch = (Char)c;
380  if (ch == '\n')
381  line++;
382  s[i] = ch;
383  if (ch == '<' || ch == '>')
384  break;
385  }
386  if (c < 0)
387  break;
388  if (ch == '<')
389  continue;
390  s[++i] = '\0';
391  if (StringEqu(s, INSDSEQ_START)) {
392  if (within)
393  continue;
394  within = true;
395 
396  ibp = new Indexblk;
397  ibp->offset = count - start_len;
398  ibp->linenum = line;
399 
400  if (! ibnp) {
401  ibnp = new IndBlkNode(ibp);
402  tibnp = ibnp;
403  } else {
404  tibnp->next = new IndBlkNode(ibp);
405  tibnp = tibnp->next;
406  }
407 
408  pp->indx++;
409  continue;
410  }
411  if (! within) {
412  if (StringEqu(s, INSDSEQ_END))
413  ErrPostEx(SEV_ERROR, ERR_FORMAT_UnexpectedEnd, "Unexpected end tag \"%s\" of XML record found at line %d.", s, line);
414  continue;
415  }
416  if (StringEqu(s, INSDSEQ_END)) {
417  ibp->len = count - ibp->offset;
418  within = false;
419  continue;
420  }
421  p = s + ((s[1] == '/') ? 2 : 1);
422  for (xkbp = xmkwl; xkbp->str; xkbp++)
423  if (StringEqu(p, xkbp->str + 1))
424  break;
425  if (! xkbp->str)
426  continue;
427  if (! ibp->xip || xip->tag != xkbp->tag) {
428  if (! ibp->xip) {
429  ibp->xip = XMLIndexNew();
430  xip = ibp->xip;
431  } else {
432  xip->next = XMLIndexNew();
433  xip = xip->next;
434  }
435  xip->tag = xkbp->tag;
436  xip->order = xkbp->order;
437  if (s[1] == '/') {
438  xip->end = count - i - ibp->offset;
439  xip->end_line = line;
440  } else {
441  xip->start = count - ibp->offset;
442  xip->start_line = line;
443  }
444  continue;
445  }
446  if (s[1] == '/') {
447  if (xip->end != 0) {
448  xip->next = XMLIndexNew();
449  xip = xip->next;
450  xip->tag = xkbp->tag;
451  xip->order = xkbp->order;
452  }
453  xip->end = count - i - ibp->offset;
454  xip->end_line = line;
455  } else {
456  if (xip->start != 0) {
457  xip->next = XMLIndexNew();
458  xip = xip->next;
459  xip->tag = xkbp->tag;
460  xip->order = xkbp->order;
461  }
462  xip->start = count - ibp->offset;
463  xip->start_line = line;
464  }
465  }
466 
467  pp->entrylist.resize(pp->indx, nullptr);
468  for (tibnp = ibnp, i = 0; tibnp; i++, tibnp = ibnp) {
469  pp->entrylist[i] = tibnp->ibp;
470  ibnp = tibnp->next;
471  delete tibnp;
472  }
473 }
474 
475 /**********************************************************/
476 static void XMLParseVersion(IndexblkPtr ibp, char* line)
477 {
478  char* p;
479  char* q;
480 
481  if (! line) {
482  ErrPostEx(SEV_FATAL, ERR_VERSION_BadVersionLine, "Empty <INSDSeq_accession-version> line. Entry dropped.");
483  ibp->drop = true;
484  return;
485  }
486 
487  for (p = line; *p != '\0' && *p != ' ' && *p != '\t';)
488  p++;
489  if (*p != '\0') {
490  ErrPostEx(SEV_FATAL, ERR_VERSION_BadVersionLine, "Incorrect <INSDSeq_accession-version> line: \"%s\". Entry dropped.", line);
491  ibp->drop = true;
492  return;
493  }
494  q = StringRChr(line, '.');
495  if (! q) {
496  ErrPostEx(SEV_FATAL, ERR_VERSION_MissingVerNum, "Missing version number in <INSDSeq_accession-version> line: \"%s\". Entry dropped.", line);
497  ibp->drop = true;
498  return;
499  }
500  for (p = q + 1; *p >= '0' && *p <= '9';)
501  p++;
502  if (*p != '\0') {
503  ErrPostEx(SEV_FATAL, ERR_VERSION_NonDigitVerNum, "Incorrect VERSION number in <INSDSeq_accession-version> line: \"%s\". Entry dropped.", line);
504  ibp->drop = true;
505  return;
506  }
507  *q = '\0';
508  if (! StringEqu(ibp->acnum, line)) {
509  *q = '.';
510  ErrPostEx(SEV_FATAL, ERR_VERSION_AccessionsDontMatch, "Accessions in <INSDSeq_accession-version> and <INSDSeq_primary-accession> lines don't match: \"%s\" vs \"%s\". Entry dropped.", line, ibp->acnum);
511  ibp->drop = true;
512  return;
513  }
514  *q++ = '.';
515  ibp->vernum = atoi(q);
516 
517  if (ibp->vernum > 0)
518  return;
519 
520  ErrPostEx(SEV_FATAL, ERR_VERSION_InvalidVersion, "Version number \"%d\" from Accession.Version value \"%s.%d\" is not a positive integer. Entry dropped.", ibp->vernum, ibp->acnum, ibp->vernum);
521  ibp->drop = true;
522 }
523 
524 /**********************************************************/
525 static void XMLInitialEntry(IndexblkPtr ibp, const char* entry, bool accver, Parser::ESource source)
526 {
527  XmlIndexPtr xip;
528  char* buf;
529 
530  if (! ibp || ! ibp->xip || ! entry)
531  return;
532 
534  ibp->is_pat = true;
535 
536  ibp->locusname[0] = '\0';
537  ibp->acnum[0] = '\0';
538  for (xip = ibp->xip; xip; xip = xip->next) {
539  if (xip->tag == INSDSEQ_LOCUS && ibp->locusname[0] == '\0') {
540  if (xip->start == 0 || xip->end == 0 || xip->start >= xip->end ||
542  StringCpy(ibp->locusname, "???");
543  StringCpy(ibp->blocusname, "???");
544  continue;
545  }
546  size_t imax = xip->end - xip->start;
547  if (imax > (int)sizeof(ibp->locusname) - 1)
548  imax = sizeof(ibp->locusname) - 1;
549  StringNCpy(ibp->locusname, entry + xip->start, imax);
550  ibp->locusname[imax] = '\0';
551  StringCpy(ibp->blocusname, ibp->locusname);
552  } else if (xip->tag == INSDSEQ_PRIMARY_ACCESSION && ibp->acnum[0] == '\0') {
553  if (xip->start == 0 || xip->end == 0 || xip->start >= xip->end) {
554  StringCpy(ibp->acnum, "???");
555  continue;
556  }
557  size_t imax = xip->end - xip->start;
558  if (imax > (int)sizeof(ibp->acnum) - 1)
559  imax = sizeof(ibp->acnum) - 1;
560  StringNCpy(ibp->acnum, entry + xip->start, imax);
561  ibp->acnum[imax] = '\0';
562  }
563  if (ibp->locusname[0] != '\0' && ibp->acnum[0] != '\0')
564  break;
565  }
566 
568  if (ibp->acnum[0] == '\0')
570  else
572 
573  if (accver) {
574  for (xip = ibp->xip; xip; xip = xip->next) {
575  if (xip->tag != INSDSEQ_ACCESSION_VERSION)
576  continue;
577  buf = XMLGetTagValue(entry, xip);
578  XMLParseVersion(ibp, buf);
579  if (buf) {
581  MemFree(buf);
582  }
583  break;
584  }
585  }
586 
587  ibp->bases = 0;
588  ibp->date = nullptr;
589  StringCpy(ibp->division, "???");
590  for (xip = ibp->xip; xip; xip = xip->next) {
591  if (xip->tag == INSDSEQ_LENGTH && ibp->bases == 0) {
592  buf = XMLGetTagValue(entry, xip);
593  if (! buf)
594  continue;
595  ibp->bases = (size_t)atoi(buf);
596  MemFree(buf);
597  } else if (xip->tag == INSDSEQ_UPDATE_DATE && ! ibp->date) {
598  buf = XMLGetTagValue(entry, xip);
599  if (! buf)
600  continue;
601  ibp->date = GetUpdateDate(buf, source);
602  MemFree(buf);
603  } else if (xip->tag == INSDSEQ_DIVISION && ibp->division[0] == '?') {
604  if (xip->start == 0 || xip->end == 0 || xip->start >= xip->end ||
605  xip->end - xip->start < 3)
606  continue;
607  StringNCpy(ibp->division, entry + xip->start, 3);
608  ibp->division[3] = '\0';
609  if (NStr::CompareNocase(ibp->division, "EST") == 0)
610  ibp->EST = true;
611  else if (StringEqu(ibp->division, "STS"))
612  ibp->STS = true;
613  else if (StringEqu(ibp->division, "GSS"))
614  ibp->GSS = true;
615  else if (StringEqu(ibp->division, "HTC"))
616  ibp->HTC = true;
617  } else if (xip->tag == INSDSEQ_MOLTYPE && ibp->is_prot == false) {
618  buf = XMLGetTagValue(entry, xip);
619  if (NStr::CompareNocase(buf, "AA") == 0)
620  ibp->is_prot = true;
621  MemFree(buf);
622  }
623  if (ibp->bases > 0 && ibp->date && ibp->division[0] != '?')
624  break;
625  }
626 }
627 
628 /**********************************************************/
629 static const char* XMLStringByTag(XmlKwordBlkPtr xkbp, Int4 tag)
630 {
631  for (; xkbp->str; xkbp++)
632  if (xkbp->tag == tag)
633  break;
634  if (! xkbp->str)
635  return ("???");
636  return (xkbp->str);
637 }
638 
639 /**********************************************************/
640 static bool XMLTagCheck(XmlIndexPtr xip, XmlKwordBlkPtr xkbp)
641 {
642  XmlIndexPtr txip;
643  bool ret = true;
644  for (txip = xip; txip; txip = txip->next) {
645  if (txip->start == 0) {
646  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLMissingStartTag, "XML record's missing start tag for \"%s\" at line %d.", XMLStringByTag(xkbp, txip->tag), txip->end_line);
647  ret = false;
648  }
649  if (txip->end == 0) {
650  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLMissingEndTag, "XML record's missing end tag for \"%s\" at line %d.", XMLStringByTag(xkbp, txip->tag), txip->start_line);
651  ret = false;
652  }
653  if (txip->next && txip->order >= txip->next->order) {
654  ErrPostEx(SEV_ERROR, ERR_FORMAT_LineTypeOrder, "XML tag \"%s\" at line %d is out of order.", XMLStringByTag(xkbp, txip->next->tag), (txip->next->start > 0) ? txip->next->start_line : txip->next->end_line);
655  ret = false;
656  }
657  }
658  return (ret);
659 }
660 
661 /**********************************************************/
662 static bool XMLSameTagsCheck(XmlIndexPtr xip, const char* name)
663 {
664  bool ret = true;
665 
666  for (XmlIndexPtr txip = xip; txip; txip = txip->next) {
667  if (txip->start == 0) {
668  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLMissingStartTag, "XML record's missing start tag for \"%s\" at line %d.", name, txip->end_line);
669  ret = false;
670  }
671  if (txip->end == 0) {
672  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLMissingEndTag, "XML record's missing end tag for \"%s\" at line %d.", name, txip->start_line);
673  ret = false;
674  }
675  }
676  return (ret);
677 }
678 
679 /**********************************************************/
680 static XmlIndexPtr XMLIndexSameSubTags(const char* entry, XmlIndexPtr xip, Int4 tag)
681 {
682  XmlIndexPtr xipsub;
683  XmlIndexPtr txipsub;
684  const char* name;
685  const char* c;
686  char* p;
687  size_t count;
688  Char s[60];
689  Int4 line;
690  Int4 i;
691 
692  if (! entry || ! xip)
693  return nullptr;
694 
695  name = XMLStringByTag(xmsubkwl, tag);
696  if (! name)
697  return nullptr;
698 
699  s[0] = '\0';
700  xipsub = nullptr;
701  txipsub = nullptr;
702  line = xip->start_line;
703  c = entry + xip->start;
704  for (count = xip->start + 1;;) {
705  if (*c != '<') {
706  c++;
707  count++;
708  if (*c == '\0' || count > xip->end)
709  break;
710  if (*c == '\n')
711  line++;
712  }
713  if (*c != '<')
714  continue;
715 
716  for (s[0] = '<', i = 1; i < 50; i++) {
717  c++;
718  count++;
719  if (*c == '\0' || count > xip->end)
720  break;
721  if (*c == '\n')
722  line++;
723  s[i] = *c;
724  if (*c == '<' || *c == '>')
725  break;
726  }
727  if (*c == '\0' || count > xip->end)
728  break;
729  if (*c == '<')
730  continue;
731  s[++i] = '\0';
732  p = s + ((s[1] == '/') ? 2 : 1);
733  if (! StringEqu(p, name + 1))
734  continue;
735 
736  if (! xipsub) {
737  xipsub = XMLIndexNew();
738  txipsub = xipsub;
739  } else if ((s[1] != '/' && txipsub->start != 0) ||
740  (s[1] == '/' && txipsub->end != 0)) {
741  txipsub->next = XMLIndexNew();
742  txipsub = txipsub->next;
743  }
744  if (s[1] == '/') {
745  txipsub->end = count - i;
746  txipsub->end_line = line;
747  } else {
748  txipsub->start = count;
749  txipsub->start_line = line;
750  }
751  txipsub->tag = tag;
752  }
753 
754  if (XMLSameTagsCheck(xipsub, name))
755  return (xipsub);
756 
757  XMLIndexFree(xipsub);
758  return nullptr;
759 }
760 
761 /**********************************************************/
762 static bool XMLAccessionsCheck(ParserPtr pp, IndexblkPtr ibp, const char* entry)
763 {
764  XmlIndexPtr xip;
765  XmlIndexPtr xipsec;
766  string buf;
767  char* p;
768 
769  bool ret = true;
770  size_t len = StringLen(ibp->acnum) + StringLen(XML_FAKE_ACC_TAG);
771 
772  for (xip = ibp->xip; xip; xip = xip->next)
773  if (xip->tag == INSDSEQ_SECONDARY_ACCESSIONS)
774  break;
775 
776  if (! xip) {
777  buf.reserve(len);
778  buf.append(XML_FAKE_ACC_TAG);
779  buf.append(ibp->acnum);
780  ret = GetAccession(pp, buf.c_str(), ibp, 2);
781  return ret;
782  }
783 
784  xip->subtags = XMLIndexSameSubTags(entry, xip, INSDSECONDARY_ACCN);
785  if (! xip->subtags) {
787  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLFormatError, "Incorrectly formatted \"%s\" XML block. Entry dropped.", p);
788  ibp->drop = true;
789  return false;
790  }
791 
792  for (xipsec = xip->subtags; xipsec; xipsec = xipsec->next)
793  len += (xipsec->end - xipsec->start + 1);
794 
795  buf.reserve(len);
796  buf.append(XML_FAKE_ACC_TAG);
797  buf.append(ibp->acnum);
798  for (xipsec = xip->subtags; xipsec; xipsec = xipsec->next) {
799  p = XMLGetTagValue(entry, xipsec);
800  if (p) {
801  buf.append(" ");
802  buf.append(p);
803  MemFree(p);
804  }
805  }
806  ret = GetAccession(pp, buf.c_str(), ibp, 2);
807  return ret;
808 }
809 
810 /**********************************************************/
811 static bool XMLKeywordsCheck(const char* entry, IndexblkPtr ibp, Parser::ESource source)
812 {
813  XmlIndexPtr xip;
814  XmlIndexPtr xipkwd;
815  ValNodePtr vnp;
816  char* p;
817 
818  bool tpa_check = (source == Parser::ESource::EMBL);
819 
820  if (! entry || ! ibp || ! ibp->xip)
821  return true;
822 
823  for (xip = ibp->xip; xip; xip = xip->next)
824  if (xip->tag == INSDSEQ_KEYWORDS)
825  break;
826  if (! xip)
827  return true;
828 
829  xip->subtags = XMLIndexSameSubTags(entry, xip, INSDKEYWORD);
830  if (! xip->subtags) {
832  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLFormatError, "Incorrectly formatted \"%s\" XML block. Entry dropped.", p);
833  ibp->drop = true;
834  return false;
835  }
836 
837  size_t len = 0;
838  for (xipkwd = xip->subtags; xipkwd; xipkwd = xipkwd->next)
839  len += (xipkwd->end - xipkwd->start + 2);
840 
841  string buf;
842  buf.reserve(len);
843  for (xipkwd = xip->subtags; xipkwd; xipkwd = xipkwd->next) {
844  p = XMLGetTagValue(entry, xipkwd);
845  if (p) {
846  if (! buf.empty())
847  buf += "; ";
848  buf += p;
849  MemFree(p);
850  }
851  }
852 
854  check_est_sts_gss_tpa_kwds(vnp, len, ibp, tpa_check, ibp->specialist_db, ibp->inferential, ibp->experimental, ibp->assembly);
855  delete vnp;
856  return true;
857 }
858 
859 /**********************************************************/
860 static bool XMLErrField(Int4 tag)
861 {
862  ErrPostEx(SEV_ERROR, ERR_FORMAT_MissingField, "No %s data in XML format file. Entry dropped.", XMLStringByTag(xmkwl, tag));
863  return false;
864 }
865 
866 /**********************************************************/
868 {
869  XmlIndexPtr xip;
870  bool got_locus = false;
871  bool got_length = false;
872  bool got_moltype = false;
873  bool got_division = false;
874  bool got_update_date = false;
875  bool got_definition = false;
876  bool got_accession = false;
877  bool got_version = false;
878  bool got_source = false;
879  bool got_organism = false;
880  bool got_reference = false;
881  bool got_primary = false;
882  bool got_features = false;
883  bool ret = true;
884 
885  ibp->origin = false;
886  ibp->is_contig = false;
887  for (xip = ibp->xip; xip; xip = xip->next) {
888  if (xip->tag == INSDSEQ_LOCUS && pp->source != Parser::ESource::USPTO)
889  got_locus = true;
890  else if (xip->tag == INSDSEQ_LENGTH)
891  got_length = true;
892  else if (xip->tag == INSDSEQ_MOLTYPE)
893  got_moltype = true;
894  else if (xip->tag == INSDSEQ_DIVISION)
895  got_division = true;
896  else if (xip->tag == INSDSEQ_UPDATE_DATE)
897  got_update_date = true;
898  else if (xip->tag == INSDSEQ_DEFINITION)
899  got_definition = true;
900  else if (xip->tag == INSDSEQ_PRIMARY_ACCESSION)
901  got_accession = true;
902  else if (xip->tag == INSDSEQ_ACCESSION_VERSION)
903  got_version = true;
904  else if (xip->tag == INSDSEQ_SOURCE)
905  got_source = true;
906  else if (xip->tag == INSDSEQ_ORGANISM)
907  got_organism = true;
908  else if (xip->tag == INSDSEQ_REFERENCES)
909  got_reference = true;
910  else if (xip->tag == INSDSEQ_PRIMARY)
911  got_primary = true;
912  else if (xip->tag == INSDSEQ_FEATURE_TABLE)
913  got_features = true;
914  else if (xip->tag == INSDSEQ_CONTIG)
915  ibp->is_contig = true;
916  else if (xip->tag == INSDSEQ_SEQUENCE)
917  ibp->origin = true;
918  }
919 
920  if (got_locus == false && pp->source != Parser::ESource::USPTO)
921  ret = XMLErrField(INSDSEQ_LOCUS);
922  if (got_length == false)
924  if (got_moltype == false)
926  if (got_division == false)
928  if (got_update_date == false && pp->source != Parser::ESource::USPTO)
930  if (got_definition == false)
932  if (got_accession == false) {
933  ErrPostEx(SEV_ERROR, ERR_ACCESSION_NoAccessNum, "No accession number for this record. Entry dropped.");
934  ret = false;
935  }
936  if (got_version == false) {
937  if (pp->accver != false)
939  } else if (pp->source == Parser::ESource::USPTO) {
940  ErrPostEx(SEV_REJECT, ERR_ENTRY_InvalidLineType, "Line type %s is not allowed for USPTO records. Entry dropped.", XMLStringByTag(xmkwl, INSDSEQ_PRIMARY));
941  ret = false;
942  }
943  if (got_source == false)
945  if (got_organism == false)
947  if (got_reference == false && pp->source != Parser::ESource::Flybase &&
948  ibp->is_wgs == false &&
950  ! StringEquN(ibp->acnum, "NW_", 3)))
952  if (got_primary && ibp->is_tpa == false && ibp->tsa_allowed == false) {
953  ErrPostEx(SEV_ERROR, ERR_ENTRY_InvalidLineType, "Line type %s is allowed for TPA or TSA records only. Continue anyway.", XMLStringByTag(xmkwl, INSDSEQ_PRIMARY));
954  }
955  if (got_features == false)
957  if (ibp->is_contig && ibp->segnum != 0) {
958  ErrPostEx(SEV_ERROR, ERR_FORMAT_ContigInSegset, "%s data are not allowed for members of segmented sets. Entry dropped.", XMLStringByTag(xmkwl, INSDSEQ_CONTIG));
959  ret = false;
960  }
961 
962  ibp->is_tpa_wgs_con = (ibp->is_contig && ibp->is_wgs && ibp->is_tpa);
963 
964  return (ret);
965 }
966 
967 /**********************************************************/
968 char* XMLLoadEntry(ParserPtr pp, bool err)
969 {
970  IndexblkPtr ibp;
971  char* entry;
972  char* p;
973  size_t i;
974  Int4 c;
975 
976  if (! pp || ! s_HasInput(*pp)) {
977  return nullptr;
978  }
979 
980  ibp = pp->entrylist[pp->curindx];
981  if (! ibp || ibp->len == 0)
982  return nullptr;
983 
984  entry = StringNew(ibp->len);
985  s_SetPointer(*pp, ibp->offset);
986 
987 
988  for (p = entry, i = 0; i < ibp->len; i++) {
989  c = s_GetCharAndAdvance(*pp);
990  if (c < 0)
991  break;
992  if (c == 13) {
993  c = 10;
994  }
995  if (c > 126 || (c < 32 && c != 10)) {
996  if (err)
997  ErrPostEx(SEV_WARNING, ERR_FORMAT_NonAsciiChar, "None-ASCII character within the record which begins at line %d, decimal value %d, replaced by #.", ibp->linenum, c);
998  *p++ = '#';
999  } else
1000  *p++ = (Char)c;
1001  }
1002  if (i != ibp->len) {
1003  MemFree(entry);
1004  return nullptr;
1005  }
1006  *p = '\0';
1007 
1008  return (entry);
1009 }
1010 
1011 
1012 /**********************************************************/
1013 static bool XMLIndexSubTags(const char* entry, XmlIndexPtr xip, XmlKwordBlkPtr xkbp)
1014 {
1015  XmlKwordBlkPtr txkbp;
1016  XmlIndexPtr xipsub;
1017  const char* c;
1018  char* p;
1019  Char s[60];
1020  size_t count;
1021  Int4 line;
1022  Int4 i;
1023 
1024  if (! entry || ! xip)
1025  return false;
1026 
1027  s[0] = '\0';
1028  xipsub = nullptr;
1029  line = xip->start_line;
1030  c = entry + xip->start;
1031  for (count = xip->start + 1;;) {
1032  if (*c != '<') {
1033  c++;
1034  count++;
1035  if (*c == '\0' || count > xip->end)
1036  break;
1037  if (*c == '\n')
1038  line++;
1039  }
1040  if (*c != '<')
1041  continue;
1042 
1043  for (s[0] = '<', i = 1; i < 50; i++) {
1044  c++;
1045  count++;
1046  if (*c == '\0' || count > xip->end)
1047  break;
1048  if (*c == '\n')
1049  line++;
1050  s[i] = *c;
1051  if (*c == '<' || *c == '>')
1052  break;
1053  }
1054  if (*c == '\0' || count > xip->end)
1055  break;
1056  if (*c == '<')
1057  continue;
1058  s[++i] = '\0';
1059  p = s + ((s[1] == '/') ? 2 : 1);
1060  for (txkbp = xkbp; txkbp->str; txkbp++)
1061  if (StringEqu(p, txkbp->str + 1))
1062  break;
1063  if (! txkbp->str)
1064  continue;
1065  if (! xipsub || xipsub->tag != txkbp->tag) {
1066  if (! xipsub) {
1067  xipsub = XMLIndexNew();
1068  xip->subtags = xipsub;
1069  } else {
1070  xipsub->next = XMLIndexNew();
1071  xipsub = xipsub->next;
1072  }
1073  xipsub->tag = txkbp->tag;
1074  xipsub->order = txkbp->order;
1075  if (s[1] == '/') {
1076  xipsub->end = count - i;
1077  xipsub->end_line = line;
1078  } else {
1079  xipsub->start = count;
1080  xipsub->start_line = line;
1081  }
1082  continue;
1083  }
1084  if (s[1] == '/') {
1085  if (xipsub->end != 0) {
1086  xipsub->next = XMLIndexNew();
1087  xipsub = xipsub->next;
1088  xipsub->tag = txkbp->tag;
1089  xipsub->order = txkbp->order;
1090  }
1091  xipsub->end = count - i;
1092  xipsub->end_line = line;
1093  } else {
1094  if (xipsub->start != 0) {
1095  xipsub->next = XMLIndexNew();
1096  xipsub = xipsub->next;
1097  xipsub->tag = txkbp->tag;
1098  xipsub->order = txkbp->order;
1099  }
1100  xipsub->start = count;
1101  xipsub->start_line = line;
1102  }
1103  }
1104 
1105  if (! XMLTagCheck(xip->subtags, xkbp))
1106  return false;
1107 
1108  return true;
1109 }
1110 
1111 /**********************************************************/
1113 {
1114  bool got_key = false;
1115  bool got_location = false;
1116  bool ret = true;
1117 
1118  for (; xip; xip = xip->next) {
1119  if (xip->tag == INSDFEATURE_KEY)
1120  got_key = true;
1121  else if (xip->tag == INSDFEATURE_LOCATION)
1122  got_location = true;
1123  }
1124 
1125  if (! got_key) {
1126  ErrPostEx(SEV_ERROR, ERR_FORMAT_MissingField, "Feature table is missing %s data in XML format file.", XMLStringByTag(xmfeatkwl, INSDFEATURE_KEY));
1127  ret = false;
1128  }
1129 
1130  if (! got_location) {
1131  ErrPostEx(SEV_ERROR, ERR_FORMAT_MissingField, "Feature table is missing %s data in XML format file.", XMLStringByTag(xmfeatkwl, INSDFEATURE_LOCATION));
1132  ret = false;
1133  }
1134  return (ret);
1135 }
1136 
1137 /**********************************************************/
1139 {
1140  bool got_from = false;
1141  bool got_to = false;
1142  bool got_point = false;
1143  bool got_accession = false;
1144  bool ret = true;
1145 
1146  for (; xip; xip = xip->next) {
1147  if (xip->tag == INSDINTERVAL_FROM)
1148  got_from = true;
1149  else if (xip->tag == INSDINTERVAL_TO)
1150  got_to = true;
1151  else if (xip->tag == INSDINTERVAL_POINT)
1152  got_point = true;
1153  else if (xip->tag == INSDINTERVAL_ACCESSION)
1154  got_accession = true;
1155  }
1156 
1157  if (! got_accession) {
1158  ErrPostEx(SEV_ERROR, ERR_FORMAT_MissingField, "Feature's interval block is missing %s data in XML format file.", XMLStringByTag(xmintkwl, INSDINTERVAL_ACCESSION));
1159  ret = false;
1160  }
1161 
1162  if (got_point) {
1163  if (got_from || got_to) {
1165  ret = false;
1166  }
1167  } else if (got_from == false || got_to == false) {
1169  ret = false;
1170  }
1171 
1172  return (ret);
1173 }
1174 
1175 /**********************************************************/
1177 {
1178  for (; xip; xip = xip->next) {
1179  if (xip->tag == INSDQUALIFIER_NAME)
1180  break;
1181  }
1182 
1183  if (xip)
1184  return true;
1185 
1186  ErrPostEx(SEV_ERROR, ERR_FORMAT_MissingField, "Qualifier block is missing %s data in XML format file.", XMLStringByTag(xmqualkwl, INSDQUALIFIER_NAME));
1187  return false;
1188 }
1189 
1190 /**********************************************************/
1191 static bool XMLIndexFeatures(const char* entry, XmlIndexPtr xip)
1192 {
1193  XmlIndexPtr xipfeat;
1194  XmlIndexPtr xipsub;
1195  XmlIndexPtr txip;
1196 
1197  if (! xip || ! entry)
1198  return true;
1199 
1200  for (; xip; xip = xip->next) {
1201  if (xip->tag == INSDSEQ_FEATURE_TABLE)
1202  break;
1203  }
1204 
1205  if (! xip)
1206  return true;
1207 
1208  xip->subtags = XMLIndexSameSubTags(entry, xip, INSDFEATURE);
1209  if (! xip->subtags) {
1210  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLFormatError, "Incorrectly formatted \"%s\" XML block. Entry dropped.", XMLStringByTag(xmkwl, INSDSEQ_FEATURE_TABLE));
1211  return false;
1212  }
1213 
1214  for (xipfeat = xip->subtags; xipfeat; xipfeat = xipfeat->next) {
1215  if (XMLIndexSubTags(entry, xipfeat, xmfeatkwl) == false ||
1216  XMLCheckRequiredFeatTags(xipfeat->subtags) == false)
1217  break;
1218  for (txip = xipfeat->subtags; txip; txip = txip->next) {
1219  if (txip->tag == INSDFEATURE_INTERVALS) {
1220  txip->subtags = XMLIndexSameSubTags(entry, txip, INSDINTERVAL);
1221  if (! txip->subtags)
1222  break;
1223  xipsub = txip->subtags;
1224  for (; xipsub; xipsub = xipsub->next)
1225  if (XMLIndexSubTags(entry, xipsub, xmintkwl) == false ||
1226  XMLCheckRequiredIntTags(xipsub->subtags) == false)
1227  break;
1228  } else if (txip->tag == INSDFEATURE_QUALS) {
1229  txip->subtags = XMLIndexSameSubTags(entry, txip, INSDQUALIFIER);
1230  if (! txip->subtags)
1231  break;
1232  xipsub = txip->subtags;
1233  for (; xipsub; xipsub = xipsub->next)
1234  if (XMLIndexSubTags(entry, xipsub, xmqualkwl) == false ||
1235  XMLCheckRequiredQualTags(xipsub->subtags) == false)
1236  break;
1237  }
1238  }
1239  if (txip)
1240  break;
1241  }
1242 
1243  if (! xipfeat)
1244  return true;
1245 
1246  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLFormatError, "Incorrectly formatted \"%s\" XML block. Entry dropped.", XMLStringByTag(xmkwl, INSDSEQ_FEATURE_TABLE));
1247  return false;
1248 }
1249 
1250 /**********************************************************/
1252 {
1253  bool got_reference = false;
1254  bool got_journal = false;
1255  bool ret = true;
1256 
1257  for (; xip; xip = xip->next) {
1258  if (xip->tag == INSDREFERENCE_REFERENCE)
1259  got_reference = true;
1260  else if (xip->tag == INSDREFERENCE_JOURNAL)
1261  got_journal = true;
1262  }
1263 
1264  if (! got_reference) {
1266  ret = false;
1267  }
1268 
1269  if (! got_journal) {
1271  ret = false;
1272  }
1273  return (ret);
1274 }
1275 
1276 /**********************************************************/
1277 static Int2 XMLGetRefTypePos(char* reftag, size_t bases)
1278 {
1279  if (! reftag || *reftag == '\0')
1280  return (ParFlat_REF_NO_TARGET);
1281 
1282  const string str = "1.." + to_string(bases);
1283  if (StringEqu(reftag, str.c_str()))
1284  return (ParFlat_REF_END);
1285  if (StringEqu(reftag, "sites"))
1286  return (ParFlat_REF_SITES);
1287  return (ParFlat_REF_BTW);
1288 }
1289 
1290 /**********************************************************/
1291 static Int2 XMLGetRefType(char* reftag, size_t bases)
1292 {
1293  char* p;
1294 
1295  if (! reftag)
1296  return (ParFlat_REF_NO_TARGET);
1297 
1298  for (p = reftag; *p != '\0' && *p != '(';)
1299  p++;
1300  if (*p == '\0')
1301  return (ParFlat_REF_NO_TARGET);
1302 
1303  const string str = "(bases 1 to " + to_string(bases) + ")";
1304  const string str1 = "(bases 1 to " + to_string(bases) + ";";
1305 
1306  if (StringStr(p, str.c_str()) || StringStr(p, str1.c_str()))
1307  return (ParFlat_REF_END);
1308  if (StringStr(p, "(sites)"))
1309  return (ParFlat_REF_SITES);
1310  return (ParFlat_REF_BTW);
1311 }
1312 
1313 /**********************************************************/
1315 {
1316  bool got_dbname = false;
1317  bool got_id = false;
1318  bool ret = true;
1319 
1320  for (; xip; xip = xip->next) {
1321  if (xip->tag == INSDXREF_DBNAME)
1322  got_dbname = true;
1323  else if (xip->tag == INSDXREF_ID)
1324  got_id = true;
1325  }
1326 
1327  if (! got_dbname) {
1328  ErrPostEx(SEV_ERROR, ERR_FORMAT_MissingField, "%s block is missing %s data in XML format file.", XMLStringByTag(xmsubkwl, INSDXREF), XMLStringByTag(xmrefkwl, INSDXREF_DBNAME));
1329  ret = false;
1330  }
1331 
1332  if (! got_id) {
1333  ErrPostEx(SEV_ERROR, ERR_FORMAT_MissingField, "%s block is missing %s data in XML format file.", XMLStringByTag(xmsubkwl, INSDXREF), XMLStringByTag(xmrefkwl, INSDXREF_ID));
1334  ret = false;
1335  }
1336  return (ret);
1337 }
1338 
1339 /**********************************************************/
1340 static bool XMLIndexReferences(const char* entry, XmlIndexPtr xip, size_t bases)
1341 {
1342  XmlIndexPtr xipref;
1343  XmlIndexPtr txip;
1344  XmlIndexPtr xipsub;
1345  char* reftagref;
1346  char* reftagpos;
1347 
1348  if (! xip || ! entry)
1349  return true;
1350 
1351  for (; xip; xip = xip->next) {
1352  if (xip->tag == INSDSEQ_REFERENCES)
1353  break;
1354  }
1355  if (! xip)
1356  return true;
1357 
1358  xip->subtags = XMLIndexSameSubTags(entry, xip, INSDREFERENCE);
1359  if (! xip->subtags) {
1360  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLFormatError, "Incorrectly formatted \"%s\" XML block. Entry dropped.", XMLStringByTag(xmkwl, INSDSEQ_REFERENCES));
1361  return false;
1362  }
1363 
1364  for (xipref = xip->subtags; xipref; xipref = xipref->next) {
1365  if (XMLIndexSubTags(entry, xipref, xmrefkwl) == false ||
1366  XMLCheckRequiredRefTags(xipref->subtags) == false)
1367  break;
1368 
1369  reftagref = nullptr;
1370  reftagpos = nullptr;
1371  for (txip = xipref->subtags; txip; txip = txip->next) {
1372  if (txip->tag == INSDREFERENCE_REFERENCE) {
1373  if (reftagref)
1374  MemFree(reftagref);
1375  reftagref = XMLGetTagValue(entry, txip);
1376  continue;
1377  }
1378  if (txip->tag == INSDREFERENCE_POSITION) {
1379  if (reftagpos)
1380  MemFree(reftagpos);
1381  reftagpos = XMLGetTagValue(entry, txip);
1382  continue;
1383  }
1384  if (txip->tag == INSDREFERENCE_AUTHORS) {
1385  txip->subtags = XMLIndexSameSubTags(entry, txip, INSDAUTHOR);
1386  if (! txip->subtags)
1387  break;
1388  } else if (txip->tag == INSDREFERENCE_XREF) {
1389  txip->subtags = XMLIndexSameSubTags(entry, txip, INSDXREF);
1390  if (! txip->subtags)
1391  break;
1392  xipsub = txip->subtags;
1393  for (; xipsub; xipsub = xipsub->next)
1394  if (XMLIndexSubTags(entry, xipsub, xmxrefkwl) == false ||
1395  XMLCheckRequiredXrefTags(xipsub->subtags) == false)
1396  break;
1397  }
1398  }
1399 
1400  if (reftagpos) {
1401  xipref->type = XMLGetRefTypePos(reftagpos, bases);
1402  MemFree(reftagpos);
1403  } else
1404  xipref->type = XMLGetRefType(reftagref, bases);
1405  if (reftagref)
1406  MemFree(reftagref);
1407 
1408  if (txip)
1409  break;
1410  }
1411 
1412  if (! xipref)
1413  return true;
1414 
1415  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLFormatError, "Incorrectly formatted \"%s\" XML block. Entry dropped.", XMLStringByTag(xmkwl, INSDSEQ_REFERENCES));
1416  return false;
1417 }
1418 
1419 /**********************************************************/
1421 {
1422  IndexblkPtr ibp;
1423  char* entry;
1424 
1425  XMLPerformIndex(pp);
1426 
1427  if (pp->indx == 0)
1428  return false;
1429 
1430  pp->curindx = 0;
1431  for (auto ibpp = pp->entrylist.begin(); ibpp != pp->entrylist.end(); ++ibpp, pp->curindx++) {
1432  ibp = *ibpp;
1433  if (ibp->len == 0) {
1434  ErrPostEx(SEV_ERROR, ERR_FORMAT_MissingEnd, "Missing end tag of XML record, which starts at line %d. Entry dropped.", ibp->linenum);
1435  ibp->drop = true;
1436  continue;
1437  }
1438  entry = XMLLoadEntry(pp, true);
1439  if (! entry) {
1440  ErrPostEx(SEV_FATAL, ERR_INPUT_CannotReadEntry, "Failed ro read entry from file, which starts at line %d. Entry dropped.", ibp->linenum);
1441  ibp->drop = true;
1442  continue;
1443  }
1444 
1445  XMLInitialEntry(ibp, entry, pp->accver, pp->source);
1446  if (ibp->drop) {
1447  MemFree(entry);
1448  continue;
1449  }
1450  if (XMLTagCheck(ibp->xip, xmkwl) == false) {
1451  ErrPostEx(SEV_ERROR, ERR_FORMAT_XMLFormatError, "Incorrectly formatted XML record. Entry dropped.");
1452  ibp->drop = true;
1453  MemFree(entry);
1454  continue;
1455  }
1456  if (XMLAccessionsCheck(pp, ibp, entry) == false) {
1457  MemFree(entry);
1458  continue;
1459  }
1460  XMLGetSegment(entry, ibp);
1461  if (XMLCheckRequiredTags(pp, ibp) == false) {
1462  ibp->drop = true;
1463  MemFree(entry);
1464  continue;
1465  }
1466  if (XMLKeywordsCheck(entry, ibp, pp->source) == false) {
1467  MemFree(entry);
1468  continue;
1469  }
1470  if (XMLIndexFeatures(entry, ibp->xip) == false ||
1471  XMLIndexReferences(entry, ibp->xip, ibp->bases) == false) {
1472  ibp->drop = true;
1473  MemFree(entry);
1474  continue;
1475  }
1476  MemFree(entry);
1477  }
1478 
1479  pp->num_drop = 0;
1480  for (auto ibpp = pp->entrylist.begin(); ibpp != pp->entrylist.end(); ++ibpp)
1481  if ((*ibpp)->drop)
1482  pp->num_drop++;
1483 
1484  if (pp->indx > 0)
1485  return true;
1486  return false;
1487 }
1488 
1489 /**********************************************************/
1490 DataBlkPtr XMLBuildRefDataBlk(char* entry, const XmlIndex* xip, int type)
1491 {
1492  XmlIndexPtr txip;
1493  DataBlkPtr dbp;
1494  DataBlkPtr tdbp;
1495 
1496  if (! entry || ! xip)
1497  return nullptr;
1498 
1499  while (xip && xip->tag != INSDSEQ_REFERENCES)
1500  xip = xip->next;
1501  if (! xip || ! xip->subtags)
1502  return nullptr;
1503 
1504  for (dbp = nullptr, txip = xip->subtags; txip; txip = txip->next) {
1505  if (txip->type != type || ! txip->subtags)
1506  continue;
1507  if (! dbp) {
1508  dbp = new DataBlk;
1509  tdbp = dbp;
1510  } else {
1511  tdbp->mpNext = new DataBlk;
1512  tdbp = tdbp->mpNext;
1513  }
1514  tdbp->mType = txip->type;
1515  tdbp->mOffset = entry;
1516  tdbp->mpData = txip->subtags;
1517  tdbp->mpNext = nullptr;
1518  }
1519  return (dbp);
1520 }
1521 
1522 /**********************************************************/
1523 void XMLGetKeywords(const char* entry, const XmlIndex* xip, TKeywordList& keywords)
1524 {
1525  XmlIndexPtr xipkwd;
1526  char* p;
1527 
1528  keywords.clear();
1529  if (! entry || ! xip)
1530  return;
1531 
1532  for (; xip; xip = xip->next)
1533  if (xip->tag == INSDSEQ_KEYWORDS && xip->subtags)
1534  break;
1535  if (! xip)
1536  return;
1537 
1538  for (xipkwd = xip->subtags; xipkwd; xipkwd = xipkwd->next) {
1539  p = XMLGetTagValue(entry, xipkwd);
1540  if (! p)
1541  continue;
1542 
1543  keywords.push_back(p);
1544  MemFree(p);
1545  }
1546 }
1547 
1548 /**********************************************************/
1549 char* XMLConcatSubTags(const char* entry, const XmlIndex* xip, Int4 tag, Char sep)
1550 {
1551  const XmlIndex* txip;
1552 
1553  if (! entry || ! xip)
1554  return nullptr;
1555 
1556  while (xip && xip->tag != tag)
1557  xip = xip->next;
1558 
1559  if (! xip || ! xip->subtags)
1560  return nullptr;
1561 
1562  size_t i = 0;
1563  for (txip = xip->subtags; txip; txip = txip->next)
1564  i += (txip->end - txip->start + 2);
1565 
1566  string buf;
1567  buf.reserve(i);
1568  for (txip = xip->subtags; txip; txip = txip->next) {
1569  if (txip->start >= txip->end)
1570  continue;
1571  if (! buf.empty()) {
1572  buf += sep;
1573  buf += ' ';
1574  }
1575  buf.append(entry + txip->start, txip->end - txip->start);
1576  }
1578 }
1579 
void XMLIndexFree(XmlIndexPtr xip)
Definition: block.cpp:130
char * mOffset
Definition: ftablock.h:334
CFlatFileData * mpData
Definition: ftablock.h:333
DataBlk * mpNext
Definition: ftablock.h:338
int mType
Definition: ftablock.h:332
#define ERR_FORMAT_LineTypeOrder
Definition: flat2err.h:40
#define ERR_FORMAT_MissingEnd
Definition: flat2err.h:39
#define INSDXREF_DBNAME
Definition: fta_xml.h:101
#define INSDAUTHOR
Definition: fta_xml.h:103
#define INSDSEQ_ACCESSION_VERSION
Definition: fta_xml.h:55
#define INSDSEQ_OTHER_SEQIDS
Definition: fta_xml.h:56
#define INSDSEQ_TOPOLOGY
Definition: fta_xml.h:46
#define INSDSEQ_START
Definition: fta_xml.h:39
#define INSDREFERENCE_REMARK
Definition: fta_xml.h:98
#define INSDINTERVAL
Definition: fta_xml.h:81
#define INSDSEQ_PRIMARY_ACCESSION
Definition: fta_xml.h:53
#define INSDSEQ_UPDATE_RELEASE
Definition: fta_xml.h:50
#define INSDINTERVAL_POINT
Definition: fta_xml.h:84
#define INSDSEQ_MOLTYPE
Definition: fta_xml.h:45
#define INSDSEQ_DEFINITION
Definition: fta_xml.h:52
#define INSDINTERVAL_TO
Definition: fta_xml.h:83
#define INSDINTERVAL_FROM
Definition: fta_xml.h:82
#define INSDQUALIFIER_NAME
Definition: fta_xml.h:87
#define INSDSEQ_CREATE_RELEASE
Definition: fta_xml.h:51
#define INSDSEQ_STRANDEDNESS
Definition: fta_xml.h:44
#define INSDREFERENCE_PUBMED
Definition: fta_xml.h:97
#define INSDSEQ_FEATURE_TABLE
Definition: fta_xml.h:68
#define INSDSEQ_COMMENT
Definition: fta_xml.h:64
#define INSDSEQ_ORGANISM
Definition: fta_xml.h:61
#define INSDREFERENCE
Definition: fta_xml.h:89
#define INSDFEATURE_LOCATION
Definition: fta_xml.h:78
#define INSDREFERENCE_AUTHORS
Definition: fta_xml.h:92
#define INSDREFERENCE_XREF
Definition: fta_xml.h:99
#define INSDQUALIFIER_VALUE
Definition: fta_xml.h:88
#define INSDSEQ_SEGMENT
Definition: fta_xml.h:59
#define INSDSEQ_REFERENCES
Definition: fta_xml.h:63
#define INSDSEQ_SECONDARY_ACCESSIONS
Definition: fta_xml.h:57
#define INSDFEATURE_KEY
Definition: fta_xml.h:77
#define INSDKEYWORD
Definition: fta_xml.h:75
#define INSDREFERENCE_POSITION
Definition: fta_xml.h:91
#define INSDSEQ_SOURCE_DB
Definition: fta_xml.h:66
#define INSDXREF_ID
Definition: fta_xml.h:102
#define INSDSEQ_LOCUS
Definition: fta_xml.h:42
#define INSDREFERENCE_TITLE
Definition: fta_xml.h:94
#define INSDSEQ_END
Definition: fta_xml.h:40
#define INSDSECONDARY_ACCN
Definition: fta_xml.h:74
#define INSDSEQ_KEYWORDS
Definition: fta_xml.h:58
#define INSDFEATURE_QUALS
Definition: fta_xml.h:80
#define INSDINTERVAL_ACCESSION
Definition: fta_xml.h:85
#define INSDSEQ_DATABASE_REFERENCE
Definition: fta_xml.h:67
#define INSDXREF
Definition: fta_xml.h:100
#define INSDSEQ_TAXONOMY
Definition: fta_xml.h:62
#define INSDSEQ_SEQUENCE
Definition: fta_xml.h:69
#define INSDSEQ_ENTRY_VERSION
Definition: fta_xml.h:54
#define INSDSEQ_CREATE_DATE
Definition: fta_xml.h:49
#define INSDFEATURE_INTERVALS
Definition: fta_xml.h:79
#define INSDSEQ_LENGTH
Definition: fta_xml.h:43
#define INSDSEQ_DIVISION
Definition: fta_xml.h:47
#define INSDREFERENCE_JOURNAL
Definition: fta_xml.h:95
#define INSDSEQ_UPDATE_DATE
Definition: fta_xml.h:48
#define INSDSEQ_SOURCE
Definition: fta_xml.h:60
#define INSDREFERENCE_MEDLINE
Definition: fta_xml.h:96
#define INSDREFERENCE_CONSORTIUM
Definition: fta_xml.h:93
#define INSDSEQ_CONTIG
Definition: fta_xml.h:70
#define INSDQUALIFIER
Definition: fta_xml.h:86
#define INSDREFERENCE_REFERENCE
Definition: fta_xml.h:90
#define INSDSEQ_PRIMARY
Definition: fta_xml.h:65
#define INSDFEATURE
Definition: fta_xml.h:76
std::list< std::string > TKeywordList
Definition: ftablock.h:168
bool StringEquN(const char *s1, const char *s2, size_t n)
Definition: ftacpp.hpp:115
bool StringEqu(const char *s1, const char *s2)
Definition: ftacpp.hpp:105
void StringCpy(char *d, const char *s)
Definition: ftacpp.hpp:83
void StringNCpy(char *d, const char *s, size_t n)
Definition: ftacpp.hpp:84
void MemFree(char *p)
Definition: ftacpp.hpp:55
size_t StringLen(const char *s)
Definition: ftacpp.hpp:60
char * StringRChr(char *s, const char c)
Definition: ftacpp.hpp:87
char * StringNew(size_t sz)
Definition: ftacpp.hpp:43
void FtaInstallPrefix(int prefix, const char *name, const char *location)
Definition: ftaerr.cpp:321
#define PREFIX_LOCUS
Definition: ftaerr.hpp:15
#define PREFIX_ACCESSION
Definition: ftaerr.hpp:14
static const char * str(char *buf, int n)
Definition: stats.c:84
int offset
Definition: replacements.h:160
#define SEV_WARNING
Definition: gicache.c:90
#define SEV_ERROR
Definition: gicache.c:91
#define SEV_FATAL
Definition: gicache.c:93
#define SEV_REJECT
Definition: gicache.c:92
#define StringStr
Definition: ncbistr.hpp:322
#define StringSave
Definition: ncbistr.hpp:326
#define Char
Definition: ncbistd.hpp:124
#define ErrPostEx(sev, err_code,...)
Definition: ncbierr.hpp:78
int16_t Int2
2-byte (16-bit) signed integer
Definition: ncbitype.h:100
int32_t Int4
4-byte (32-bit) signed integer
Definition: ncbitype.h:102
char Char
Alias for char.
Definition: ncbitype.h:93
uint16_t Uint2
2-byte (16-bit) unsigned integer
Definition: ncbitype.h:101
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static int CompareNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive compare of a substring with another string.
Definition: ncbistr.cpp:219
@ ParFlat_REF_BTW
Definition: index.h:61
@ ParFlat_REF_NO_TARGET
Definition: index.h:63
@ ParFlat_REF_SITES
Definition: index.h:62
@ ParFlat_REF_END
Definition: index.h:60
CRef< CDate_std > GetUpdateDate(const char *ptr, Parser::ESource source)
Definition: indx_blk.cpp:611
#define ERR_FORMAT_XMLMissingStartTag
Definition: indx_err.h:52
#define ERR_VERSION_NonDigitVerNum
Definition: indx_err.h:83
#define ERR_FORMAT_XMLInvalidINSDInterval
Definition: indx_err.h:55
#define ERR_VERSION_MissingVerNum
Definition: indx_err.h:82
#define ERR_ACCESSION_NoAccessNum
Definition: indx_err.h:68
#define ERR_SEGMENT_BadLocusName
Definition: indx_err.h:78
#define ERR_FORMAT_ContigInSegset
Definition: indx_err.h:47
#define ERR_FORMAT_XMLFormatError
Definition: indx_err.h:54
#define ERR_FORMAT_UnexpectedEnd
Definition: indx_err.h:51
#define ERR_INPUT_CannotReadEntry
Definition: indx_err.h:100
#define ERR_SEGMENT_IncompSeg
Definition: indx_err.h:79
#define ERR_FORMAT_XMLMissingEndTag
Definition: indx_err.h:53
#define ERR_VERSION_BadVersionLine
Definition: indx_err.h:85
#define ERR_VERSION_InvalidVersion
Definition: indx_err.h:88
#define ERR_FORMAT_MissingField
Definition: indx_err.h:42
#define ERR_FORMAT_NonAsciiChar
Definition: indx_err.h:40
#define ERR_ENTRY_InvalidLineType
Definition: indx_err.h:64
#define ERR_VERSION_AccessionsDontMatch
Definition: indx_err.h:84
@ e_not_set
char * buf
int i
int len
const CharType(& source)[N]
Definition: pointer.h:1149
const char * tag
const CConstRef< CSeq_id > GetAccession(const CSeq_id_Handle &id_handle)
Indexblk * ibp
Definition: indx_blk.h:56
IndBlkNode * next
Definition: indx_blk.h:57
Char acnum[200]
Definition: ftablock.h:171
Char division[4]
Definition: ftablock.h:176
bool assembly
Definition: ftablock.h:246
bool tsa_allowed
Definition: ftablock.h:216
Char blocusname[200]
Definition: ftablock.h:183
CRef< objects::CDate_std > date
Definition: ftablock.h:192
bool is_tpa_wgs_con
Definition: ftablock.h:214
Int2 vernum
Definition: ftablock.h:172
bool is_tpa
Definition: ftablock.h:211
bool is_prot
Definition: ftablock.h:227
bool is_wgs
Definition: ftablock.h:210
bool origin
Definition: ftablock.h:206
bool is_contig
Definition: ftablock.h:202
bool STS
Definition: ftablock.h:198
bool is_pat
Definition: ftablock.h:207
bool HTC
Definition: ftablock.h:200
bool drop
Definition: ftablock.h:187
bool experimental
Definition: ftablock.h:252
size_t bases
Definition: ftablock.h:177
bool inferential
Definition: ftablock.h:250
Uint2 segtotal
Definition: ftablock.h:180
bool EST
Definition: ftablock.h:197
size_t linenum
Definition: ftablock.h:185
size_t len
Definition: ftablock.h:189
size_t offset
Definition: ftablock.h:173
bool specialist_db
Definition: ftablock.h:248
Uint2 segnum
Definition: ftablock.h:178
Char locusname[200]
Definition: ftablock.h:175
XmlIndexPtr xip
Definition: ftablock.h:222
bool GSS
Definition: ftablock.h:199
vector< IndexblkPtr > entrylist
TokenBlk * next
Definition: ftablock.h:137
char * str
Definition: ftablock.h:136
TokenBlk * list
Definition: ftablock.h:142
Int2 type
Definition: ftablock.h:161
size_t start
Definition: ftablock.h:157
XmlIndex * next
Definition: ftablock.h:163
Int4 end_line
Definition: ftablock.h:160
Int4 start_line
Definition: ftablock.h:159
XmlIndex * subtags
Definition: ftablock.h:162
size_t end
Definition: ftablock.h:158
Int4 tag
Definition: ftablock.h:155
Int4 order
Definition: ftablock.h:156
const char * str
Definition: xm_index.cpp:56
Int4 order
Definition: xm_index.cpp:57
Definition: type.c:6
void check_est_sts_gss_tpa_kwds(ValNodePtr kwds, size_t len, IndexblkPtr entry, bool tpa_check, bool &specialist_db, bool &inferential, bool &experimental, bool &assembly)
Definition: utilfun.cpp:1447
void FreeTokenstatblk(TokenStatBlkPtr tsbp)
Definition: utilfun.cpp:521
TokenStatBlkPtr TokenString(const char *str, Char delimiter)
Definition: utilfun.cpp:476
ValNodePtr ConstructValNode(CSeq_id::E_Choice choice, const char *data)
Definition: utilfun.cpp:1513
static bool XMLKeywordsCheck(const char *entry, IndexblkPtr ibp, Parser::ESource source)
Definition: xm_index.cpp:811
static bool XMLTagCheck(XmlIndexPtr xip, XmlKwordBlkPtr xkbp)
Definition: xm_index.cpp:640
static bool XMLIndexReferences(const char *entry, XmlIndexPtr xip, size_t bases)
Definition: xm_index.cpp:1340
DataBlkPtr XMLBuildRefDataBlk(char *entry, const XmlIndex *xip, int type)
Definition: xm_index.cpp:1490
char * XMLFindTagValue(const char *entry, const XmlIndex *xip, Int4 tag)
Definition: xm_index.cpp:214
static Int2 XMLGetRefTypePos(char *reftag, size_t bases)
Definition: xm_index.cpp:1277
char * XMLGetTagValue(const char *entry, const XmlIndex *xip)
Definition: xm_index.cpp:202
static bool XMLCheckRequiredFeatTags(XmlIndexPtr xip)
Definition: xm_index.cpp:1112
XmlKwordBlk xmrefkwl[]
Definition: xm_index.cpp:112
static bool XMLCheckRequiredRefTags(XmlIndexPtr xip)
Definition: xm_index.cpp:1251
XmlKwordBlk xmkwl[]
Definition: xm_index.cpp:63
XmlKwordBlk xmfeatkwl[]
Definition: xm_index.cpp:96
static bool XMLCheckRequiredIntTags(XmlIndexPtr xip)
Definition: xm_index.cpp:1138
XmlKwordBlk xmqualkwl[]
Definition: xm_index.cpp:126
void XMLGetKeywords(const char *entry, const XmlIndex *xip, TKeywordList &keywords)
Definition: xm_index.cpp:1523
static void XMLGetSegment(const char *entry, IndexblkPtr ibp)
Definition: xm_index.cpp:270
static const char * XMLStringByTag(XmlKwordBlkPtr xkbp, Int4 tag)
Definition: xm_index.cpp:629
bool XMLIndex(ParserPtr pp)
Definition: xm_index.cpp:1420
static void XMLParseVersion(IndexblkPtr ibp, char *line)
Definition: xm_index.cpp:476
static XmlIndexPtr XMLIndexSameSubTags(const char *entry, XmlIndexPtr xip, Int4 tag)
Definition: xm_index.cpp:680
XmlKwordBlk xmintkwl[]
Definition: xm_index.cpp:104
static int s_GetCharAndAdvance(Parser &config)
Definition: xm_index.cpp:318
static Int2 XMLGetRefType(char *reftag, size_t bases)
Definition: xm_index.cpp:1291
static bool XMLCheckRequiredQualTags(XmlIndexPtr xip)
Definition: xm_index.cpp:1176
static bool XMLCheckRequiredTags(ParserPtr pp, IndexblkPtr ibp)
Definition: xm_index.cpp:867
static bool XMLAccessionsCheck(ParserPtr pp, IndexblkPtr ibp, const char *entry)
Definition: xm_index.cpp:762
static void XMLPerformIndex(ParserPtr pp)
Definition: xm_index.cpp:332
#define XML_FAKE_ACC_TAG
Definition: xm_index.cpp:51
char * XMLLoadEntry(ParserPtr pp, bool err)
Definition: xm_index.cpp:968
XmlKwordBlk xmsubkwl[]
Definition: xm_index.cpp:138
static bool XMLSameTagsCheck(XmlIndexPtr xip, const char *name)
Definition: xm_index.cpp:662
static XmlIndexPtr XMLIndexNew(void)
Definition: xm_index.cpp:152
static string XMLRestoreSpecialCharacters(string_view s)
Definition: xm_index.cpp:169
static bool XMLDelSegnum(IndexblkPtr ibp, const char *segnum, size_t len2)
Definition: xm_index.cpp:225
static bool XMLIndexSubTags(const char *entry, XmlIndexPtr xip, XmlKwordBlkPtr xkbp)
Definition: xm_index.cpp:1013
static bool XMLCheckRequiredXrefTags(XmlIndexPtr xip)
Definition: xm_index.cpp:1314
static bool XMLIndexFeatures(const char *entry, XmlIndexPtr xip)
Definition: xm_index.cpp:1191
void s_SetPointer(Parser &config, size_t offset)
Definition: xm_index.cpp:326
XmlKwordBlk xmxrefkwl[]
Definition: xm_index.cpp:132
static void XMLInitialEntry(IndexblkPtr ibp, const char *entry, bool accver, Parser::ESource source)
Definition: xm_index.cpp:525
char * XMLConcatSubTags(const char *entry, const XmlIndex *xip, Int4 tag, Char sep)
Definition: xm_index.cpp:1549
static bool s_HasInput(const Parser &config)
Definition: xm_index.cpp:312
static bool XMLErrField(Int4 tag)
Definition: xm_index.cpp:860
Modified on Wed Apr 24 14:14:33 2024 by modify_doxy.py rev. 669887