1 /* @source ajfeat *************************************************************
2 **
3 ** A genome feature (in AJAX program context) is a description of a
4 ** genomic entity which was determined by some 'source' analysis
5 ** (which may be of 'wet lab' experimental or 'in silico'
6 ** computational nature), has a 'primary' descriptor ('Primary_Tag'),
7 ** may have some 'score' asserting the level of analysis confidence in
8 ** its identity (e.g. log likelihood relative to a null hypothesis or
9 ** other similar entity), has a 'Position' in the genome, and may have
10 ** any arbitrary number of descriptor tags associated with it.
11 **
12 ** @author Copyright (C) 1999 Richard Bruskiewich
13 ** @version $Revision: 1.192 $
14 ** @modified 2000 Ian Longden.
15 ** @modified 2001 Peter Rice.
16 ** @modified $Date: 2013/06/29 22:31:59 $ by $Author: rice $
17 ** @@
18 **
19 ** This library is free software; you can redistribute it and/or
20 ** modify it under the terms of the GNU Lesser General Public
21 ** License as published by the Free Software Foundation; either
22 ** version 2.1 of the License, or (at your option) any later version.
23 **
24 ** This library is distributed in the hope that it will be useful,
25 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
26 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27 ** Lesser General Public License for more details.
28 **
29 ** You should have received a copy of the GNU Lesser General Public
30 ** License along with this library; if not, write to the Free Software
31 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
32 ** MA  02110-1301,  USA.
33 **
34 ** Implementation Notes:
35 **
36 ** see also the header file, ajfeat.h, for details on class structure.
37 **
38 ** FT6.2 todo alternate mandatory qualifiers /citation /compare
39 **            labelled with m/ in Efeatures.*
40 ** FT6.2 todo /compare special value accession.version
41 ** FT6.2 todo check spaces in /anticodon /codon and other special values
42 **            when used in practice
43 ** FT6.2 todo warning for /cons_splice with YES YES
44 ** FT6.2 todo list of db_xref databases from
45 **            http://www.ncbi.nlm.nih.gov/projects/collab/db_xref.html
46 ** FT6.2 todo list of /country country names from
47 **            http://www.ncbi.nlm.nih.gov/projects/collab/country.html
48 ** FT6.2 todo EC_number value check
49 ** FT6.2 todo /frequency value check 0.0 to 1.0
50 ** FT6.2 todo QWORD values with no spaces /translation /locus_tag
51 **            /old_locus_tag
52 ** FT6.2 todo vocab for mod_base ... rel_std*.dat Aug-09 has
53 **     794 OTHER
54 **    1475 p
55 **     971 d
56 **     331 m5c
57 **     300 m1a
58 **     260 t
59 **     242 m7g
60 **     241 m2g
61 **     215 gm
62 **     202 m1g
63 **     186 m22g
64 **     153 cm
65 **     102 um
66 **      93 t6a
67 **      55 s4u
68 **      52 i
69 **      52 ac4c
70 **      49 m1f
71 **      48 m1i
72 **      41 x
73 **      41 i6a
74 **      33 m3c
75 **      31 ms2i6a
76 **      31 m6a
77 **      27 q
78 **      22 m2a
79 **      17 tm
80 **      11 mt6a
81 **      11 mcm5s2u
82 **       8 yw
83 **       6 s2t
84 **       6 osyw
85 **       6 fm
86 **       6 cmnm5u
87 **       5 s2c
88 **       5 mam5s2u
89 **       4 mo5u
90 **       4 mcm5u
91 **       3 o5u
92 **       3 ms2t6a
93 **
94 ** FT6.2 todo *qualifier for non-standard qualifiers (for Artemis)
95 ******************************************************************************/
96 
97 #include "ajlib.h"
98 
99 #include "ajfeat.h"
100 #include "ajfeatread.h"
101 #include "ajfeatwrite.h"
102 #include "ajtagval.h"
103 #include "ajmath.h"
104 #include "ajlist.h"
105 #include "ajtable.h"
106 #include "ajutil.h"
107 #include "ajreg.h"
108 #include "ajsys.h"
109 #include "ajnam.h"
110 #include "ajseq.h"
111 #include "ajseqread.h"
112 #include "ajfiledata.h"
113 #include "ajfileio.h"
114 
115 #define FEATDEBUG 0
116 
117 static AjPRegexp featRegTagReplace = NULL;
118 
119 static AjPRegexp featRegSpecialAnticodon = NULL;
120 static AjPRegexp featRegSpecialBiomaterial = NULL;
121 static AjPRegexp featRegSpecialCodon = NULL;
122 static AjPRegexp featRegSpecialCodonBad = NULL;
123 static AjPRegexp featRegSpecialColdate = NULL;
124 static AjPRegexp featRegSpecialCompare = NULL;
125 static AjPRegexp featRegSpecialConssplice = NULL;
126 static AjPRegexp featRegSpecialEstlen = NULL;
127 static AjPRegexp featRegSpecialInference = NULL;
128 static AjPRegexp featRegSpecialLatlon = NULL;
129 static AjPRegexp featRegSpecialMobile = NULL;
130 static AjPRegexp featRegSpecialPrimer = NULL;
131 static AjPRegexp featRegSpecialRptRange = NULL;
132 static AjPRegexp featRegSpecialRptRangeLab = NULL;
133 static AjPRegexp featRegSpecialRptRangeComp = NULL;
134 static AjPRegexp featRegSpecialRptunitSeq = NULL;
135 static AjPRegexp featRegSpecialRptunitSeqPos = NULL;
136 static AjPRegexp featRegSpecialTrans = NULL;
137 static AjPRegexp featRegSpecialTransBad = NULL;
138 static AjPRegexp featRegSpecialTransComp = NULL;
139 static AjPRegexp featRegSpecialTransBadComp = NULL;
140 
141 
142 
143 
144 
145 static AjBool   FeatInitDone         = AJFALSE;
146 static AjPTable FeatTypeTableDna     = NULL;
147 static AjPTable FeatTagsTableDna     = NULL;
148 static AjPTable FeatTypeTableProtein = NULL;
149 static AjPTable FeatTagsTableProtein = NULL;
150 
151 static AjPTable FeatTypeTableGff2 = NULL;
152 static AjPTable FeatTagsTableGff2 = NULL;
153 static AjPTable FeatTypeTableGff2protein = NULL;
154 static AjPTable FeatTagsTableGff2protein = NULL;
155 
156 static AjPTable FeatTypeTableGff3 = NULL;
157 static AjPTable FeatTagsTableGff3 = NULL;
158 static AjPTable FeatTypeTableGff3protein = NULL;
159 static AjPTable FeatTagsTableGff3protein = NULL;
160 
161 static AjPTable FeatTypeTableEmbl = NULL;
162 static AjPTable FeatTagsTableEmbl = NULL;
163 
164 static AjPTable FeatTypeTablePir = NULL;
165 static AjPTable FeatTagsTablePir = NULL;
166 
167 static AjPTable FeatTypeTableSwiss = NULL;
168 static AjPTable FeatTagsTableSwiss = NULL;
169 
170 static AjPTable FeatTypeTableRefseqp = NULL;
171 static AjPTable FeatTagsTableRefseqp = NULL;
172 
173 static AjPTable FeatCategoryTable     = NULL;
174 static ajint  featWarnCount = 0;
175 
176 static AjPStr featTypeMiscfeat   = NULL;
177 static AjPStr featTypeEmpty      = NULL;
178 static AjPStr featDefSource = NULL;
179 static AjPStr featFmtTmp = NULL;
180 static AjPStr featTagTmp = NULL;
181 static AjPStr featTagTmp2 = NULL;
182 static AjPStr featValTmp = NULL;
183 static AjPStr featValTmp2 = NULL;
184 static AjPStr featTagNote = NULL;
185 
186 static AjPStrTok featVocabSplit  = NULL;
187 
188 static AjPStr featTransBegStr = NULL;
189 static AjPStr featTransEndStr = NULL;
190 static AjPStr featTransAaStr  = NULL;
191 static AjPStr featTmpStr      = NULL;
192 static AjPStr featTempQry = NULL;
193 
194 
195 static const AjPTable featVocabInit(ajuint ivocab);
196 static void         featClear(AjPFeature thys );
197 static AjBool       featFeatType(const AjPStr line, AjPStr* type,
198 				 AjPStr* sofaid, AjPStr* tag, AjPStr* req);
199 static AjPFeature   featFeatureNew(void);
200 static void         featInit(void);
201 static void         featTableInit(AjPFeattable thys,
202 				  const AjPStr name);
203 static AjPFeattable featTableNew(void);
204 static AjPFeattable featTableNewS(const AjPStr name);
205 static const AjPStr featTableTypeInternal(const AjPStr type,
206 					  const AjPTable table);
207 static const AjPStr featTableTypeInternalLimit(const AjPStr type,
208                                                const AjPTable table);
209 static const AjPStr featTagDna(const AjPStr type, AjBool* known);
210 static AjBool       featTagGff3PredefinedTag(const AjPStr tag);
211 static AjBool       featTagName(const AjPStr line, AjPStr* name, AjPStr* type,
212 				AjPStr* rest);
213 static const AjPStr featTagProt(const AjPStr type, AjBool* known);
214 static void         featTagSetDefault(AjPFeature thys,
215 				      const AjPStr tag, const AjPStr value,
216 				      AjPStr* pdeftag, AjPStr* pdefval);
217 static void         featTagSetDefaultDna(const AjPStr tag, const AjPStr value,
218 					 AjPStr* pdeftag, AjPStr* pdefval);
219 static void         featTagSetDefaultProt(const AjPStr tag,
220 					  const AjPStr value,
221 					  AjPStr* pdeftag, AjPStr* pdefval);
222 static AjBool       featTagSpecialAllAnticodon(const AjPStr val);
223 static AjBool       featTagSpecialAllBiomaterial(const AjPStr val);
224 static AjBool       featTagSpecialAllCitation(const AjPStr val);
225 static AjBool       featTagSpecialAllCodon(AjPStr* pval);
226 static AjBool       featTagSpecialAllCollectiondate(const AjPStr pval);
227 static AjBool       featTagSpecialAllConssplice(AjPStr* pval);
228 static AjBool       featTagSpecialAllInference(const AjPStr pval);
229 static AjBool       featTagSpecialAllLatlon(const AjPStr pval);
230 static AjBool       featTagSpecialAllMobile(const AjPStr pval);
231 static AjBool       featTagSpecialAllPcrprimers(const AjPStr pval);
232 static AjBool       featTagSpecialAllRptunit(const AjPStr val);
233 static AjBool       featTagSpecialAllRange(const AjPStr val);
234 static AjBool       featTagSpecialAllRptunitseq(AjPStr *Pval);
235 static AjBool       featTagSpecialAllTranslexcept(const AjPStr val);
236 static AjBool       featTagSpecialAllDbxref(const AjPStr val);
237 static AjBool       featTagSpecialAllProteinid(const AjPStr val);
238 static AjBool       featTagSpecialAllReplace(AjPStr* pval);
239 static AjBool       featTagSpecialAllTranslation(AjPStr* pval);
240 static AjBool       featTagSpecialAllEstimatedlength(AjPStr* pval);
241 static AjBool       featTagSpecialAllCompare(const AjPStr val);
242 static AjBool       featTagSpecialAllNcrnaclass(const AjPStr val);
243 static AjPTagval    featTagval(const AjPFeature thys, const AjPStr tag);
244 static AjPTagval    featTagvalNew(const AjPFeature thys,
245 				  const AjPStr tag, const AjPStr value);
246 static AjPTagval    featTagvalNewDna(const AjPStr tag, const AjPStr value);
247 static AjPTagval    featTagvalNewProt(const AjPStr tag, const AjPStr value);
248 static const AjPStr featTypeDna(const AjPStr type);
249 static const AjPStr featTypeDnaLimit(const AjPStr type);
250 static const AjPStr featTypeProt(const AjPStr type);
251 static const AjPStr featTypeProtLimit(const AjPStr type);
252 static AjBool       featVocabRead(const char *name,
253 				  AjPTable pTypeTable, AjPTable pTagsTable);
254 static AjBool       featVocabReadTypes(const AjPStr fname,
255 				       AjPTable pTypeTable,
256 				       const AjPTable pTagsTable,
257 				       AjBool recursion);
258 static AjBool       featVocabReadTags(const AjPStr fname,
259 				      AjPTable pTagsTable,
260 				       AjBool recursion);
261 static AjBool featTypeTestDnaWild(const AjPStr type, const AjPStr str);
262 static AjBool featTypeTestProtWild(const AjPStr type, const AjPStr str);
263 static AjBool featTableTypeTestWild(const AjPStr type,
264                                     const AjPTable table,
265                                     const AjPStr str);
266 
267 
268 static void feattableMakeQry(const AjPFeattable thys, AjPStr* qry);
269 
270 
271 
272 /* @datastatic FeatPVocab *****************************************************
273 **
274 ** Feature vocabularies
275 **
276 ** @alias FeatSVocab
277 ** @alias FeatOVocab
278 **
279 ** @attr Name [const char*] Vocabulary name
280 ** @attr Truename [const char*] Vocabulary true name used for definition files
281 ** @attr Nucleotide [AjBool] True if suitable for nucleotide data
282 ** @attr Protein [AjBool] True if suitable for protein data
283 ** @attr Typetable [AjPTable*] Type table
284 ** @attr Tagstable [AjPTable*] Tags table
285 ** @attr Desc [const char*] Description
286 ** @attr Alias [AjBool] True if name is an alias for an identical definition
287 ** @attr Padding [ajint] Padding to alignment boundary
288 ** @@
289 ******************************************************************************/
290 
291 typedef struct FeatSVocab
292 {
293     const char* Name;
294     const char* Truename;
295     AjBool Nucleotide;
296     AjBool Protein;
297     AjPTable* Typetable;
298     AjPTable* Tagstable;
299     const char* Desc;
300     AjBool Alias;
301     ajint Padding;
302 } FeatOVocab;
303 
304 #define FeatPVocab FeatOVocab*
305 
306 
307 
308 
309 /* @funclist featVocabDef *****************************************************
310 **
311 ** Feature vocabularies
312 **
313 ** Includes pointers to the type and tag tables to be initialised
314 **
315 ******************************************************************************/
316 
317 static FeatOVocab featVocabDef[] =
318 {
319     /* Name       Truename     Nucleotide Prot
320          Typetable              Tagstable
321 	 Description         Alias   Padding */
322     {"gff3",      "gff3",        AJTRUE,    AJFALSE,
323          &FeatTypeTableGff3,    &FeatTagsTableGff3,
324 	 "GFF version 3",    AJFALSE, 0},
325     {"gff3",      "gff3protein", AJFALSE,    AJTRUE,
326 	 &FeatTypeTableGff3protein,    &FeatTagsTableGff3protein,
327 	 "GFF version 3",    AJTRUE,  0},
328     {"gff",       "gff3",        AJTRUE,    AJFALSE,
329          &FeatTypeTableGff3,    &FeatTagsTableGff3,
330 	 "GFF version 3",    AJFALSE, 0},
331     {"gff",       "gff3protein", AJFALSE,    AJTRUE,
332          &FeatTypeTableGff3protein,    &FeatTagsTableGff3protein,
333 	 "GFF version 3",    AJFALSE, 0},
334     {"gff2",      "gff2",        AJTRUE,    AJFALSE,
335 	 &FeatTypeTableGff2,    &FeatTagsTableGff2,
336 	 "GFF version 2",    AJFALSE, 0},
337     {"gff2",      "gff2protein", AJFALSE,    AJTRUE,
338 	 &FeatTypeTableGff2protein,    &FeatTagsTableGff2protein,
339 	 "GFF version 2",    AJFALSE, 0},
340     {"embl",      "embl", AJTRUE,    AJFALSE,
341          &FeatTypeTableEmbl,    &FeatTagsTableEmbl,
342 	 "embl format",      AJFALSE, 0},
343     {"em",        "embl", AJTRUE,    AJFALSE,
344 	 &FeatTypeTableEmbl,    &FeatTagsTableEmbl,
345 	 "embl format",      AJTRUE,  0},
346     {"genbank",   "embl", AJTRUE,    AJFALSE,
347 	 &FeatTypeTableEmbl,    &FeatTagsTableEmbl,
348 	 "genbank format",   AJFALSE, 0},
349     {"gb",        "embl", AJTRUE,    AJFALSE,
350          &FeatTypeTableEmbl,    &FeatTagsTableEmbl,
351 	 "genbank format",   AJTRUE,  0},
352     {"ddbj",      "embl", AJTRUE,    AJFALSE,
353 	 &FeatTypeTableEmbl,    &FeatTagsTableEmbl,
354 	 "ddbj format",      AJFALSE, 0},
355     {"refseq",    "embl", AJTRUE,    AJFALSE,
356 	 &FeatTypeTableEmbl,    &FeatTagsTableEmbl,
357 	 "genbank format",   AJTRUE,  0},
358     {"refseqp",   "refseqp", AJFALSE,   AJTRUE,
359 	 &FeatTypeTableRefseqp, &FeatTagsTableRefseqp,
360 	 "genbank format",   AJTRUE,  0},
361     {"pir",       "pir", AJFALSE,   AJTRUE,
362 	 &FeatTypeTablePir,     &FeatTagsTablePir,
363 	 "PIR format",       AJFALSE, 0},
364     {"nbrf",      "pir", AJFALSE,   AJTRUE,
365 	 &FeatTypeTablePir,     &FeatTagsTablePir,
366 	 "PIR format",       AJTRUE,  0},
367     {"sw",        "swiss", AJFALSE,   AJTRUE,
368 	 &FeatTypeTableSwiss,   &FeatTagsTableSwiss,
369 	 "SwissProt format", AJTRUE,  0},
370     {"swissprot", "swiss", AJFALSE,   AJTRUE,
371 	 &FeatTypeTableSwiss,   &FeatTagsTableSwiss,
372 	 "SwissProt format", AJTRUE,  0},
373     {"dasgff",    "gff3", AJTRUE,    AJFALSE,
374 	 &FeatTypeTableGff3,    &FeatTagsTableGff3,
375 	 "DAS GFF format",   AJFALSE, 0},
376     {"dasgff",    "gff3protein",    AJFALSE, AJTRUE,
377 	 &FeatTypeTableGff3protein,    &FeatTagsTableGff3protein,
378 	 "DAS GFF format",   AJFALSE, 0},
379     {"debug",     "emboss", AJTRUE,    AJFALSE,
380 	 &FeatTypeTableDna,    &FeatTagsTableDna,
381 	 "Debugging trace",  AJFALSE, 0},
382     {"debug",     "protein", AJFALSE,    AJTRUE,
383          &FeatTypeTableProtein,   &FeatTagsTableProtein,
384 	 "Debugging trace",  AJFALSE, 0},
385     {NULL, NULL, AJFALSE, AJFALSE, NULL, NULL, NULL, AJFALSE, 0}
386 };
387 
388 static FeatPVocab featVocab = featVocabDef;
389 
390 
391 
392 
393 
394 
395 /* @datastatic FeatPCategory **************************************************
396 **
397 ** Feature output types
398 **
399 ** @alias FeatSCategory
400 ** @alias FeatOCategory
401 **
402 ** @attr Name [const char*] Specified name
403 ** @attr Desc [const char*] Description
404 ** @attr Types [const char*] Internal type names in this category
405 ** @@
406 ******************************************************************************/
407 
408 typedef struct FeatSCategory
409 {
410     const char* Name;
411     const char* Desc;
412     const char* Types;
413 } FeatOCategory;
414 
415 #define FeatPCategory FeatOCategory*
416 
417 
418 
419 
420 static FeatOCategory featCategory[] =
421 {
422     {"other", "all other features",
423      "SO:2000061,SO:0000110,SO:0000723,SO:0000298,SO:0000724,SO:0000704,"
424      "SO:0000410,SO:0000409,SO:0000297,SO:0000313,SO:0005836_rep_origin"},
425     {"component", "component of a sequence assembly",
426      ""},
427     {"supercomponent", "reference sequence assembly",
428      ""},
429     {"translation", "translation to protein",
430      "SO:0000316,SO:0000419,SO:0000418,SO:0000725,"
431      "SO:0000204,SO:0000205,SO:0000139"},
432     {"transcription", "transcription of RNA",
433      "SO:0000147,SO:0000188,SO:0000673,SO:0005836,SO:0000234,SO:0000551,"
434      "SO:0000553,SO:0000185_precursor_RNA,SO:0000185,SO:0000252,"
435      "SO:0000013,SO:0000275,SO:0000274,SO:0000253,SO:0000557,SO:0000555"},
436     {"promoter", "promoter regions and regulation of transcription",
437      "SO:0000167,SO:0000172,SO:0000174,SO:0000178,SO:0000140,SO:0000173"
438      "SO:0000175,SO:0000176,SO:0000165,SO:0000141"},
439     {"variation", "polymorphic regions",
440      ""},
441     {"structural", "mapping, sequence and assembly - with no "
442                    "biological information",
443      "SO:0005850,SO:0000002,SO:0000331,SO:0000730"},
444     {"similarity", "areas similar to other sequences",
445      ""},
446     {"repeat", "areas of repetitive sequence",
447      "SO:0000657,SO:0000726,SO:0000005,SO:0000286"},
448     {"experimental", "experimental results",
449      ""},
450     {"immunoglobulin", "immunoglobulin processing regions",
451      "SO:0000001_C_region,SO:0000001_J_segment,SO:0000001_N_region,"
452      "SO:0000001_S_region,SO:0000001_V_region,SO:0000001_V_segment,"
453      "SO:0000458"},
454     {NULL, NULL,
455      NULL}
456 };
457 
458 
459 
460 
461 /* ==================================================================== */
462 /* ========================= constructors ============================= */
463 /* ==================================================================== */
464 
465 
466 
467 
468 /* @section Feature Object Constructors ***************************************
469 **
470 ** All constructors return a new feature or feature table set by pointer.
471 ** It is the responsibility of the user to first destroy any previous feature.
472 ** The target pointer does not need to be initialised to NULL, but it is good
473 ** programming practice to do so anyway.
474 **
475 ** Generally, however, the AjPFeattable feature table object will first
476 ** be created, prior to creating any 'AjPFeature' objects and adding them.
477 **
478 ** To replace or reuse an existing feature object see instead
479 ** the {Feature Assignments} and {Feature Modifiers} methods.
480 **
481 ******************************************************************************/
482 
483 
484 
485 
486 /* @func ajFeatNew ************************************************************
487 **
488 ** Constructor - must specify associated 'ajFeattable'
489 **               to which the new feature is automatically added!
490 **
491 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
492 **                         will own the feature
493 ** @param  [r] source   [const AjPStr]      Analysis basis for feature
494 ** @param  [r] type     [const AjPStr]      Type of feature (e.g. exon)
495 ** @param  [r]  Start    [ajint]  Start position of the feature
496 ** @param  [r]  End      [ajint]  End position of the feature
497 ** @param  [r] score    [float]      Analysis score for the feature
498 ** @param  [r]  strand   [char]  Strand of the feature
499 ** @param  [r]  frame    [ajint]   Frame of the feature
500 ** @return [AjPFeature] newly allocated feature object
501 ** @category new [AjPFeature] Constructor - must specify the associated
502 **                           (non-null) AjPFeattable
503 **
504 ** @release 2.0.0
505 ** @@
506 ******************************************************************************/
507 
ajFeatNew(AjPFeattable thys,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score,char strand,ajint frame)508 AjPFeature ajFeatNew(AjPFeattable thys,
509 		     const AjPStr source,
510 		     const AjPStr type,
511 		     ajint Start, ajint End,
512 		     float score,
513 		     char  strand,
514 		     ajint frame)
515 {
516     ajuint flags    = 0;
517     AjPFeature ret = NULL;
518 
519     if(ajStrMatchC(thys->Type, "P"))
520         ret = ajFeatNewProtFlags(thys,source,type,Start,End,score,flags);
521     else
522         ret = ajFeatNewNucFlags(thys,source,type,Start,End,score,strand,frame,
523                                 0,0,0,NULL, NULL,flags);
524 
525     return ret;
526 }
527 
528 
529 
530 
531 /* @func ajFeatNewBetween ******************************************************
532 **
533 ** Simple constructor with location between the start positions and
534 ** the previous base.
535 **
536 ** User must specify associated 'ajFeattable' to which the new feature
537 ** is automatically added!
538 **
539 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
540 **                         will own the feature
541 ** @param  [r]  Start    [ajint]  Start position of the feature
542 ** @return [AjPFeature] newly allocated feature object
543 **
544 ** @release 6.5.0
545 ** @@
546 ******************************************************************************/
547 
ajFeatNewBetween(AjPFeattable thys,ajint Start)548 AjPFeature ajFeatNewBetween(AjPFeattable thys,
549                             ajint Start)
550 {
551     AjPStr source = NULL;
552     float score   = 0.0;
553     char strand   = '.';
554     ajint frame   = 0;
555     ajint flags   = AJFEATFLAG_BETWEEN_SEQ;
556 
557     AjPFeature ret = NULL ;
558 
559     /*ajDebug("ajFeatNewBetween %d\n", Start);*/
560 
561     if(!featTypeMiscfeat)
562 	featTypeMiscfeat = ajStrNewC("misc_feature");
563 
564     ret = ajFeatNewNucFlags(thys,source,featTypeMiscfeat,
565                             Start-1,Start,score,strand,frame,
566                             0,0,0,NULL,NULL,flags);
567 
568     return ret;
569 }
570 
571 
572 
573 
574 /* @func ajFeatNewSub *********************************************************
575 **
576 ** Constructor - must specify associated 'ajFeattable'
577 **               to which the new feature is automatically added!
578 **
579 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
580 **                         will own the feature
581 ** @param  [u] parent   [AjPFeature]   Parent feature
582 ** @param  [r] source   [const AjPStr]      Analysis basis for feature
583 ** @param  [r] type     [const AjPStr]      Type of feature (e.g. exon)
584 ** @param  [r]  Start    [ajint]  Start position of the feature
585 ** @param  [r]  End      [ajint]  End position of the feature
586 ** @param  [r] score    [float]      Analysis score for the feature
587 ** @param  [r]  strand   [char]  Strand of the feature
588 ** @param  [r]  frame    [ajint]   Frame of the feature
589 ** @return [AjPFeature] newly allocated feature object
590 ** @category new [AjPFeature] Constructor - must specify the associated
591 **                           (non-null) AjPFeattable
592 **
593 ** @release 6.4.0
594 ** @@
595 ******************************************************************************/
596 
ajFeatNewSub(AjPFeattable thys,AjPFeature parent,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score,char strand,ajint frame)597 AjPFeature ajFeatNewSub(AjPFeattable thys,
598                         AjPFeature parent,
599                         const AjPStr source,
600                         const AjPStr type,
601                         ajint Start, ajint End,
602                         float score,
603                         char  strand,
604                         ajint frame)
605 {
606     ajuint flags    = 0;
607     AjPFeature ret = NULL;
608 
609     if(ajStrMatchC(thys->Type, "P"))
610         ret = ajFeatNewProtFlagsSub(thys,parent,
611                                     source,type,Start,End,score,flags);
612     else
613         ret = ajFeatNewNucFlagsSub(thys,parent,
614                                    source,type,Start,End,score,strand,frame,
615                                    0,0,0,NULL, NULL,flags);
616 
617     return ret;
618 }
619 
620 
621 
622 
623 /* @func ajFeatNewII **********************************************************
624 **
625 ** Simple constructor with only start and end positions
626 **
627 ** User must specify associated 'ajFeattable' to which the new feature
628 ** is automatically added!
629 **
630 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
631 **                         will own the feature
632 ** @param  [r]  Start    [ajint]  Start position of the feature
633 ** @param  [r]  End      [ajint]  End position of the feature
634 ** @return [AjPFeature] newly allocated feature object
635 ** @category new [AjPFeature] Simple constructor with only start and end
636 **                            positions
637 **
638 ** @release 2.1.0
639 ** @@
640 ******************************************************************************/
641 
ajFeatNewII(AjPFeattable thys,ajint Start,ajint End)642 AjPFeature ajFeatNewII(AjPFeattable thys,
643 		       ajint Start, ajint End)
644 {
645     AjPStr source = NULL;
646     float score   = 0.0;
647     char strand   = '.';
648     ajint frame   = 0;
649     ajint flags   = 0;
650 
651     AjPFeature ret = NULL ;
652 
653     /*ajDebug("ajFeatNewII %d %d\n", Start, End);*/
654 
655     if(!featTypeMiscfeat)
656 	featTypeMiscfeat = ajStrNewC("misc_feature");
657 
658     if(Start > End)
659 	ret = ajFeatNewNucFlags(thys,source,featTypeMiscfeat,
660                                 End,Start,score,'-',frame,
661                                 0,0,0,NULL, NULL,flags);
662     else
663 	ret = ajFeatNewNucFlags(thys,source,featTypeMiscfeat,
664                                 Start,End,score,strand,frame,
665                                 0,0,0,NULL, NULL,flags);
666 
667     return ret;
668 }
669 
670 
671 
672 
673 /* @func ajFeatNewIISub *******************************************************
674 **
675 ** Simple constructor with only start and end positions
676 **
677 ** User must specify associated 'ajFeattable' to which the new feature
678 ** is automatically added!
679 **
680 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
681 **                         will own the feature
682 ** @param  [u] parent   [AjPFeature]   Parent feature
683 ** @param  [r]  Start    [ajint]  Start position of the feature
684 ** @param  [r]  End      [ajint]  End position of the feature
685 ** @return [AjPFeature] newly allocated feature object
686 ** @category new [AjPFeature] Simple constructor with only start and end
687 **                            positions
688 **
689 ** @release 6.4.0
690 ** @@
691 ******************************************************************************/
692 
ajFeatNewIISub(AjPFeattable thys,AjPFeature parent,ajint Start,ajint End)693 AjPFeature ajFeatNewIISub(AjPFeattable thys,
694                         AjPFeature parent,
695                           ajint Start, ajint End)
696 {
697     AjPStr source = NULL;
698     float score   = 0.0;
699     char strand   = '.';
700     ajint frame   = 0;
701     ajint flags   = 0;
702 
703     AjPFeature ret = NULL ;
704 
705     /*ajDebug("ajFeatNewII %d %d\n", Start, End);*/
706 
707     if(!featTypeMiscfeat)
708 	featTypeMiscfeat = ajStrNewC("misc_feature");
709 
710     if(Start > End)
711 	ret = ajFeatNewNucFlagsSub(thys,parent,
712                                    source,featTypeMiscfeat,
713                                    End,Start,score,'-',frame,
714                                    0,0,0,NULL, NULL,flags);
715     else
716 	ret = ajFeatNewNucFlagsSub(thys,parent,
717                                    source,featTypeMiscfeat,
718                                    Start,End,score,strand,frame,
719                                    0,0,0,NULL, NULL,flags);
720 
721     return ret;
722 }
723 
724 
725 
726 
727 /* @func ajFeatNewIIRev *******************************************************
728 **
729 ** Simple constructor with only start and end positions, sets feature to be
730 ** on the reverse strand
731 **
732 ** User must specify associated 'ajFeattable' to which the new feature
733 ** is automatically added!
734 **
735 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
736 **                         will own the feature
737 ** @param  [r]  Start    [ajint]  Start position of the feature
738 ** @param  [r]  End      [ajint]  End position of the feature
739 ** @return [AjPFeature] newly allocated feature object
740 ** @category new [AjPFeature] Simple constructor with only start and end
741 **                            positions, sets feature to be
742 **                            on the reverse strand
743 **
744 ** @release 2.8.0
745 ** @@
746 ******************************************************************************/
747 
ajFeatNewIIRev(AjPFeattable thys,ajint Start,ajint End)748 AjPFeature ajFeatNewIIRev(AjPFeattable thys,
749 			  ajint Start, ajint End)
750 {
751     AjPFeature ret = NULL ;
752 
753     /*ajDebug("ajFeatNewIIRev %d %d\n", Start, End);*/
754 
755     if(Start > End)
756 	ret = ajFeatNewII(thys,End,Start);
757     else
758 	ret = ajFeatNewII(thys,Start,End);
759 
760     ret->Strand = '-';
761 
762     return ret;
763 }
764 
765 
766 
767 
768 /* @func ajFeatNewIIRevSub ****************************************************
769 **
770 ** Simple constructor with only start and end positions, sets feature to be
771 ** on the reverse strand
772 **
773 ** User must specify associated 'ajFeattable' to which the new feature
774 ** is automatically added!
775 **
776 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
777 **                         will own the feature
778 ** @param  [u] parent   [AjPFeature]   Parent feature
779 ** @param  [r]  Start    [ajint]  Start position of the feature
780 ** @param  [r]  End      [ajint]  End position of the feature
781 ** @return [AjPFeature] newly allocated feature object
782 ** @category new [AjPFeature] Simple constructor with only start and end
783 **                            positions, sets feature to be
784 **                            on the reverse strand
785 **
786 ** @release 6.4.0
787 ** @@
788 ******************************************************************************/
789 
ajFeatNewIIRevSub(AjPFeattable thys,AjPFeature parent,ajint Start,ajint End)790 AjPFeature ajFeatNewIIRevSub(AjPFeattable thys, AjPFeature parent,
791                              ajint Start, ajint End)
792 {
793     AjPFeature ret = NULL ;
794 
795     /*ajDebug("ajFeatNewIIRev %d %d\n", Start, End);*/
796 
797     if(Start > End)
798 	ret = ajFeatNewIISub(thys,parent,End,Start);
799     else
800 	ret = ajFeatNewIISub(thys,parent,Start,End);
801 
802     ret->Strand = '-';
803 
804     return ret;
805 }
806 
807 
808 
809 
810 /* @func ajFeatNewProt ********************************************************
811 **
812 ** Constructor - must specify associated 'ajFeattable'
813 **               to which the new feature is automatically added!
814 **
815 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
816 **                         will own the feature
817 ** @param  [r] source   [const AjPStr]      Analysis basis for feature
818 ** @param  [r] type     [const AjPStr]      Type of feature (e.g. exon)
819 ** @param  [r]  Start    [ajint]  Start position of the feature
820 ** @param  [r]  End      [ajint]  End position of the feature
821 ** @param  [r] score    [float]      Analysis score for the feature
822 ** @return [AjPFeature] newly allocated feature object
823 ** @category new [AjPFeature] Protein-specific constructor -
824 **                            must specify the associated
825 **                            (non-null) AjPFeattable
826 **
827 ** @release 2.0.0
828 ** @@
829 **
830 ******************************************************************************/
831 
ajFeatNewProt(AjPFeattable thys,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score)832 AjPFeature ajFeatNewProt(AjPFeattable thys,
833 			 const AjPStr source,
834 			 const AjPStr type,
835 			 ajint Start, ajint End,
836 			 float score)
837 {
838     return ajFeatNewProtFlags(thys, source, type, Start, End, score, 0);
839 }
840 
841 
842 
843 
844 /* @func ajFeatNewProtSub *****************************************************
845 **
846 ** Constructor - must specify associated 'ajFeattable'
847 **               to which the new feature is automatically added!
848 **
849 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
850 **                         will own the feature
851 ** @param  [u] parent   [AjPFeature]   Parent feature
852 ** @param  [r] source   [const AjPStr]      Analysis basis for feature
853 ** @param  [r] type     [const AjPStr]      Type of feature (e.g. exon)
854 ** @param  [r]  Start    [ajint]  Start position of the feature
855 ** @param  [r]  End      [ajint]  End position of the feature
856 ** @param  [r] score    [float]      Analysis score for the feature
857 ** @return [AjPFeature] newly allocated feature object
858 ** @category new [AjPFeature] Protein-specific constructor -
859 **                            must specify the associated
860 **                            (non-null) AjPFeattable
861 **
862 ** @release 6.4.0
863 ** @@
864 **
865 ******************************************************************************/
866 
ajFeatNewProtSub(AjPFeattable thys,AjPFeature parent,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score)867 AjPFeature ajFeatNewProtSub(AjPFeattable thys, AjPFeature parent,
868                             const AjPStr source,
869                             const AjPStr type,
870                             ajint Start, ajint End,
871                             float score)
872 {
873     return ajFeatNewProtFlagsSub(thys, parent,
874                                  source, type, Start, End, score, 0);
875 }
876 
877 
878 
879 
880 /* @func ajFeatNewProtFlags ***************************************************
881 **
882 ** Constructor - must specify associated 'ajFeattable'
883 **               to which the new feature is automatically added!
884 **
885 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
886 **                         will own the feature
887 ** @param  [r] source   [const AjPStr]      Analysis basis for feature
888 ** @param  [r] type     [const AjPStr]      Type of feature (e.g. exon)
889 ** @param  [r]  Start    [ajint]  Start position of the feature
890 ** @param  [r]  End      [ajint]  End position of the feature
891 ** @param  [r] score    [float]      Analysis score for the feature
892 ** @param  [r]  flags    [ajuint]  flags.
893 ** @return [AjPFeature] newly allocated feature object
894 ** @category new [AjPFeature] Protein-specific constructor -
895 **                            must specify the associated
896 **                            (non-null) AjPFeattable
897 **
898 ** @release 6.4.0
899 ** @@
900 **
901 ******************************************************************************/
902 
ajFeatNewProtFlags(AjPFeattable thys,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score,ajuint flags)903 AjPFeature ajFeatNewProtFlags(AjPFeattable thys,
904                               const AjPStr source,
905                               const AjPStr type,
906                               ajint Start, ajint End,
907                               float score,
908                               ajuint flags)
909 {
910     AjPFeature ret = NULL ;
911 
912     if(!featDefSource)
913 	ajStrAssignS(&featDefSource, ajUtilGetProgram());
914 
915     ajDebug("\najFeatNewProtFlags '%S' %d .. %d %x\n",
916             type, Start, End, flags);
917 
918     if(!ajStrGetLen(type))
919 	return NULL;
920 
921     featInit();
922 
923     /* Allocate the object... and a new Tags list */
924     ret = featFeatureNew() ;
925 
926     thys->Groups++;
927     ret->Group = thys->Groups;
928     ret->Exon  = 0;
929 
930     if(ajStrGetLen(source))
931 	ajStrAssignS(&ret->Source, source);
932     else
933 	ajStrAssignS(&ret->Source, featDefSource);
934 
935     ajStrAssignS(&ret->Type, featTypeProt(type));
936     ajDebug("ajFeatNewProt feature type '%S' => '%S'\n", type, ret->Type);
937 
938     ret->Score = score;
939 
940     ret->Flags = flags;
941 
942     ret->Strand = '\0' ;
943 
944     ret->Frame  = 0 ;
945     ret->Start  = Start;
946     ret->End    = End;
947     ret->Start2 = 0;
948     ret->End2   = 0;
949 
950     ret->Protein = ajTrue;
951 
952     if(!(ret->Flags & AJFEATFLAG_REMOTEID) &&
953        !(ret->Flags & AJFEATFLAG_LABEL))
954     {
955 	thys->Len = AJMAX(thys->Len, ret->Start);
956 	thys->Len = AJMAX(thys->Len, ret->End);
957     }
958 
959     ajFeattableAdd(thys,ret) ;
960 
961     return ret;
962 }
963 
964 
965 
966 
967 /* @func ajFeatNewProtFlagsSub ************************************************
968 **
969 ** Constructor - must specify associated 'ajFeattable'
970 **               to which the new feature is automatically added!
971 **
972 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
973 **                         will own the feature
974 ** @param  [u] parent   [AjPFeature]   Parent feature
975 ** @param  [r] source   [const AjPStr]      Analysis basis for feature
976 ** @param  [r] type     [const AjPStr]      Type of feature (e.g. exon)
977 ** @param  [r]  Start    [ajint]  Start position of the feature
978 ** @param  [r]  End      [ajint]  End position of the feature
979 ** @param  [r] score    [float]      Analysis score for the feature
980 ** @param  [r]  flags    [ajuint]  flags.
981 ** @return [AjPFeature] newly allocated feature object
982 ** @category new [AjPFeature] Protein-specific constructor -
983 **                            must specify the associated
984 **                            (non-null) AjPFeattable
985 **
986 ** @release 6.4.0
987 ** @@
988 **
989 ******************************************************************************/
990 
ajFeatNewProtFlagsSub(AjPFeattable thys,AjPFeature parent,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score,ajuint flags)991 AjPFeature ajFeatNewProtFlagsSub(AjPFeattable thys,
992                                  AjPFeature parent,
993                                  const AjPStr source,
994                                  const AjPStr type,
995                                  ajint Start, ajint End,
996                                  float score,
997                                  ajuint flags)
998 {
999     AjPFeature ret = NULL ;
1000 
1001     if(!featDefSource)
1002 	ajStrAssignS(&featDefSource, ajUtilGetProgram());
1003 
1004     ajDebug("\najFeatNewProtFlagsSub '%S' %d .. %d %x\n",
1005             type, Start, End, flags);
1006 
1007     if(!ajStrGetLen(type))
1008 	return NULL;
1009 
1010     featInit();
1011 
1012     /* Allocate the object... and a new Tags list */
1013     ret = featFeatureNew() ;
1014 
1015     thys->Groups++;
1016     ret->Group = thys->Groups;
1017     ret->Exon  = 0;
1018 
1019     if(ajStrGetLen(source))
1020 	ajStrAssignS(&ret->Source, source);
1021     else
1022 	ajStrAssignS(&ret->Source, featDefSource);
1023 
1024     ajStrAssignS(&ret->Type, featTypeProt(type));
1025     ajDebug("ajFeatNewProt feature type '%S' => '%S'\n", type, ret->Type);
1026 
1027     ret->Score = score;
1028 
1029     ret->Flags = flags;
1030 
1031     ret->Strand = '\0' ;
1032 
1033     ret->Frame  = 0 ;
1034     ret->Start  = Start;
1035     ret->End    = End;
1036     ret->Start2 = 0;
1037     ret->End2   = 0;
1038 
1039     ret->Protein = ajTrue;
1040 
1041     if(!(ret->Flags & AJFEATFLAG_REMOTEID) &&
1042        !(ret->Flags & AJFEATFLAG_LABEL))
1043     {
1044 	thys->Len = AJMAX(thys->Len, ret->Start);
1045 	thys->Len = AJMAX(thys->Len, ret->End);
1046     }
1047 
1048     if(!parent->Subfeatures)
1049         parent->Subfeatures = ajListNew();
1050 
1051     ajListPushAppend(parent->Subfeatures, ret);
1052 
1053     return ret;
1054 }
1055 
1056 
1057 
1058 
1059 /* @func ajFeatCompByStart ****************************************************
1060 **
1061 ** Compare two features by their start.
1062 **
1063 ** @param [r] a [const void *] feature
1064 ** @param [r] b [const void *] another feature
1065 **
1066 ** @return [ajint] -1 if a is less than b, 0 if a is equal to b else +1.
1067 **
1068 ** @release 6.4.0
1069 ** @@
1070 ******************************************************************************/
1071 
ajFeatCompByStart(const void * a,const void * b)1072 ajint ajFeatCompByStart(const void *a, const void *b)
1073 {
1074     const AjPFeature gfa;
1075     const AjPFeature gfb;
1076     ajint val = 0;
1077 
1078     gfa = *(AjPFeature const *) a;
1079     gfb = *(AjPFeature const *) b;
1080 
1081     val = gfa->Start - gfb->Start;
1082 
1083     if(val)
1084 	return val;
1085     else
1086     {
1087 	val = gfb->End - gfa->End;
1088 	if(val)
1089 	    return val;
1090     }
1091 
1092     return 0;
1093 }
1094 
1095 
1096 
1097 
1098 /* @func ajFeatCompByEnd ******************************************************
1099 **
1100 ** Compare two features by their end.
1101 **
1102 ** @param [r] a [const void *] feature
1103 ** @param [r] b [const void *] another feature
1104 **
1105 ** @return [ajint] -1 if a is less than b, 0 if a is equal to b else +1.
1106 **
1107 ** @release 6.4.0
1108 ** @@
1109 ******************************************************************************/
1110 
ajFeatCompByEnd(const void * a,const void * b)1111 ajint ajFeatCompByEnd(const void *a, const void *b)
1112 {
1113     const AjPFeature gfa;
1114     const AjPFeature gfb;
1115 
1116     ajint val = 0;
1117 
1118     gfa = *(AjPFeature const *) a;
1119     gfb = *(AjPFeature const *) b;
1120 
1121     val = gfa->End - gfb->End;
1122 
1123     if(val)
1124 	return val;
1125     else
1126     {
1127 	val = gfa->Start - gfb->Start;
1128 	if(val)
1129 	    return val;
1130     }
1131 
1132     return 0;
1133 }
1134 
1135 
1136 
1137 
1138 /* @func ajFeatCompByGroup ****************************************************
1139 **
1140 ** Compare two features by their group and exon numbers
1141 **
1142 ** @param [r] a [const void *] feature
1143 ** @param [r] b [const void *] another feature
1144 **
1145 ** @return [ajint] -1 if a is less than b, 0 if a is equal to b else +1.
1146 **
1147 ** @release 6.4.0
1148 ** @@
1149 ******************************************************************************/
1150 
ajFeatCompByGroup(const void * a,const void * b)1151 ajint ajFeatCompByGroup(const void *a, const void *b)
1152 {
1153     const AjPFeature gfa;
1154     const AjPFeature gfb;
1155 
1156     ajint val = 0;
1157 
1158     gfa = *(AjPFeature const *) a;
1159     gfb = *(AjPFeature const *) b;
1160 
1161     val = gfa->Group - gfb->Group;
1162 
1163     if(val)
1164 	return val;
1165 
1166     val = gfa->Exon - gfb->Exon;
1167 
1168     return val;
1169 }
1170 
1171 
1172 
1173 
1174 /* @func ajFeatCompByType *****************************************************
1175 **
1176 ** Compare two features by their type (key).
1177 **
1178 ** @param [r] a [const void *] feature
1179 ** @param [r] b [const void *] another feature
1180 **
1181 ** @return [ajint] -1 if a is less than b, 0 if a is equal to b else +1.
1182 **
1183 ** @release 6.4.0
1184 ** @@
1185 ******************************************************************************/
1186 
ajFeatCompByType(const void * a,const void * b)1187 ajint ajFeatCompByType(const void *a, const void *b)
1188 {
1189     const AjPFeature gfa;
1190     const AjPFeature gfb;
1191 
1192     ajint val = 0;
1193 
1194     gfa = *(AjPFeature const *) a;
1195     gfb = *(AjPFeature const *) b;
1196 
1197     val = ajStrVcmp(&gfa->Type,&gfb->Type);
1198 
1199     if(val)
1200 	return val;
1201     else
1202     {
1203 	val = gfa->Start - gfb->Start;
1204 
1205 	if(val)
1206 	    return val;
1207 	else
1208 	{
1209 	    val = gfa->End - gfb->End;
1210 
1211 	    if(val)
1212 		return val;
1213 	}
1214     }
1215 
1216     return 0;
1217 }
1218 
1219 
1220 
1221 
1222 /******************************************************************************
1223 **
1224 ** Utility classes...
1225 **
1226 ******************************************************************************/
1227 
1228 
1229 
1230 
1231 /* @func ajFeatNewNuc *********************************************************
1232 **
1233 ** Constructor for a new feature,
1234 ** automatically added to the specified table.
1235 **
1236 ** @param  [u]   thys     [AjPFeattable] Pointer to the ajFeattable which
1237 **                         will own the feature
1238 ** @param  [r] source   [const AjPStr]      Analysis basis for feature
1239 ** @param  [r] type     [const AjPStr]      Type of feature (e.g. exon)
1240 ** @param  [r]  Start    [ajint]  Start position of the feature
1241 ** @param  [r]  End      [ajint]  End position of the feature
1242 ** @param  [r] score    [float]      Analysis score for the feature
1243 ** @param  [r]  strand   [char]  Strand of the feature
1244 ** @param  [r]  frame    [ajint]   Frame of the feature
1245 ** @param  [r]  exon     [ajint]  exon number (0 for default value)
1246 ** @param  [r]  Start2   [ajint]  2nd Start position of the feature
1247 ** @param  [r]  End2     [ajint]  2nd End position of the feature
1248 ** @param  [r] entryid  [const AjPStr] Entry ID for location in
1249 **                                        another entry
1250 ** @param  [r] label    [const AjPStr] Label for location (non-numeric)
1251 ** @return [AjPFeature] newly allocated feature object
1252 **
1253 ** @release 6.4.0
1254 ** @@
1255 ******************************************************************************/
1256 
ajFeatNewNuc(AjPFeattable thys,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score,char strand,ajint frame,ajint exon,ajint Start2,ajint End2,const AjPStr entryid,const AjPStr label)1257 AjPFeature ajFeatNewNuc(AjPFeattable thys,
1258                         const AjPStr source,
1259                         const AjPStr type,
1260                         ajint        Start,
1261                         ajint        End,
1262                         float        score,
1263                         char         strand,
1264                         ajint        frame,
1265                         ajint        exon,
1266                         ajint        Start2,
1267                         ajint        End2,
1268                         const AjPStr entryid,
1269                         const AjPStr label)
1270 {
1271     return ajFeatNewNucFlags(thys, source, type, Start, End,
1272                              score, strand, frame, exon, Start2, End2,
1273                              entryid, label, 0);
1274 }
1275 
1276 
1277 
1278 
1279 /* @func ajFeatNewNucSub ******************************************************
1280 **
1281 ** Constructor for a new feature,
1282 ** automatically added to the specified table.
1283 **
1284 ** @param  [u]   thys     [AjPFeattable] Pointer to the ajFeattable which
1285 **                         will own the feature
1286 ** @param  [u] parent   [AjPFeature]   Parent feature
1287 ** @param  [r] source   [const AjPStr]      Analysis basis for feature
1288 ** @param  [r] type     [const AjPStr]      Type of feature (e.g. exon)
1289 ** @param  [r]  Start    [ajint]  Start position of the feature
1290 ** @param  [r]  End      [ajint]  End position of the feature
1291 ** @param  [r] score    [float]      Analysis score for the feature
1292 ** @param  [r]  strand   [char]  Strand of the feature
1293 ** @param  [r]  frame    [ajint]   Frame of the feature
1294 ** @param  [r]  exon     [ajint]  exon number (0 for default value)
1295 ** @param  [r]  Start2   [ajint]  2nd Start position of the feature
1296 ** @param  [r]  End2     [ajint]  2nd End position of the feature
1297 ** @param  [r] entryid  [const AjPStr] Entry ID for location in
1298 **                                        another entry
1299 ** @param  [r] label    [const AjPStr] Label for location (non-numeric)
1300 ** @return [AjPFeature] newly allocated feature object
1301 **
1302 ** @release 6.4.0
1303 ** @@
1304 ******************************************************************************/
1305 
ajFeatNewNucSub(AjPFeattable thys,AjPFeature parent,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score,char strand,ajint frame,ajint exon,ajint Start2,ajint End2,const AjPStr entryid,const AjPStr label)1306 AjPFeature ajFeatNewNucSub(AjPFeattable thys,
1307                            AjPFeature parent,
1308                            const AjPStr source,
1309                            const AjPStr type,
1310                            ajint        Start,
1311                            ajint        End,
1312                            float        score,
1313                            char         strand,
1314                            ajint        frame,
1315                            ajint        exon,
1316                            ajint        Start2,
1317                            ajint        End2,
1318                            const AjPStr entryid,
1319                            const AjPStr label)
1320 {
1321     return ajFeatNewNucFlagsSub(thys, parent,
1322                                 source, type, Start, End,
1323                                 score, strand, frame, exon, Start2, End2,
1324                                 entryid, label, 0);
1325 }
1326 
1327 
1328 
1329 
1330 /* @func ajFeatNewNucFlags ****************************************************
1331 **
1332 ** Constructor for a new feature,
1333 ** automatically added to the specified table.
1334 **
1335 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
1336 **                         will own the feature
1337 ** @param  [r] source    [const AjPStr]      Analysis basis for feature
1338 ** @param  [r] type      [const AjPStr]      Type of feature (e.g. exon)
1339 ** @param  [r]  Start    [ajint]  Start position of the feature
1340 ** @param  [r]  End      [ajint]  End position of the feature
1341 ** @param  [r] score     [float]      Analysis score for the feature
1342 ** @param  [r]  strand   [char]  Strand of the feature
1343 ** @param  [r]  frame    [ajint]   Frame of the feature
1344 ** @param  [r]  exon     [ajint]  exon number (0 for default value)
1345 ** @param  [r]  Start2   [ajint]  2nd Start position of the feature
1346 ** @param  [r]  End2     [ajint]  2nd End position of the feature
1347 ** @param  [r] entryid   [const AjPStr] Entry ID for location in
1348 **                                        another entry
1349 ** @param  [r] label     [const AjPStr] Label for location (non-numeric)
1350 ** @param  [r]  flags    [ajuint]  flags.
1351 ** @return [AjPFeature] newly allocated feature object
1352 **
1353 ** @release 6.4.0
1354 ** @@
1355 ******************************************************************************/
1356 
ajFeatNewNucFlags(AjPFeattable thys,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score,char strand,ajint frame,ajint exon,ajint Start2,ajint End2,const AjPStr entryid,const AjPStr label,ajuint flags)1357 AjPFeature ajFeatNewNucFlags(AjPFeattable thys,
1358                              const AjPStr source,
1359                              const AjPStr type,
1360                              ajint        Start,
1361                              ajint        End,
1362                              float        score,
1363                              char         strand,
1364                              ajint        frame,
1365                              ajint        exon,
1366                              ajint        Start2,
1367                              ajint        End2,
1368                              const AjPStr entryid,
1369                              const AjPStr label,
1370                              ajuint       flags)
1371 {
1372     AjPFeature ret          = NULL;
1373 
1374     ajDebug("ajFeatNewNucFlags %d %d '%c' type: '%S'\n",
1375             Start, End, strand, type);
1376 
1377     if(!featDefSource)
1378 	ajStrAssignS(&featDefSource, ajUtilGetProgram());
1379 
1380     if(!ajStrGetLen(type))
1381 	return NULL;
1382 
1383     featInit();
1384 
1385     /* Allocate the object... */
1386 
1387     ret = featFeatureNew();
1388 
1389     thys->Groups++;
1390     ret->Group = thys->Groups;
1391     ret->Exon  = exon;
1392 
1393     if(ajStrGetLen(source))
1394 	ajStrAssignS(&ret->Source, source);
1395     else
1396 	ajStrAssignS(&ret->Source, featDefSource);
1397 
1398     /*ajDebug("featFeatNew type '%S'\n", thys->Type);*/
1399 
1400     if(ajStrMatchC(thys->Type, "P"))
1401 	ajStrAssignS(&ret->Type, featTypeProt(type));
1402     else
1403 	ajStrAssignS(&ret->Type, featTypeDna(type));
1404 
1405     ajDebug("featFeatNew feature type '%S' => '%S'\n", type, ret->Type);
1406     ret->Score = score;
1407 
1408     ret->Flags = flags;
1409 
1410     if(strand == '+' || strand == '-')
1411         ret->Strand = strand;
1412     else ret->Strand = '\0';
1413 
1414     ret->Frame  = frame ;
1415     ret->Start  = Start;
1416     ret->End    = End;
1417     ret->Start2 = Start2;
1418     ret->End2   = End2;
1419 
1420     if(ajStrGetLen(entryid))
1421 	ajStrAssignS(&ret->Remote, entryid);
1422     else
1423     {
1424 	if(!(ret->Flags & AJFEATFLAG_REMOTEID) &&
1425 	   !(ret->Flags & AJFEATFLAG_LABEL))
1426 	{
1427 	    thys->Len = AJMAX(thys->Len, ret->Start);
1428 	    thys->Len = AJMAX(thys->Len, ret->End);
1429 	}
1430     }
1431 
1432     if(ajStrGetLen(label))
1433     {
1434 	ajStrAssignS(&ret->Label, label);
1435 	ajFeatWarn("%S: Feature label '%S' used",
1436 	       thys->Seqid, label);
1437     }
1438 
1439     ajFeattableAdd(thys,ret);
1440 
1441     return ret ;
1442 }
1443 
1444 
1445 
1446 
1447 /* @func ajFeatNewNucFlagsSub *************************************************
1448 **
1449 ** Constructor for a new feature,
1450 ** automatically added to the specified table.
1451 **
1452 ** @param  [u]   thys    [AjPFeattable] Pointer to the ajFeattable which
1453 **                         will own the feature
1454 ** @param  [u] parent   [AjPFeature]   Parent feature
1455 ** @param  [r] source    [const AjPStr]      Analysis basis for feature
1456 ** @param  [r] type      [const AjPStr]      Type of feature (e.g. exon)
1457 ** @param  [r]  Start    [ajint]  Start position of the feature
1458 ** @param  [r]  End      [ajint]  End position of the feature
1459 ** @param  [r] score     [float]      Analysis score for the feature
1460 ** @param  [r]  strand   [char]  Strand of the feature
1461 ** @param  [r]  frame    [ajint]   Frame of the feature
1462 ** @param  [r]  exon     [ajint]  exon number (0 for default value)
1463 ** @param  [r]  Start2   [ajint]  2nd Start position of the feature
1464 ** @param  [r]  End2     [ajint]  2nd End position of the feature
1465 ** @param  [r] entryid   [const AjPStr] Entry ID for location in
1466 **                                        another entry
1467 ** @param  [r] label     [const AjPStr] Label for location (non-numeric)
1468 ** @param  [r]  flags    [ajuint]  flags.
1469 ** @return [AjPFeature] newly allocated feature object
1470 **
1471 ** @release 6.4.0
1472 ** @@
1473 ******************************************************************************/
1474 
ajFeatNewNucFlagsSub(AjPFeattable thys,AjPFeature parent,const AjPStr source,const AjPStr type,ajint Start,ajint End,float score,char strand,ajint frame,ajint exon,ajint Start2,ajint End2,const AjPStr entryid,const AjPStr label,ajuint flags)1475 AjPFeature ajFeatNewNucFlagsSub(AjPFeattable thys,
1476                                 AjPFeature parent,
1477                                 const AjPStr source,
1478                                 const AjPStr type,
1479                                 ajint        Start,
1480                                 ajint        End,
1481                                 float        score,
1482                                 char         strand,
1483                                 ajint        frame,
1484                                 ajint        exon,
1485                                 ajint        Start2,
1486                                 ajint        End2,
1487                                 const AjPStr entryid,
1488                                 const AjPStr label,
1489                                 ajuint       flags)
1490 {
1491     AjPFeature ret          = NULL;
1492 
1493     ajDebug("ajFeatNewNucFlagsSub %d %d '%c' type: '%S'\n",
1494             Start, End, strand, type);
1495 
1496     if(!featDefSource)
1497 	ajStrAssignS(&featDefSource, ajUtilGetProgram());
1498 
1499     if(!ajStrGetLen(type))
1500 	return NULL;
1501 
1502     featInit();
1503 
1504     /* Allocate the object... */
1505 
1506     ret = featFeatureNew();
1507 
1508     thys->Groups++;
1509     ret->Group = thys->Groups;
1510     ret->Exon  = exon;
1511 
1512     if(ajStrGetLen(source))
1513 	ajStrAssignS(&ret->Source, source);
1514     else
1515 	ajStrAssignS(&ret->Source, featDefSource);
1516 
1517     /*ajDebug("featFeatNew type '%S'\n", thys->Type);*/
1518 
1519     if(ajStrMatchC(thys->Type, "P"))
1520 	ajStrAssignS(&ret->Type, featTypeProt(type));
1521     else
1522 	ajStrAssignS(&ret->Type, featTypeDna(type));
1523 
1524     ajDebug("featFeatNew feature type '%S' => '%S'\n", type, ret->Type);
1525     ret->Score = score;
1526 
1527     ret->Flags = flags;
1528 
1529     if(strand == '+' || strand == '-')
1530         ret->Strand = strand;
1531     else ret->Strand = '\0';
1532 
1533     ret->Frame  = frame ;
1534     ret->Start  = Start;
1535     ret->End    = End;
1536     ret->Start2 = Start2;
1537     ret->End2   = End2;
1538 
1539     if(ajStrGetLen(entryid))
1540 	ajStrAssignS(&ret->Remote, entryid);
1541     else
1542     {
1543 	if(!(ret->Flags & AJFEATFLAG_REMOTEID) &&
1544 	   !(ret->Flags & AJFEATFLAG_LABEL))
1545 	{
1546 	    thys->Len = AJMAX(thys->Len, ret->Start);
1547 	    thys->Len = AJMAX(thys->Len, ret->End);
1548 	}
1549     }
1550 
1551     if(ajStrGetLen(label))
1552     {
1553 	ajStrAssignS(&ret->Label, label);
1554 	ajFeatWarn("%S: Feature label '%S' used",
1555 	       thys->Seqid, label);
1556     }
1557 
1558     if(!parent->Subfeatures)
1559         parent->Subfeatures = ajListNew();
1560 
1561     ajListPushAppend(parent->Subfeatures, ret);
1562 
1563     return ret ;
1564 }
1565 
1566 
1567 
1568 
1569 /* ==================================================================== */
1570 /* =========================== destructor ============================= */
1571 /* ==================================================================== */
1572 
1573 
1574 
1575 
1576 /* @section Feature Object Destructors ****************************************
1577 **
1578 ** (Simple minded) object destruction by release of memory.
1579 **
1580 ** No reference counting (for now).
1581 **
1582 ******************************************************************************/
1583 
1584 
1585 
1586 
1587 /* @func ajFeattableDel *******************************************************
1588 **
1589 ** Destructor for ajFeattable objects.
1590 ** If the given object (pointer) is NULL, or a NULL pointer, simply returns.
1591 **
1592 ** @param  [d] pthis [AjPFeattable*] Pointer to the object to be deleted.
1593 **         The pointer is always deleted.
1594 ** @return [void]
1595 ** @category delete [AjPFeattable] Default destructor
1596 **
1597 ** @release 2.1.0
1598 ** @@
1599 ******************************************************************************/
1600 
ajFeattableDel(AjPFeattable * pthis)1601 void ajFeattableDel(AjPFeattable *pthis)
1602 {
1603     AjPFeattable thys;
1604 
1605     if(!pthis)
1606 	return;
1607 
1608     thys = *pthis;
1609 
1610     /*ajDebug("ajFeattableDel %x\n", thys);*/
1611 
1612     if(!thys)
1613 	return;
1614 
1615     ajFeattableClear(thys);
1616 
1617     ajStrDel(&thys->Seqid);
1618     ajStrDel(&thys->Type);
1619     ajStrDel(&thys->Db);
1620     ajStrDel(&thys->Setdb);
1621     ajStrDel(&thys->Full);
1622     ajStrDel(&thys->Qry);
1623     ajStrDel(&thys->Formatstr);
1624     ajStrDel(&thys->Filename);
1625     ajStrDel(&thys->TextPtr);
1626 
1627     ajListFree(&thys->Features);
1628 
1629     AJFREE(*pthis);
1630     *pthis = NULL;
1631 
1632     return;
1633 }
1634 
1635 
1636 
1637 
1638 /* @func ajFeatDel ************************************************************
1639 **
1640 ** Destructor for AjPFeature objects.
1641 ** If the given object (pointer) is NULL, or a NULL pointer, simply returns.
1642 **
1643 ** @param  [d] pthis [AjPFeature*] Pointer to the object to be deleted.
1644 **         The pointer is always deleted.
1645 ** @return [void]
1646 ** @category delete [AjPFeature] Default destructor
1647 **
1648 ** @release 1.0.0
1649 ** @@
1650 ******************************************************************************/
1651 
ajFeatDel(AjPFeature * pthis)1652 void ajFeatDel(AjPFeature *pthis)
1653 {
1654     if(!pthis)
1655 	return ;
1656 
1657     if(!*pthis)
1658 	return ;
1659 
1660     featClear(*pthis);
1661 
1662     AJFREE(*pthis);
1663     *pthis = NULL ;
1664 
1665     return;
1666 }
1667 
1668 
1669 
1670 
1671 /* @funcstatic featClear ******************************************************
1672 **
1673 ** Deletes all feature tag-value pairs from a feature line
1674 **
1675 ** @param [u] thys [AjPFeature] Feature
1676 ** @return [void]
1677 **
1678 ** @release 1.0.0
1679 ** @@
1680 ******************************************************************************/
1681 
featClear(AjPFeature thys)1682 static void featClear(AjPFeature thys)
1683 {
1684     AjIList       iter = NULL;
1685     AjPTagval     item = NULL;
1686     AjPFeature subfeat = NULL;
1687 
1688     if(!thys)
1689 	return;
1690 
1691     /* We need to delete the associated Tag data structures too!!!*/
1692 
1693     if(thys->Subfeatures)
1694     {
1695         iter = ajListIterNew(thys->Subfeatures);
1696 	while(!ajListIterDone(iter))
1697 	{
1698 	    subfeat = (AjPFeature)ajListIterGet(iter);
1699             ajFeatDel(&subfeat);
1700         }
1701 	ajListIterDel(&iter);
1702     }
1703 
1704     ajListFree(&(thys->Subfeatures));
1705 
1706     if(thys->Tags)
1707     {
1708 	iter = ajListIterNew(thys->Tags);
1709 	while(!ajListIterDone(iter))
1710 	{
1711 	    item = (AjPTagval)ajListIterGet(iter);
1712 	    /* assuming a simple block memory free for now...*/
1713 	    ajTagvalDel(&item);
1714 	    ajListIterRemove(iter);
1715 	}
1716 	ajListIterDel(&iter);
1717     }
1718 
1719     ajListFree(&(thys->Tags));
1720 
1721     if(thys->GffTags)
1722     {
1723 	iter = ajListIterNew(thys->GffTags);
1724 	while(!ajListIterDone(iter))
1725 	{
1726 	    item = (AjPTagval)ajListIterGet(iter);
1727 	    /* assuming a simple block memory free for now...*/
1728 	    ajTagvalDel(&item);
1729 	    ajListIterRemove(iter);
1730 	}
1731 	ajListIterDel(&iter);
1732     }
1733 
1734     ajListFree(&(thys->GffTags));
1735 
1736     ajStrDel(&thys->Source);
1737     ajStrDel(&thys->Type);
1738     ajStrDel(&thys->Remote);
1739     ajStrDel(&thys->Label);
1740 
1741     return;
1742 }
1743 
1744 
1745 
1746 
1747 /* ==================================================================== */
1748 /* ========================== Assignments ============================= */
1749 /* ==================================================================== */
1750 
1751 
1752 
1753 
1754 /* @section Feature Assignments ***********************************************
1755 **
1756 ******************************************************************************/
1757 
1758 
1759 
1760 
1761 /* @func ajFeatSortByType *****************************************************
1762 **
1763 ** Sort Feature table by Type.
1764 **
1765 ** @param [u] Feattab [AjPFeattable] Feature table to be sorted.
1766 **
1767 ** @return [void]
1768 **
1769 ** @release 1.0.0
1770 ** @@
1771 ******************************************************************************/
1772 
ajFeatSortByType(AjPFeattable Feattab)1773 void ajFeatSortByType(AjPFeattable Feattab)
1774 {
1775     ajListSort(Feattab->Features, &ajFeatCompByType);
1776 
1777     return;
1778 }
1779 
1780 
1781 
1782 
1783 /* @func ajFeatSortByStart ****************************************************
1784 **
1785 ** Sort Feature table by Start position.
1786 **
1787 ** @param [u] Feattab [AjPFeattable] Feature table to be sorted.
1788 **
1789 ** @return [void]
1790 **
1791 ** @release 1.0.0
1792 ** @@
1793 ******************************************************************************/
1794 
ajFeatSortByStart(AjPFeattable Feattab)1795 void ajFeatSortByStart(AjPFeattable Feattab)
1796 {
1797     ajListSort(Feattab->Features, &ajFeatCompByStart);
1798 }
1799 
1800 
1801 
1802 
1803 /* @func ajFeatSortByEnd ******************************************************
1804 **
1805 ** Sort Feature table by End position.
1806 **
1807 ** @param [u] Feattab [AjPFeattable] Feature table to be sorted.
1808 **
1809 ** @return [void]
1810 **
1811 ** @release 1.0.0
1812 ** @@
1813 ******************************************************************************/
1814 
ajFeatSortByEnd(AjPFeattable Feattab)1815 void ajFeatSortByEnd(AjPFeattable Feattab)
1816 {
1817     ajListSort(Feattab->Features, &ajFeatCompByEnd);
1818 
1819     return;
1820 }
1821 
1822 
1823 
1824 
1825 /* ==================================================================== */
1826 /* ========================== Modifiers ============================= */
1827 /* ==================================================================== */
1828 
1829 
1830 
1831 
1832 /* @section Feature Table Modifiers ******************************************
1833 **
1834 ******************************************************************************/
1835 
1836 
1837 
1838 
1839 /* @func ajFeattableAdd *******************************************************
1840 **
1841 ** Method to add a new AjPFeature to a AjPFeattable
1842 **
1843 ** @param  [u] thys    [AjPFeattable] The feature table
1844 ** @param  [u] feature [AjPFeature]        Feature to be added to the set
1845 ** @return [void]
1846 ** @category modify [AjPFeattable] Adds an AjPFeature to a set
1847 **
1848 ** @release 2.1.0
1849 ** @@
1850 ******************************************************************************/
1851 
ajFeattableAdd(AjPFeattable thys,AjPFeature feature)1852 void ajFeattableAdd(AjPFeattable thys, AjPFeature feature)
1853 {
1854     if(!(feature->Flags & AJFEATFLAG_REMOTEID) &&
1855        !(feature->Flags & AJFEATFLAG_LABEL))
1856     {
1857 	thys->Len = AJMAX(thys->Len, feature->Start);
1858 	thys->Len = AJMAX(thys->Len, feature->End);
1859     }
1860 
1861     ajListPushAppend(thys->Features, feature);
1862 
1863     return;
1864 }
1865 
1866 
1867 
1868 
1869 /* @func ajFeattableAddNew ****************************************************
1870 **
1871 ** Method to add a new AjPFeature to a AjPFeattable as a new feature,
1872 ** updating the feature group.
1873 **
1874 ** @param  [u] thys    [AjPFeattable] The feature table
1875 ** @param  [u] feature [AjPFeature]        Feature to be added to the set
1876 ** @return [void]
1877 ** @category modify [AjPFeattable] Adds an AjPFeature to a set
1878 **
1879 ** @release 2.1.0
1880 ** @@
1881 ******************************************************************************/
1882 
ajFeattableAddNew(AjPFeattable thys,AjPFeature feature)1883 void ajFeattableAddNew(AjPFeattable thys, AjPFeature feature)
1884 {
1885     AjIList       iter = NULL;
1886     AjPFeature subfeat = NULL;
1887 
1888     if(!(feature->Flags & AJFEATFLAG_REMOTEID) &&
1889        !(feature->Flags & AJFEATFLAG_LABEL))
1890     {
1891 	thys->Len = AJMAX(thys->Len, feature->Start);
1892 	thys->Len = AJMAX(thys->Len, feature->End);
1893     }
1894 
1895     thys->Groups++;
1896     feature->Group = thys->Groups;
1897 
1898     if(feature->Subfeatures)
1899     {
1900         iter = ajListIterNew(feature->Subfeatures);
1901         while(!ajListIterDone(iter))
1902         {
1903             subfeat = (AjPFeature)ajListIterGet(iter);
1904             subfeat->Group = thys->Groups;
1905         }
1906         ajListIterDel(&iter);
1907     }
1908 
1909     ajListPushAppend(thys->Features, feature);
1910 
1911     return;
1912 }
1913 
1914 
1915 
1916 
1917 /* @func ajFeattableMerge *****************************************************
1918 **
1919 ** Merges a feature table into an existing feature table.
1920 **
1921 ** @param [u] thys     [AjPFeattable]        Feature table to be appended to
1922 ** @param [r] srctable [const AjPFeattable]  Additional feature table
1923 ** @return [ajuint] Size of the new feature table.
1924 **
1925 ** @release 6.5.0
1926 ** @@
1927 ******************************************************************************/
1928 
ajFeattableMerge(AjPFeattable thys,const AjPFeattable srctable)1929 ajuint ajFeattableMerge(AjPFeattable thys, const AjPFeattable srctable)
1930 {
1931     AjIList iter;
1932     AjPFeature featsrc;
1933     AjPFeature feat = NULL;
1934 
1935     if(!thys)
1936 	return 0;
1937 
1938     if(!srctable)
1939 	return 0;
1940 
1941     iter = ajListIterNewread(srctable->Features);
1942 
1943     while(!ajListIterDone(iter))
1944     {
1945 	featsrc = ajListIterGet(iter);
1946 	feat = ajFeatNewFeat(featsrc);
1947 	ajFeattableAdd(thys, feat);
1948     }
1949 
1950     ajListIterDel(&iter);
1951 
1952     return (ajuint) ajListGetLength(thys->Features);
1953 }
1954 
1955 
1956 
1957 
1958 /* ==================================================================== */
1959 /* ======================== Operators ==================================*/
1960 /* ==================================================================== */
1961 
1962 
1963 
1964 
1965 /* @section Feature Object Operators ******************************************
1966 **
1967 ** These functions use the contents of a feature object,
1968 ** but do not make any changes.
1969 **
1970 ******************************************************************************/
1971 
1972 
1973 
1974 
1975 /* @funcstatic featTableInit **************************************************
1976 **
1977 ** Initialise the components of a previously allocated AjPFeattable object.
1978 **
1979 ** @param [u]   thys       [AjPFeattable]   Target feature table object
1980 ** @param [r]  name       [const AjPStr]   Name of the table (e.g.
1981 **                                           sequence name)
1982 ** @return [void]
1983 **
1984 ** @release 2.1.0
1985 ** @@
1986 **
1987 ******************************************************************************/
1988 
featTableInit(AjPFeattable thys,const AjPStr name)1989 static void featTableInit(AjPFeattable thys,
1990 			  const AjPStr name)
1991 {
1992     /*ajDebug("featTableInit Entering...\n");*/
1993 
1994     /*ajDebug("featTableInit initialising seqid: '%S'\n", name);*/
1995     ajStrAssignS(&thys->Seqid,name) ;
1996     thys->Format = 0;
1997 
1998     return;
1999 }
2000 
2001 
2002 
2003 
2004 /* @func ajFeattableClear *****************************************************
2005 **
2006 ** Clears a feature table of all features
2007 **
2008 ** @param [u] thys [AjPFeattable] Feature table
2009 ** @return [void]
2010 **
2011 ** @release 2.1.0
2012 ** @@
2013 ******************************************************************************/
2014 
ajFeattableClear(AjPFeattable thys)2015 void ajFeattableClear(AjPFeattable thys)
2016 {
2017     AjIList iter       = NULL ;
2018     AjPFeature feature = NULL ;
2019 
2020     if(!thys)
2021 	return ;
2022 
2023     if(MAJSTRGETLEN(thys->Seqid))
2024         ajStrSetClear(&thys->Seqid);
2025     if(MAJSTRGETLEN(thys->Type))
2026         ajStrSetClear(&thys->Type);
2027     if(MAJSTRGETLEN(thys->Db))
2028         ajStrSetClear(&thys->Db);
2029     if(MAJSTRGETLEN(thys->Setdb))
2030         ajStrSetClear(&thys->Setdb);
2031     if(MAJSTRGETLEN(thys->Full))
2032         ajStrSetClear(&thys->Full);
2033     if(MAJSTRGETLEN(thys->Qry))
2034         ajStrSetClear(&thys->Qry);
2035     if(MAJSTRGETLEN(thys->Formatstr))
2036         ajStrSetClear(&thys->Formatstr);
2037     if(MAJSTRGETLEN(thys->Filename))
2038         ajStrSetClear(&thys->Filename);
2039     if(MAJSTRGETLEN(thys->TextPtr))
2040         ajStrSetClear(&thys->TextPtr);
2041 
2042     if(thys->Features)
2043     {
2044 	iter = ajListIterNew(thys->Features) ;
2045 	while(!ajListIterDone(iter))
2046 	{
2047 	    feature = (AjPFeature)ajListIterGet(iter) ;
2048 	    ajFeatDel(&feature) ;
2049 	    ajListIterRemove(iter) ;
2050 	}
2051 	ajListIterDel(&iter) ;
2052     }
2053 
2054     thys->Format = 0;
2055     thys->Start = 0;
2056     thys->End = 0;
2057     thys->Len = 0;
2058     thys->Offset = 0;
2059     thys->Rev = ajFalse;
2060     thys->Reversed = ajFalse;
2061     thys->Trimmed = ajFalse;
2062 
2063     thys->Groups = 0;
2064     thys->Fpos = 0L;
2065     thys->Circular = AJFALSE;
2066 
2067     return;
2068 }
2069 
2070 
2071 
2072 
2073 /* @funcstatic featFeatType ***************************************************
2074 **
2075 ** Process Efeatures file line
2076 **
2077 ** Lines starting with text are new types
2078 **
2079 ** Lines with '=' are aliases that update a previous defined type name
2080 ** and can have only + and - tag lines.
2081 **
2082 ** Lines starting with / or m/ are tags for the current type
2083 **
2084 ** Lines starting with +/ or -/ add and remove tags for the current type
2085 **
2086 ** @param [r] line [const AjPStr] Tags file line
2087 ** @param [w] type [AjPStr*] Feature type
2088 ** @param [w] intids [AjPStr*] Internal feature keys, preferably based on the
2089 **                             Sequence Ontology Feature Annotation ID
2090 ** @param [w] tag [AjPStr*] Tag name
2091 ** @param [w] req [AjPStr*] Required (mandatory) code
2092 **                          M = mandatory, m = alternate mandatory,
2093 **                          + = add to existing tags,
2094 **                          - = remove from existing tags
2095 ** @return [AjBool] ajTrue if a match was found
2096 **                  ajFalse means an error occurred
2097 **
2098 ** @release 3.0.0
2099 ******************************************************************************/
2100 
featFeatType(const AjPStr line,AjPStr * type,AjPStr * intids,AjPStr * tag,AjPStr * req)2101 static AjBool featFeatType(const AjPStr line, AjPStr* type,
2102 			   AjPStr* intids, AjPStr* tag, AjPStr* req)
2103 {
2104     const char* cp = ajStrGetPtr(line);
2105     const char* cq;
2106     ajint i;
2107     AjBool istag = ajFalse;
2108 
2109     ajStrAssignClear(type);
2110     ajStrAssignClear(intids);
2111     ajStrAssignClear(tag);
2112     ajStrAssignClear(req);
2113 
2114     while(isspace((ajint)*cp))
2115 	cp++;
2116 
2117     if(!*cp)
2118         return ajFalse;
2119 
2120     if(*cp == '/')
2121 	istag = ajTrue;
2122     else if(*cp == 'm' || *cp == 'M' || *cp == '-')
2123     {
2124 	if(*(cp+1) == '/')
2125 	{
2126 	    istag = ajTrue;
2127 	    ajStrAppendK(req, *cp++);
2128 	}
2129     }
2130     else if(*cp == '+')
2131     {
2132 	if(*(cp+1) == 'm' || *(cp+1) == 'M')
2133 	{
2134 	    if(*(cp+2) == '/')
2135 	    {
2136 		istag = ajTrue;
2137 		ajStrAppendK(req, *cp++);
2138 		ajStrAppendK(req, *cp++);
2139 	    }
2140 	}
2141 	else
2142 	{
2143 	    if(*(cp+1) == '/')
2144 	    {
2145 		istag = ajTrue;
2146 		ajStrAppendK(req, *cp++);
2147 	    }
2148 	}
2149     }
2150 
2151     if(istag)
2152     {
2153 	/* /tag name */
2154 	cp++;
2155 	cq = cp;
2156 	i = 0;
2157 
2158 	while(*cp && !isspace((ajint)*cp++))
2159 	{
2160 	    i++;
2161 	}
2162 
2163 	ajStrAssignLenC(tag, cq, i);
2164 
2165 	if(!ajStrGetLen(*tag))
2166             return ajFalse;
2167     }
2168     else
2169     {
2170 	/* type internal id */
2171 	cq = cp;
2172 	i = 0;
2173 
2174 	while(*cp && !isspace((ajint)*cp++))
2175 	{
2176 	    i++;
2177 	}
2178 
2179 	ajStrAssignLenC(type, cq, i);
2180 
2181 	if(!ajStrGetLen(*type))
2182             return ajFalse;
2183 
2184 	while(*cp && isspace((ajint)*cp))
2185 	    cp++;
2186 
2187 	if(!*cp)
2188 	    return ajTrue;
2189 
2190 	if(*cp == '=')
2191 	    ajStrAppendK(req, *cp++);
2192 
2193 	while(*cp && isspace((ajint)*cp))
2194 	    cp++;
2195 
2196 	cq = cp;
2197 	i = 0;
2198 
2199 	while(*cp && !isspace((ajint)*cp++))
2200 	    i++;
2201 
2202 	ajStrAppendLenC(intids, cq, i);
2203 
2204 	while(*cp)
2205 	{
2206 	    while(*cp && isspace((ajint)*cp))
2207 		cp++;
2208 
2209 	    if(!*cp)
2210 		return ajTrue;
2211 
2212 	    cq = cp;
2213 	    i = 0;
2214 
2215 	    while(*cp && !isspace((ajint)*cp++))
2216 		i++;
2217 
2218 	    ajStrAppendK(intids, ' ');
2219 	    ajStrAppendLenC(intids, cq, i);
2220 	}
2221     }
2222 
2223     return ajTrue;
2224 }
2225 
2226 
2227 
2228 
2229 /* @func ajFeatTypeGetCategory ************************************************
2230 **
2231 ** returns the category name for a feature type
2232 **
2233 ** Used to identify category for DASGFF output
2234 **
2235 ** @param [r] type [const AjPStr] Feature type
2236 ** @return [const AjPStr] Feature category
2237 **
2238 **
2239 ** @release 6.1.0
2240 ******************************************************************************/
2241 
ajFeatTypeGetCategory(const AjPStr type)2242 const AjPStr ajFeatTypeGetCategory(const AjPStr type)
2243 {
2244     ajuint i;
2245     AjPStrTok catsplit  = NULL;
2246     AjPStr token = NULL;
2247     AjPStr name = NULL;
2248     AjPStr types = NULL;
2249     AjPStr refname = NULL;
2250     const AjPStr ret = NULL;
2251 
2252     if(FeatCategoryTable == NULL)
2253     {
2254         FeatCategoryTable = ajTablestrNewCase(200);
2255 
2256         for(i=0;featCategory[i].Name;i++)
2257         {
2258             name = ajStrNewC(featCategory[i].Name);
2259             types = ajStrNewC(featCategory[i].Types);
2260 
2261             if(!i)
2262             {
2263                 token = ajStrNewC("");
2264                 refname = ajStrNewRef(name);
2265                 ajTablePut(FeatCategoryTable, token, refname);
2266                 token = NULL;
2267             }
2268 
2269             catsplit = ajStrTokenNewC(types,",");
2270 
2271             while(ajStrTokenNextParse(catsplit,&token))
2272             {
2273                 refname = ajStrNewRef(name);
2274                 ajTablePut(FeatCategoryTable, token, refname);
2275                 token = NULL;
2276             }
2277 
2278             ajStrDel(&token);
2279             ajStrDel(&name);
2280             ajStrDel(&types);
2281             ajStrTokenDel(&catsplit);
2282         }
2283 
2284     }
2285 
2286     ret = ajTablestrFetchS(FeatCategoryTable,type);
2287     if(!ret)
2288     {
2289         token = ajStrNewC("");
2290         ret = ajTablestrFetchS(FeatCategoryTable,token);
2291         ajStrDel(&token);
2292     }
2293 
2294     return ret;
2295 }
2296 
2297 
2298 
2299 
2300 /* @func ajFeattableGetEntry **************************************************
2301 **
2302 ** Return the full text
2303 **
2304 ** @param [r] thys [const AjPFeattable] Feature table object
2305 **
2306 ** @return [const AjPStr] Returned full text
2307 **
2308 **
2309 ** @release 6.4.0
2310 ******************************************************************************/
2311 
ajFeattableGetEntry(const AjPFeattable thys)2312 const AjPStr ajFeattableGetEntry(const AjPFeattable thys)
2313 {
2314     if(thys->TextPtr)
2315         return thys->TextPtr;
2316 
2317     return ajStrConstEmpty();
2318 }
2319 
2320 
2321 
2322 
2323 /* @func ajFeattableGetQryC ***************************************************
2324 **
2325 ** Returns the query string of a feature table data object.
2326 ** Because this is a pointer to the real internal string
2327 ** the caller must take care not to change the character string in any way.
2328 ** If the string is to be changed (case for example) then it must first
2329 ** be copied.
2330 **
2331 ** @param [r] ftable [const AjPFeattable] Feature table data object.
2332 ** @return [const char*] Query as a character string.
2333 **
2334 ** @release 6.4.0
2335 ** @@
2336 ******************************************************************************/
2337 
ajFeattableGetQryC(const AjPFeattable ftable)2338 const char* ajFeattableGetQryC(const AjPFeattable ftable)
2339 {
2340     return MAJSTRGETPTR(ajFeattableGetQryS(ftable));
2341 }
2342 
2343 
2344 
2345 
2346 /* @func ajFeattableGetQryS ***************************************************
2347 **
2348 ** Returns the query string of a feature table data object.
2349 ** Because this is a pointer to the real internal string
2350 ** the caller must take care not to change the character string in any way.
2351 ** If the string is to be changed (case for example) then it must first
2352 ** be copied.
2353 **
2354 ** @param [r] ftable [const AjPFeattable] Feature table data object.
2355 ** @return [const AjPStr] Query as a string.
2356 **
2357 ** @release 6.4.0
2358 ** @@
2359 ******************************************************************************/
2360 
ajFeattableGetQryS(const AjPFeattable ftable)2361 const AjPStr ajFeattableGetQryS(const AjPFeattable ftable)
2362 {
2363     ajDebug("ajFeattableGetQryS '%S'\n", ftable->Qry);
2364 
2365     if(ajStrGetLen(ftable->Qry))
2366 	return ftable->Qry;
2367 
2368     feattableMakeQry(ftable, &featTempQry);
2369 
2370     return featTempQry;
2371 }
2372 
2373 
2374 
2375 
2376 /* @func ajFeattableGetTypeC **************************************************
2377 **
2378 ** Returns the name of a feature table object. This is a copy of the
2379 ** pointer to the name, and is still owned by the feature table
2380 ** and is not to be destroyed.
2381 **
2382 ** @param [r] thys [const AjPFeattable] Feature table
2383 ** @return [const char*] Feature table type.
2384 **
2385 ** @release 4.0.0
2386 ** @@
2387 ******************************************************************************/
2388 
ajFeattableGetTypeC(const AjPFeattable thys)2389 const char* ajFeattableGetTypeC(const AjPFeattable thys)
2390 {
2391     return ajStrGetPtr(thys->Type);
2392 }
2393 
2394 
2395 
2396 
2397 /* @func ajFeattableGetTypeS **************************************************
2398 **
2399 ** Returns the name of a feature table object. This is a copy of the
2400 ** pointer to the name, and is still owned by the feature table
2401 ** and is not to be destroyed.
2402 **
2403 ** @param [r] thys [const AjPFeattable] Feature table
2404 ** @return [const AjPStr] Feature table name.
2405 **
2406 ** @release 4.0.0
2407 ** @@
2408 ******************************************************************************/
2409 
ajFeattableGetTypeS(const AjPFeattable thys)2410 const AjPStr ajFeattableGetTypeS(const AjPFeattable thys)
2411 {
2412     return thys->Type;
2413 }
2414 
2415 
2416 
2417 
2418 /* @func ajFeattableGetXrefs **************************************************
2419 **
2420 ** Returns all cross-references from a feature table
2421 **
2422 ** @param [r] thys [const AjPFeattable] Feature table
2423 ** @param [u] Pxreflist [AjPList*] List of sequence cross-reference objects
2424 ** @param [w] Ptaxid [ajuint*] Taxon ID
2425 ** @return [AjBool] True on success
2426 **
2427 ** @release 6.1.0
2428 ** @@
2429 ******************************************************************************/
2430 
ajFeattableGetXrefs(const AjPFeattable thys,AjPList * Pxreflist,ajuint * Ptaxid)2431 AjBool ajFeattableGetXrefs(const AjPFeattable thys, AjPList *Pxreflist,
2432                            ajuint *Ptaxid)
2433 {
2434     AjIList iterfeat     = NULL;
2435     AjIList itertags     = NULL;
2436     AjPTagval item = NULL;
2437     AjPSeqXref  xref = NULL;
2438     ajlong ipos;
2439     ajuint inum = 0;
2440     AjPFeature feat  = NULL;
2441     AjPList xreflist;
2442     AjPStrTok handle = NULL;
2443     AjPStr tmpstr = NULL;
2444     const AjPStr tagval = NULL;
2445 
2446     if(!*Pxreflist)
2447         *Pxreflist = ajListNew();
2448     xreflist = *Pxreflist;
2449 
2450     *Ptaxid = 0;
2451 
2452     if(thys->Features)
2453     {
2454 	iterfeat = ajListIterNewread(thys->Features);
2455 
2456 	while(!ajListIterDone(iterfeat))
2457 	{
2458             feat = (AjPFeature)ajListIterGet(iterfeat);
2459             if(feat->Tags)
2460             {
2461                 itertags = ajListIterNewread(feat->Tags);
2462 
2463                 while(!ajListIterDone(itertags))
2464                 {
2465                     item = (AjPTagval)ajListIterGet(itertags);
2466 
2467                     if(ajStrMatchCaseC(MAJTAGVALGETTAG(item), "db_xref"))
2468                     {
2469                         tagval = ajTagvalGetValue(item);
2470                         ipos = ajStrFindAnyK(tagval, ':');
2471                         if(ipos > 0)
2472                         {
2473                             inum++;
2474                             xref = ajSeqxrefNew();
2475                             ajStrAssignSubS(&xref->Db,
2476                                             tagval, 0, ipos-1);
2477                             ajStrAssignSubS(&xref->Id,
2478                                             tagval, ipos+1, -1);
2479                             ajListPushAppend(xreflist, xref);
2480                             xref->Start = ajFeatGetStart(feat);
2481                             xref->End   = ajFeatGetEnd(feat);
2482                             xref->Type = XREF_DBXREF;
2483                             if(!*Ptaxid && ajStrMatchCaseC(xref->Db, "taxon"))
2484                             {
2485                                 if(!ajStrToUint(xref->Id, Ptaxid))
2486                                     *Ptaxid = 0;
2487                             }
2488                             xref = NULL;
2489                         }
2490                     }
2491                 }
2492 
2493                 ajListIterDel(&itertags);
2494             }
2495 
2496             if(feat->GffTags)
2497             {
2498                 itertags = ajListIterNewread(feat->GffTags);
2499 
2500                 while(!ajListIterDone(itertags))
2501                 {
2502                     item = (AjPTagval)ajListIterGet(itertags);
2503 
2504                     if(ajStrMatchCaseC(MAJTAGVALGETTAG(item), "Dbxref"))
2505                     {
2506                         tagval = ajTagvalGetValue(item);
2507                         handle = ajStrTokenNewC(tagval, ",");
2508                         while(ajStrTokenNextParse(handle, &tmpstr))
2509                         {
2510                             ipos = ajStrFindAnyK(tmpstr, ':');
2511                             if(ipos > 0)
2512                             {
2513                                 inum++;
2514                                 xref = ajSeqxrefNew();
2515                                 ajStrAssignSubS(&xref->Db,
2516                                                 tmpstr, 0, ipos-1);
2517                                 ajStrAssignSubS(&xref->Id,
2518                                                 tmpstr, ipos+1, -1);
2519                                 ajListPushAppend(xreflist, xref);
2520                                 xref->Start = ajFeatGetStart(feat);
2521                                 xref->End   = ajFeatGetEnd(feat);
2522                                 xref->Type = XREF_DBXREF;
2523                                 if(!*Ptaxid &&
2524                                    ajStrMatchCaseC(xref->Db, "taxon"))
2525                                 {
2526                                     if(!ajStrToUint(xref->Id, Ptaxid))
2527                                         *Ptaxid = 0;
2528                                 }
2529                                 xref = NULL;
2530                             }
2531                         }
2532 
2533                         ajStrTokenDel(&handle);
2534                         ajStrDel(&tmpstr);
2535                     }
2536                 }
2537 
2538                 ajListIterDel(&itertags);
2539             }
2540         }
2541      }
2542 
2543     ajListIterDel(&iterfeat);
2544 
2545     if(!inum)
2546         return ajFalse;
2547 
2548     return ajTrue;
2549 }
2550 
2551 
2552 
2553 
2554 /* @funcstatic feattableMakeQry ***********************************************
2555 **
2556 ** Sets the query for a feature table data object.
2557 **
2558 ** @param [r] thys [const AjPFeattable] Feature table data object
2559 ** @param [w] qry [AjPStr*] Query string in full
2560 ** @return [void]
2561 **
2562 ** @release 6.4.0
2563 ** @@
2564 ******************************************************************************/
2565 
feattableMakeQry(const AjPFeattable thys,AjPStr * qry)2566 static void feattableMakeQry(const AjPFeattable thys, AjPStr* qry)
2567 {
2568     ajDebug("feattableMakeQry (Seqid <%S> Formatstr <%S> Db <%S> "
2569 	    "Filename <%S>)\n",
2570 	    thys->Seqid, thys->Formatstr, thys->Db,
2571 	    thys->Filename);
2572 
2573     /* ajResourceTrace(thys); */
2574 
2575     if(ajStrGetLen(thys->Db))
2576 	ajFmtPrintS(qry, "%S-id:%S", thys->Db, thys->Seqid);
2577     else
2578     {
2579 	ajFmtPrintS(qry, "%S::%S:%S", thys->Formatstr,
2580                     thys->Filename,thys->Seqid);
2581     }
2582 
2583     ajDebug("      result: <%S>\n",
2584 	    *qry);
2585 
2586     return;
2587 }
2588 
2589 
2590 
2591 
2592 /* @func ajFeatframeGetFrame **************************************************
2593 **
2594 ** Converts a frame number in the range 0 to 3 to a GFF frame character
2595 ** or '.' as the general default
2596 **
2597 ** @param [r] frame [ajint] Feature frame number
2598 ** @return [char] character for this frame in GFF
2599 **
2600 ** @release 6.4.0
2601 ******************************************************************************/
2602 
ajFeatframeGetFrame(ajint frame)2603 char ajFeatframeGetFrame(ajint frame)
2604 {
2605     static char framestr[] = ".012";
2606 
2607     if(frame < 0)
2608 	return '.';
2609 
2610     if(frame > 3)
2611 	return '.';
2612 
2613     return framestr[frame];
2614 }
2615 
2616 
2617 
2618 
2619 /* @func ajFeatframeGetFrameNuc ***********************************************
2620 **
2621 ** Converts a frame number in the range 0 to 3 to a GFF frame character
2622 ** or '0' for the nucleotide default
2623 **
2624 ** @param [r] frame [ajint] Feature frame number
2625 ** @return [char] character for this frame in GFF
2626 **
2627 ** @release 6.4.0
2628 ******************************************************************************/
2629 
ajFeatframeGetFrameNuc(ajint frame)2630 char ajFeatframeGetFrameNuc(ajint frame)
2631 {
2632     static char framestr[] = ".012";
2633 
2634     if(frame <= 0)
2635 	return '0';
2636 
2637     if(frame > 3)
2638 	return '0';
2639 
2640     return framestr[frame];
2641 }
2642 
2643 
2644 
2645 
2646 /* @func ajFeatstrandGetStrand ************************************************
2647 **
2648 ** Converts a strand number to a GFF strand character. NULL characters
2649 ** are converted to '+' All other values are simply cast to character.
2650 **
2651 ** @param [r] strand [ajint] Strand
2652 ** @return [char] GFF character for this strand.
2653 **
2654 ** @release 6.4.0
2655 ** @@
2656 ******************************************************************************/
2657 
ajFeatstrandGetStrand(ajint strand)2658 char ajFeatstrandGetStrand(ajint strand)
2659 {
2660     if(ajSysCastItoc(strand) != '-')
2661 	return '+';
2662 
2663     return '-';
2664 }
2665 
2666 
2667 
2668 
2669 /* @func ajFeattableIsCircular ************************************************
2670 **
2671 ** Returns true if a feature table is circular
2672 **
2673 ** @param [r] thys [const AjPFeattable] Feature table
2674 ** @return [AjBool] ajTrue for a circular feature table
2675 **
2676 ** @release 2.5.0
2677 ** @@
2678 ******************************************************************************/
2679 
ajFeattableIsCircular(const AjPFeattable thys)2680 AjBool ajFeattableIsCircular(const AjPFeattable thys)
2681 {
2682     return thys->Circular;
2683 }
2684 
2685 
2686 
2687 
2688 /* @func ajFeattableIsNuc *****************************************************
2689 **
2690 ** Returns ajTrue if a feature table is nucleotide
2691 **
2692 ** @param [r] thys [const AjPFeattable] Feature table
2693 ** @return [AjBool] ajTrue for a protein feature table
2694 **
2695 ** @release 2.5.0
2696 ** @@
2697 ******************************************************************************/
2698 
ajFeattableIsNuc(const AjPFeattable thys)2699 AjBool ajFeattableIsNuc(const AjPFeattable thys)
2700 {
2701     if(ajStrMatchC(thys->Type, "N"))
2702 	return ajTrue;
2703 
2704     if(ajStrMatchC(thys->Type, "P"))
2705 	return ajFalse;
2706 
2707     return ajTrue;
2708 }
2709 
2710 
2711 
2712 
2713 /* @func ajFeattableIsProt ****************************************************
2714 **
2715 ** Returns ajTrue if a feature table is protein
2716 **
2717 ** @param [r] thys [const AjPFeattable] Feature table
2718 ** @return [AjBool] ajTrue for a protein feature table
2719 **
2720 ** @release 2.5.0
2721 ** @@
2722 ******************************************************************************/
2723 
ajFeattableIsProt(const AjPFeattable thys)2724 AjBool ajFeattableIsProt(const AjPFeattable thys)
2725 {
2726     if(ajStrMatchC(thys->Type, "P"))
2727 	return ajTrue;
2728 
2729     if(ajStrMatchC(thys->Type, "N"))
2730 	return ajFalse;
2731 
2732     return ajTrue;
2733 }
2734 
2735 
2736 
2737 
2738 /* @func ajFeattableGetBegin **************************************************
2739 **
2740 ** Returns the feature table start position, or 1 if no start has been set.
2741 **
2742 ** @param [r] thys [const AjPFeattable] feature table object
2743 ** @return [ajint] Start position.
2744 **
2745 ** @release 6.2.0
2746 ** @@
2747 ******************************************************************************/
2748 
ajFeattableGetBegin(const AjPFeattable thys)2749 ajint ajFeattableGetBegin(const AjPFeattable thys)
2750 {
2751     if(!thys->Start)
2752 	return 1;
2753 
2754     return ajFeattablePos(thys, thys->Start);
2755 }
2756 
2757 
2758 
2759 
2760 /* @func ajFeattableGetEnd ****************************************************
2761 **
2762 ** Returns the features table end position, or the feature table length if
2763 ** no end has been set.
2764 **
2765 ** @param [r] thys [const AjPFeattable] feature table object
2766 ** @return [ajint] End position.
2767 **
2768 ** @release 6.2.0
2769 ** @@
2770 ******************************************************************************/
2771 
ajFeattableGetEnd(const AjPFeattable thys)2772 ajint ajFeattableGetEnd(const AjPFeattable thys)
2773 {
2774     if(!thys->End)
2775 	return (ajFeattableGetLen(thys));
2776 
2777     return ajFeattablePosI(thys, ajFeattableGetBegin(thys), thys->End);
2778 }
2779 
2780 
2781 
2782 
2783 /* @func ajFeattableGetLen ****************************************************
2784 **
2785 ** Returns the sequence length of a feature table
2786 **
2787 ** @param [r] thys [const AjPFeattable] Feature table
2788 ** @return [ajint] Length in bases or residues
2789 **
2790 ** @release 6.2.0
2791 ** @@
2792 ******************************************************************************/
2793 
ajFeattableGetLen(const AjPFeattable thys)2794 ajint ajFeattableGetLen(const AjPFeattable thys)
2795 {
2796     if(!thys)
2797 	return 0;
2798 
2799     return (thys->Len);
2800 }
2801 
2802 
2803 
2804 
2805 /* @func ajFeattableGetName ***************************************************
2806 **
2807 ** Returns the name of a feature table object. This is a copy of the
2808 ** pointer to the name, and is still owned by the feature table
2809 ** and is not to be destroyed.
2810 **
2811 ** @param [r] thys [const AjPFeattable] Feature table
2812 ** @return [const AjPStr] Feature table name.
2813 **
2814 ** @release 2.1.0
2815 ** @@
2816 ******************************************************************************/
2817 
ajFeattableGetName(const AjPFeattable thys)2818 const AjPStr ajFeattableGetName(const AjPFeattable thys)
2819 {
2820     if(!thys)
2821         return NULL;
2822 
2823     return thys->Seqid;
2824 }
2825 
2826 
2827 
2828 
2829 /* @func ajFeattableGetSize ***************************************************
2830 **
2831 ** Returns the size of a feature table object.
2832 **
2833 ** @param [r] thys [const AjPFeattable] Feature table
2834 ** @return [ajuint] Feature table size.
2835 **
2836 ** @release 6.1.0
2837 ** @@
2838 ******************************************************************************/
2839 
ajFeattableGetSize(const AjPFeattable thys)2840 ajuint ajFeattableGetSize(const AjPFeattable thys)
2841 {
2842     if(!thys)
2843         return 0;
2844 
2845     return (ajuint) ajListGetLength(thys->Features);
2846 }
2847 
2848 
2849 
2850 
2851 /* @func ajFeattableGetScorerange *********************************************
2852 **
2853 ** Returns the range of scores for feature table object.
2854 **
2855 ** @param [r] thys [const AjPFeattable] Feature table
2856 ** @param [w] minscore [float*] Minimum score
2857 ** @param [w] maxscore [float*] Maximum score
2858 ** @return [AjBool] True if scores were found
2859 **
2860 ** @release 6.5.0
2861 ** @@
2862 ******************************************************************************/
2863 
ajFeattableGetScorerange(const AjPFeattable thys,float * minscore,float * maxscore)2864 AjBool ajFeattableGetScorerange(const AjPFeattable thys,
2865                                 float *minscore, float *maxscore)
2866 {
2867     AjBool ret = ajFalse;
2868     float curmin = 0.0;
2869     float curmax = 0.0;
2870     AjIList iter;
2871     AjPFeature gf = NULL;
2872 
2873     if(!thys)
2874         return 0;
2875 
2876     *minscore = 0.0;
2877     *maxscore = 0.0;
2878 
2879     iter = ajListIterNewread(thys->Features);
2880     while(!ajListIterDone(iter))
2881     {
2882         gf = ajListIterGet(iter);
2883 
2884         curmin = 0.0;
2885         curmax = 0.0;
2886 
2887         if(ajFeatGetScorerange(gf, &curmin, &curmax))
2888         {
2889             if(curmin < *minscore)
2890             {
2891                 ret = ajTrue;
2892                 *minscore = curmin;
2893             }
2894             if(curmax > *maxscore)
2895             {
2896                 ret = ajTrue;
2897                 *maxscore = curmax;
2898             }
2899         }
2900     }
2901 
2902     ajListIterDel(&iter);
2903 
2904     return ret;
2905 }
2906 
2907 
2908 
2909 
2910 /* @func ajFeatGetScorerange **************************************************
2911 **
2912 ** Returns the range of scores for a feature object.
2913 **
2914 ** @param [r] thys [const AjPFeature] Feature
2915 ** @param [w] minscore [float*] Minimum score
2916 ** @param [w] maxscore [float*] Maximum score
2917 ** @return [AjBool] True if scores were found
2918 **
2919 ** @release 6.5.0
2920 ** @@
2921 ******************************************************************************/
2922 
ajFeatGetScorerange(const AjPFeature thys,float * minscore,float * maxscore)2923 AjBool ajFeatGetScorerange(const AjPFeature thys,
2924                            float *minscore, float *maxscore)
2925 {
2926     AjBool ret = ajFalse;
2927     float curmin = 0.0;
2928     float curmax = 0.0;
2929     AjIList iter;
2930     AjPFeature gf = NULL;
2931 
2932     if(!thys)
2933         return 0;
2934 
2935     *minscore = 0.0;
2936     *maxscore = 0.0;
2937 
2938     if(thys->Score < *minscore)
2939     {
2940         ret = ajTrue;
2941         *minscore = curmin;
2942     }
2943     if(thys->Score > *maxscore)
2944     {
2945         ret = ajTrue;
2946         *maxscore = curmax;
2947     }
2948 
2949     iter = ajListIterNewread(thys->Subfeatures);
2950     while(!ajListIterDone(iter))
2951     {
2952         gf = ajListIterGet(iter);
2953 
2954         curmin = 0.0;
2955         curmax = 0.0;
2956 
2957         if(ajFeatGetScorerange(gf, &curmin, &curmax))
2958         {
2959             if(curmin < *minscore)
2960             {
2961                 ret = ajTrue;
2962                 *minscore = curmin;
2963             }
2964             if(curmax > *maxscore)
2965             {
2966                 ret = ajTrue;
2967                 *maxscore = curmax;
2968             }
2969         }
2970     }
2971 
2972     ajListIterDel(&iter);
2973 
2974     return ret;
2975 }
2976 
2977 
2978 
2979 
2980 /* @func ajFeatGetFlags *******************************************************
2981 **
2982 ** Returns the sequence matching a feature. For multiple location features
2983 ** (joins in an EMBL/GenBank feature table) the full feature table is used
2984 ** to find all exons.
2985 **
2986 ** The database name is used to retrieve sequences from other entries
2987 **
2988 ** @param [r] thys [const AjPFeature] Feature
2989 ** @param [u] Pflagstr [AjPStr*] Sequence for this feature
2990 ** @return [AjBool] True on success
2991 **
2992 ** @release 6.2.0
2993 ** @@
2994 ******************************************************************************/
2995 
ajFeatGetFlags(const AjPFeature thys,AjPStr * Pflagstr)2996 AjBool ajFeatGetFlags(const AjPFeature thys,  AjPStr* Pflagstr)
2997 {
2998     ajStrAssignC(Pflagstr, "");
2999 
3000     if(thys->Flags & AJFEATFLAG_START_BEFORE_SEQ)
3001         ajStrAppendC(Pflagstr, "<start ");
3002     if(thys->Flags & AJFEATFLAG_END_AFTER_SEQ)
3003         ajStrAppendC(Pflagstr, ">end ");
3004     if(thys->Flags & AJFEATFLAG_BETWEEN_SEQ)
3005         ajStrAppendC(Pflagstr, "x^y ");
3006     if(thys->Flags & AJFEATFLAG_START_TWO)
3007         ajStrAppendC(Pflagstr, "startrange ");
3008     if(thys->Flags & AJFEATFLAG_END_TWO)
3009         ajStrAppendC(Pflagstr, "endrange ");
3010     if(thys->Flags & AJFEATFLAG_POINT)
3011         ajStrAppendC(Pflagstr, "single-base ");
3012     if(thys->Flags & AJFEATFLAG_COMPLEMENT_MAIN)
3013         ajStrAppendC(Pflagstr, "complement(join) ");
3014     if(thys->Flags & AJFEATFLAG_MULTIPLE)
3015         ajStrAppendC(Pflagstr, "multiple ");
3016     if(thys->Flags & AJFEATFLAG_GROUP)
3017         ajStrAppendC(Pflagstr, "group ");
3018     if(thys->Flags & AJFEATFLAG_ORDER)
3019         ajStrAppendC(Pflagstr, "order ");
3020     if(thys->Flags & AJFEATFLAG_ONEOF)
3021         ajStrAppendC(Pflagstr, "oneof ");
3022     if(thys->Flags & AJFEATFLAG_REMOTEID)
3023         ajStrAppendC(Pflagstr, "remoteid ");
3024     if(thys->Flags & AJFEATFLAG_LABEL)
3025         ajStrAppendC(Pflagstr, "LABEL ");
3026     if(thys->Flags & AJFEATFLAG_START_UNSURE)
3027         ajStrAppendC(Pflagstr, "start-unsure ");
3028     if(thys->Flags & AJFEATFLAG_END_UNSURE)
3029         ajStrAppendC(Pflagstr, "end-unsure ");
3030 
3031     ajStrTrimWhite(Pflagstr);
3032 
3033     return ajTrue;
3034 }
3035 
3036 
3037 
3038 
3039 /* @func ajFeatGetSeq *********************************************************
3040 **
3041 ** Returns the sequence matching a feature.
3042 **
3043 ** The database name is used to retrieve sequences from other entries
3044 **
3045 ** @param [r] thys [const AjPFeature] Feature
3046 ** @param [r] seq [const AjPSeq] Sequence for the current feature table
3047 ** @param [u] Pseqstr [AjPStr*] Sequence for this feature
3048 ** @return [AjBool] True on success
3049 **
3050 ** @release 6.1.0
3051 ** @@
3052 ******************************************************************************/
3053 
ajFeatGetSeq(const AjPFeature thys,const AjPSeq seq,AjPStr * Pseqstr)3054 AjBool ajFeatGetSeq(const AjPFeature thys,
3055                     const AjPSeq seq, AjPStr* Pseqstr)
3056 {
3057     AjPSeq remoteseq = NULL;
3058 /*    AjBool isjoin = ajFalse; */
3059     AjPStr tmpseq = NULL;
3060     AjBool compjoin = ajFalse;
3061 
3062     ajStrSetClear(Pseqstr);
3063 
3064 /*    isjoin = ajFeatIsMultiple(thys); */
3065 
3066     ajDebug("ajFeatGetSeq usa:%S\n",
3067             ajSeqGetUsaS(seq));
3068 
3069     if(thys->Flags & AJFEATFLAG_BETWEEN_SEQ)
3070         return ajTrue;
3071 
3072     ajFeatTrace(thys);
3073 
3074     if(thys->Flags & AJFEATFLAG_REMOTEID)
3075     {
3076         if(!remoteseq)
3077             remoteseq = ajSeqNew();
3078 
3079         ajFeatGetRemoteseq(thys, ajSeqGetUsaS(seq), remoteseq);
3080         ajStrAppendS(Pseqstr, ajSeqGetSeqS(remoteseq));
3081     }
3082     else
3083     {
3084         if(thys->Strand == '-' && !compjoin)
3085         {
3086             ajStrAppendSubS(&tmpseq, ajSeqGetSeqS(seq),
3087                             ajFeatGetStart(thys)-1, ajFeatGetEnd(thys)-1);
3088             ajSeqstrReverse(&tmpseq);
3089             ajStrInsertS(Pseqstr, 0, tmpseq);
3090             ajStrDel(&tmpseq);
3091         }
3092         else
3093         {
3094             ajStrAppendSubS(Pseqstr, ajSeqGetSeqS(seq),
3095                             ajFeatGetStart(thys)-1, ajFeatGetEnd(thys)-1);
3096         }
3097     }
3098 
3099     ajSeqDel(&remoteseq);
3100 
3101     return ajTrue;
3102 }
3103 
3104 
3105 
3106 
3107 /* @func ajFeatGetSeqJoin *****************************************************
3108 **
3109 ** Returns the sequence matching a feature. For multiple location features
3110 ** (joins in an EMBL/GenBank feature table) the full feature table is used
3111 ** to find all exons.
3112 **
3113 ** The database name is used to retrieve sequences from other entries
3114 **
3115 ** @param [r] thys [const AjPFeature] Feature
3116 ** @param [r] seq [const AjPSeq] Sequence for the current feature table
3117 ** @param [u] Pseqstr [AjPStr*] Sequence for this feature
3118 ** @return [AjBool] True on success
3119 **
3120 ** @release 6.2.0
3121 ** @@
3122 ******************************************************************************/
3123 
ajFeatGetSeqJoin(const AjPFeature thys,const AjPSeq seq,AjPStr * Pseqstr)3124 AjBool ajFeatGetSeqJoin(const AjPFeature thys,
3125                         const AjPSeq seq, AjPStr* Pseqstr)
3126 {
3127     const AjPFeature gf;
3128     AjIList iter = NULL;
3129     AjPSeq remoteseq = NULL;
3130 /*    AjBool isjoin = ajFalse; */
3131     AjPStr tmpseq = NULL;
3132     AjBool compjoin = ajFalse;
3133     AjPStr flags = NULL;
3134     ajuint count=0;
3135 
3136     ajDebug("ajFeatGetSeqJoin nfeat:%Lu usa:%S %u..%u %S\n",
3137             ajListGetLength(thys->Subfeatures), ajSeqGetUsaS(seq),
3138             thys->Start, thys->End, thys->Type);
3139 
3140     if(!ajListGetLength(thys->Subfeatures))
3141         return ajFeatGetSeq(thys, seq, Pseqstr);
3142 
3143     ajStrSetClear(Pseqstr);
3144 
3145 /*    isjoin = ajFeatIsMultiple(thys); */
3146     if(thys->Flags & AJFEATFLAG_COMPLEMENT_MAIN)
3147         compjoin = ajTrue;
3148 
3149 
3150     iter = ajListIterNewread(thys->Subfeatures);
3151 
3152     while(!ajListIterDone(iter))
3153     {
3154         count++;
3155         gf = (const AjPFeature) ajListIterGet(iter);
3156 
3157         ajFeatGetFlags(gf, &flags);
3158         ajFeatTrace(gf);
3159 
3160         if(gf->Flags & AJFEATFLAG_BETWEEN_SEQ)
3161             continue;
3162 
3163         if(gf->Flags & AJFEATFLAG_REMOTEID)
3164         {
3165             if(!remoteseq)
3166                 remoteseq = ajSeqNew();
3167 
3168             ajFeatGetRemoteseq(gf, ajSeqGetUsaS(seq), remoteseq);
3169             ajStrAppendS(Pseqstr, ajSeqGetSeqS(remoteseq));
3170         }
3171         else
3172         {
3173             if(gf->Strand == '-' && !compjoin)
3174             {
3175                 ajStrAppendSubS(&tmpseq, ajSeqGetSeqS(seq),
3176                                 ajFeatGetStart(gf)-1, ajFeatGetEnd(gf)-1);
3177                 ajSeqstrReverse(&tmpseq);
3178                 ajStrAppendS(Pseqstr, tmpseq);
3179                 ajStrDel(&tmpseq);
3180             }
3181             else
3182             {
3183                 ajStrAppendSubS(Pseqstr, ajSeqGetSeqS(seq),
3184                                 ajFeatGetStart(gf)-1, ajFeatGetEnd(gf)-1);
3185             }
3186         }
3187     }
3188 
3189     if(compjoin)
3190         ajSeqstrReverse(Pseqstr);
3191 
3192     ajListIterDel(&iter);
3193     ajSeqDel(&remoteseq);
3194     ajStrDel(&flags);
3195 
3196     return ajTrue;
3197 }
3198 
3199 
3200 
3201 
3202 /* @func ajFeatGetRemoteseq ***************************************************
3203 **
3204 ** Returns a sequence entry from a feature location which points to
3205 ** another entry
3206 **
3207 ** @param [r] thys [const AjPFeature] Feature
3208 ** @param [r] usa [const AjPStr] usa of query
3209 ** @param [u] seq [AjPSeq] Sequence object for results
3210 ** @return [AjBool] True on success
3211 **
3212 ** @release 6.1.0
3213 ** @@
3214 ******************************************************************************/
3215 
ajFeatGetRemoteseq(const AjPFeature thys,const AjPStr usa,AjPSeq seq)3216 AjBool ajFeatGetRemoteseq(const AjPFeature thys, const AjPStr usa,
3217                                 AjPSeq seq)
3218 {
3219     AjPStr baseusa = NULL;
3220     ajuint ilen;
3221     const AjPStr remoteid = NULL;
3222 
3223     remoteid = ajSeqtestIsSeqversion(thys->Remote);
3224 
3225     if(!remoteid)
3226         remoteid = thys->Remote;
3227 
3228     ajSeqUsaGetBase(usa, &baseusa);
3229 
3230     ajStrAppendK(&baseusa, ':');
3231     ajStrAppendS(&baseusa, remoteid);
3232     ajSeqGetFromUsa(baseusa, thys->Protein, seq);
3233 
3234     ilen = ajSeqGetLen(seq);
3235 
3236     if(thys->Strand == '-')
3237         ajSeqSetRangeRev(seq, ajFeatGetStart(thys), ajFeatGetEnd(thys));
3238     else
3239         ajSeqSetRange(seq, ajFeatGetStart(thys), ajFeatGetEnd(thys));
3240 
3241     ajSeqTrim(seq);
3242 
3243     ajDebug("ajFeatGetRemoteseq (%S) '%S' => '%S' %u %u..%u (%u)\n",
3244             thys->Remote, usa, baseusa, ilen,
3245             ajFeatGetStart(thys), ajFeatGetEnd(thys), ajSeqGetLen(seq));
3246 
3247     ajStrDel(&baseusa);
3248 
3249     return ajTrue;
3250 }
3251 
3252 
3253 
3254 
3255 /* @func ajFeatGetSubtype *****************************************************
3256 **
3257 ** Returns the feature type of the first subfeature
3258 **
3259 ** @param [r] thys [const AjPFeature] Feature
3260 ** @return [const AjPStr] Subfeature type
3261 **
3262 ** @release 6.5.0
3263 ** @@
3264 ******************************************************************************/
3265 
ajFeatGetSubtype(const AjPFeature thys)3266 const AjPStr ajFeatGetSubtype(const AjPFeature thys)
3267 {
3268     AjPFeature subft= NULL;
3269 
3270     if(!ajListGetLength(thys->Subfeatures))
3271         return NULL;
3272 
3273     ajListPeek(thys->Subfeatures, (void**) &subft);
3274 
3275     return subft->Type;
3276 }
3277 
3278 
3279 
3280 
3281 /* @func ajFeatGetXrefs *******************************************************
3282 **
3283 ** Returns all cross-references from a feature
3284 **
3285 ** @param [r] thys [const AjPFeature] Feature
3286 ** @param [u] Pxreflist [AjPList*] List of sequence cross-reference objects
3287 ** @return [AjBool] True on success
3288 **
3289 ** @release 6.1.0
3290 ** @@
3291 ******************************************************************************/
3292 
ajFeatGetXrefs(const AjPFeature thys,AjPList * Pxreflist)3293 AjBool ajFeatGetXrefs(const AjPFeature thys, AjPList *Pxreflist)
3294 {
3295     AjIList iter     = NULL;
3296     AjPTagval item = NULL;
3297     AjPSeqXref  xref = NULL;
3298     ajlong ipos;
3299     ajuint inum = 0;
3300     AjPList xreflist;
3301     AjPStrTok handle = NULL;
3302     AjPStr tmpstr = NULL;
3303     const AjPStr tagval = NULL;
3304 
3305     if(!*Pxreflist)
3306         *Pxreflist = ajListNew();
3307     xreflist = *Pxreflist;
3308 
3309     if(thys->Tags)
3310     {
3311 	iter = ajListIterNewread(thys->Tags);
3312 
3313 	while(!ajListIterDone(iter))
3314 	{
3315 	    item = (AjPTagval)ajListIterGet(iter);
3316 
3317 	    if(ajStrMatchCaseC(MAJTAGVALGETTAG(item), "db_xref"))
3318 	    {
3319                 tagval = ajTagvalGetValue(item);
3320                 ipos = ajStrFindAnyK(tagval, ':');
3321 
3322                 if(ipos > 0)
3323                 {
3324                     inum++;
3325                     xref = ajSeqxrefNew();
3326                     ajStrAssignSubS(&xref->Db, tagval, 0, ipos-1);
3327                     ajStrAssignSubS(&xref->Id, tagval, ipos+1, -1);
3328                     xref->Start = ajFeatGetStart(thys)-1;
3329                     xref->End   = ajFeatGetEnd(thys)-1;
3330                     ajListPushAppend(xreflist, xref);
3331                     xref->Type = XREF_DBXREF;
3332                     xref = NULL;
3333                 }
3334             }
3335 	}
3336 
3337         ajListIterDel(&iter);
3338     }
3339 
3340     if(thys->GffTags)
3341     {
3342         iter = ajListIterNewread(thys->GffTags);
3343 
3344         while(!ajListIterDone(iter))
3345         {
3346             item = (AjPTagval)ajListIterGet(iter);
3347 
3348             if(ajStrMatchCaseC(MAJTAGVALGETTAG(item), "Dbxref"))
3349             {
3350                 tagval = ajTagvalGetValue(item);
3351                 handle = ajStrTokenNewC(tagval, ",");
3352 
3353                 while(ajStrTokenNextParse(handle, &tmpstr))
3354                 {
3355                     ipos = ajStrFindAnyK(tmpstr, ':');
3356 
3357                     if(ipos > 0)
3358                     {
3359                         inum++;
3360                         xref = ajSeqxrefNew();
3361                         ajStrAssignSubS(&xref->Db,
3362                                         tmpstr, 0, ipos-1);
3363                         ajStrAssignSubS(&xref->Id,
3364                                         tmpstr, ipos+1, -1);
3365                         ajListPushAppend(xreflist, xref);
3366                         xref->Start = ajFeatGetStart(thys);
3367                         xref->End   = ajFeatGetEnd(thys);
3368                         xref->Type = XREF_DBXREF;
3369                     }
3370                 }
3371 
3372                 ajStrTokenDel(&handle);
3373                 ajStrDel(&tmpstr);
3374             }
3375         }
3376 
3377         ajListIterDel(&iter);
3378     }
3379 
3380     if(!inum)
3381         return ajFalse;
3382 
3383     return ajTrue;
3384 }
3385 
3386 
3387 
3388 
3389 /* @func ajFeatLocMark ********************************************************
3390 **
3391 ** Returns a sequence entry converted to lower case where a feature
3392 ** location matches.
3393 **
3394 ** @param [r] thys [const AjPFeature] Feature
3395 ** @param [r] table [const AjPFeattable] Feature table
3396 ** @param [u] Pseqstr [AjPStr*] Sequence to be marked in lower case
3397 ** @return [AjBool] true on success
3398 **
3399 ** @release 4.1.0
3400 ** @@
3401 ******************************************************************************/
3402 
ajFeatLocMark(const AjPFeature thys,const AjPFeattable table,AjPStr * Pseqstr)3403 AjBool ajFeatLocMark(const AjPFeature thys, const AjPFeattable table,
3404                      AjPStr* Pseqstr)
3405 {
3406     const AjPFeature gf;
3407     AjIList iter = NULL;
3408 
3409     iter = ajListIterNewread(table->Features);
3410 
3411     while(!ajListIterDone(iter))
3412     {
3413         gf = (const AjPFeature) ajListIterGet(iter);
3414 
3415         if(gf->Group == thys->Group)
3416         {
3417             if(gf->Flags & AJFEATFLAG_BETWEEN_SEQ)
3418                 continue;
3419 
3420             if(gf->Flags & AJFEATFLAG_REMOTEID)
3421                 continue;
3422 
3423             ajStrFmtLowerSub(Pseqstr,ajFeatGetStart(gf)-1,ajFeatGetEnd(gf)-1);
3424         }
3425     }
3426 
3427     ajListIterDel(&iter);
3428 
3429     return ajTrue;
3430 }
3431 
3432 
3433 
3434 
3435 /* @func ajFeatGetNoteC *******************************************************
3436 **
3437 ** Finds a named note tag (with a * prefix)
3438 **
3439 ** @param [r] thys [const AjPFeature] Feature object
3440 ** @param [r] name [const char*] Tag name
3441 ** @param [w] val [AjPStr*] Tag value (if found)
3442 **
3443 ** @return [AjBool] ajTrue on success (feature tag found)
3444 **
3445 ** @release 4.0.0
3446 ** @@
3447 ******************************************************************************/
3448 
ajFeatGetNoteC(const AjPFeature thys,const char * name,AjPStr * val)3449 AjBool ajFeatGetNoteC(const AjPFeature thys, const char* name, AjPStr* val)
3450 {
3451     return ajFeatGetNoteCI(thys, name, 0, val);
3452 }
3453 
3454 
3455 
3456 
3457 /* @func ajFeatGetNoteCI ******************************************************
3458 **
3459 ** Finds a named note tag (with a * prefix)
3460 **
3461 ** @param [r] thys [const AjPFeature] Feature object
3462 ** @param [r] name [const char*] Tag name
3463 ** @param [r] count [ajint] Tag count: zero for any, 1 for first, 2 for second
3464 ** @param [w] val [AjPStr*] Tag value (if found)
3465 **
3466 ** @return [AjBool] ajTrue on success (feature tag found)
3467 **
3468 ** @release 4.0.0
3469 ** @@
3470 ******************************************************************************/
3471 
ajFeatGetNoteCI(const AjPFeature thys,const char * name,ajint count,AjPStr * val)3472 AjBool ajFeatGetNoteCI(const AjPFeature thys, const char* name, ajint count,
3473 		      AjPStr* val)
3474 {
3475     AjIList iter     = NULL;
3476     AjPTagval item = NULL;
3477     ajint icount     = 0;
3478     ajuint ilen = strlen(name);
3479     const AjPStr tagval = NULL;
3480 
3481     /*ajDebug("ajFeatGetNoteCI '%s'\n", name);*/
3482 
3483     if(thys->Tags)
3484     {
3485 	iter = ajListIterNewread(thys->Tags);
3486 
3487 	while(!ajListIterDone(iter))
3488 	{
3489 	    item = (AjPTagval)ajListIterGet(iter);
3490 	    if(ajFeattagIsNote(MAJTAGVALGETTAG(item)))
3491 	    {
3492                 tagval = ajTagvalGetValue(item);
3493 		if(ajStrGetCharFirst(tagval) == '*')
3494 		{
3495 		    /*ajDebug("  testing *name\n");*/
3496 		    if(ajCharPrefixCaseC(ajStrGetPtr(tagval)+1, name))
3497 		    {
3498 			icount++;
3499 			/*ajDebug("  found [%d] '%S'\n", icount, name);*/
3500 
3501 			if(icount >= count)
3502 			{
3503 			    if(ajStrGetLen(tagval) > (ilen+1))
3504 			    {
3505 				if(ajStrGetCharPos(tagval, ilen+1) != ' ')
3506 				    return ajFalse;
3507 
3508 				ajStrAssignC(val,
3509 					     ajStrGetPtr(tagval) +
3510 					     ilen+2);
3511 
3512 			    }
3513 			    else	/* no value */
3514 				ajStrAssignClear(val);
3515 
3516 			    ajListIterDel(&iter);
3517 			    return ajTrue;
3518 			}
3519 		    }
3520 		}
3521 	    }
3522 	}
3523     }
3524 
3525     ajStrDel(val);
3526     ajListIterDel(&iter);
3527 
3528     return ajFalse;
3529 }
3530 
3531 
3532 
3533 
3534 /* @func ajFeatGetNoteSI ******************************************************
3535 **
3536 ** Finds a named note tag (with a * prefix)
3537 **
3538 ** @param [r] thys [const AjPFeature] Feature object
3539 ** @param [r] name [const AjPStr] Tag name
3540 ** @param [r] count [ajint] Tag count: zero for any, 1 for first, 2 for second
3541 ** @param [w] val [AjPStr*] Tag value (if found)
3542 **
3543 ** @return [AjBool] ajTrue on success (feature tag found)
3544 **
3545 ** @release 6.2.0
3546 ** @@
3547 ******************************************************************************/
3548 
ajFeatGetNoteSI(const AjPFeature thys,const AjPStr name,ajint count,AjPStr * val)3549 AjBool ajFeatGetNoteSI(const AjPFeature thys, const AjPStr name, ajint count,
3550                        AjPStr* val)
3551 {
3552     return ajFeatGetNoteCI(thys, ajStrGetPtr(name), count, val);
3553 }
3554 
3555 
3556 
3557 
3558 /* @func ajFeatGetNoteS *******************************************************
3559 **
3560 ** Finds a named note tag (with a * prefix)
3561 **
3562 ** @param [r] thys [const AjPFeature] Feature object
3563 ** @param [r] name [const AjPStr] Tag name
3564 ** @param [w] val [AjPStr*] Tag value (if found)
3565 **
3566 ** @return [AjBool] ajTrue on success (feature tag found)
3567 **
3568 ** @release 6.2.0
3569 ** @@
3570 ******************************************************************************/
3571 
ajFeatGetNoteS(const AjPFeature thys,const AjPStr name,AjPStr * val)3572 AjBool ajFeatGetNoteS(const AjPFeature thys, const AjPStr name, AjPStr* val)
3573 {
3574     return ajFeatGetNoteSI(thys, name, 0, val);
3575 }
3576 
3577 
3578 
3579 
3580 /* @func ajFeatGetTagC ********************************************************
3581 **
3582 ** Returns the nth value of a named feature tag.
3583 **
3584 ** If not found as a tag, also searches for a named note
3585 **
3586 ** @param [r] thys [const AjPFeature] Feature object
3587 ** @param [r] tname [const char*] Tag name
3588 ** @param [r] num [ajint] Tag number
3589 ** @param [w] Pval [AjPStr*] Tag value (if found)
3590 **
3591 ** @return [AjBool] ajTrue on success (feature tag found)
3592 **
3593 ** @release 6.1.0
3594 ** @@
3595 ******************************************************************************/
3596 
ajFeatGetTagC(const AjPFeature thys,const char * tname,ajint num,AjPStr * Pval)3597 AjBool ajFeatGetTagC(const AjPFeature thys, const char* tname, ajint num,
3598 		    AjPStr* Pval)
3599 {
3600     AjIList iter     = NULL;
3601     AjPTagval item = NULL;
3602     ajint inum       = 0;
3603     AjBool isnote;
3604     ajint noteposcolon=0;
3605     ajint noteposvalue=0;
3606     const AjPStr tagval = NULL;
3607 
3608     ajDebug("ajFeatGetTagC '%s'\n", tname);
3609     isnote = ajCharMatchC(tname, "note");
3610     noteposcolon = strlen(tname) + 1;
3611     noteposvalue = strlen(tname) + 3;
3612 
3613     if(thys->Tags)
3614     {
3615 	iter = ajListIterNewread(thys->Tags);
3616 	while(!ajListIterDone(iter))
3617 	{
3618 	    item = (AjPTagval)ajListIterGet(iter);
3619             tagval = ajTagvalGetValue(item);
3620 
3621             ajDebug("testing '%S'\n", ajTagvalGetTag(item));
3622 
3623 	    if(ajStrMatchCaseC(MAJTAGVALGETTAG(item), tname))
3624 	    {
3625 		inum++;
3626                 ajDebug("test1 inum %d\n", inum);
3627 
3628 		if(num == inum)
3629 		{
3630                     ajDebug("++match1\n");
3631 		    ajStrAssignS(Pval, tagval);
3632 		    ajListIterDel(&iter);
3633 		    return ajTrue;
3634 		}
3635 	    }
3636 	    else if(!isnote &&
3637 		    ajStrMatchCaseC(MAJTAGVALGETTAG(item), "note") &&
3638 		    ajStrGetCharFirst(tagval) == '*' &&
3639 		    ajCharPrefixCaseC(ajStrGetPtr(tagval)+1, tname) &&
3640 		    ajStrGetCharPos(tagval, noteposcolon) == ':')
3641 	    {
3642 		inum++;
3643                 ajDebug("test2 inum %d\n", inum);
3644 
3645 		if(num == inum)
3646 		{
3647                     ajDebug("++match2 from %d\n", noteposvalue);
3648 		    ajStrAssignSubS(Pval, tagval, noteposvalue, -1);
3649 		    ajListIterDel(&iter);
3650 		    return ajTrue;
3651 		}
3652 	    }
3653 	}
3654     }
3655 
3656     ajDebug("No match to '%s'\n", tname);
3657 
3658     ajStrDel(Pval);
3659     ajListIterDel(&iter);
3660 
3661     return ajFalse;
3662 }
3663 
3664 
3665 
3666 
3667 /* @func ajFeatGetTagS ********************************************************
3668 **
3669 ** Returns the nth value of a named feature tag.
3670 **
3671 ** If not found as a tag, also searches for a named note
3672 **
3673 ** @param [r] thys [const AjPFeature] Feature object
3674 ** @param [r] name [const AjPStr] Tag name
3675 ** @param [r] num [ajint] Tag number
3676 ** @param [w] val [AjPStr*] Tag value (if found)
3677 **
3678 ** @return [AjBool] ajTrue on success (feature tag found)
3679 **
3680 ** @release 6.1.0
3681 ** @@
3682 ******************************************************************************/
3683 
ajFeatGetTagS(const AjPFeature thys,const AjPStr name,ajint num,AjPStr * val)3684 AjBool ajFeatGetTagS(const AjPFeature thys, const AjPStr name, ajint num,
3685                      AjPStr* val)
3686 {
3687     AjIList iter     = NULL;
3688     AjPTagval item = NULL;
3689     ajint inum       = 0;
3690     AjBool isnote;
3691     ajint noteposcolon=0;
3692     ajint noteposvalue=0;
3693     const AjPStr tagval = NULL;
3694 
3695     isnote = ajStrMatchC(name, "note");
3696     noteposcolon = ajStrGetLen(name) + 1;
3697     noteposvalue = ajStrGetLen(name) + 3;
3698 
3699     if(thys->Tags)
3700     {
3701 	iter = ajListIterNewread(thys->Tags);
3702 
3703 	while(!ajListIterDone(iter))
3704 	{
3705 	    item = (AjPTagval)ajListIterGet(iter);
3706             tagval = ajTagvalGetValue(item);
3707 	    if(ajStrMatchCaseS(MAJTAGVALGETTAG(item), name))
3708 	    {
3709 		inum++;
3710 
3711 		if(num == inum)
3712 		{
3713 		    ajStrAssignS(val, tagval);
3714 		    ajListIterDel(&iter);
3715 		    return ajTrue;
3716 		}
3717 	    }
3718 	    else if(!isnote &&
3719 		    ajStrMatchCaseC(MAJTAGVALGETTAG(item), "note") &&
3720 		    ajStrGetCharFirst(tagval) == '*' &&
3721 		    ajCharPrefixCaseS(ajStrGetPtr(tagval)+1, name) &&
3722 		    ajStrGetCharPos(tagval, noteposcolon) == ':')
3723 	    {
3724 		inum++;
3725 
3726 		if(num == inum)
3727 		{
3728 		    ajStrAssignSubS(val, tagval, noteposvalue, -1);
3729 		    ajListIterDel(&iter);
3730 		    return ajTrue;
3731 		}
3732 	    }
3733 	}
3734     }
3735 
3736     ajStrDel(val);
3737     ajListIterDel(&iter);
3738 
3739     return ajFalse;
3740 }
3741 
3742 
3743 
3744 
3745 /* @func ajFeatGetType ********************************************************
3746 **
3747 ** Returns the type (key) of a feature object. This is a copy of the
3748 ** pointer to the type, and is still owned by the feature
3749 ** and is not to be destroyed.
3750 **
3751 ** @param [r] thys [const AjPFeature] Feature object
3752 **
3753 ** @return [const AjPStr] Feature type, read only
3754 **
3755 ** @release 2.1.0
3756 ** @@
3757 ******************************************************************************/
3758 
ajFeatGetType(const AjPFeature thys)3759 const AjPStr ajFeatGetType(const AjPFeature thys)
3760 {
3761     if(!FeatInitDone)
3762 	featInit();
3763 
3764     if(thys->Protein)
3765 	return ajFeattypeGetExternal(thys->Type, FeatTypeTableProtein);
3766     else
3767 	return ajFeattypeGetExternal(thys->Type, FeatTypeTableDna);
3768 }
3769 
3770 
3771 
3772 
3773 /* @func ajFeatGetSource*******************************************************
3774 **
3775 ** Returns the source name of a feature object.
3776 **
3777 ** @param [r] thys [const AjPFeature] Feature object
3778 **
3779 ** @return [const AjPStr] Feature source name
3780 **
3781 ** @release 4.0.0
3782 ** @@
3783 ******************************************************************************/
3784 
ajFeatGetSource(const AjPFeature thys)3785 const AjPStr ajFeatGetSource(const AjPFeature thys)
3786 {
3787     return thys->Source;
3788 }
3789 
3790 
3791 
3792 
3793 /* @func ajFeatGetStart *******************************************************
3794 **
3795 ** Returns the start position of a feature object.
3796 **
3797 ** @param [r] thys [const AjPFeature] Feature object
3798 **
3799 ** @return [ajuint] Feature start position
3800 **
3801 ** @release 2.1.0
3802 ** @@
3803 ******************************************************************************/
3804 
ajFeatGetStart(const AjPFeature thys)3805 ajuint ajFeatGetStart(const AjPFeature thys)
3806 {
3807     if((thys->Flags & AJFEATFLAG_START_TWO) &&
3808        (thys->Start2 < thys->Start))
3809         return thys->Start2;
3810 
3811     return thys->Start;
3812 }
3813 
3814 
3815 
3816 
3817 /* @func ajFeatGetStrand ******************************************************
3818 **
3819 ** Returns the strand of a feature object.
3820 **
3821 ** @param [r] thys [const AjPFeature] Feature object
3822 **
3823 ** @return [char] Feature strand code
3824 **
3825 ** @release 4.0.0
3826 ** @@
3827 ******************************************************************************/
3828 
ajFeatGetStrand(const AjPFeature thys)3829 char ajFeatGetStrand(const AjPFeature thys)
3830 {
3831     if(thys->Protein)
3832         return '.';
3833 
3834     if(thys->Strand == '-')
3835 	return '-';
3836     else
3837 	return '+';
3838 }
3839 
3840 
3841 
3842 
3843 /* @func ajFeatGetEnd *********************************************************
3844 **
3845 ** Returns the end position of a feature object.
3846 **
3847 ** @param [r] thys [const AjPFeature] Feature object
3848 **
3849 ** @return [ajuint] Feature end position
3850 **
3851 ** @release 2.1.0
3852 ** @@
3853 ******************************************************************************/
3854 
ajFeatGetEnd(const AjPFeature thys)3855 ajuint ajFeatGetEnd(const AjPFeature thys)
3856 {
3857     if((thys->Flags & AJFEATFLAG_END_TWO) &&
3858        (thys->End2 < thys->End))
3859         return thys->End2;
3860 
3861     return thys->End;
3862 }
3863 
3864 
3865 
3866 
3867 /* @func ajFeatGetLength ******************************************************
3868 **
3869 ** Returns the sequence length of a feature object.
3870 **
3871 ** @param [r] thys [const AjPFeature] Feature object
3872 **
3873 ** @return [ajuint] Feature length
3874 **
3875 ** @release 4.0.0
3876 ** @@
3877 ******************************************************************************/
3878 
ajFeatGetLength(const AjPFeature thys)3879 ajuint ajFeatGetLength(const AjPFeature thys)
3880 {
3881     return thys->End - thys->Start + 1;
3882 }
3883 
3884 
3885 
3886 
3887 /* @func ajFeatGetScore *******************************************************
3888 **
3889 ** Returns the score of a feature object.
3890 **
3891 ** @param [r] thys [const AjPFeature] Feature object
3892 **
3893 ** @return [float] Feature score
3894 **
3895 ** @release 4.0.0
3896 ** @@
3897 ******************************************************************************/
3898 
ajFeatGetScore(const AjPFeature thys)3899 float ajFeatGetScore(const AjPFeature thys)
3900 {
3901     return thys->Score;
3902 }
3903 
3904 
3905 
3906 
3907 /* @func ajFeatGetForward *****************************************************
3908 **
3909 ** Returns the direction of a feature object.
3910 **
3911 ** @param [r] thys [const AjPFeature] Feature object
3912 **
3913 ** @return [AjBool] ajTrue for a forward direction, ajFalse for reverse
3914 **
3915 ** @release 2.1.0
3916 ** @@
3917 ******************************************************************************/
3918 
ajFeatGetForward(const AjPFeature thys)3919 AjBool ajFeatGetForward(const AjPFeature thys)
3920 {
3921     if(ajSysCastItoc(thys->Strand) != '-')
3922 	return ajTrue;
3923 
3924     return ajFalse;
3925 }
3926 
3927 
3928 
3929 
3930 /* @func ajFeatGetFrame *******************************************************
3931 **
3932 ** Returns the reading frame of a feature object.
3933 **
3934 ** @param [r] thys [const AjPFeature] Feature object
3935 **
3936 ** @return [ajint] Feature reading frame (zero for undefined)
3937 **
3938 ** @release 2.1.0
3939 ** @@
3940 ******************************************************************************/
3941 
ajFeatGetFrame(const AjPFeature thys)3942 ajint ajFeatGetFrame(const AjPFeature thys)
3943 {
3944     return thys->Frame;
3945 }
3946 
3947 
3948 
3949 
3950 /* @func ajFeatGetTranslation *************************************************
3951 **
3952 ** Returns translation tag value
3953 **
3954 ** @param [r] thys [const AjPFeature] Feature
3955 ** @param [w] Ptrans [AjPStr*] Translations
3956 **
3957 ** @return [AjBool] True if translation tag was found
3958 **
3959 ** @release 6.1.0
3960 ** @@
3961 ******************************************************************************/
3962 
ajFeatGetTranslation(const AjPFeature thys,AjPStr * Ptrans)3963 AjBool ajFeatGetTranslation(const AjPFeature thys, AjPStr *Ptrans)
3964 {
3965     return ajFeatGetTagC(thys, "translation", 1, Ptrans);
3966 }
3967 
3968 
3969 
3970 
3971 /*========================================================================
3972 ======================= NEW FUNCTIONS ====================================
3973 ========================================================================*/
3974 
3975 
3976 
3977 
3978 /* @func ajFeatTest ***********************************************************
3979 **
3980 ** Temporary testing function for feature handling
3981 ** to be deleted when all is working happily
3982 **
3983 ** @return [void]
3984 **
3985 ** @release 2.0.0
3986 ** @@
3987 ******************************************************************************/
3988 
ajFeatTest(void)3989 void ajFeatTest(void)
3990 {
3991     AjPFeattable table = NULL;
3992     AjPStr desc        = NULL;
3993     AjPStr source      = NULL;
3994     AjPStr type        = NULL;
3995     AjPFeature ft      = NULL;
3996 
3997     featInit();
3998     table = ajFeattableNew(NULL);
3999 
4000     ajStrAssignC(&source, "testft");
4001     ajStrAssignC(&type, "misc_feature");
4002     ajStrAssignC(&desc, "Just testing");
4003 
4004     ft = ajFeatNew(table, source, type, 5, 7, (float)1.23, '+', 0);
4005     ajFeatSetDesc(ft, desc);
4006 
4007     ajStrAssignC(&desc, "Testing again");
4008     ft = ajFeatNew(table, source, type, 9, 19, (float)4.56, '-', 3);
4009     ajFeatSetDesc(ft, desc);
4010 
4011     ajFeattableTrace(table);
4012 
4013     ajFeattableDel(&table);
4014     ajStrDel(&desc);
4015     ajStrDel(&source);
4016     ajStrDel(&type);
4017 
4018     return;
4019 }
4020 
4021 
4022 
4023 
4024 /* @funcstatic featInit *******************************************************
4025 **
4026 ** Initialises everything needed for feature handling
4027 **
4028 ** @return [void]
4029 **
4030 ** @release 2.0.0
4031 ** @@
4032 ******************************************************************************/
4033 
featInit(void)4034 static void featInit(void)
4035 {
4036     if(FeatInitDone)
4037 	return;
4038 
4039     FeatInitDone = ajTrue;
4040 
4041     if(!FeatTypeTableDna)
4042     {
4043 	FeatTypeTableDna = ajTablestrNewCase(200);
4044 	FeatTagsTableDna = ajTablestrNewCase(200);
4045 	featVocabRead("emboss",FeatTypeTableDna, FeatTagsTableDna);
4046     }
4047 
4048     if(!FeatTypeTableProtein)
4049     {
4050 	FeatTypeTableProtein = ajTablestrNewCase(200);
4051 	FeatTagsTableProtein = ajTablestrNewCase(200);
4052 	featVocabRead("protein", FeatTypeTableProtein, FeatTagsTableProtein);
4053     }
4054 
4055     /*ajDebug("Tables internal (Dna, Prot) Type: %x %x Tags: %x %x\n",
4056 	    FeatTypeTableDna, FeatTypeTableProtein,
4057 	    FeatTagsTableDna, FeatTagsTableProtein);*/
4058 
4059 
4060     return;
4061 }
4062 
4063 
4064 
4065 
4066 /* @funcstatic featVocabRead **************************************************
4067 **
4068 ** Reads the possible feature types (keys) and tags (qualifiers)
4069 ** from files.
4070 **
4071 ** @param [r] name [const char*] Feature type ("emboss", "protein", or external
4072 **                               feature types "swiss", "gff", "embl", etc.
4073 ** @param [w] pTypeTable [AjPTable] Feature type table
4074 ** @param [w] pTagsTable [AjPTable] Feature tags table
4075 ** @return [AjBool] ajTrue on success
4076 **
4077 ** @release 2.0.0
4078 ** @@
4079 ******************************************************************************/
4080 
featVocabRead(const char * name,AjPTable pTypeTable,AjPTable pTagsTable)4081 static AjBool featVocabRead(const char* name,
4082 			    AjPTable pTypeTable, AjPTable pTagsTable)
4083 {
4084     AjPStr TypeFName = NULL;
4085     AjPStr TagsFName = NULL;
4086 
4087     /* First read in the list of all possible tags */
4088 
4089     ajFmtPrintS(&TagsFName, "Etags.%s", name);
4090     ajDebug("featVocabRead '%S' typetable %x tagstable %x\n",
4091 	    TagsFName, pTypeTable, pTagsTable);
4092 
4093     if(!featVocabReadTags(TagsFName, pTagsTable, ajTrue))
4094 	return ajFalse;
4095 
4096     /*ajDebug("Trace tagstable '%S'", TagsFName);*/
4097     /*ajTablestrTrace(pTagsTable);*/
4098 
4099   /* Efeatures file
4100   ** format: featuretype
4101   **            M/mandatorytag
4102   **             /tag
4103   **             /tag
4104   **
4105   ** All tags must be defined in the Etags file (read earlier into pTagsTable)
4106   */
4107 
4108     ajFmtPrintS(&TypeFName, "Efeatures.%s", name);
4109     /*ajDebug("Trying to open %S...\n",TypeFName);*/
4110     if(!featVocabReadTypes(TypeFName, pTypeTable, pTagsTable, ajTrue))
4111 	return ajFalse;
4112 
4113     /*ajDebug("Trace typetable '%S'", TypeFName);*/
4114     /*ajTablestrTrace(pTypeTable);*/
4115 
4116     ajStrDel(&TagsFName);
4117     ajStrDel(&TypeFName);
4118 
4119     return ajTrue;
4120 }
4121 
4122 
4123 
4124 
4125 /* @funcstatic featVocabReadTags **********************************************
4126 **
4127 ** Reads the possible feature tags (qualifiers)
4128 ** from files.
4129 **
4130 ** @param [r] fname [const AjPStr] Feature tags definitions datafile name
4131 ** @param [w] pTagsTable [AjPTable] Feature tags table
4132 ** @param [r] recursion [AjBool] If true process any include lines
4133 ** @return [AjBool] ajTrue on success
4134 **
4135 ** @release 6.0.0
4136 ** @@
4137 ******************************************************************************/
4138 
featVocabReadTags(const AjPStr fname,AjPTable pTagsTable,AjBool recursion)4139 static AjBool featVocabReadTags(const AjPStr fname, AjPTable pTagsTable,
4140 				       AjBool recursion)
4141 {
4142     AjPFile TagsFile = NULL;
4143     AjPStr TagsFName = NULL;
4144     AjPStr line      = NULL;
4145     AjPStr tagname   = NULL;		/* stored in table */
4146     AjPStr tagstr    = NULL;		/* stored in table */
4147     AjPStr defname   = NULL;		/* stored in table */
4148     AjPStr tagtype   = NULL;
4149     AjPStr token     = NULL;
4150     AjPStr rest      = NULL;
4151     ajint linecount = 0;
4152     ajlong tagscount = 0;
4153     ajint numtype   = -1;
4154     ajint i;
4155 
4156     const char* TagType[] =
4157     {
4158 	"QTEXT",			/* quoted text */
4159 	"QWORD",			/* quoted text, no space */
4160 	"BTEXT",			/* bracketed text */
4161 	"TEXT",				/* unquoted, no white space */
4162 	"VOID",				/* no value */
4163 	"LIMITED",			/* limited vocabulary */
4164 	"QLIMITED",		 /* limited vocabulary, with quotes */
4165 	"SPECIAL",			/* special formatting */
4166 	"QSPECIAL",		 /* special formatting, with quotes */
4167 	"TAGVAL",		       /* /type=value for swissprot */
4168 	NULL
4169     };
4170 
4171     TagsFile = ajDatafileNewInNameS(fname);
4172 
4173     if(!TagsFile)
4174     {
4175 	ajErr("Unable to read feature tags data file '%S'\n", fname);
4176 	return ajFalse;
4177     }
4178 
4179     tagscount = ajTableGetLength(pTagsTable);
4180     linecount = 0;
4181 
4182     while(ajReadlineTrim(TagsFile,&line))
4183     {
4184 	linecount++;
4185 	ajStrRemoveWhiteExcess(&line);
4186 
4187 	if(ajStrPrefixC(line, "#"))
4188 	{
4189 	    if(recursion && ajStrPrefixCaseC(line, "#include "))
4190 	    {
4191 		ajStrCutStart(&line, 9);
4192 		ajStrExtractWord(line, &rest, &TagsFName);
4193 		ajStrDel(&rest);
4194 		if(!featVocabReadTags(TagsFName, pTagsTable, ajTrue))
4195 		{
4196 		    ajStrDel(&line);
4197 		    ajStrDel(&TagsFName);
4198 		    return ajFalse;
4199 		}
4200 		tagscount = ajTableGetLength(pTagsTable);
4201 	    }
4202 
4203 	    if(recursion && ajStrPrefixCaseC(line, "#includeonly "))
4204 	    {
4205 		ajStrCutStart(&line, 13);
4206 		ajStrExtractWord(line, &rest, &TagsFName);
4207 		ajStrDel(&rest);
4208 
4209 		if(!featVocabReadTags(TagsFName, pTagsTable, ajFalse))
4210 		{
4211 		    ajStrDel(&line);
4212 		    ajStrDel(&TagsFName);
4213 		    return ajFalse;
4214 		}
4215 		tagscount = ajTableGetLength(pTagsTable);
4216 	    }
4217 	}
4218 	else if(ajStrGetLen(line)) /* skip comments */
4219 	{
4220 	    ajStrDel(&tagname);		/* create a new tag */
4221 
4222 	    if(featTagName(line, &tagname, &tagtype, &featTmpStr))
4223 	    {
4224 		numtype = -1;
4225 
4226 		for(i=0; TagType[i]; i++)
4227 		    if(!ajStrCmpC(tagtype,TagType[i]))
4228 		    {
4229 			numtype = i;
4230 			break;
4231 		    }
4232 
4233 		if(numtype < 0)
4234 		{
4235 		    /*ajDebug("Bad feature tag type '%S' in %F line %d\n",
4236 			    tagtype, TagsFile, linecount);*/
4237 		    ajErr("Bad feature tag type '%S' in %F line %d",
4238 			  tagtype, TagsFile, linecount);
4239 		    break;
4240 		}
4241 		ajStrDel(&tagtype);
4242 
4243 		tagscount++;
4244 
4245 		if(tagscount == 1) /* save first tag as the default */
4246 		{
4247 		    tagstr = NULL;
4248 		    ajStrAssignClear(&defname);
4249 		    ajStrAssignS(&tagstr, tagname);
4250 
4251 		    if(ajTablePut (pTagsTable, defname, tagstr))
4252 			ajErr("%S duplicate tag for '%S'",
4253 			      fname, defname);
4254 
4255 		    tagstr  = NULL;
4256 		    defname = NULL;
4257 		}
4258 
4259 		tagstr = NULL;
4260 		ajFmtPrintS(&tagstr, "%s;", TagType[numtype]);
4261 
4262 		/*
4263 		 ** Controlled vocabulary :
4264 		 ** read the list of valid values
4265 		 */
4266 
4267 		if(ajCharMatchCaseC(TagType[numtype], "LIMITED") ||
4268 		   ajCharMatchCaseC(TagType[numtype], "QLIMITED"))
4269 		{
4270 		    ajStrTokenAssignC(&featVocabSplit, featTmpStr, "\", \t");
4271 
4272 		    while(ajStrTokenNextParse(featVocabSplit, &token))
4273 		    {
4274 			ajFmtPrintAppS(&tagstr, "%S;", token);
4275 		    }
4276 
4277 		    ajStrDelStatic(&featTmpStr);
4278 		    ajStrTokenDel(&featVocabSplit);
4279 		}
4280 
4281 		if(ajTablePut(pTagsTable, tagname, tagstr))
4282 		    ajErr("%S duplicate tag for '%S'", fname, tagname);
4283 
4284 		tagstr  = NULL;
4285 		tagname = NULL;
4286 	    }
4287 	    else
4288 	    {
4289 		/*ajDebug("** line format bad **\n%S", line);*/
4290 	    }
4291 	}
4292     }
4293 
4294     ajFileClose(&TagsFile);
4295     ajStrDel(&TagsFName);
4296     ajStrDel(&line);
4297     ajStrDel(&token);
4298     ajStrDel(&tagname);
4299     ajStrDel(&tagtype);
4300 
4301     /*
4302        ajTableTrace(pTagsTable);
4303        ajTablestrPrint(pTagsTable);
4304        */
4305 
4306     return ajTrue;
4307 }
4308 
4309 
4310 
4311 
4312 /* @funcstatic featTagName ****************************************************
4313 **
4314 ** Process anything up to ':' as an entry ID (a feature in another entry)
4315 ** Anything up to ',' is this location
4316 **
4317 ** @param [r] line [const AjPStr] Tags file line
4318 ** @param [w] name [AjPStr*] Tag name
4319 ** @param [w] type [AjPStr*] Tag type
4320 ** @param [w] rest [AjPStr*] Remainder of line
4321 ** @return [AjBool] ajTrue if a match was found
4322 **                  ajFalse means an error occurred
4323 **
4324 ** @release 3.0.0
4325 ******************************************************************************/
4326 
featTagName(const AjPStr line,AjPStr * name,AjPStr * type,AjPStr * rest)4327 static AjBool featTagName(const AjPStr line, AjPStr* name, AjPStr* type,
4328 			  AjPStr* rest)
4329 {
4330     const char* cp = ajStrGetPtr(line);
4331 
4332     ajStrAssignClear(name);
4333     ajStrAssignClear(type);
4334     ajStrAssignClear(rest);
4335 
4336     while(isspace((ajint)*cp))
4337 	cp++;
4338 
4339     while(*cp && !isspace((ajint)*cp))
4340 	ajStrAppendK(name, *cp++);
4341 
4342     while(isspace((ajint)*cp))
4343 	cp++;
4344 
4345     if(!*cp)
4346     {
4347 	ajStrAssignClear(name);
4348 
4349 	return ajFalse;
4350     }
4351 
4352     while(isalpha((ajint)*cp))
4353 	ajStrAppendK(type, *cp++);
4354 
4355     if(!ajStrMatchC(*type, "LIMITED") || ajStrMatchC(*type, "QLIMITED"))
4356 	return ajTrue;
4357 
4358     while(isspace((ajint)*cp))
4359 	cp++;
4360 
4361     while(*cp)
4362 	ajStrAppendK(rest, *cp++);
4363 
4364     return ajTrue;
4365 }
4366 
4367 
4368 
4369 
4370 /* @funcstatic featVocabReadTypes *********************************************
4371 **
4372 ** Reads the possible feature types (keys)
4373 ** from files.
4374 **
4375 ** @param [r] fname [const AjPStr] Feature type definitions datafile name
4376 ** @param [w] pTypeTable [AjPTable] Feature type table
4377 ** @param [r] pTagsTable [const AjPTable] Feature tags table
4378 ** @param [r] recursion [AjBool] If true process any include lines
4379 ** @return [AjBool] ajTrue on success
4380 **
4381 ** @release 6.0.0
4382 ** @@
4383 ******************************************************************************/
4384 
featVocabReadTypes(const AjPStr fname,AjPTable pTypeTable,const AjPTable pTagsTable,AjBool recursion)4385 static AjBool featVocabReadTypes(const AjPStr fname, AjPTable pTypeTable,
4386 				 const AjPTable pTagsTable,
4387 				 AjBool recursion)
4388 {
4389     AjPStr TypeFName = NULL;
4390     AjPFile TypeFile = NULL;
4391     AjPStr line      = NULL;
4392     AjPStr intids    = NULL;
4393     AjPStr tag       = NULL;
4394     AjPStr req       = NULL;
4395     AjPStr localname = NULL;
4396     AjPStr sofaname  = NULL;
4397     AjPStr type      = NULL;
4398     AjPStr defname   = NULL;
4399     AjPStr defid     = NULL;
4400     AjPStr typtagstr = NULL;
4401     AjPStr savetype  = NULL;
4402     AjPStr firstid   = NULL;
4403     AjPStr token     = NULL;
4404     AjPStr rest      = NULL;
4405     AjPStr editstr   = NULL;
4406     AjPStr modtype   = NULL;
4407     const AjPStr tablestr  = NULL;
4408     const AjPStr sofaid    = NULL;
4409     const AjPStr storetype  = NULL;
4410 
4411     ajlong typecount = 0;
4412     ajint filetypecount = 0;
4413 
4414     char reqchar;
4415     char modchar;
4416     ajlong ipos;
4417     AjBool ismodtype = ajFalse;
4418     AjPStr* Ptyptagstr = NULL;
4419 /*    AjBool taginternal = ajFalse; */
4420     AjBool newdefid    = ajFalse;
4421     static ajuint level = 0;
4422 
4423     level++;
4424 
4425     TypeFile = ajDatafileNewInNameS(fname);
4426 
4427     if(!TypeFile)
4428     {
4429 	ajErr("Unable to read feature types data file '%S'\n", fname);
4430         level--;
4431 	return ajFalse;
4432     }
4433 
4434     filetypecount = 0;
4435     typecount = ajTableGetLength(pTypeTable);
4436 
4437     while(ajReadlineTrim(TypeFile,&line))
4438     {
4439 	ajStrRemoveWhiteExcess(&line);
4440 
4441 	if(ajStrPrefixC(line,"#")) /* if a comment skip it */
4442 	{
4443 	    if(recursion && ajStrPrefixCaseC(line, "#include "))
4444 	    {
4445 		ajStrCutStart(&line, 9);
4446 		ajStrExtractFirst(line, &rest, &TypeFName);
4447 		ajStrDel(&rest);
4448 
4449 		if(!featVocabReadTypes(TypeFName, pTypeTable, pTagsTable,
4450 				       ajTrue))
4451 		{
4452 		    ajStrDel(&line);
4453 		    ajStrDel(&TypeFName);
4454                     ajStrDel(&firstid);
4455                     ajStrDel(&savetype);
4456                     ajStrDel(&sofaname);
4457                     level--;
4458                     return ajFalse;
4459 		}
4460 
4461 		typecount = ajTableGetLength(pTypeTable);
4462 	    }
4463 
4464 	    if(recursion && ajStrPrefixCaseC(line, "#includeonly "))
4465 	    {
4466 		ajStrCutStart(&line, 13);
4467 		ajStrExtractFirst(line, &rest, &TypeFName);
4468 		ajStrDel(&rest);
4469 
4470                 if(!featVocabReadTypes(TypeFName, pTypeTable, pTagsTable,
4471 				       ajFalse))
4472 		{
4473 		    ajStrDel(&line);
4474 		    ajStrDel(&TypeFName);
4475                     ajStrDel(&firstid);
4476                     ajStrDel(&savetype);
4477                     ajStrDel(&sofaname);
4478                     level--;
4479 		    return ajFalse;
4480 
4481 		}
4482 		typecount = ajTableGetLength(pTypeTable);
4483 	    }
4484 	}
4485 	else if(ajStrGetLen(line))
4486 	{
4487 	    if(featFeatType(line, &type, &intids, &tag, &req))
4488 	    {
4489 		if(ajStrGetLen(type))	/* new feature type */
4490 		{
4491 		    if(!ismodtype &&
4492 		       ajStrGetLen(savetype)) /* save previous type and tags */
4493 		    {
4494 #if FEATDEBUG
4495 			ajDebug("%S %Ld saved '%S' as '%S'\n",
4496                                 fname, typecount, savetype, typtagstr);
4497 			ajDebug("+type %S='%S'\n",
4498                                 savetype, typtagstr);
4499 #endif
4500 /*
4501 			tablestr = ajTablePut(pTypeTable,
4502 					      savetype, typtagstr);
4503 */
4504 			tablestr = ajTableFetchS(pTypeTable, savetype);
4505 
4506                         if(tablestr)
4507                         {
4508                             if(recursion)
4509                             {
4510                                 ajErr("%S duplicate type %S='%S' "
4511                                       "already defined as '%S'",
4512                                       fname, savetype, typtagstr, tablestr);
4513                             }
4514                             else
4515                             {
4516 #if FEATDEBUG
4517                                 ajDebug("found savetype '%S' with value '%S'\n",
4518                                        savetype, tablestr);
4519 #endif
4520                             }
4521 
4522                             ajStrDel(&typtagstr);
4523                             ajStrDel(&savetype);
4524                         }
4525                         else
4526                         {
4527                             ajTablePut(pTypeTable, savetype, typtagstr);
4528                             typtagstr = NULL;
4529                             savetype = NULL;
4530                         }
4531 		    }
4532 
4533 		    if(ajStrMatchC(req, "="))
4534                     {
4535 			ismodtype = ajTrue;
4536 			ajStrAssignS(&modtype, type);
4537 
4538 			if(ajStrMatchC(type, ".")) /* replace default */
4539 			    ajStrAssignClear(&type);
4540 
4541 			ajStrAssignS(&localname, type);
4542 			ajStrAssignS(&sofaname, intids);
4543 			tablestr = ajTableFetchS(pTypeTable, localname);
4544 
4545 			if(tablestr)
4546 			{
4547 #if FEATDEBUG
4548 			    ajDebug("%S duplicate alias type "
4549 				  "%S='%S' already defined as '%S'\n",
4550 				  fname, localname,
4551 				  sofaname, tablestr);
4552 #endif
4553 			    ajStrDel(&localname);
4554 			}
4555                         else
4556                         {
4557                             ajTablePut(pTypeTable, localname,
4558                                        sofaname);
4559                             localname = NULL;
4560                             sofaname = NULL;
4561 			}
4562 
4563 			Ptyptagstr = ajTablestrFetchmod(pTypeTable, intids);
4564 
4565                         if(!Ptyptagstr)
4566                             ajWarn("%S (level %u) undefined internal ID '%S'",
4567                                    fname, level, intids);
4568 
4569 			ipos = ajStrFindAnyK(*Ptyptagstr, ';');
4570 
4571 			if(ipos >= 0)
4572 			  ajStrCutStart(Ptyptagstr, (size_t) ipos);
4573 			else
4574 			    ajStrInsertK(Ptyptagstr, 0, ';');
4575 
4576 			ajStrInsertS(Ptyptagstr, 0, type);
4577                         ajStrDel(&savetype);
4578 			savetype  = type;
4579                         type = NULL;
4580 			typtagstr = *Ptyptagstr;
4581 /*                        taginternal = ajTrue; */
4582 		    }
4583 		    else
4584 		    {
4585 			typecount++;
4586 			filetypecount++;
4587 
4588 			if(typecount == 1)  /* type saved as "" default */
4589 			{
4590 			    defname   = NULL;
4591 			    defid = NULL;
4592 			    ajStrAssignClear(&defname);
4593 			    ajStrAssignS(&defid, type);
4594                             newdefid = ajTrue;
4595 			    tablestr = ajTableFetchS(pTypeTable, defname);
4596 
4597 			    if(tablestr)
4598                             {
4599 				ajErr("%S duplicate type %S='%S' "
4600                                       "already defined as '%S'",
4601 				      fname, defname, typtagstr, tablestr);
4602                                 ajStrDel(&typtagstr);
4603                                 ajStrDel(&defname);
4604                             }
4605                             else
4606                             {
4607                                 ajTablePut(pTypeTable, defname, defid);
4608                                 defname = NULL;
4609                             }
4610 
4611 			}
4612 
4613 			ismodtype = ajFalse;
4614 
4615 			/*
4616 			** set up new feature type and type-tag strings
4617 			** ready to save the details
4618 			*/
4619 
4620 			typtagstr = ajStrNewResC(";", 256);
4621 /*                        taginternal = ajFalse; */
4622 
4623 			if(ajStrGetLen(intids))
4624 			{
4625 			    sofaid = ajStrParseWhite(intids);
4626 			    ajStrAssignS(&firstid, sofaid);
4627 			    storetype = type;
4628 
4629 			    while(sofaid)
4630 			    {
4631                                 if(newdefid)
4632                                 {
4633                                     ajStrAssignS(&defid, sofaid);
4634                                     newdefid = ajFalse;
4635                                     defid = NULL;
4636                                 }
4637 
4638 #if FEATDEBUG
4639                                 ajDebug("+type %B storetype:'%S' "
4640 					"firstid:'%S'\n",
4641 					ajStrMatchCaseS(storetype, firstid),
4642 					storetype, firstid);
4643 #endif
4644 
4645 				if(!ajStrMatchCaseS(storetype, firstid))
4646 				{
4647 				    ajStrAssignS(&localname, storetype);
4648 				    ajStrAssignS(&sofaname, firstid);
4649 #if FEATDEBUG
4650 				    ajDebug("%S sofaid "
4651                                             "'%S' = '%S'\n",
4652                                             fname,localname, sofaname);
4653 				    ajDebug("+type (alias) %S='%S'\n",
4654                                             localname, sofaname);
4655 #endif
4656 				    tablestr = ajTableFetchS(pTypeTable,
4657                                                              localname);
4658 				    if(tablestr)
4659                                     {
4660                                         if(recursion)
4661                                         {
4662                                             ajErr("%S duplicate localname type "
4663                                                   "%S='%S' already defined "
4664                                                   "as '%S'",
4665                                                   fname, localname,
4666                                                   sofaname, tablestr);
4667                                         }
4668                                         ajStrDel(&localname);
4669                                         ajStrDel(&sofaname);
4670                                     }
4671                                     else
4672                                     {
4673                                         ajTablePut(pTypeTable,
4674                                                    localname, sofaname);
4675                                         localname = NULL;
4676                                         sofaname = NULL;
4677                                         storetype  = sofaid;
4678                                     }
4679 
4680 				}
4681 
4682 				sofaid = ajStrParseWhite(NULL);
4683 			    }
4684 
4685 			    ajStrInsertS(&typtagstr, 0, type);
4686 			    ajStrAssignClear(&type);
4687                             ajStrDel(&savetype);
4688 			    savetype  = firstid;
4689 			    firstid = NULL;
4690 			    sofaid = NULL;
4691 			    ajStrAssignClear(&intids);
4692 			}
4693 			else
4694 			{
4695                             ajStrDel(&savetype);
4696 			    savetype  = type;
4697 			    type      = NULL;
4698 			    ajStrAssignClear(&intids);
4699 			}
4700 		    }
4701 		}
4702 		else			/* tag name */
4703 		{
4704 		    if(!ajTableFetchS(pTagsTable, tag))
4705 		    {
4706 			if(ismodtype)
4707 			    ajFeatWarn("%S: tag %S (feature %S) "
4708 				     "not in Etags file",
4709 				     fname, tag, modtype);
4710 			else
4711 			    ajFeatWarn("%S: tag %S (feature %S) "
4712 				     "not in Etags file",
4713 				     fname, tag, savetype);
4714 		    }
4715 
4716 		    modchar = ajStrGetCharFirst(req);
4717 		    reqchar = ajStrGetCharLast(req);
4718 
4719 		    if(modchar == '-')
4720 		    {
4721 			ajFmtPrintS(&editstr, ";%S;", tag);
4722 			ajStrExchangeSC(&typtagstr, editstr, ";");
4723 
4724 			if(!modtype)
4725 			    ajFeatWarn("%S: delete tag '%S' for %S not modified",
4726 					 fname, tag, modtype);
4727 		    }
4728 		    else
4729 		    {
4730 			if(reqchar == 'M' ||
4731 			   reqchar == 'm')
4732 			    ajFmtPrintAppS(&typtagstr, "*");
4733 
4734 			ajFmtPrintAppS(&typtagstr, "%S;", tag);
4735 
4736 			if(modchar == '+')
4737 			{
4738 			    if(!modtype)
4739 				ajFeatWarn("%S: new tag '%S' for %S not modified",
4740 					 fname, tag, modtype);
4741 			}
4742 		    }
4743 		}
4744 	    }
4745 	}
4746     }
4747 
4748     if(filetypecount > 0)		/* save the last feature type */
4749     {
4750 #if FEATDEBUG
4751 	ajDebug("+type (final) %S='%S'\n",
4752                 savetype, typtagstr);
4753 #endif
4754 	tablestr = ajTableFetchS(pTypeTable, savetype);
4755 	if(tablestr)
4756         {
4757             if(recursion)
4758             {
4759                 ajErr("%S: duplicate type %S='%S' already defined as '%S'",
4760                       fname, savetype, typtagstr, tablestr);
4761             }
4762             ajStrDel(&typtagstr);
4763             ajStrDel(&savetype);
4764         }
4765         else
4766         {
4767             ajTablePut(pTypeTable, savetype, typtagstr);
4768             typtagstr = NULL;
4769             savetype = NULL;
4770         }
4771     }
4772 
4773     ajFileClose(&TypeFile);
4774 
4775     ajDebug("Total types...: %Ld\n", typecount);
4776 
4777     ajStrDel(&line);
4778     ajStrDel(&token);
4779     ajStrDel(&intids);
4780 
4781 
4782     /*
4783        ajTableTrace(pTypeTable);
4784        ajTablestrPrint(pTypeTable);
4785     */
4786 
4787     ajStrDelStatic(&featTmpStr);
4788     ajStrDel(&TypeFName);
4789     ajStrDel(&req);
4790     ajStrDel(&tag);
4791     ajStrDel(&type);
4792     ajStrDel(&intids);
4793     ajStrDel(&modtype);
4794     ajStrDel(&localname);
4795     ajStrDel(&sofaname);
4796     ajStrDel(&firstid);
4797     ajStrDel(&savetype);
4798 
4799     level--;
4800 
4801     return ajTrue;
4802 }
4803 
4804 
4805 
4806 
4807 /* @func ajFeatVocabGetTags ***************************************************
4808 **
4809 ** Returns tags table for a named feature format
4810 **
4811 ** @param [r] name [const char*] Feature format name
4812 ** @return [const AjPTable] Tags table on success
4813 **                          NULL on failure
4814 **
4815 ** @release 6.4.0
4816 ******************************************************************************/
4817 
ajFeatVocabGetTags(const char * name)4818 const AjPTable ajFeatVocabGetTags(const char* name)
4819 {
4820     ajuint i;
4821 
4822     if(!FeatInitDone)
4823         featInit();
4824 
4825     for(i=0; featVocab[i].Name; i++)
4826     {
4827         if(!strcmp(name, featVocab[i].Truename) ||
4828            !strcmp(name, featVocab[i].Name))
4829         {
4830             if(!*(featVocab[i].Tagstable))
4831                 if(!featVocabInit(i))
4832                     return NULL;
4833 
4834             return *(featVocab[i].Tagstable);
4835         }
4836     }
4837 
4838     return NULL;
4839 }
4840 
4841 
4842 
4843 
4844 /* @func ajFeatVocabGetTagsNuc ************************************************
4845 **
4846 ** Returns tags table for a named nucleotide feature format
4847 **
4848 ** @param [r] name [const char*] Feature format name
4849 ** @return [const AjPTable] Tags table on success
4850 **                          NULL on failure
4851 **
4852 ** @release 6.4.0
4853 ******************************************************************************/
4854 
ajFeatVocabGetTagsNuc(const char * name)4855 const AjPTable ajFeatVocabGetTagsNuc(const char* name)
4856 {
4857     ajuint i;
4858 
4859     if(!FeatInitDone)
4860         featInit();
4861 
4862     for(i=0; featVocab[i].Name; i++)
4863     {
4864         if(!featVocab[i].Nucleotide)
4865             continue;
4866 
4867         if(!strcmp(name, featVocab[i].Truename) ||
4868            !strcmp(name, featVocab[i].Name))
4869         {
4870             if(!*(featVocab[i].Tagstable))
4871                 if(!featVocabInit(i))
4872                     return NULL;
4873 
4874             return *(featVocab[i].Tagstable);
4875         }
4876     }
4877 
4878     return NULL;
4879 }
4880 
4881 
4882 
4883 
4884 /* @func ajFeatVocabGetTagsProt ***********************************************
4885 **
4886 ** Returns tags table for a named protein feature format
4887 **
4888 ** @param [r] name [const char*] Feature format name
4889 ** @return [const AjPTable] Tags table on success
4890 **                          NULL on failure
4891 **
4892 ** @release 6.4.0
4893 ******************************************************************************/
4894 
ajFeatVocabGetTagsProt(const char * name)4895 const AjPTable ajFeatVocabGetTagsProt(const char* name)
4896 {
4897     ajuint i;
4898 
4899     if(!FeatInitDone)
4900         featInit();
4901 
4902     for(i=0; featVocab[i].Name; i++)
4903     {
4904         if(!featVocab[i].Protein)
4905             continue;
4906 
4907         if(!strcmp(name, featVocab[i].Truename) ||
4908            !strcmp(name, featVocab[i].Name))
4909         {
4910             if(!*(featVocab[i].Tagstable))
4911                 if(!featVocabInit(i))
4912                     return NULL;
4913 
4914             return *(featVocab[i].Tagstable);
4915         }
4916     }
4917 
4918     return NULL;
4919 }
4920 
4921 
4922 
4923 
4924 /* @func ajFeatVocabGetTypes **************************************************
4925 **
4926 ** Returns types table for a named feature format
4927 **
4928 ** @param [r] name [const char*] Feature format name
4929 ** @return [const AjPTable] Type table on success
4930 **                          NULL on failure
4931 **
4932 ** @release 6.4.0
4933 ******************************************************************************/
4934 
ajFeatVocabGetTypes(const char * name)4935 const AjPTable ajFeatVocabGetTypes(const char* name)
4936 {
4937     ajuint i;
4938 
4939     if(!FeatInitDone)
4940         featInit();
4941 
4942     for(i=0; featVocab[i].Name; i++)
4943     {
4944         if(!strcmp(name, featVocab[i].Truename) ||
4945            !strcmp(name, featVocab[i].Name))
4946         {
4947             if(!*(featVocab[i].Typetable))
4948                 if(!featVocabInit(i))
4949                     return NULL;
4950 
4951             return *(featVocab[i].Typetable);
4952         }
4953     }
4954 
4955     return NULL;
4956 }
4957 
4958 
4959 
4960 
4961 /* @func ajFeatVocabGetTypesNuc ***********************************************
4962 **
4963 ** Returns types table for a named nucleotide feature format
4964 **
4965 ** @param [r] name [const char*] Feature format name
4966 ** @return [const AjPTable] Type table on success
4967 **                          NULL on failure
4968 **
4969 ** @release 6.4.0
4970 ******************************************************************************/
4971 
ajFeatVocabGetTypesNuc(const char * name)4972 const AjPTable ajFeatVocabGetTypesNuc(const char* name)
4973 {
4974     ajuint i;
4975 
4976     if(!FeatInitDone)
4977         featInit();
4978 
4979     for(i=0; featVocab[i].Name; i++)
4980     {
4981         if(!featVocab[i].Nucleotide)
4982             continue;
4983 
4984         if(!strcmp(name, featVocab[i].Truename) ||
4985            !strcmp(name, featVocab[i].Name))
4986         {
4987             if(!*(featVocab[i].Typetable))
4988                 if(!featVocabInit(i))
4989                     return NULL;
4990 
4991             return *(featVocab[i].Typetable);
4992         }
4993     }
4994 
4995     return NULL;
4996 }
4997 
4998 
4999 
5000 
5001 /* @func ajFeatVocabGetTypesProt **********************************************
5002 **
5003 ** Returns types table for a named protein feature format
5004 **
5005 ** @param [r] name [const char*] Feature format name
5006 ** @return [const AjPTable] Type table on success
5007 **                          NULL on failure
5008 **
5009 ** @release 6.4.0
5010 ******************************************************************************/
5011 
ajFeatVocabGetTypesProt(const char * name)5012 const AjPTable ajFeatVocabGetTypesProt(const char* name)
5013 {
5014     ajuint i;
5015 
5016     if(!FeatInitDone)
5017         featInit();
5018 
5019     for(i=0; featVocab[i].Name; i++)
5020     {
5021         if(!featVocab[i].Protein)
5022             continue;
5023 
5024         if(!strcmp(name, featVocab[i].Truename) ||
5025            !strcmp(name, featVocab[i].Name))
5026         {
5027             if(!*(featVocab[i].Typetable))
5028                 if(!featVocabInit(i))
5029                     return NULL;
5030 
5031             return *(featVocab[i].Typetable);
5032         }
5033     }
5034 
5035     return NULL;
5036 }
5037 
5038 
5039 
5040 
5041 /* @func ajFeatVocabInit ******************************************************
5042 **
5043 ** Initialises feature table internals for a named feature format
5044 **
5045 ** @param [r] name [const char*] Feature format name
5046 ** @return [const AjPTable] Type table on success
5047 **                          NULL on failure
5048 **
5049 ** @release 6.4.0
5050 ******************************************************************************/
5051 
ajFeatVocabInit(const char * name)5052 const AjPTable ajFeatVocabInit(const char* name)
5053 {
5054     ajuint i;
5055 
5056     if(!FeatInitDone)
5057         featInit();
5058 
5059     for(i=0; featVocab[i].Name; i++)
5060     {
5061         if(!strcmp(name, featVocab[i].Truename) ||
5062            !strcmp(name, featVocab[i].Name))
5063         {
5064             if(*(featVocab[i].Typetable))
5065                 return *(featVocab[i].Typetable);
5066             else
5067                 return featVocabInit(i);
5068         }
5069     }
5070 
5071     return NULL;
5072 }
5073 
5074 
5075 
5076 
5077 /* @func ajFeatVocabInitNuc ***************************************************
5078 **
5079 ** Initialises feature table internals for a named feature format
5080 **
5081 ** @param [r] name [const char*] Feature format name
5082 ** @return [const AjPTable] Type table on success
5083 **                          NULL on failure
5084 **
5085 ** @release 6.4.0
5086 ******************************************************************************/
5087 
ajFeatVocabInitNuc(const char * name)5088 const AjPTable ajFeatVocabInitNuc(const char* name)
5089 {
5090     ajuint i;
5091 
5092     if(!FeatInitDone)
5093         featInit();
5094 
5095     for(i=0; featVocab[i].Name; i++)
5096     {
5097         if(!featVocab[i].Nucleotide)
5098             continue;
5099 
5100         if(!strcmp(name, featVocab[i].Truename) ||
5101            !strcmp(name, featVocab[i].Name))
5102         {
5103             if(*(featVocab[i].Typetable))
5104                 return *(featVocab[i].Typetable);
5105             else
5106                 return featVocabInit(i);
5107         }
5108     }
5109 
5110     return NULL;
5111 }
5112 
5113 
5114 
5115 
5116 /* @func ajFeatVocabInitProt **************************************************
5117 **
5118 ** Initialises feature table internals for a named feature format
5119 **
5120 ** @param [r] name [const char*] Feature format name
5121 ** @return [const AjPTable] Type table on success
5122 **                          NULL on failure
5123 **
5124 ** @release 6.4.0
5125 ******************************************************************************/
5126 
ajFeatVocabInitProt(const char * name)5127 const AjPTable ajFeatVocabInitProt(const char* name)
5128 {
5129     ajuint i;
5130 
5131     if(!FeatInitDone)
5132         featInit();
5133 
5134     for(i=0; featVocab[i].Name; i++)
5135     {
5136         if(!featVocab[i].Protein)
5137             continue;
5138 
5139         if(!strcmp(name, featVocab[i].Truename) ||
5140            !strcmp(name, featVocab[i].Name))
5141         {
5142             if(*(featVocab[i].Typetable))
5143                 return *(featVocab[i].Typetable);
5144             else
5145                 return featVocabInit(i);
5146         }
5147     }
5148 
5149     return NULL;
5150 }
5151 
5152 
5153 
5154 
5155 /* @funcstatic featVocabInit **************************************************
5156 **
5157 ** Initialises feature table internals for a named feature format
5158 ** and returns the types table
5159 **
5160 ** @param [r] ivocab [ajuint] Vocabulary index
5161 ** @return [const AjPTable] Table if found
5162 **
5163 ** @release 6.4.0
5164 ******************************************************************************/
5165 
featVocabInit(ajuint ivocab)5166 static const AjPTable featVocabInit(ajuint ivocab)
5167 {
5168     const char* name = featVocab[ivocab].Truename;
5169     AjPTable *Ptypetable = featVocab[ivocab].Typetable;
5170     AjPTable *Ptagstable = featVocab[ivocab].Tagstable;
5171 
5172     if(!FeatInitDone)
5173         featInit();
5174 
5175     if(!*Ptypetable)
5176     {
5177 	*Ptypetable = ajTablestrNewCase(200);
5178 	*Ptagstable = ajTablestrNewCase(200);
5179 
5180 	featVocabRead(name, *Ptypetable, *Ptagstable);
5181 
5182         if(!*Ptagstable)
5183             return NULL;
5184 
5185         return *Ptypetable;
5186     }
5187 
5188     return *Ptypetable;
5189 }
5190 
5191 
5192 
5193 
5194 /* @func ajFeatSetDescApp *****************************************************
5195 **
5196 ** Sets the description for a feature
5197 **
5198 ** @param [u] thys [AjPFeature] Feature
5199 ** @param [r] desc [const AjPStr] Feature description (simple text)
5200 ** @return [void]
5201 **
5202 ** @release 2.3.0
5203 ** @@
5204 ******************************************************************************/
5205 
ajFeatSetDescApp(AjPFeature thys,const AjPStr desc)5206 void ajFeatSetDescApp(AjPFeature thys, const AjPStr desc)
5207 {
5208     AjPTagval tv        = NULL;
5209 
5210     if(!featTagNote)
5211 	ajStrAssignC(&featTagNote, "note");
5212 
5213     tv = featTagval(thys, featTagNote);
5214 
5215     if(tv)
5216     {
5217 	ajTagvalAppendC(tv, ", ");
5218 	ajTagvalAppendS(tv, desc);
5219     }
5220     else
5221 	ajFeatTagSet(thys, featTagNote, desc);
5222 
5223     return;
5224 }
5225 
5226 
5227 
5228 
5229 /* @func ajFeatSetDesc ********************************************************
5230 **
5231 ** Sets the description for a feature
5232 **
5233 ** @param [u] thys [AjPFeature] Feature
5234 ** @param [r] desc [const AjPStr] Feature description (simple text)
5235 ** @return [void]
5236 **
5237 ** @release 2.0.0
5238 ** @@
5239 ******************************************************************************/
5240 
ajFeatSetDesc(AjPFeature thys,const AjPStr desc)5241 void ajFeatSetDesc(AjPFeature thys, const AjPStr desc)
5242 {
5243     ajFeatTagSetC(thys, "note", desc);
5244 
5245     return;
5246 }
5247 
5248 
5249 
5250 
5251 /* @func ajFeatSetSource ******************************************************
5252 **
5253 ** Sets the source for a feature
5254 **
5255 ** @param [u] thys [AjPFeature] Feature
5256 ** @param [r] source [const AjPStr] Feature source
5257 ** @return [void]
5258 **
5259 ** @release 6.4.0
5260 ** @@
5261 ******************************************************************************/
5262 
ajFeatSetSource(AjPFeature thys,const AjPStr source)5263 void ajFeatSetSource(AjPFeature thys, const AjPStr source)
5264 {
5265     ajStrAssignS(&thys->Source, source);
5266 
5267     return;
5268 }
5269 
5270 
5271 
5272 
5273 /* @func ajFeatSetScore *******************************************************
5274 **
5275 ** Sets the score for a feature
5276 **
5277 ** @param [u] thys [AjPFeature] Feature
5278 ** @param [r] score [float] Score value
5279 ** @return [void]
5280 **
5281 ** @release 4.0.0
5282 ** @@
5283 ******************************************************************************/
5284 
ajFeatSetScore(AjPFeature thys,float score)5285 void ajFeatSetScore(AjPFeature thys, float score)
5286 {
5287     thys->Score = score;
5288     return;
5289 }
5290 
5291 
5292 
5293 
5294 /* @func ajFeatSetStrand ******************************************************
5295 **
5296 ** Sets the strand for a feature
5297 **
5298 ** @param [u] thys [AjPFeature] Feature
5299 ** @param [r] rev [AjBool] True if reverse strand
5300 ** @return [void]
5301 **
5302 ** @release 4.0.0
5303 ** @@
5304 ******************************************************************************/
5305 
ajFeatSetStrand(AjPFeature thys,AjBool rev)5306 void ajFeatSetStrand(AjPFeature thys, AjBool rev)
5307 {
5308     if(rev)
5309 	thys->Strand = '-';
5310     else
5311 	thys->Strand = '+';
5312 
5313     return;
5314 }
5315 
5316 
5317 
5318 
5319 /* @func ajFeatTagSetC ********************************************************
5320 **
5321 ** Sets a feature tag value
5322 **
5323 ** @param [u] thys [AjPFeature] Feature
5324 ** @param [r] tag [const char*] Feature tag
5325 ** @param [r] value [const AjPStr] Feature tag value
5326 ** @return [AjBool] ajTrue is value was valid
5327 **                  ajFalse if it was "corrected"
5328 **
5329 ** @release 2.0.0
5330 ** @@
5331 ******************************************************************************/
5332 
ajFeatTagSetC(AjPFeature thys,const char * tag,const AjPStr value)5333 AjBool ajFeatTagSetC(AjPFeature thys, const char* tag, const AjPStr value)
5334 {
5335     AjPStr tmptag = NULL;
5336     AjBool ret = ajFalse;
5337 
5338     ajStrAssignC(&tmptag, tag);
5339 
5340     ret = ajFeatTagSet(thys, tmptag, value);
5341     ajStrDel(&tmptag);
5342 
5343     return ret;
5344 }
5345 
5346 
5347 
5348 
5349 /* @func ajFeatTagSet *********************************************************
5350 **
5351 ** Sets a feature tag value
5352 **
5353 ** @param [u] thys [AjPFeature] Feature
5354 ** @param [r] tag [const AjPStr] Feature tag
5355 ** @param [r] value [const AjPStr] Feature tag value
5356 ** @return [AjBool] ajTrue is value was valid
5357 **                  ajFalse if it was "corrected"
5358 **
5359 ** @release 2.0.0
5360 ** @@
5361 ******************************************************************************/
5362 
ajFeatTagSet(AjPFeature thys,const AjPStr tag,const AjPStr value)5363 AjBool ajFeatTagSet(AjPFeature thys, const AjPStr tag, const  AjPStr value)
5364 {
5365     AjBool ret     = ajTrue;
5366     AjPTagval tv = NULL;
5367     AjBool knowntag = ajTrue;
5368 
5369     const AjPStr tmptag        = NULL;		/* this comes from AjPTable */
5370                                            /* so please, please don't delete */
5371     const char* cp;
5372 
5373     ajDebug("ajFeatTagSet '%S' '%S' type: '%S' Prot: %B\n",
5374             tag, value, thys->Type, thys->Protein);
5375 
5376     featInit();
5377 
5378     if(thys->Protein)
5379     {
5380 	tmptag = ajFeattagGetNameS(tag, FeatTagsTableProtein, &knowntag);
5381 	ajFeattagFormat(tmptag,  FeatTagsTableProtein, &featFmtTmp);
5382     }
5383     else
5384     {
5385 	tmptag = ajFeattagGetNameS(tag, FeatTagsTableDna, &knowntag);
5386 	ajFeattagFormat(tmptag,  FeatTagsTableDna, &featFmtTmp);
5387     }
5388 
5389     ajStrAssignS(&featValTmp, value);
5390     ajStrAssignS(&featTagTmp, tmptag);
5391 
5392     cp = ajStrGetPtr(featFmtTmp);
5393 
5394     switch(CASE2(cp[0], cp[1]))
5395     {
5396         case CASE2('L','I') :			/* limited */
5397             /* ajDebug("case limited\n"); */
5398             break;
5399         case CASE2('Q', 'L') :		/* limited, escape quotes */
5400             /* ajDebug("case qlimited\n"); */
5401             break;
5402         case CASE2('Q', 'S') :		/* special regexp, quoted */
5403             /* ajDebug("case qspecial\n"); */
5404             if(!ajFeattagSpecial(tmptag, &featValTmp))
5405             {
5406                 ret = ajFalse;
5407                 featTagSetDefault(thys, tmptag, value, &featTagTmp,
5408                                   &featValTmp);
5409             }
5410             break;
5411         case CASE2('S','P') :	/* special regexp */
5412             /* ajDebug("case special\n"); */
5413             if(!ajFeattagSpecial(tmptag, &featValTmp))
5414             {
5415                 ret = ajFalse;
5416                 featTagSetDefault(thys, tmptag, value, &featTagTmp,
5417                                   &featValTmp);
5418             }
5419             break;
5420         case CASE2('T','E') :	     /* no space, no quotes, wrap at margin */
5421             /* ajDebug("case text\n"); */
5422             break;
5423         case CASE2('V','O') :		      /* no value, so an error here */
5424             /*ajDebug("case void\n");*/
5425             break;
5426         case CASE2('Q','T') :		    /* escape quotes, wrap at space */
5427             /* ajDebug("case qtext\n"); */
5428             break;
5429         case CASE2('Q','W') :		    /* escape quotes, remove space */
5430             /* ajDebug("case qword\n"); */
5431             break;
5432         default:
5433             ajFeatWarn("Unknown internal feature tag type '%S' for '%S'",
5434                      featFmtTmp, tmptag);
5435     }
5436 
5437     tv = featTagval(thys, featTagTmp);
5438 
5439     if(tv)				/* replace current value */
5440     {
5441 	ajTagvalReplaceS(tv, featValTmp);
5442 	return ret;
5443     }
5444 
5445     /* new tag-value */
5446     tv = featTagvalNew(thys, featTagTmp, featValTmp);
5447     ajListPushAppend(thys->Tags, tv);
5448     /* ajDebug("...new tag-value\n"); */
5449 
5450     return ret;
5451 }
5452 
5453 
5454 
5455 
5456 /* @func ajFeattagSpecialGff2 *************************************************
5457 **
5458 ** Special processing for known GFF tags
5459 **
5460 ** This function will be very similar to featTagSpecial, with scope
5461 ** for future GFF-specific extensions
5462 **
5463 ** @param  [r] tag [const AjPStr] original tag name
5464 ** @param  [u] pval [AjPStr*] tag value
5465 ** @return [AjBool] ajTrue on success
5466 **
5467 ** @release 6.4.0
5468 ** @@
5469 ******************************************************************************/
5470 
ajFeattagSpecialGff2(const AjPStr tag,AjPStr * pval)5471 AjBool ajFeattagSpecialGff2(const AjPStr tag, AjPStr* pval)
5472 {
5473     /*ajDebug("ajFeattagSpecialGff2 '%S' '%S'\n", tag, *pval);*/
5474 
5475     if(ajStrMatchC(tag, "anticodon"))
5476 	return featTagSpecialAllAnticodon(*pval);
5477 
5478     else if(ajStrMatchC(tag, "bio_material") ||
5479             ajStrMatchC(tag, "culture_collection") ||
5480             ajStrMatchC(tag, "specimen_voucher"))
5481 	return featTagSpecialAllBiomaterial(*pval);
5482 
5483     else if(ajStrMatchC(tag, "citation"))
5484 	return featTagSpecialAllCitation(*pval);
5485 
5486     else if(ajStrMatchC(tag, "codon"))
5487 	return featTagSpecialAllCodon(pval);
5488 
5489     else if(ajStrMatchC(tag, "collection_date"))
5490 	return featTagSpecialAllCollectiondate(*pval);
5491 
5492     else if(ajStrMatchC(tag, "compare"))
5493 	return featTagSpecialAllCompare(*pval);
5494 
5495     else if(ajStrMatchC(tag, "cons_splice"))
5496 	return featTagSpecialAllConssplice(pval);
5497 
5498     else if(ajStrMatchC(tag, "db_xref"))
5499 	return featTagSpecialAllDbxref(*pval);
5500 
5501     else if(ajStrMatchC(tag, "estimated_length"))
5502 	return featTagSpecialAllEstimatedlength(pval);
5503 
5504      else if(ajStrMatchC(tag, "inference"))
5505 	return featTagSpecialAllInference(*pval);
5506 
5507     else if(ajStrMatchC(tag, "lat_lon"))
5508 	return featTagSpecialAllLatlon(*pval);
5509 
5510     else if(ajStrMatchC(tag, "mobile_element"))
5511 	return featTagSpecialAllMobile(*pval);
5512 
5513     else if(ajStrMatchC(tag, "PCR_primers"))
5514 	return featTagSpecialAllPcrprimers(*pval);
5515 
5516     else if(ajStrMatchC(tag, "protein_id"))
5517 	return featTagSpecialAllProteinid(*pval);
5518 
5519     else if(ajStrMatchC(tag, "replace"))
5520 	return featTagSpecialAllReplace(pval);
5521 
5522     else if(ajStrMatchC(tag, "rpt_unit"))
5523 	return featTagSpecialAllRptunit(*pval);
5524 
5525     else if(ajStrMatchC(tag, "rpt_unit_range") ||
5526             ajStrMatchC(tag, "tag_peptide"))
5527 	return featTagSpecialAllRange(*pval);
5528 
5529     else if(ajStrMatchC(tag, "rpt_unit_seq"))
5530 	return featTagSpecialAllRptunitseq(pval);
5531 
5532     else if(ajStrMatchC(tag, "transl_except"))
5533 	return featTagSpecialAllTranslexcept(*pval);
5534 
5535     else if(ajStrMatchC(tag, "translation"))
5536 	return featTagSpecialAllTranslation(pval);
5537 
5538     /*ajDebug("Unrecognised special GFF feature tag '%S'\n", tag);*/
5539     ajFeatWarn("Unrecognised special GFF feature tag '%S'",   tag);
5540 
5541     return ajFalse;
5542 }
5543 
5544 
5545 
5546 
5547 /* @funcstatic featTagGff3PredefinedTag ***************************************
5548 **
5549 ** Checks whether the specified tag is one of GFF3 tags
5550 ** that have predefined meanings
5551 **
5552 ** @param  [r] tag [const AjPStr] tag name
5553 ** @return [AjBool] ajTrue on success
5554 **
5555 ** @release 6.4.0
5556 ** @@
5557 ******************************************************************************/
5558 
featTagGff3PredefinedTag(const AjPStr tag)5559 static AjBool featTagGff3PredefinedTag(const AjPStr tag)
5560 {
5561     const char* tags[] = {"ID", "Name", "Alias", "Parent", "Target", "Gap",
5562                           "Derives_from", "Note", "Dbxref",
5563                           "Ontology_term", "Is_circular", NULL};
5564     int i=0;
5565 
5566     while(tags[i])
5567 	if(ajStrMatchC(tag, tags[i++]))
5568 	    return ajTrue;
5569 
5570     return ajFalse;
5571 }
5572 
5573 
5574 
5575 
5576 /* @func ajFeattagSpecialGff3 *************************************************
5577 **
5578 ** Special processing for known GFF3 tags
5579 **
5580 ** This function will be very similar to featTagSpecial, with scope
5581 ** for future GFF3-specific extensions
5582 **
5583 ** @param  [r] tag [const AjPStr] original tag name
5584 ** @param  [u] pval [AjPStr*] tag value
5585 ** @return [AjBool] ajTrue on success
5586 **
5587 ** @release 6.4.0
5588 ** @@
5589 ******************************************************************************/
5590 
ajFeattagSpecialGff3(const AjPStr tag,AjPStr * pval)5591 AjBool ajFeattagSpecialGff3(const AjPStr tag, AjPStr* pval)
5592 {
5593     /*ajDebug("featTagGff3Special '%S' '%S'\n", tag, *pval);*/
5594 
5595     if(ajStrMatchC(tag, "anticodon"))
5596 	return featTagSpecialAllAnticodon(*pval);
5597 
5598     else if(ajStrMatchC(tag, "bio_material") ||
5599             ajStrMatchC(tag, "culture_collection") ||
5600             ajStrMatchC(tag, "specimen_voucher"))
5601 	return featTagSpecialAllBiomaterial(*pval);
5602 
5603     else if(ajStrMatchC(tag, "citation"))
5604 	return featTagSpecialAllCitation(*pval);
5605 
5606     else if(ajStrMatchC(tag, "codon"))
5607 	return featTagSpecialAllCodon(pval);
5608 
5609     else if(ajStrMatchC(tag, "collection_date"))
5610 	return featTagSpecialAllCollectiondate(*pval);
5611 
5612     else if(ajStrMatchC(tag, "compare"))
5613 	return featTagSpecialAllCompare(*pval);
5614 
5615     else if(ajStrMatchC(tag, "cons_splice"))
5616 	return featTagSpecialAllConssplice(pval);
5617 
5618     else if(ajStrMatchC(tag, "db_xref"))
5619 	return featTagSpecialAllDbxref(*pval);
5620 
5621     else if(ajStrMatchC(tag, "estimated_length"))
5622 	return featTagSpecialAllEstimatedlength(pval);
5623 
5624     else if(ajStrMatchC(tag, "inference"))
5625 	return featTagSpecialAllInference(*pval);
5626 
5627     else if(ajStrMatchC(tag, "lat_lon"))
5628 	return featTagSpecialAllLatlon(*pval);
5629 
5630     else if(ajStrMatchC(tag, "mobile_element"))
5631 	return featTagSpecialAllMobile(*pval);
5632 
5633     else if(ajStrMatchC(tag, "ncRNA_class"))
5634 	return featTagSpecialAllNcrnaclass(*pval);
5635 
5636     else if(ajStrMatchC(tag, "PCR_primers"))
5637 	return featTagSpecialAllPcrprimers(*pval);
5638 
5639     else if(ajStrMatchC(tag, "protein_id"))
5640 	return featTagSpecialAllProteinid(*pval);
5641 
5642     else if(ajStrMatchC(tag, "replace"))
5643 	return featTagSpecialAllReplace(pval);
5644 
5645     else if(ajStrMatchC(tag, "rpt_unit"))
5646 	return featTagSpecialAllRptunit(*pval);
5647 
5648     else if(ajStrMatchC(tag, "rpt_unit_range") ||
5649             ajStrMatchC(tag, "tag_peptide"))
5650 	return featTagSpecialAllRange(*pval);
5651 
5652     else if(ajStrMatchC(tag, "rpt_unit_seq"))
5653 	return featTagSpecialAllRptunitseq(pval);
5654 
5655     else if(ajStrMatchC(tag, "transl_except"))
5656 	return featTagSpecialAllTranslexcept(*pval);
5657 
5658     else if(ajStrMatchC(tag, "translation"))
5659 	return featTagSpecialAllTranslation(pval);
5660 
5661     /*ajDebug("Unrecognised special GFF feature tag '%S'\n", tag);*/
5662     ajFeatWarn("Unrecognised special GFF feature tag '%S'",   tag);
5663 
5664     return ajFalse;
5665 }
5666 
5667 
5668 
5669 
5670 /* @func ajFeatTagAddCC *******************************************************
5671 **
5672 ** Sets a feature tag value, creating a new feature tag even if one
5673 ** already exists.
5674 **
5675 ** @param [u] thys [AjPFeature] Feature
5676 ** @param [r] tag [const char*] Feature tag
5677 ** @param [r] value [const char*] Feature tag value
5678 ** @return [AjBool] ajTrue if value was valid
5679 **                  ajFalse if it was bad and was "corrected"
5680 **
5681 ** @release 2.4.0
5682 ** @@
5683 ******************************************************************************/
5684 
ajFeatTagAddCC(AjPFeature thys,const char * tag,const char * value)5685 AjBool ajFeatTagAddCC(AjPFeature thys, const char* tag, const char* value)
5686 {
5687     AjBool ret;
5688     AjPStr tagstr = NULL;
5689     AjPStr valstr = NULL;
5690 
5691     ajStrAssignC(&tagstr, tag);
5692     ajStrAssignC(&valstr, value);
5693 
5694     ret = ajFeatTagAddSS(thys, tagstr, valstr);
5695     ajStrDel(&tagstr);
5696     ajStrDel(&valstr);
5697 
5698     return ret;
5699 }
5700 
5701 
5702 
5703 
5704 /* @func ajFeatTagAddCS *******************************************************
5705 **
5706 ** Sets a feature tag value, creating a new feature tag even if one
5707 ** already exists.
5708 **
5709 ** @param [u] thys [AjPFeature] Feature
5710 ** @param [r] tag [const char*] Feature tag
5711 ** @param [r] value [const AjPStr] Feature tag value
5712 ** @return [AjBool] ajTrue if value was valid
5713 **                  ajFalse if it was bad and was "corrected"
5714 **
5715 ** @release 2.4.0
5716 ** @@
5717 ******************************************************************************/
5718 
ajFeatTagAddCS(AjPFeature thys,const char * tag,const AjPStr value)5719 AjBool  ajFeatTagAddCS(AjPFeature thys, const char* tag, const AjPStr value)
5720 {
5721     AjBool ret;
5722     static AjPStr tagstr = NULL;
5723 
5724     ajStrAssignC(&tagstr, tag);
5725 
5726     ret = ajFeatTagAddSS(thys, tagstr, value);
5727 
5728     ajStrDel(&tagstr);
5729 
5730     return ret;
5731 }
5732 
5733 
5734 
5735 
5736 /* @func ajFeatTagAddSS *******************************************************
5737 **
5738 ** Sets a feature tag value, creating a new feature tag even if one
5739 ** already exists.
5740 **
5741 ** @param [u] thys [AjPFeature] Feature
5742 ** @param [r] tag [const AjPStr] Feature tag
5743 ** @param [r] value [const AjPStr] Feature tag value
5744 ** @return [AjBool] ajTrue if value was valid
5745 **                  ajFalse if it was bad and was "corrected"
5746 **
5747 ** @release 2.0.0
5748 ** @@
5749 ******************************************************************************/
5750 
ajFeatTagAddSS(AjPFeature thys,const AjPStr tag,const AjPStr value)5751 AjBool ajFeatTagAddSS(AjPFeature thys, const AjPStr tag, const AjPStr value)
5752 {
5753     AjBool ret     = ajTrue;
5754     AjPTagval tv = NULL;
5755     const AjPStr tmptag  = NULL;		/* this comes from AjPTable */
5756                                        /* so please, please don't delete */
5757     AjBool knowntag = ajTrue;
5758     const char* cp;
5759 
5760 #if FEATDEBUG
5761     ajDebug("ajFeatTagAddSS '%S' '%S' type: '%S' Prot: %B\n",
5762 	    tag, value, thys->Type, thys->Protein);
5763 #endif
5764 
5765     featInit();
5766 
5767     if(thys->Protein)
5768     {
5769 	tmptag = ajFeattagGetNameS(tag, FeatTagsTableProtein, &knowntag);
5770 	ajFeattagFormat(tmptag,  FeatTagsTableProtein, &featFmtTmp);
5771     }
5772     else
5773     {
5774 	tmptag = ajFeattagGetNameS(tag, FeatTagsTableDna, &knowntag);
5775 	ajFeattagFormat(tmptag, FeatTagsTableDna, &featFmtTmp);
5776     }
5777 
5778 #if FEATDEBUG
5779     ajDebug("tag: '%S' format: '%S'\n", tmptag, featFmtTmp);
5780 #endif
5781 
5782     ajStrAssignS(&featValTmp2, value);
5783     ajStrAssignS(&featTagTmp2, tmptag);
5784 
5785     cp = ajStrGetPtr(featFmtTmp);
5786 
5787     switch(CASE2(cp[0], cp[1]))
5788     {
5789         case CASE2('L','I') :			/* limited */
5790             /* ajDebug("case limited\n"); */
5791             break;
5792         case CASE2('Q', 'L') :		/* limited, escape quotes */
5793             /* ajDebug("case qlimited\n"); */
5794             break;
5795         case CASE2('Q', 'S') :		/* special regexp, quoted */
5796             /* ajDebug("case qspecial\n"); */
5797             if(!ajFeattagSpecial(tmptag, &featValTmp2))
5798             {
5799                 ret = ajFalse;
5800                 featTagSetDefault(thys, tmptag, value, &featTagTmp2,
5801                                   &featValTmp2);
5802             }
5803             break;
5804         case CASE2('S','P') :			/* special regexp */
5805             /* ajDebug("case special\n");*/
5806             if(!ajFeattagSpecial(tmptag, &featValTmp2))
5807             {
5808                 ret = ajFalse;
5809                 featTagSetDefault(thys, tmptag, value, &featTagTmp2,
5810                                   &featValTmp2);
5811             }
5812             break;
5813         case CASE2('T','E') :	     /* no space, no quotes, wrap at margin */
5814             /* ajDebug("case text\n"); */
5815             break;
5816         case CASE2('V','O') :		      /* no value, so an error here */
5817             /* ajDebug("case void\n"); */
5818             break;
5819         case CASE2('Q','T') :		    /* escape quotes, wrap at space */
5820             /* ajDebug("case qtext\n"); */
5821             if(!knowntag && tag)
5822                 ajFmtPrintS(&featValTmp2, "*%S: %S", tag, value);
5823             /*ajDebug("ajFeatTagAdd qtext knowntag %B tag '%S' Tmp '%S' '%S'\n",
5824               knowntag, tag, featTagTmp2, featValTmp2);*/
5825             break;
5826         case CASE2('Q','W') :		    /* escape quotes, remove space */
5827             /* ajDebug("case qword\n"); */
5828             break;
5829         default:
5830             ajFeatWarn("Unknown internal feature tag type '%S' for '%S'",
5831                      featFmtTmp, tmptag);
5832     }
5833 
5834     tv = featTagvalNew(thys, featTagTmp2, featValTmp2);
5835 
5836     ajListPushAppend(thys->Tags, tv);
5837     /* ajDebug("...new tag-value\n"); */
5838 
5839     return ret;
5840 }
5841 
5842 
5843 
5844 
5845 /* @func ajFeatTagAddTag ******************************************************
5846 **
5847 ** Sets a feature tag value, creating a new feature tag even if one
5848 ** already exists.
5849 **
5850 ** @param [u] thys [AjPFeature] Feature
5851 ** @param [r] tagval [const AjPTagval] Tag value pair
5852 ** @return [AjBool] ajTrue if value was valid
5853 **                  ajFalse if it was bad and was "corrected"
5854 **
5855 ** @release 6.5.0
5856 ** @@
5857 ******************************************************************************/
5858 
ajFeatTagAddTag(AjPFeature thys,const AjPTagval tagval)5859 AjBool ajFeatTagAddTag(AjPFeature thys, const AjPTagval tagval)
5860 {
5861     return ajFeatTagAddSS(thys,
5862                           MAJTAGVALGETTAG(tagval),
5863                           MAJTAGVALGETVALUE(tagval));
5864 }
5865 
5866 
5867 
5868 
5869 /* @func ajFeattagSpecial *****************************************************
5870 **
5871 ** Special processing for known internal (EMBL) tags
5872 **
5873 ** @param  [r] tag [const AjPStr] original tag name
5874 ** @param  [u] pval [AjPStr*] parameter value
5875 ** @return [AjBool] ajTrue on success
5876 **
5877 ** @release 6.4.0
5878 ** @@
5879 ******************************************************************************/
5880 
ajFeattagSpecial(const AjPStr tag,AjPStr * pval)5881 AjBool ajFeattagSpecial(const AjPStr tag, AjPStr* pval)
5882 {
5883     /*ajDebug("featTagSpecial '%S'\n", tag);*/
5884 
5885     if(ajStrMatchC(tag, "anticodon"))
5886 	return featTagSpecialAllAnticodon(*pval);
5887 
5888     else if(ajStrMatchC(tag, "bio_material") ||
5889             ajStrMatchC(tag, "culture_collection") ||
5890             ajStrMatchC(tag, "specimen_voucher"))
5891 	return featTagSpecialAllBiomaterial(*pval);
5892 
5893     else if(ajStrMatchC(tag, "citation"))
5894 	return featTagSpecialAllCitation(*pval);
5895 
5896     else if(ajStrMatchC(tag, "codon"))
5897 	return featTagSpecialAllCodon(pval);
5898 
5899     else if(ajStrMatchC(tag, "collection_date"))
5900 	return featTagSpecialAllCollectiondate(*pval);
5901 
5902     else if(ajStrMatchC(tag, "compare"))
5903 	return featTagSpecialAllCompare(*pval);
5904 
5905     else if(ajStrMatchC(tag, "cons_splice"))
5906 	return featTagSpecialAllConssplice(pval);
5907 
5908     else if(ajStrMatchC(tag, "db_xref"))
5909 	return featTagSpecialAllDbxref(*pval);
5910 
5911     else if(ajStrMatchC(tag, "estimated_length"))
5912 	return featTagSpecialAllEstimatedlength(pval);
5913 
5914     else if(ajStrMatchC(tag, "inference"))
5915 	return featTagSpecialAllInference(*pval);
5916 
5917     else if(ajStrMatchC(tag, "lat_lon"))
5918 	return featTagSpecialAllLatlon(*pval);
5919 
5920     else if(ajStrMatchC(tag, "mobile_element"))
5921 	return featTagSpecialAllMobile(*pval);
5922 
5923     else if(ajStrMatchC(tag, "ncRNA_class"))
5924 	return featTagSpecialAllNcrnaclass(*pval);
5925 
5926     else if(ajStrMatchC(tag, "PCR_primers"))
5927 	return featTagSpecialAllPcrprimers(*pval);
5928 
5929     else if(ajStrMatchC(tag, "protein_id"))
5930 	return featTagSpecialAllProteinid(*pval);
5931 
5932     else if(ajStrMatchC(tag, "replace"))
5933 	return featTagSpecialAllReplace(pval);
5934 
5935     else if(ajStrMatchC(tag, "rpt_unit"))
5936 	return featTagSpecialAllRptunit(*pval);
5937 
5938     else if(ajStrMatchC(tag, "rpt_unit_range") ||
5939             ajStrMatchC(tag, "tag_peptide"))
5940 	return featTagSpecialAllRange(*pval);
5941 
5942     else if(ajStrMatchC(tag, "rpt_unit_seq"))
5943 	return featTagSpecialAllRptunitseq(pval);
5944 
5945     else if(ajStrMatchC(tag, "transl_except"))
5946 	return featTagSpecialAllTranslexcept(*pval);
5947 
5948     else if(ajStrMatchC(tag, "translation"))
5949 	return featTagSpecialAllTranslation(pval);
5950 
5951     /*ajDebug("Unrecognised special EMBL feature tag '%S'\n", tag);*/
5952     ajFeatWarn("Unrecognised special EMBL feature tag '%S'",   tag);
5953 
5954     return ajFalse;
5955 }
5956 
5957 
5958 
5959 
5960 /* @funcstatic featTagSpecialAllBiomaterial ***********************************
5961 **
5962 ** Tests a string as a valid internal (EMBL) feature /bio_material tag
5963 **
5964 ** The format is a known type and optional :name
5965 **
5966 ** @param  [r] val [const AjPStr] parameter value
5967 ** @return [AjBool] ajTrue for a valid value, possibly corrected
5968 **                  ajFalse if invalid, to be converted to default (note) type
5969 **
5970 ** @release 6.1.0
5971 ** @@
5972 ******************************************************************************/
5973 
featTagSpecialAllBiomaterial(const AjPStr val)5974 static AjBool featTagSpecialAllBiomaterial(const AjPStr val)
5975 {
5976     AjPStr inststr = NULL;
5977     AjPStr collstr = NULL;
5978     AjPStr idstr = NULL;
5979     AjBool ret = ajFalse;
5980 
5981     if(!featRegSpecialBiomaterial)
5982 	featRegSpecialBiomaterial = ajRegCompC("^([^:]+)(:([^:]+))?(:(.*))?$");
5983 
5984     if(ajRegExec(featRegSpecialBiomaterial, val))
5985     {
5986 	ajRegSubI(featRegSpecialBiomaterial, 1, &inststr);
5987 	ajRegSubI(featRegSpecialBiomaterial, 3, &collstr);
5988 	ajRegSubI(featRegSpecialBiomaterial, 5, &idstr);
5989         ret = ajTrue;
5990     }
5991 
5992     if(!ret)
5993     {
5994 	ajFeatWarn("bad /bio_material value '%S'", val);
5995     }
5996 
5997     ajStrDel(&inststr);
5998     ajStrDel(&collstr);
5999     ajStrDel(&idstr);
6000 
6001     return ret;
6002 }
6003 
6004 
6005 
6006 
6007 /* @funcstatic featTagSpecialAllAnticodon *************************************
6008 **
6009 ** Tests a string as a valid internal (EMBL) feature /anticodon tag
6010 **
6011 ** The format is  (pos:base_range,aa:amino_acid)
6012 **
6013 ** @param  [r] val [const AjPStr] parameter value
6014 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6015 **                  ajFalse if invalid, to be converted to default (note) type
6016 **
6017 ** @release 2.0.0
6018 ** @@
6019 ******************************************************************************/
6020 
featTagSpecialAllAnticodon(const AjPStr val)6021 static AjBool featTagSpecialAllAnticodon(const AjPStr val)
6022 {
6023     /*
6024        static AjPStr begstr = NULL;
6025        static AjPStr endstr = NULL;
6026        static AjPStr aastr  = NULL;
6027        AjBool saveit = ajFalse;
6028     */
6029     AjBool ret = ajFalse;
6030 
6031     if(!featRegSpecialAnticodon)
6032 	featRegSpecialAnticodon =
6033 	    ajRegCompC("^[(]pos:([0-9]+)[.][.]([0-9]+),aa:([^)]+)[)]$");
6034 
6035     if(ajRegExec(featRegSpecialAnticodon, val))
6036     {
6037 	ret = ajTrue;
6038 	/*
6039 	if(saveit)
6040 	{
6041 	    ajRegSubI(featRegSpecialAnticodon, 1, &begstr);
6042 	    ajRegSubI(featRegSpecialAnticodon, 2, &endstr);
6043 	    ajRegSubI(featRegSpecialAnticodon, 3, &aastr);
6044 	}
6045 	*/
6046 
6047     }
6048 
6049     if(!ret)
6050     {
6051 	ajFeatWarn("bad /anticodon value '%S'",   val);
6052     }
6053 
6054     return ret;
6055 }
6056 
6057 
6058 
6059 
6060 /* @funcstatic featTagSpecialAllCitation **************************************
6061 **
6062 ** Tests a string as a valid internal (EMBL) feature /citation tag
6063 **
6064 ** The format is [1] where the number is a citation in an EMBL entry.
6065 **
6066 ** @param  [r] val [const AjPStr] parameter value
6067 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6068 **                  ajFalse if invalid, to be converted to default (note) type
6069 **
6070 ** @release 2.0.0
6071 ** @@
6072 ******************************************************************************/
6073 
featTagSpecialAllCitation(const AjPStr val)6074 static AjBool featTagSpecialAllCitation(const AjPStr val)
6075 {
6076     const char* cp = ajStrGetPtr(val);
6077     ajint i = 0;
6078     AjBool ret = ajFalse;
6079 
6080     if(*cp++ == '[')
6081     {
6082 	while(*cp)
6083 	{
6084 	    if(!isdigit((ajint)*cp))
6085 	       break;
6086 
6087 	    i++;
6088 	    cp++;
6089 	}
6090 
6091 	if(*cp++ == ']')
6092 	    if(!*cp)
6093 		ret = ajTrue;
6094 	if(!i)
6095 	    ret = ajFalse;
6096     }
6097 
6098     if(!ret)
6099     {
6100 	ajFeatWarn("bad /citation value '%S'",   val);
6101     }
6102 
6103     return ret;
6104 }
6105 
6106 
6107 
6108 
6109 /* @funcstatic featTagSpecialAllCodon *****************************************
6110 **
6111 ** Tests a string as a valid internal (EMBL) feature /codon tag
6112 **
6113 ** The format is (seq:"ttt",aa:Leu)
6114 **
6115 ** Corrects missing quotes
6116 **
6117 ** @param  [u] pval [AjPStr*] parameter value
6118 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6119 **                  ajFalse if invalid, to be converted to default (note) type
6120 **
6121 ** @release 2.0.0
6122 ** @@
6123 ******************************************************************************/
6124 
featTagSpecialAllCodon(AjPStr * pval)6125 static AjBool featTagSpecialAllCodon(AjPStr* pval)
6126 {
6127     AjPStr seqstr = NULL;
6128     AjPStr aastr  = NULL;
6129     AjBool saveit = ajFalse;
6130     AjBool ret = ajFalse;
6131 
6132     if(!featRegSpecialCodon)
6133 	featRegSpecialCodon =
6134 	    ajRegCompC("^[(]seq:\"([acgt][acgt][acgt])\",aa:([^)]+)[)]$");
6135 
6136     if(!featRegSpecialCodonBad)	/* sometimes fails to quote sequence */
6137 	featRegSpecialCodonBad =
6138 	    ajRegCompC("^[(]seq:([acgt][acgt][acgt]),aa:([^)]+)[)]$");
6139 
6140     if(ajRegExec(featRegSpecialCodon, *pval))
6141     {
6142 	ret = ajTrue;
6143 
6144 	if(saveit)
6145 	{
6146 	    ajRegSubI(featRegSpecialCodon, 1, &seqstr);
6147 	    ajRegSubI(featRegSpecialCodon, 2, &aastr);
6148 	}
6149     }
6150 
6151     else if(ajRegExec(featRegSpecialCodonBad, *pval))
6152     {
6153 	ret = ajTrue;
6154 	ajRegSubI(featRegSpecialCodonBad, 1, &seqstr);	/* needed correction */
6155 	ajRegSubI(featRegSpecialCodonBad, 2, &aastr);
6156 	ajFmtPrintS(pval, "(seq:\"%S\",aa:%S)",seqstr, aastr);
6157 	ajFeatWarn("unquoted /codon value corrected to '%S'", *pval);
6158     }
6159 
6160     if(!ret)
6161     {
6162 	ajFeatWarn("bad /codon value '%S'",   *pval);
6163     }
6164 
6165     ajStrDel(&seqstr);
6166     ajStrDel(&aastr);
6167 
6168     return ret;
6169 }
6170 
6171 
6172 
6173 
6174 /* @funcstatic featTagSpecialAllCollectiondate ********************************
6175 **
6176 ** Tests a string as a valid internal (EMBL) feature /collection_date tag
6177 **
6178 ** The format is YYYY Mmm-YYYY or DD-Mmm-YYYY
6179 **
6180 ** @param  [r] val [const AjPStr] parameter value
6181 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6182 **                  ajFalse if invalid, to be converted to default (note) type
6183 **
6184 ** @release 4.0.0
6185 ** @@
6186 ******************************************************************************/
6187 
featTagSpecialAllCollectiondate(const AjPStr val)6188 static AjBool featTagSpecialAllCollectiondate(const AjPStr val)
6189 {
6190     AjPStr daystr = NULL;
6191     AjPStr monstr  = NULL;
6192     ajint day;
6193     ajint i;
6194     AjBool ret = ajFalse;
6195     AjBool ok;
6196     const char* months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6197 			    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
6198 
6199     if(!featRegSpecialColdate)
6200 	featRegSpecialColdate =
6201 	    ajRegCompC("^((\\d\\d)[-])?(([ADFJMNOS][A-Za-z][A-Za-z])[-])?([12]"
6202                        "[7890]\\d\\d)$");
6203 
6204     if(ajRegExec(featRegSpecialColdate, val))
6205     {
6206 	ret = ajTrue;
6207 	ajRegSubI(featRegSpecialColdate, 2, &daystr);
6208 	ajRegSubI(featRegSpecialColdate, 4, &monstr);
6209 
6210 	if(ajStrGetLen(daystr))
6211 	{
6212 	    if(!ajStrGetLen(monstr))
6213 		ret = ajFalse;
6214 
6215 	    ajStrToInt(daystr, &day);
6216 
6217 	    if(day<1 || day > 31)
6218 		ret = ajFalse;
6219 	}
6220 
6221 	if(ajStrGetLen(monstr))
6222 	{
6223 	    ok = ajFalse;
6224 
6225 	    for(i=0;i<12;i++)
6226 		if(ajStrMatchCaseC(monstr, months[i]))
6227 		{
6228 		    ok = ajTrue;
6229 		    break;
6230 		}
6231 
6232 	    if(!ok)
6233                 ret = ajFalse;
6234 	}
6235     }
6236 
6237     if(!ret)
6238 	ajFeatWarn("bad /collection_date value '%S'", val);
6239 
6240     ajStrDel(&daystr);
6241     ajStrDel(&monstr);
6242 
6243     return ret;
6244 }
6245 
6246 
6247 
6248 
6249 /* @funcstatic featTagSpecialAllConssplice ************************************
6250 **
6251 ** Tests a string as a valid internal (EMBL) feature /cons_splice tag
6252 **
6253 ** The format is (5'site:YES,3'site:NO) where the booleans can
6254 ** be YES, NO, or ABSENT (intended for use where one site is NO and
6255 ** the other is missing)
6256 **
6257 ** Corrects missing parts of the value and bad case.
6258 **
6259 ** @param  [u] pval [AjPStr*] parameter value
6260 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6261 **                  ajFalse if invalid, to be converted to default (note) type
6262 **
6263 ** @release 2.0.0
6264 ** @@
6265 ******************************************************************************/
6266 
featTagSpecialAllConssplice(AjPStr * pval)6267 static AjBool featTagSpecialAllConssplice(AjPStr* pval)
6268 {
6269     AjPStr begstr = NULL;
6270     AjPStr endstr = NULL;
6271     const char* cp;
6272     const char* cq;
6273     ajint i;
6274     AjBool islow = ajFalse;
6275     AjBool ret = ajFalse;
6276 
6277     if(!featRegSpecialConssplice)
6278 	featRegSpecialConssplice =
6279 	    ajRegCompC("^[(]5'site:([A-Za-z]+),3'site:([A-Za-z]+)[)]$");
6280 
6281 
6282     if(ajStrPrefixC(*pval, "(5'site:") && ajStrGetCharLast(*pval) == ')')
6283     {
6284 	cp = ajStrGetPtr(*pval);
6285 	cp += 8;
6286 	cq = cp;
6287 	i=0;
6288 
6289 	while(*cp && (*cp != ','))
6290 	{
6291 	    if(islower((ajint)*cp++))
6292 		islow = ajTrue;
6293 
6294 	    i++;
6295 	}
6296 
6297 	ajStrAssignLenC(&begstr, cq, i);
6298 
6299 	if(ajCharPrefixC(cp, ",3'site:"))
6300 	{
6301 	    cp += 8;
6302 	    cq = cp;
6303 	    i=0;
6304 
6305 	    while(*cp && (*cp != ')'))
6306 	    {
6307 		if(islower((ajint)*cp++))
6308 		    islow = ajTrue;
6309 
6310 		i++;
6311 	    }
6312 	    ajStrAssignLenC(&endstr, cq, i);
6313 
6314 	    if(*cp == ')' && !*(cp+1) &&
6315 	       ajStrGetLen(begstr) && ajStrGetLen(endstr))
6316 		ret = ajTrue;
6317 
6318 	    switch(ajStrGetCharFirst(begstr))
6319 	    {
6320                 case 'Y':
6321                     if(!ajStrMatchCaseC(begstr, "yes"))
6322                         ret = ajFalse;
6323 
6324                     break;
6325                 case 'N':
6326                     if(!ajStrMatchCaseC(begstr, "no"))
6327                         ret = ajFalse;
6328 
6329                     break;
6330                 case 'A':
6331                     if(!ajStrMatchCaseC(begstr, "absent"))
6332                         ret = ajFalse;
6333 
6334                     break;
6335                 default:
6336                     ret = ajFalse;
6337 	    }
6338 
6339 	    switch(ajStrGetCharFirst(endstr))
6340 	    {
6341                 case 'Y':
6342                     if(!ajStrMatchCaseC(endstr, "yes"))
6343                         ret = ajFalse;
6344 
6345                     break;
6346                 case 'N':
6347                     if(!ajStrMatchCaseC(endstr, "no"))
6348                         ret = ajFalse;
6349 
6350                     break;
6351                 case 'A':
6352                     if(!ajStrMatchCaseC(endstr, "absent"))
6353                         ret = ajFalse;
6354 
6355                     break;
6356                 default:
6357                     ret = ajFalse;
6358 	    }
6359 	}
6360     }
6361 
6362     if(!ret)
6363     {
6364 	ajFeatWarn("bad /cons_splice value '%S'",   *pval);
6365 	ajDebug("bad /cons_splice value '%S' beg: '%S' end: '%S'",
6366 		*pval, begstr, endstr);
6367     }
6368 
6369     if(islow)
6370     {
6371 	ajFmtPrintS(pval, "(5'site:%S,3'site:%S)", begstr, endstr);
6372 	ajFeatWarn("bad /cons_splice value corrected to '%S'", *pval);
6373     }
6374 
6375     ajStrDel(&begstr);
6376     ajStrDel(&endstr);
6377 
6378     return ret;
6379 }
6380 
6381 
6382 
6383 
6384 /* @funcstatic featTagSpecialAllInference *************************************
6385 **
6386 ** Tests a string as a valid internal (EMBL) feature /inference tag
6387 **
6388 ** The format is TYPE:EVIDENCE_BASIS
6389 ** where TYPE is a list of defined values with optionally " (same species)"
6390 ** and EVIDENCE is dbname:accesion.version of algorithm:version
6391 **
6392 ** @param  [r] val [const AjPStr] parameter value
6393 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6394 **                  ajFalse if invalid, to be converted to default (note) type
6395 **
6396 ** @release 4.0.0
6397 ** @@
6398 ******************************************************************************/
6399 
featTagSpecialAllInference(const AjPStr val)6400 static AjBool featTagSpecialAllInference(const AjPStr val)
6401 {
6402     AjPStr typstr = NULL;
6403     ajint i;
6404     AjBool ret = ajFalse;
6405     AjBool ok;
6406     const char* types[] =
6407     {
6408 	"non-experimental evidence, no additional details recorded",
6409 	"similar to sequence",
6410 	"similar to AA sequence",
6411 	"similar to AA sequence sequence", /* found in EMBL 104 */
6412 	"similar to DNA sequence",
6413 	"similar to RNA sequence",
6414 	"similar to RNA sequence, mRNA",
6415 	"similar to RNA sequence,mRNA", /* nonstandard, found in EMBL 104 */
6416 	"similar to RNA sequence, EST",
6417 	"similar to RNA sequence, other RNA",
6418 	"profile",
6419 	"nucleotide motif",
6420 	"protein motif",
6421 	"ab initio prediction",
6422         "alignment",
6423 	NULL
6424     };
6425 
6426     if(!featRegSpecialInference)
6427 	featRegSpecialInference = ajRegCompC("^([^:]+)(:([^:]+)?)*$");
6428 
6429     if(ajRegExec(featRegSpecialInference, val))
6430     {
6431 	ret = ajTrue;
6432 	ajRegSubI(featRegSpecialInference, 1, &typstr);
6433 
6434 	ok = ajFalse;
6435 	for(i=0; types[i]; i++)
6436 	{
6437 	    if(ajStrPrefixC(typstr, types[i]))
6438 	    {
6439 		if(ajStrMatchC(typstr, types[i]))
6440 		{
6441 		    ok = ajTrue;
6442 		    break;
6443 		}
6444 
6445 		if(ajStrSuffixC(typstr, " (same species)"))
6446 		{
6447 		    if(ajStrGetLen(typstr) == strlen(types[i]) + 15)
6448 		    {
6449 			ok = ajTrue;
6450 			break;
6451 		    }
6452 		}
6453 
6454 		else if(ajStrSuffixC(typstr, "(same species)"))
6455 		{       /* found in EMBL 104 without expected space */
6456 		    if(ajStrGetLen(typstr) == strlen(types[i]) + 14)
6457 		    {
6458 			ok = ajTrue;
6459 			break;
6460 		    }
6461 		}
6462 
6463                 else if(ajStrSuffixC(typstr, " (same species) "))
6464 		{       /* found in EMBL 104 with extra trailing space */
6465 		    if(ajStrGetLen(typstr) == strlen(types[i]) + 16)
6466 		    {
6467 			ok = ajTrue;
6468 			break;
6469 		    }
6470 		}
6471 	    }
6472 	}
6473 
6474 	if(!ok)
6475 	    ret = ajFalse;
6476     }
6477 
6478     if(!ret)
6479 	ajFeatWarn("bad /inference value '%S' type: '%S'", val, typstr);
6480 
6481     ajStrDel(&typstr);
6482     return ret;
6483 }
6484 
6485 
6486 
6487 
6488 /* @funcstatic featTagSpecialAllLatlon ****************************************
6489 **
6490 ** Tests a string as a valid internal (EMBL) feature /lat_lon tag
6491 **
6492 ** @param  [r] val [const AjPStr] parameter value
6493 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6494 **                  ajFalse if invalid, to be converted to default (note) type
6495 **
6496 ** @release 4.0.0
6497 ** @@
6498 ******************************************************************************/
6499 
featTagSpecialAllLatlon(const AjPStr val)6500 static AjBool featTagSpecialAllLatlon(const AjPStr val)
6501 {
6502     AjPStr labstr = NULL;
6503     AjBool saveit = ajFalse;
6504     AjBool ret = ajFalse;
6505 
6506     if(!featRegSpecialLatlon)
6507       featRegSpecialLatlon = ajRegCompC("^[0-9.]+ [NS] [0-9.]+ [EW]$");
6508 
6509     if(ajRegExec(featRegSpecialLatlon, val))
6510     {
6511 	ret = ajTrue;
6512 	if(saveit)
6513 	    ajRegSubI(featRegSpecialLatlon, 1, &labstr);
6514     }
6515 
6516     if(!ret)
6517     {
6518 	ajFeatWarn("bad /lat_lon value '%S'",   val);
6519     }
6520 
6521     return ret;
6522 }
6523 
6524 
6525 
6526 
6527 /* @funcstatic featTagSpecialAllPcrprimers ************************************
6528 **
6529 ** Tests a string as a valid internal (EMBL) feature /PCR_primers tag
6530 **
6531 ** @param  [r] val [const AjPStr] parameter value
6532 ** @return [AjBool] ajTrue for a valid value
6533 **                  ajFalse if invalid, to be converted to default (note) type
6534 **
6535 ** @release 4.0.0
6536 ** @@
6537 ******************************************************************************/
6538 
featTagSpecialAllPcrprimers(const AjPStr val)6539 static AjBool featTagSpecialAllPcrprimers(const AjPStr val)
6540 {
6541     AjBool ret = ajFalse;
6542 
6543     if(!featRegSpecialPrimer)
6544       featRegSpecialPrimer = ajRegCompC("^((fwd|rev)_name: [^,]+, )?"
6545 					"(fwd|rev)_seq: [acgtubdhkmnrsvwxy<>i]+"
6546 					"(, ((fwd|rev)_name: [^,]+, )?"
6547 					"(fwd|rev)_seq: [acgtubdhkmnrsvwxy<>i]+)*");
6548 
6549     if(ajRegExec(featRegSpecialPrimer, val))
6550     {
6551 	ret = ajTrue;
6552     }
6553 
6554     if(!ret)
6555     {
6556 	ajFeatWarn("bad /PCR_primers value '%S'",   val);
6557     }
6558 
6559     return ret;
6560 }
6561 
6562 
6563 
6564 
6565 /* @funcstatic featTagSpecialAllRptunit ***************************************
6566 **
6567 ** Tests a string as a valid internal (EMBL) feature /rpt_unit tag
6568 **
6569 ** The format is 123..789
6570 ** Labels are also allowed which should be feature tags in the entry.
6571 ** Genbank (NCBI) appear to be putting the sequence consensus in. Usually
6572 ** this is a valid "label" - except of course that the label does not exist.
6573 ** One horror (July 2002) was: /rpt_unit=TCCTCACGTAG(T/C)
6574 ** others are /rpt_unit=gaa;taa /rpt_unit=(CA)2(TG)6(CA)2
6575 ** /rpt_unit=attatatgata(n)6-7gttt(n)3gtagactagtt(n)3ttatgttt
6576 **
6577 ** Version 6 of the feature table allows /rpt_unit="sequence" to include
6578 ** these nasties trim spaces and resolve ambiguities. Not to be used
6579 ** for "alu" etc.
6580 **
6581 ** Location can be complement(nn..nn)
6582 **
6583 ** @param  [r] val [const AjPStr] parameter value
6584 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6585 **                  ajFalse if invalid, to be converted to default (note) type
6586 **
6587 ** @release 2.0.0
6588 ** @@
6589 ******************************************************************************/
6590 
featTagSpecialAllRptunit(const AjPStr val)6591 static AjBool featTagSpecialAllRptunit(const AjPStr val)
6592 {
6593     AjBool ret = ajFalse;
6594 
6595     /*
6596     AjBool saveit = ajFalse;
6597     AjPStr begstr = NULL;
6598     AjPStr endstr = NULL;
6599     AjPStr labstr = NULL;
6600     */
6601 
6602     if(!featRegSpecialRptRange)				/* base range */
6603 	featRegSpecialRptRange =
6604 	    ajRegCompC("^(([a-zA-Z0-9_]+:)?[0-9]+)[.][.]([0-9]+)$");
6605     if(!featRegSpecialRptRangeLab)			/* feature label */
6606 	featRegSpecialRptRangeLab =
6607 	    ajRegCompC("^(([a-zA-Z0-9_]+:)?[a-zA-Z0-9_]+)$");
6608     if(!featRegSpecialRptRangeComp)	/* complement(base range) */
6609 	featRegSpecialRptRangeComp =
6610 	    ajRegCompC("^(complement[(]([a-zA-Z0-9_]+:)?[0-9]+)"
6611 		       "[.][.]([0-9]+)[)]$");
6612     if(!featRegSpecialRptunitSeq)
6613         featRegSpecialRptunitSeq =
6614             ajRegCompC("^([abcdghkmnrstuvwxyABCDGHKMNRSTUVWXY0-9/();-]+)$");
6615 
6616     if(ajRegExec(featRegSpecialRptRange, val))
6617     {
6618 	ret = ajTrue;
6619 	/*
6620 	if(saveit)
6621 	{
6622 	    ajRegSubI(featRegSpecialRptRange, 1, &begstr);
6623 	    ajRegSubI(featRegSpecialRptRange, 3, &endstr);
6624 	}
6625         */
6626     }
6627 
6628     else if(ajRegExec(featRegSpecialRptRangeLab, val))
6629     {
6630 	ret = ajTrue;
6631 	/*
6632 	if(saveit)
6633 	    ajRegSubI(featRegSpecialRptRangeLab, 1, &labstr);
6634         */
6635     }
6636 
6637     else if(ajRegExec(featRegSpecialRptRangeComp, val))
6638     {
6639 	ret = ajTrue;
6640 	/*
6641 	if(saveit)
6642 	{
6643 	    ajRegSubI(featRegSpecialRptRangeComp, 3, &begstr);
6644 	    ajRegSubI(featRegSpecialRptRangeComp, 1, &endstr);
6645 	}
6646         */
6647     }
6648 
6649     if(ajRegExec(featRegSpecialRptRangeComp, val))
6650     {
6651 	ret = ajTrue;
6652 	/*
6653 	if(saveit)
6654 	{
6655 	  ajRegSubI(featRegSpecialRptRangeComp, 3, &begstr);
6656 	  ajRegSubI(featRegSpecialRptRangeComp, 1, &endstr);
6657 	}
6658         */
6659     }
6660 
6661     /* provided because EMBL/Genbank has things like this:
6662        /rpt_unit=TCCTCACGTAG(T/C)
6663        /rpt_unit=(A)n
6664        */
6665 
6666     else if(ajRegExec(featRegSpecialRptunitSeq, val))
6667     {
6668 	ret = ajTrue;
6669 	/*
6670 	if(saveit)
6671 	    ajRegSubI(featRegSpecialRptunitSeq, 1, &labstr);
6672         */
6673     }
6674 
6675     if(!ret)
6676     {
6677 	ajFeatWarn("bad /rpt_unit value '%S'",   val);
6678     }
6679 
6680     return ret;
6681 }
6682 
6683 
6684 
6685 
6686 /* @funcstatic featTagSpecialAllRange *****************************************
6687 **
6688 ** Tests a string as a valid internal (EMBL) feature /rpt_unit_range tag
6689 **
6690 ** The format is 123..789
6691 ** Labels are also allowed which should be feature tags in the entry.
6692 ** Genbank (NCBI) appear to be putting the sequence consensus in. Usually
6693 ** this is a valid "label" - except of course that the label does not exist.
6694 ** One horror (July 2002) was: /rpt_unit=TCCTCACGTAG(T/C)
6695 ** others are /rpt_unit=gaa;taa /rpt_unit=(CA)2(TG)6(CA)2
6696 ** /rpt_unit=attatatgata(n)6-7gttt(n)3gtagactagtt(n)3ttatgttt
6697 **
6698 ** Version 6 of the feature table allows /rpt_unit="sequence" to include
6699 ** these nasties trim spaces and resolve ambiguities. Not to be used
6700 ** for "alu" etc.
6701 **
6702 ** Location can be complement(nn..nn)
6703 **
6704 ** @param  [r] val [const AjPStr] parameter value
6705 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6706 **                  ajFalse if invalid, to be converted to default (note) type
6707 **
6708 ** @release 6.1.0
6709 ** @@
6710 ******************************************************************************/
6711 
featTagSpecialAllRange(const AjPStr val)6712 static AjBool featTagSpecialAllRange(const AjPStr val)
6713 {
6714      AjBool ret = ajFalse;
6715     /*
6716     AjBool saveit = ajFalse;
6717     AjPStr begstr = NULL;
6718     AjPStr endstr = NULL;
6719     AjPStr labstr = NULL;
6720     */
6721 
6722      if(!featRegSpecialRptRange)				/* base range */
6723 	featRegSpecialRptRange =
6724 	    ajRegCompC("^(([a-zA-Z0-9_]+:)?[0-9]+)[.][.]([0-9]+)$");
6725 
6726      if(!featRegSpecialRptRangeLab)			/* feature label */
6727 	featRegSpecialRptRangeLab =
6728 	    ajRegCompC("^(([a-zA-Z0-9_]+:)?[a-zA-Z0-9_]+)$");
6729 
6730      if(!featRegSpecialRptRangeComp)	/* complement(base range) */
6731 	featRegSpecialRptRangeComp =
6732 	    ajRegCompC("^(complement[(]([a-zA-Z0-9_]+:)?[0-9]+)"
6733 		       "[.][.]([0-9]+)[)]$");
6734 
6735     if(ajRegExec(featRegSpecialRptRange, val))
6736     {
6737 	ret = ajTrue;
6738 	/*
6739 	if(saveit)
6740 	{
6741 	    ajRegSubI(featRegSpecialRptRange, 1, &begstr);
6742 	    ajRegSubI(featRegSpecialRptRange, 3, &endstr);
6743 	}
6744         */
6745     }
6746 
6747     else if(ajRegExec(featRegSpecialRptRangeLab, val))
6748     {
6749 	ret = ajTrue;
6750 	/*
6751 	if(saveit)
6752 	    ajRegSubI(featRegSpecialRptRangeLab, 1, &labstr);
6753         */
6754     }
6755 
6756     else if(ajRegExec(featRegSpecialRptRangeComp, val))
6757     {
6758 	ret = ajTrue;
6759 	/*
6760 	if(saveit)
6761 	{
6762 	    ajRegSubI(featRegSpecialRptRangeComp, 3, &begstr);
6763 	    ajRegSubI(featRegSpecialRptRangeComp, 1, &endstr);
6764 	}
6765         */
6766     }
6767 
6768 
6769     if(!ret)
6770     {
6771 	ajFeatWarn("bad /rpt_unit_tange value '%S'",   val);
6772     }
6773 
6774     return ret;
6775 }
6776 
6777 
6778 
6779 
6780 /* @funcstatic featTagSpecialAllRptunitseq ************************************
6781 **
6782 ** Tests a string as a valid internal (EMBL) feature /rpt_unit_seq tag
6783 **
6784 ** examples from GenBank include /rpt_unit_seq=TCCTCACGTAG(T/C)
6785 ** others are /rpt_unit_seq=gaa;taa /rpt_unit_seq=(CA)2(TG)6(CA)2
6786 ** /rpt_unit_seq=attatatgata(n)6-7gttt(n)3gtagactagtt(n)3ttatgttt
6787 **
6788 ** Corrects extra spaces from long sequence values
6789 **
6790 ** @param  [u] pval [AjPStr*] parameter value
6791 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6792 **                  ajFalse if invalid, to be converted to default (note) type
6793 **
6794 ** @release 4.0.0
6795 ** @@
6796 ******************************************************************************/
6797 
featTagSpecialAllRptunitseq(AjPStr * pval)6798 static AjBool featTagSpecialAllRptunitseq(AjPStr *pval)
6799 {
6800     AjBool ret = ajFalse;
6801     ajuint i;
6802     const char* specials[] =
6803     {
6804         "a-rich",               /* found in EMBL 104 */
6805         "at-rich",              /* found in EMBL 104 */
6806         "c-rich",               /* found in EMBL 104 */
6807         "ct-rich",              /* found in EMBL 104 */
6808         "CT-rich",              /* found in EMBL 104 */
6809         "g-rich",               /* found in EMBL 104 */
6810         "ga-rich",              /* found in EMBL 104 */
6811         "GA-rich",              /* found in EMBL 104 */
6812         "gc-rich",              /* found in EMBL 104 */
6813         "t-rich",               /* found in EMBL 104 */
6814         "CT_AT",                /* found in EMBL 104 */
6815         "TA_CA",                /* found in EMBL 104 */
6816         "AGAT_AGAC",            /* found in EMBL 104 */
6817         "GAA-repeat",           /* found in EMBL 104 */
6818         "GGA-repeat",           /* found in EMBL 104 */
6819         "tgtc (imperfect)",     /* found in EMBL 104 */
6820         "score",                /* found in EMBL 104 */
6821         "direct",               /* found in EMBL 104 */
6822         "dispersed",            /* found in EMBL 104 */
6823         "inverted",             /* found in EMBL 104 */
6824         "ca repeat",            /* found in EMBL 104 */
6825         "cac/caa/cag compound repeat", /* found in EMBL 104 */
6826         "cata interrupted repeat",     /* found in EMBL 104 */
6827         "CA dinucleotide microsatellite",          /* found in EMBL 104 */
6828         "gaa/gac compound repeat",     /* found in EMBL 104 */
6829         "dodecanucleotide",          /* found in EMBL 104 */
6830         "heptamer",             /* found in EMBL 104 */
6831         "gttt..gt",             /* found in EMBL 104 */
6832         "telunit",              /* found in EMBL 104 */
6833         "af(12)",               /* found in EMBL 104 */
6834         "alu",                  /* found in EMBL 104 */
6835         "Alu",                  /* found in EMBL 104 */
6836         "AluJo",                /* found in EMBL 104 */
6837         "AluSg",                /* found in EMBL 104 */
6838         "AluY",                 /* found in EMBL 104 */
6839         "hif2DR",               /* found in EMBL 104 */
6840         "B1element",            /* found in EMBL 104 */
6841         "L1MC/D",               /* found in EMBL 104 */
6842         "L1MC3",                /* found in EMBL 104 */
6843         "L1MD3",                /* found in EMBL 104 */
6844         "L1ME",                 /* found in EMBL 104 */
6845         "RMER17B",              /* found in EMBL 104 */
6846         "RLTR11A",              /* found in EMBL 104 */
6847         "poly A",               /* found in EMBL 104 */
6848         "core-vntr1",           /* found in EMBL 104 */
6849         "core-vntr2",           /* found in EMBL 104 */
6850         NULL
6851     };
6852 
6853     /*
6854     AjBool saveit = ajFalse;
6855     AjPStr labstr = NULL;
6856     */
6857 
6858     if(!featRegSpecialRptunitSeq)
6859         featRegSpecialRptunitSeq =
6860             ajRegCompC("^([ abcdghkmnrstuvwxyABCDGHKMNRSTUVWXY0-9"
6861                        "_/\\[\\]\\(\\):;.,+-]+)$");
6862 
6863     if(!featRegSpecialRptunitSeqPos)
6864         featRegSpecialRptunitSeqPos =
6865             ajRegCompC("^((complement[\\(])?[<]?\\d+[.][.]?[>]?\\d+[\\)]?)$");
6866 
6867     if(ajRegExec(featRegSpecialRptunitSeq, *pval))
6868     {
6869         ajStrRemoveWhite(pval);   /* remove wrapping spaces in long seq. */
6870 
6871 	ret = ajTrue;
6872 	/*
6873 	if(saveit)
6874 	    ajRegSubI(featRegSpecialRptunitSeq, 1, &labstr);
6875         */
6876     }
6877     else if(ajRegExec(featRegSpecialRptunitSeqPos, *pval))
6878     {
6879 	ret = ajTrue;
6880     }
6881     else
6882     {
6883 	for(i=0; specials[i]; i++)
6884 	{
6885             if(ajStrMatchC(*pval, specials[i]))
6886             {
6887                 ret = ajTrue;
6888                 break;
6889             }
6890         }
6891     }
6892 
6893     if(!ret)
6894     {
6895 	ajFeatWarn("bad /rpt_unit_seq value '%S'",   *pval);
6896     }
6897 
6898     return ret;
6899 }
6900 
6901 
6902 
6903 
6904 /* @funcstatic featTagSpecialAllTranslexcept **********************************
6905 **
6906 ** Tests a string as a valid internal (EMBL) feature /transl_except tag
6907 **
6908 ** The format is (pos:213..215,aa:Trp)
6909 **
6910 ** FT 6.2 todo aa 3 letter codes, or Sec (U) or TERM or OTHER
6911 **
6912 ** FT 6.2 todo pos can be 1 or 2 bases for polyA-completed stops (TERM)
6913 ** which should have a /note
6914 **
6915 ** @param  [r] val [const AjPStr] parameter value
6916 ** @return [AjBool] ajTrue for a valid value, possibly corrected
6917 **                  ajFalse if invalid, to be converted to default (note) type
6918 **
6919 ** @release 2.0.0
6920 ** @@
6921 ******************************************************************************/
6922 
featTagSpecialAllTranslexcept(const AjPStr val)6923 static AjBool featTagSpecialAllTranslexcept(const AjPStr val)
6924 {
6925     AjBool saveit = ajFalse;
6926     AjBool ret = ajFalse;
6927 
6928     if(!featRegSpecialTrans)
6929 	featRegSpecialTrans =
6930 	    ajRegCompC("^[(]pos:([0-9]+)[.][.]([0-9]+),aa:([^)]+)[)]$");
6931 
6932     if(!featRegSpecialTransBad)		/* start position only */
6933 	featRegSpecialTransBad =
6934 	    ajRegCompC("^[(]pos:([0-9]+),aa:([^)]+)[)]$");
6935 
6936     if(!featRegSpecialTransComp)
6937 	featRegSpecialTransComp =
6938 	    ajRegCompC("^[(]pos:complement\\(([0-9]+)[.][.]([0-9]+)\\),"
6939 		       "aa:([^)]+)[)]$");
6940 
6941     if(!featRegSpecialTransBadComp)
6942 	featRegSpecialTransBadComp =
6943 	    ajRegCompC("^[(]pos:complement\\(([0-9]+)\\),"
6944 		       "aa:([^)]+)[)]$");
6945 
6946     if(ajRegExec(featRegSpecialTrans, val))
6947     {
6948 	ret = ajTrue;
6949 
6950 	if(saveit)
6951 	{
6952 	    ajRegSubI(featRegSpecialTrans, 1, &featTransBegStr);
6953 	    ajRegSubI(featRegSpecialTrans, 2, &featTransEndStr);
6954 	    ajRegSubI(featRegSpecialTrans, 3, &featTransAaStr);
6955 	}
6956     }
6957     else if(ajRegExec(featRegSpecialTransComp, val))
6958     {
6959 	ret = ajTrue;
6960 
6961 	if(saveit)
6962 	{
6963 	    ajRegSubI(featRegSpecialTransComp, 1, &featTransBegStr);
6964 	    ajRegSubI(featRegSpecialTransComp, 2, &featTransEndStr);
6965 	    ajRegSubI(featRegSpecialTransComp, 3, &featTransAaStr);
6966 	}
6967     }
6968 
6969 /* Can have single base (or 2 base) positions where trailing As are
6970    added as post-processing in some species */
6971 
6972     else if(ajRegExec(featRegSpecialTransBad, val))
6973     {
6974 	ret = ajTrue;
6975 
6976 	if(saveit)
6977 	{
6978 	    ajRegSubI(featRegSpecialTransBad, 1, &featTransBegStr);
6979 	    ajRegSubI(featRegSpecialTransBad, 2, &featTransAaStr);
6980 	}
6981     }
6982     else if(ajRegExec(featRegSpecialTransBadComp, val))
6983     {
6984 	ret = ajTrue;
6985 
6986 	if(saveit)
6987 	{
6988 	    ajRegSubI(featRegSpecialTransBadComp, 1, &featTransBegStr);
6989 	    ajRegSubI(featRegSpecialTransBadComp, 2, &featTransAaStr);
6990 	}
6991     }
6992 
6993     if(!ret)
6994     {
6995 	ajFeatWarn("bad /transl_except value '%S'",   val);
6996     }
6997 
6998     return ret;
6999 }
7000 
7001 
7002 
7003 
7004 /* @funcstatic featTagSpecialAllDbxref ****************************************
7005 **
7006 ** Tests a string as a valid internal (EMBL) feature /db_xref tag
7007 **
7008 ** The format is <database>:<identifier>
7009 **
7010 ** @param  [r] val [const AjPStr] parameter value
7011 ** @return [AjBool] ajTrue for a valid value, possibly corrected
7012 **                  ajFalse if invalid, to be converted to default (note) type
7013 **
7014 ** @release 2.0.0
7015 ** @@
7016 ******************************************************************************/
7017 
featTagSpecialAllDbxref(const AjPStr val)7018 static AjBool featTagSpecialAllDbxref(const AjPStr val)
7019 {
7020     const char* cp = NULL;
7021     AjBool ret           = ajTrue;
7022 
7023     /*
7024     AjBool saveit = ajFalse;
7025     AjPStr dbstr  = NULL;
7026     AjPStr idstr  = NULL;
7027     */
7028 
7029     cp = ajStrGetPtr(val);
7030     /*
7031     if(saveit)
7032 	ajStrAssignResC(&dbstr, ajStrGetLen(val), "");
7033     */
7034     while(*cp && (*cp != ':'))
7035     {
7036 	/*
7037 	if(saveit)
7038 	    ajStrAppendK(&dbstr, *cp);
7039 	*/
7040 	cp++;
7041     }
7042 
7043     if(!*cp)
7044 	ret = ajFalse;
7045     else
7046     {
7047 	cp++;
7048 	if(!*cp)
7049 	    ret = ajFalse;
7050     }
7051 
7052     /*
7053     if(saveit)
7054 	ajStrAssignC(&idstr, cp);
7055     */
7056 
7057     if(!ret)
7058     {
7059 	ajFeatWarn("bad /db_xref value '%S'",   val);
7060     }
7061 
7062     return ret;
7063 }
7064 
7065 
7066 
7067 
7068 /* @funcstatic featTagSpecialAllProteinid *************************************
7069 **
7070 ** Tests a string as a valid internal (EMBL) feature /protein_id tag
7071 **
7072 ** The format is AAA12345.1
7073 **
7074 ** @param  [r] val [const AjPStr] parameter value
7075 ** @return [AjBool] ajTrue for a valid value, possibly corrected
7076 **                  ajFalse if invalid, to be converted to default (note) type
7077 **
7078 ** @release 2.0.0
7079 ** @@
7080 ******************************************************************************/
7081 
featTagSpecialAllProteinid(const AjPStr val)7082 static AjBool featTagSpecialAllProteinid(const AjPStr val)
7083 {
7084     const char* cp = ajStrGetPtr(val);
7085 /*    const char* cq; */
7086     ajint icp;
7087     ajint i = 0;
7088     ajint idot = 0;
7089     AjBool ret = ajFalse;
7090 
7091     /*
7092     AjBool saveit = ajFalse;
7093     AjPStr idstr    = NULL;
7094     AjPStr preidstr = NULL;
7095     */
7096 
7097     if(ajStrPrefixC(val, "ENSP"))  /* older entries had ENSEMBL Protein IDs */
7098     {
7099 	cp += 4;
7100 
7101 	while(*cp)
7102 	{
7103 	    if(!isdigit((ajint)*cp++))
7104 		break;
7105 	    i++;
7106 	}
7107 
7108         /* ENSP then all numbers */
7109 	if(!*cp && i > 5)
7110             ret = ajTrue;
7111 
7112 /*	if(ret)
7113         ajFeatWarn("ENSEMBL /protein_id value '%S'",   val);*/
7114 
7115 	/*
7116 	if(saveit)
7117 	{
7118 	    ajStrAssignS(&preidstr, val);
7119 	    ajStrAssignS(&idstr, val);
7120 	}
7121 	*/
7122     }
7123     else
7124     {
7125 	cp = ajStrGetPtr(val);
7126 /*	cq = cp; */
7127 	i=0;
7128 	while(*cp)
7129 	{
7130 	    i++;
7131 	    icp = *cp;
7132 
7133 	    if(i <= 3)
7134 	    {
7135 	      if(icp == '_')
7136 	      {
7137 		if(i!=3)
7138 		  break;
7139 	      }
7140 	      else if(!isalpha(icp) || !isupper(icp))
7141 		    break;
7142 	    }
7143 	    else if(*cp == '.')
7144 	    {
7145 		if(idot)		/* once only */
7146 		    break;
7147 
7148 		idot = i;
7149 
7150 		if(idot < 9)	/* at least ABC12345. */
7151 		    break;
7152 	    }
7153 	    else
7154 	    {
7155 		if(!isdigit(icp))
7156 		    break;
7157 	    }
7158 	    cp++;
7159 	}
7160 
7161 	/*
7162 	if(saveit)
7163 	{
7164 	    ajStrAssignLenC(&preidstr, cq, idot-1);
7165 	    ajStrAssignLenC(&idstr, cq, i);
7166 	}
7167         */
7168 
7169 	if(!*cp && idot && (i > idot))
7170 	    ret = ajTrue;
7171     }
7172 
7173     if(!ret)
7174     {
7175 	ajFeatWarn("bad /protein_id value '%S'", val);
7176     }
7177 
7178     return ret;
7179 }
7180 
7181 
7182 
7183 
7184 /* @funcstatic featTagSpecialAllReplace ***************************************
7185 **
7186 ** Tests a string as a valid internal (EMBL) feature /replace tag
7187 **
7188 ** The format is "<sequence>" where sequence is empty for a deletion
7189 **
7190 ** Corrects extra spaces from long sequence values
7191 **
7192 ** @param  [u] pval [AjPStr*] parameter value
7193 ** @return [AjBool] ajTrue for a valid value, possibly corrected
7194 **                  ajFalse if invalid, to be converted to default (note) type
7195 **
7196 ** @release 2.0.0
7197 ** @@
7198 ******************************************************************************/
7199 
featTagSpecialAllReplace(AjPStr * pval)7200 static AjBool featTagSpecialAllReplace(AjPStr* pval)
7201 {
7202     AjBool ret = ajFalse;
7203 
7204     /* n is used in old_sequence */
7205     /* and in misc_difference features */
7206     if(!featRegTagReplace)
7207 	featRegTagReplace =
7208 	    ajRegCompC("^([abcdghkmnrstuvwxyABCDGHKMNRSTUVWXY/-]*)$");
7209 
7210     /* if(!featRegTagReplace)
7211        featRegTagReplace = ajRegCompC("^\"([acgt]*)\"$");*/
7212 
7213     /* no need to add quotes here - we will add them if needed on output */
7214 
7215     /*
7216        ajDebug("Before quote '%S' %c %c\n", *pval,
7217        ajStrGetCharFirst(*pval), ajStrGetCharLast(*pval));
7218        ajStrFmtQuote(pval);
7219        ajDebug(" After quote '%S' %c %c\n", *pval,
7220        ajStrGetCharFirst(*pval), ajStrGetCharLast(*pval));
7221        */
7222 
7223     ajStrRemoveWhite(pval);   /* remove wrapping spaces in long seq. */
7224 
7225     if(ajRegExec(featRegTagReplace, *pval))
7226 	ret = ajTrue;	    /* substring 1 has the matched sequence */
7227 
7228     if(!ret)
7229     {
7230 	ajFeatWarn("bad /replace value '%S'",   *pval);
7231     }
7232 
7233     return ret;
7234 }
7235 
7236 
7237 
7238 
7239 /* @funcstatic featTagSpecialAllTranslation ***********************************
7240 **
7241 ** Tests a string as a valid internal (EMBL) feature /translation tag
7242 **
7243 ** The format is valid amino acid codes, no white space
7244 **
7245 ** Corrects extra spaces from long sequence values
7246 **
7247 ** @param  [u] pval [AjPStr*] parameter value
7248 ** @return [AjBool] ajTrue for a valid value, possibly corrected
7249 **                  ajFalse if invalid, to be converted to default (note) type
7250 **
7251 ** @release 2.0.0
7252 ** @@
7253 ******************************************************************************/
7254 
featTagSpecialAllTranslation(AjPStr * pval)7255 static AjBool featTagSpecialAllTranslation(AjPStr* pval)
7256 {
7257     AjPStr seqstr = NULL;
7258     const char* cp;
7259     ajint icp;
7260     AjBool saveit = ajFalse;
7261     AjBool ret = ajFalse;
7262 
7263     ajStrRemoveWhite(pval);   /* remove wrapping spaces in long seq. */
7264     cp = ajStrGetPtr(*pval);
7265 
7266     if(saveit)
7267 	ajStrAssignResC(&seqstr, ajStrGetLen(*pval), "");
7268 
7269     while(*cp)
7270     {
7271 	icp = *cp;
7272 
7273 	if(!isalpha(icp))
7274 	    break;
7275 
7276 	if(!isupper(icp))
7277 	    break;
7278 
7279 /*	if(strchr("JO",icp))
7280         break; */
7281 
7282 	if(saveit)
7283 	    ajStrAppendK(&seqstr, *cp);
7284 	cp++;
7285     }
7286 
7287     if(!*cp)
7288 	ret = ajTrue;
7289 
7290     if(!ret)
7291     {
7292 	ajFeatWarn("bad /translation value '%S'",   *pval);
7293     }
7294 
7295     return ret;
7296 }
7297 
7298 
7299 
7300 
7301 /* @funcstatic featTagSpecialAllEstimatedlength *******************************
7302 **
7303 ** Tests a string as a valid internal (EMBL) feature /estimated_length tag
7304 **
7305 ** The format is a positive integer, or unknown (unquoted)
7306 **
7307 ** @param [u] pval [AjPStr*] parameter value
7308 ** @return [AjBool] ajTrue for a valid value, possibly corrected
7309 **                  ajFalse if invalid, to be converted to default (note) type
7310 **
7311 ** @release 3.0.0
7312 ** @@
7313 ******************************************************************************/
7314 
featTagSpecialAllEstimatedlength(AjPStr * pval)7315 static AjBool featTagSpecialAllEstimatedlength(AjPStr* pval)
7316 {
7317     AjPStr numstr = NULL;
7318     AjBool saveit = ajFalse;
7319     AjBool ret = ajFalse;
7320 
7321     if(!featRegSpecialEstlen)
7322 	featRegSpecialEstlen = ajRegCompC("^(unknown|[1-9][0-9]*)$");
7323 
7324     if(ajRegExec(featRegSpecialEstlen, *pval))
7325     {
7326 	ret = ajTrue;
7327 
7328 	if(saveit)
7329 	    ajRegSubI(featRegSpecialEstlen, 1, &numstr);
7330     }
7331 
7332     if(!ret)
7333     {
7334 	ajFeatWarn("bad /estimated_length value '%S' corrected to 'unknown'",
7335 	       *pval);
7336 	ajStrAssignC(pval, "unknown");
7337     }
7338 
7339     ajStrDel(&numstr);
7340 
7341     return ret;
7342 }
7343 
7344 
7345 
7346 
7347 /* @funcstatic featTagSpecialAllCompare ***************************************
7348 **
7349 ** Tests a string as a valid internal (EMBL) feature /compare tag
7350 **
7351 ** The format is a sequence versin
7352 **
7353 ** @param  [r] val [const AjPStr] parameter value
7354 ** @return [AjBool] ajTrue for a valid value, possibly corrected
7355 **                  ajFalse if invalid, to be converted to default (note) type
7356 **
7357 ** @release 3.0.0
7358 ** @@
7359 ******************************************************************************/
7360 
featTagSpecialAllCompare(const AjPStr val)7361 static AjBool featTagSpecialAllCompare(const AjPStr val)
7362 {
7363     AjPStr numstr = NULL;
7364     AjBool saveit = ajFalse;
7365     AjBool ret = ajFalse;
7366 
7367 /* value is a sequence version accnumber.number */
7368     if(!featRegSpecialCompare)
7369 	featRegSpecialCompare = ajRegCompC("^([A-Z]+[0-9]+([.][1-9][0-9]*)?)$");
7370 
7371     if(ajRegExec(featRegSpecialCompare, val))
7372     {
7373 	ret = ajTrue;
7374 	if(saveit)
7375 	    ajRegSubI(featRegSpecialCompare, 1, &numstr);
7376     }
7377 
7378     if(!ret)
7379     {
7380 	ajFeatWarn("bad /compare value '%S'", val);
7381     }
7382     ajStrDel(&numstr);
7383 
7384     return ret;
7385 }
7386 
7387 
7388 
7389 
7390 /* @funcstatic featTagSpecialAllMobile ****************************************
7391 **
7392 ** Tests a string as a valid internal (EMBL) feature /mobile_element tag
7393 **
7394 ** The format is a known type and optional :name
7395 **
7396 ** @param  [r] val [const AjPStr] parameter value
7397 ** @return [AjBool] ajTrue for a valid value, possibly corrected
7398 **                  ajFalse if invalid, to be converted to default (note) type
7399 **
7400 ** @release 5.0.0
7401 ** @@
7402 ******************************************************************************/
7403 
featTagSpecialAllMobile(const AjPStr val)7404 static AjBool featTagSpecialAllMobile(const AjPStr val)
7405 {
7406     AjPStr typstr = NULL;
7407     AjPStr namstr = NULL;
7408     AjBool saveit = ajFalse;
7409     AjBool ret = ajFalse;
7410     ajuint i;
7411 
7412     const char* elements[] =
7413     {
7414 	"transposon", "retrotransposon", "integron",
7415 	"insertion sequence", "non-LTR retrotransposon",
7416 	"SINE", "MITE", "LINE", "other", NULL
7417     };
7418 
7419     /* value is a type or type:name */
7420     if(!featRegSpecialMobile)
7421 	featRegSpecialMobile = ajRegCompC("^([^:]+)(:(.*))?$");
7422 
7423     if(ajRegExec(featRegSpecialMobile, val))
7424     {
7425 	ajRegSubI(featRegSpecialMobile, 1, &typstr);
7426 
7427 	for(i=0;elements[i];i++)
7428 	    if(ajStrMatchC(typstr, elements[i])) break;
7429 
7430 	if(elements[i])
7431 	    ret = ajTrue;
7432 
7433 	if(saveit)
7434 	{
7435 	    ajRegSubI(featRegSpecialMobile, 3, &namstr);
7436 	}
7437     }
7438 
7439     if(!ret)
7440     {
7441 	ajFeatWarn("bad /mobile_element value '%S'", val);
7442     }
7443     ajStrDel(&typstr);
7444     ajStrDel(&namstr);
7445 
7446     return ret;
7447 }
7448 
7449 
7450 
7451 
7452 /* @funcstatic featTagSpecialAllNcrnaclass ************************************
7453 **
7454 ** Tests a string as a valid internal (EMBL) feature /ncRNA_class tag
7455 **
7456 ** The format is a known type and optional :name
7457 **
7458 ** value is a term taken from the INSDC controlled vocabulary for ncRNA classes
7459 ** http://www.insdc.org/page.php?page=rna_vocab
7460 ** or http://www.ebi.ac.uk/embl/Documentation/ncRNA_class.html
7461 **
7462 ** @param  [r] val [const AjPStr] parameter value
7463 ** @return [AjBool] ajTrue for a valid value, possibly corrected
7464 **                  ajFalse if invalid, to be converted to default (note) type
7465 **
7466 ** @release 6.1.0
7467 ** @@
7468 ******************************************************************************/
7469 
featTagSpecialAllNcrnaclass(const AjPStr val)7470 static AjBool featTagSpecialAllNcrnaclass(const AjPStr val)
7471 {
7472     AjPStr typstr = NULL;
7473     AjPStr namstr = NULL;
7474     AjBool ret = ajFalse;
7475     ajuint i;
7476 
7477     const char* classes[] =
7478     {
7479 	"antisense_RNA", "autocatalytically_spliced_intron",
7480         "ribozyme", "hammerhead_ribozyme",
7481         "RNase_P_RNA",
7482 	"RNase_MRP_RNA", "telomerase_RNA", "guide_RNA", "rasiRNA",
7483 	"scRNA", "siRNA", "miRNA", "piRNA",
7484 	"snoRNA", "snRNA", "SRP_RNA", "vault_RNA", "Y_RNA",
7485         "other",
7486         NULL
7487     };
7488 
7489     for(i=0;classes[i];i++)
7490         if(ajStrMatchC(val, classes[i])) break;
7491 
7492     if(classes[i])
7493         ret = ajTrue;
7494 
7495     if(!ret)
7496     {
7497 	ajFeatWarn("bad /ncRNA_class value '%S'", val);
7498     }
7499 
7500     ajStrDel(&typstr);
7501     ajStrDel(&namstr);
7502 
7503     return ret;
7504 }
7505 
7506 
7507 
7508 
7509 /* @funcstatic featTagSetDefault **********************************************
7510 **
7511 ** Sets a feature tag value, using the default feature tag
7512 **
7513 ** @param [u] thys [AjPFeature] Feature
7514 ** @param [r] tag [const AjPStr] Feature tag
7515 ** @param [r] value [const AjPStr] feature tag value
7516 ** @param [w] Pdeftag [AjPStr*] Default tag
7517 ** @param [w] Pdefval [AjPStr*] Default tag value as "*tag: value"
7518 ** @return [void]
7519 **
7520 ** @release 2.0.0
7521 ** @@
7522 ******************************************************************************/
7523 
featTagSetDefault(AjPFeature thys,const AjPStr tag,const AjPStr value,AjPStr * Pdeftag,AjPStr * Pdefval)7524 static void featTagSetDefault(AjPFeature thys,
7525 			      const AjPStr tag, const AjPStr value,
7526 			      AjPStr* Pdeftag, AjPStr* Pdefval)
7527 {
7528     featInit();
7529 
7530     if(thys->Protein)
7531 	featTagSetDefaultDna(tag, value, Pdeftag, Pdefval);
7532     else
7533 	featTagSetDefaultProt(tag, value, Pdeftag, Pdefval);
7534 
7535     return;
7536 }
7537 
7538 
7539 
7540 
7541 /* @funcstatic featTagSetDefaultDna *******************************************
7542 **
7543 ** Sets a feature tag value, using the default DNA feature tag
7544 **
7545 ** @param [r] tag [const AjPStr] Feature tag
7546 ** @param [r] value [const AjPStr] feature tag value
7547 ** @param [w] Pdeftag [AjPStr*] Default tag
7548 ** @param [w] Pdefval [AjPStr*] Default tag value as "*tag: value"
7549 ** @return [void]
7550 **
7551 ** @release 2.0.0
7552 ** @@
7553 ******************************************************************************/
7554 
featTagSetDefaultDna(const AjPStr tag,const AjPStr value,AjPStr * Pdeftag,AjPStr * Pdefval)7555 static void featTagSetDefaultDna(const AjPStr tag, const AjPStr value,
7556 				  AjPStr* Pdeftag, AjPStr* Pdefval)
7557 {
7558     featInit();
7559 
7560     ajStrAssignS(Pdeftag,
7561                  (const AjPStr) ajTableFetchC(FeatTagsTableDna, ""));
7562     ajFmtPrintS(Pdefval, "*%S: %S", tag, value);
7563 
7564     return;
7565 }
7566 
7567 
7568 
7569 
7570 /* @funcstatic featTagSetDefaultProt ******************************************
7571 **
7572 ** Sets a feature tag value, using the default protein feature tag
7573 **
7574 ** @param [r] tag [const AjPStr] Feature tag
7575 ** @param [r] value [const AjPStr] feature tag value
7576 ** @param [w] Pdeftag [AjPStr*] Default tag
7577 ** @param [w] Pdefval [AjPStr*] Default tag value as "*tag: value"
7578 ** @return [void]
7579 **
7580 ** @release 2.0.0
7581 ** @@
7582 ******************************************************************************/
7583 
featTagSetDefaultProt(const AjPStr tag,const AjPStr value,AjPStr * Pdeftag,AjPStr * Pdefval)7584 static void featTagSetDefaultProt(const AjPStr tag, const AjPStr value,
7585 				   AjPStr* Pdeftag, AjPStr* Pdefval)
7586 {
7587     featInit();
7588 
7589     ajStrAssignS(Pdeftag,
7590 		 (const AjPStr) ajTableFetchC(FeatTagsTableProtein, ""));
7591     ajFmtPrintS(Pdefval, "*%S: %S", tag, value);
7592 
7593     return;
7594 }
7595 
7596 
7597 
7598 
7599 /* @func ajFeattableNew *******************************************************
7600 **
7601 ** Constructor for a new (generic) feature table.
7602 ** Does not define the feature table type.
7603 **
7604 ** @param [r] name [const AjPStr] Name for new feature table
7605 **                                (or NULL for unnamed)
7606 ** @return [AjPFeattable] Pointer to a new (empty) feature table
7607 ** @category new [AjPFeattable] Constructor
7608 **
7609 ** @release 2.0.0
7610 ** @@
7611 ******************************************************************************/
7612 
ajFeattableNew(const AjPStr name)7613 AjPFeattable ajFeattableNew(const AjPStr name )
7614 {
7615     AjPFeattable thys = NULL;
7616 
7617     /* Allocate the object... */
7618     thys = featTableNewS(name) ;
7619 
7620     /*ajDebug("ajFeattableNew %x\n", thys);*/
7621 
7622     return thys;
7623 }
7624 
7625 
7626 
7627 
7628 /* @func ajFeattableReset *****************************************************
7629 **
7630 ** Resets a feature table with a new name
7631 **
7632 ** @param [u] thys [AjPFeattable] Feature table
7633 ** @param [r] name [const AjPStr] Name for new feature table
7634 ** @return [void]
7635 **
7636 ** @release 6.6.0
7637 ** @@
7638 ******************************************************************************/
7639 
ajFeattableReset(AjPFeattable thys,const AjPStr name)7640 void ajFeattableReset(AjPFeattable thys, const AjPStr name)
7641 {
7642     ajFeattableClear(thys);
7643 
7644     ajStrAssignS(&thys->Seqid, name);
7645 
7646     return;
7647 }
7648 
7649 
7650 
7651 
7652 /* @func ajFeattableSetCircular ***********************************************
7653 **
7654 ** Sets a feature table to be circular
7655 **
7656 ** @param [u] thys [AjPFeattable] Feature table
7657 ** @return [void]
7658 **
7659 ** @release 6.5.0
7660 ** @@
7661 ******************************************************************************/
7662 
ajFeattableSetCircular(AjPFeattable thys)7663 void ajFeattableSetCircular(AjPFeattable thys)
7664 {
7665     thys->Circular = ajTrue;
7666 
7667     return;
7668 }
7669 
7670 
7671 
7672 
7673 /* @func ajFeattableSetDefname ************************************************
7674 **
7675 ** Provides a unique (for this program run) name for a feature table.
7676 **
7677 ** @param [w] thys [AjPFeattable] Feature table
7678 ** @param [r] setname [const AjPStr] Name set by caller
7679 ** @return [void]
7680 **
7681 ** @release 6.2.0
7682 ** @@
7683 ******************************************************************************/
7684 
ajFeattableSetDefname(AjPFeattable thys,const AjPStr setname)7685 void ajFeattableSetDefname(AjPFeattable thys, const AjPStr setname)
7686 {
7687     if(ajStrGetLen(thys->Seqid))
7688     {
7689 	ajDebug("ajFeattableSetDefname already has a name '%S'\n", thys->Seqid);
7690 	return;
7691     }
7692 
7693     if(ajStrGetLen(setname))
7694 	ajStrAssignS(&thys->Seqid, setname);
7695 
7696     ajDebug("ajFeattableSetDefname set to  '%S'\n", setname);
7697 
7698     return;
7699 }
7700 
7701 
7702 
7703 
7704 /* @func ajFeattableSetLength *************************************************
7705 **
7706 ** Sets the length of a feature table with the length of the source sequence.
7707 **
7708 ** This is needed to reverse the table correctly
7709 **
7710 ** @param [u] thys [AjPFeattable] Feature table object
7711 ** @param [r] len [ajuint] Length
7712 ** @return [void]
7713 **
7714 ** @release 6.0.0
7715 ** @@
7716 **
7717 ******************************************************************************/
7718 
ajFeattableSetLength(AjPFeattable thys,ajuint len)7719 void ajFeattableSetLength(AjPFeattable thys, ajuint len)
7720 {
7721     thys->Len = len;
7722 
7723     return;
7724 }
7725 
7726 
7727 
7728 
7729 /* @func ajFeattableSetLinear *************************************************
7730 **
7731 ** Sets a feature table to be linear
7732 **
7733 ** @param [w] thys [AjPFeattable] Feature table
7734 ** @return [void]
7735 **
7736 ** @release 6.5.0
7737 ** @@
7738 ******************************************************************************/
7739 
ajFeattableSetLinear(AjPFeattable thys)7740 void ajFeattableSetLinear(AjPFeattable thys)
7741 {
7742     thys->Circular = ajFalse;
7743 
7744     return;
7745 }
7746 
7747 
7748 
7749 
7750 /* @func ajFeattableSetNuc ****************************************************
7751 **
7752 ** Sets the type of a feature table as nucleotide
7753 **
7754 ** @param [u] thys [AjPFeattable] Feature table object
7755 ** @return [void]
7756 **
7757 ** @release 4.0.0
7758 ** @@
7759 **
7760 ******************************************************************************/
7761 
ajFeattableSetNuc(AjPFeattable thys)7762 void ajFeattableSetNuc(AjPFeattable thys)
7763 {
7764     ajStrAssignEmptyC(&thys->Type, "N");
7765 
7766     return;
7767 }
7768 
7769 
7770 
7771 
7772 /* @func ajFeattableSetProt ***************************************************
7773 **
7774 ** Sets the type of a feature table as Protein
7775 **
7776 ** @param [u] thys [AjPFeattable] Feature table object
7777 ** @return [void]
7778 **
7779 ** @release 2.1.0
7780 ** @@
7781 **
7782 ******************************************************************************/
7783 
ajFeattableSetProt(AjPFeattable thys)7784 void ajFeattableSetProt(AjPFeattable thys)
7785 {
7786     ajStrAssignEmptyC(&thys->Type, "P");
7787 
7788     return;
7789 }
7790 
7791 
7792 
7793 
7794 /* @func ajFeattableSetRange **************************************************
7795 **
7796 ** Set the begin and end range for a feature table
7797 **
7798 ** @param [u] thys [AjPFeattable] Feature table object
7799 ** @param [r] fbegin [ajint] Begin position
7800 ** @param [r] fend   [ajint] End position
7801 ** @return [void]
7802 **
7803 ** @release 2.5.0
7804 ******************************************************************************/
7805 
ajFeattableSetRange(AjPFeattable thys,ajint fbegin,ajint fend)7806 void ajFeattableSetRange(AjPFeattable thys, ajint fbegin, ajint fend)
7807 {
7808     thys->Start = ajFeattablePosI(thys, 1, fbegin);
7809     thys->End   = ajFeattablePosII(thys->Len, thys->Start, fend);
7810 
7811     return;
7812 }
7813 
7814 
7815 
7816 
7817 /* @func ajFeattableSetReverse ************************************************
7818 **
7819 ** Sets a feature table to be reversed
7820 **
7821 ** @param [u] thys [AjPFeattable] Feature table
7822 ** @return [void]
7823 **
7824 ** @release 6.6.0
7825 ** @@
7826 ******************************************************************************/
7827 
ajFeattableSetReverse(AjPFeattable thys)7828 void ajFeattableSetReverse(AjPFeattable thys)
7829 {
7830     if(thys->Rev)
7831         thys->Rev = ajFalse;
7832     else
7833         thys->Rev = ajTrue;
7834 
7835     thys->Reversed = ajFalse;
7836 
7837     return;
7838 }
7839 
7840 
7841 
7842 
7843 /* @func ajFeattableReverse ***************************************************
7844 **
7845 ** Reverse the features in a feature table by iterating through and
7846 ** reversing all positions and strands.
7847 **
7848 ** @param [u] thys [AjPFeattable] Feature table object
7849 ** @return [void]
7850 **
7851 ** @release 2.5.0
7852 ******************************************************************************/
7853 
ajFeattableReverse(AjPFeattable thys)7854 void ajFeattableReverse(AjPFeattable  thys)
7855 {
7856     AjIList    iter = NULL;
7857     AjPFeature gf   = NULL;
7858 
7859     if(ajFeattableIsProt(thys))
7860 	return;
7861 
7862     if(!thys->Rev)			/* Not flagged for reversal */
7863 	return;
7864 
7865     iter = ajListIterNewread(thys->Features);
7866 
7867     while(!ajListIterDone(iter))
7868     {
7869 	gf = ajListIterGet(iter);
7870 
7871 	if((gf->Flags & AJFEATFLAG_REMOTEID) ||
7872 	   (gf->Flags & AJFEATFLAG_LABEL))
7873 	    continue;
7874 
7875 	ajFeatReverse(gf, thys->Len) ;
7876     }
7877 
7878     ajListIterDel(&iter);
7879 
7880     thys->Rev = ajFalse;
7881 
7882     if(thys->Reversed)
7883 	thys->Reversed = ajFalse;
7884     else
7885 	thys->Reversed = ajTrue;
7886 
7887     return;
7888 }
7889 
7890 
7891 
7892 
7893 /* @func ajFeatReverse ********************************************************
7894 **
7895 ** Reverse one feature by reversing all positions and strand.
7896 **
7897 ** @param [u] thys [AjPFeature] Feature object
7898 ** @param [r] ilen [ajint] Sequence length
7899 ** @return [void]
7900 **
7901 ** @release 2.5.0
7902 ******************************************************************************/
7903 
ajFeatReverse(AjPFeature thys,ajint ilen)7904 void ajFeatReverse(AjPFeature  thys, ajint ilen)
7905 {
7906     AjIList    iter = NULL;
7907     AjPFeature gf   = NULL;
7908     ajint itmp;
7909     ajint saveflags;
7910 
7911     ajDebug("ajFeatReverse ilen %d %x '%c' %d..%d %d..%d\n",
7912 	    ilen, thys->Flags, thys->Strand,
7913 	    thys->Start, thys->End, thys->Start2, thys->End2);
7914 
7915     saveflags = thys->Flags;
7916 
7917     if(thys->Start != thys->End)
7918     {
7919         if(thys->Strand == '-')
7920             thys->Strand = '+';
7921         else
7922             thys->Strand = '-';
7923     }
7924 
7925     itmp = thys->Start;
7926 
7927     if(thys->End)
7928 	thys->Start = 1 + ilen - thys->End;
7929     else
7930 	thys->Start = 0;
7931 
7932     if(itmp)
7933 	thys->End = 1 + ilen - itmp;
7934     else
7935 	thys->End = 0;
7936 
7937     itmp = thys->Start2;
7938     if(thys->End2)
7939 	thys->Start2 = 1 + ilen - thys->End2;
7940     else
7941 	thys->Start2 = 0;
7942 
7943     /* reverse the flags */
7944 
7945     if(saveflags & AJFEATFLAG_START_BEFORE_SEQ)
7946 	thys->Flags |= AJFEATFLAG_END_AFTER_SEQ;
7947     else
7948 	thys->Flags  &= ~AJFEATFLAG_END_AFTER_SEQ;
7949 
7950     if(saveflags & AJFEATFLAG_END_AFTER_SEQ)
7951 	thys->Flags |=  AJFEATFLAG_START_BEFORE_SEQ;
7952     else
7953 	thys->Flags &=  ~AJFEATFLAG_START_BEFORE_SEQ;
7954 
7955     if(saveflags & AJFEATFLAG_START_TWO)
7956 	thys->Flags |=  AJFEATFLAG_END_TWO;
7957     else
7958 	thys->Flags &=  ~AJFEATFLAG_END_TWO;
7959 
7960     if(saveflags & AJFEATFLAG_END_TWO)
7961 	thys->Flags |=  AJFEATFLAG_START_TWO;
7962     else
7963 	thys->Flags &=  ~AJFEATFLAG_START_TWO;
7964 
7965     if(saveflags & AJFEATFLAG_START_UNSURE)
7966 	thys->Flags |=  AJFEATFLAG_END_UNSURE;
7967     else
7968 	thys->Flags &=  ~AJFEATFLAG_END_UNSURE;
7969 
7970     if(saveflags & AJFEATFLAG_END_UNSURE)
7971 	thys->Flags |=  AJFEATFLAG_START_UNSURE;
7972     else
7973 	thys->Flags &=  ~AJFEATFLAG_START_UNSURE;
7974 
7975     if(itmp)
7976 	thys->End2 = 1 + ilen - itmp;
7977     else
7978 	thys->End2 = 0;
7979 
7980     /* thys->Frame is rather hard to guess ... leave alone for now */
7981 
7982     thys->Frame = 0;		/* set to unknown */
7983 
7984     /*ajDebug("     Reversed %x '%c' %d..%d %d..%d\n",
7985 	    thys->Flags, thys->Strand,
7986 	    thys->Start, thys->End, thys->Start2, thys->End2);*/
7987 
7988     if(thys->Subfeatures)
7989     {
7990         iter = ajListIterNewread(thys->Subfeatures);
7991         while(!ajListIterDone(iter))
7992         {
7993             gf = ajListIterGet(iter);
7994             ajFeatReverse(gf, ilen);
7995         }
7996         ajListIterDel(&iter);
7997     }
7998 
7999     return;
8000 }
8001 
8002 
8003 
8004 
8005 /* @func ajFeattableNewDna ****************************************************
8006 **
8007 ** Constructor for a new DNA feature table
8008 **
8009 ** @param [r] name [const AjPStr] Name for new feature table
8010 **                                (or NULL for unnamed)
8011 ** @return [AjPFeattable] Pointer to a new (empty) feature table
8012 ** @exception  'Mem_Failed' from memory allocation
8013 **
8014 ** @release 2.0.0
8015 ** @@
8016 **
8017 ******************************************************************************/
8018 
ajFeattableNewDna(const AjPStr name)8019 AjPFeattable ajFeattableNewDna(const AjPStr name)
8020 {
8021     AjPFeattable thys = NULL;
8022 
8023     /* Allocate the object... */
8024     thys = featTableNewS(name);
8025 
8026     ajStrAssignC(&thys->Type, "N");
8027 
8028     /*ajDebug("ajFeattableNewDna %x\n", thys);*/
8029 
8030     return thys;
8031 }
8032 
8033 
8034 
8035 
8036 /* @func ajFeattableNewSeq ****************************************************
8037 **
8038 ** Constructor for a new feature table for an existing sequence.
8039 ** The feature table type is determined by the sequence type.
8040 **
8041 ** @param [r] seq [const AjPSeq] Sequence object to provide the name and type
8042 ** @return [AjPFeattable] Pointer to a new (empty) feature table
8043 ** @exception  'Mem_Failed' from memory allocation
8044 **
8045 ** @release 2.0.0
8046 ** @@
8047 **
8048 ******************************************************************************/
8049 
ajFeattableNewSeq(const AjPSeq seq)8050 AjPFeattable ajFeattableNewSeq(const AjPSeq seq)
8051 {
8052     AjPFeattable thys = NULL;
8053 
8054     /* Allocate the object... */
8055     /*  AJNEW0(thys);  deleted by AJB */
8056 
8057     if(ajSeqIsProt(seq))
8058 	thys = ajFeattableNewProt(ajSeqGetNameS(seq));
8059     else
8060 	thys = ajFeattableNewDna(ajSeqGetNameS(seq));
8061 
8062     thys->Len = ajSeqGetLen(seq);
8063 
8064     return thys;
8065 }
8066 
8067 
8068 
8069 
8070 /* @func ajFeattableNewProt ***************************************************
8071 **
8072 ** Constructor for a new protein feature table
8073 **
8074 ** @param [r] name [const AjPStr] Name for new feature table
8075 **                                (or NULL for unnamed)
8076 ** @return [AjPFeattable] Pointer to a new (empty) feature table
8077 ** @exception  'Mem_Failed' from memory allocation
8078 **
8079 ** @release 2.0.0
8080 ** @@
8081 **
8082 ******************************************************************************/
8083 
ajFeattableNewProt(const AjPStr name)8084 AjPFeattable ajFeattableNewProt(const AjPStr name)
8085 {
8086     AjPFeattable thys = NULL;
8087 
8088     /* Allocate the object... */
8089     thys = featTableNewS(name);
8090 
8091     ajStrAssignC(&thys->Type, "P");
8092 
8093     /*ajDebug("ajFeattableNewProt %x\n", thys);*/
8094 
8095     return thys;
8096 }
8097 
8098 
8099 
8100 
8101 /* @funcstatic featTagvalNew **************************************************
8102 **
8103 ** Constructor for a feature tag-value pair
8104 **
8105 ** @param [r]   thys   [const AjPFeature]   Feature
8106 ** @param [r]   tag    [const AjPStr]   Tag name
8107 ** @param [r]   value  [const AjPStr]   Tag value
8108 ** @return [AjPTagval] New tag-value pair object
8109 **
8110 ** @release 2.0.0
8111 ** @@
8112 ******************************************************************************/
8113 
featTagvalNew(const AjPFeature thys,const AjPStr tag,const AjPStr value)8114 static AjPTagval featTagvalNew(const AjPFeature thys,
8115                                const AjPStr tag, const AjPStr value)
8116 {
8117     AjPTagval ret;
8118 
8119     if(thys->Protein)
8120 	ret = featTagvalNewProt(tag, value);
8121     else
8122 	ret = featTagvalNewDna(tag, value);
8123 
8124     return ret;
8125 }
8126 
8127 
8128 
8129 
8130 /* @func ajFeatGfftagAddCS ****************************************************
8131 **
8132 ** Constructor for a feature GFF3 tag-value pair
8133 **
8134 ** @param [u]   thys   [AjPFeature]   Feature
8135 ** @param [r]   tag    [const char*]  Tag name
8136 ** @param [r]   value  [const AjPStr] Tag value list
8137 ** @return [ajuint] Number of values added
8138 **
8139 ** @release 6.4.0
8140 ** @@
8141 ******************************************************************************/
8142 
ajFeatGfftagAddCS(AjPFeature thys,const char * tag,const AjPStr value)8143 ajuint ajFeatGfftagAddCS(AjPFeature thys,
8144                          const char* tag, const AjPStr value)
8145 {
8146     ajuint ret;
8147 
8148     AjPStr tagstr = NULL;
8149 
8150     tagstr= ajStrNewC(tag);
8151 
8152     ret = ajFeatGfftagAddSS(thys, tagstr, value);
8153 
8154     ajStrDel(&tagstr);
8155 
8156     return ret;
8157 }
8158 
8159 
8160 
8161 
8162 /* @func ajFeatGfftagAddSS ****************************************************
8163 **
8164 ** Constructor for a feature GFF3 tag-value pair
8165 **
8166 ** @param [u]   thys   [AjPFeature]   Feature
8167 ** @param [r]   tag    [const AjPStr]   Tag name
8168 ** @param [r]   value  [const AjPStr]   Tag value list
8169 ** @return [ajuint] Number of values added
8170 **
8171 ** @release 6.4.0
8172 ** @@
8173 ******************************************************************************/
8174 
ajFeatGfftagAddSS(AjPFeature thys,const AjPStr tag,const AjPStr value)8175 ajuint ajFeatGfftagAddSS(AjPFeature thys,
8176                          const AjPStr tag, const AjPStr value)
8177 {
8178     ajuint ret = 0;
8179     AjPTagval tagval;
8180     AjPStrTok handle = NULL;
8181     AjPStr tmpstr = NULL;
8182     AjBool predefinedTag = ajFalse;
8183 
8184     featInit();
8185     predefinedTag = featTagGff3PredefinedTag(tag);
8186 
8187     if(!thys->GffTags && predefinedTag)
8188         thys->GffTags = ajListNew();
8189 
8190     handle = ajStrTokenNewC(value, ",");
8191 
8192     while(ajStrTokenNextParse(handle, &tmpstr))
8193     {
8194         tagval = ajTagvalNewS(tag, tmpstr);
8195 
8196         ret++;
8197 
8198         if(predefinedTag)
8199             ajListPushAppend(thys->GffTags, tagval);
8200         else
8201             ajListPushAppend(thys->Tags, tagval);
8202         tagval = NULL;
8203     }
8204 
8205     ajStrTokenDel(&handle);
8206     ajStrDel(&tmpstr);
8207 
8208     return ret;
8209 }
8210 
8211 
8212 
8213 
8214 /* @func ajFeatGfftagAddTag ***************************************************
8215 **
8216 ** Sets a feature tag value, creating a new feature tag even if one
8217 ** already exists.
8218 **
8219 ** @param [u] thys [AjPFeature] Feature
8220 ** @param [r] tagval [const AjPTagval] Tag value pair
8221 ** @return [AjBool] ajTrue if value was valid
8222 **                  ajFalse if it was bad and was "corrected"
8223 **
8224 ** @release 6.5.0
8225 ** @@
8226 ******************************************************************************/
8227 
ajFeatGfftagAddTag(AjPFeature thys,const AjPTagval tagval)8228 AjBool ajFeatGfftagAddTag(AjPFeature thys, const AjPTagval tagval)
8229 {
8230     return ajFeatGfftagAddSS(thys,
8231                              MAJTAGVALGETTAG(tagval),
8232                              MAJTAGVALGETVALUE(tagval));
8233 }
8234 
8235 
8236 
8237 
8238 /* @funcstatic featTagvalNewDna ***********************************************
8239 **
8240 ** Constructor for a feature tag-value pair
8241 **
8242 ** @param [r]   tag    [const AjPStr]   Tag name
8243 ** @param [r]   value  [const AjPStr]   Tag value
8244 ** @return [AjPTagval] New tag-value pair object
8245 **
8246 ** @release 2.0.0
8247 ** @@
8248 ******************************************************************************/
8249 
featTagvalNewDna(const AjPStr tag,const AjPStr value)8250 static AjPTagval featTagvalNewDna(const AjPStr tag, const AjPStr value)
8251 {
8252     AjPTagval ret;
8253     const AjPStr tmptag = NULL;	     /* from AjPTable, don't delete */
8254     AjBool knowntag = ajTrue;
8255 
8256     featInit();
8257 
8258     tmptag = ajFeattagGetNameS(tag, FeatTagsTableDna, &knowntag);
8259 
8260     ret = ajTagvalNewS(tmptag, value);
8261 
8262     return ret;
8263 }
8264 
8265 
8266 
8267 
8268 /* @funcstatic featTagvalNewProt **********************************************
8269 **
8270 ** Constructor for a protein feature tag-value pair
8271 **
8272 ** @param [r]   tag    [const AjPStr]   Tag name
8273 ** @param [r]   value  [const AjPStr]   Tag value
8274 ** @return [AjPTagval] New tag-value pair object
8275 **
8276 ** @release 2.0.0
8277 ** @@
8278 ******************************************************************************/
8279 
featTagvalNewProt(const AjPStr tag,const AjPStr value)8280 static AjPTagval featTagvalNewProt(const AjPStr tag, const AjPStr value)
8281 {
8282     AjPTagval ret;
8283     const AjPStr tmptag = NULL;	     /* from AjPTable, don't delete */
8284     AjBool knowntag = ajTrue;
8285 
8286     featInit();
8287 
8288     tmptag = ajFeattagGetNameS(tag, FeatTagsTableProtein, &knowntag);
8289 
8290     ret = ajTagvalNewS(tmptag, value);
8291 
8292     return ret;
8293 }
8294 
8295 
8296 
8297 
8298 /* @funcstatic featTagval *****************************************************
8299 **
8300 ** Checks for the existence of a defined tag for a feature.
8301 **
8302 ** @param [r]   thys [const AjPFeature]  Feature object
8303 ** @param [r]   tag  [const AjPStr]      Tag name
8304 ** @return [AjPTagval] Returns the tag-value pair if found,
8305 **                       NULL if not found.
8306 **
8307 ** @release 2.0.0
8308 ** @@
8309 ******************************************************************************/
8310 
featTagval(const AjPFeature thys,const AjPStr tag)8311 static AjPTagval featTagval(const AjPFeature thys, const AjPStr tag)
8312 {
8313     AjIList iter    = NULL;
8314     AjPTagval ret = NULL;
8315     AjPTagval tv  = NULL;
8316 
8317     iter = ajListIterNewread(thys->Tags);
8318 
8319     while(!ajListIterDone(iter))
8320     {
8321 	tv = ajListIterGet(iter);
8322 
8323 	if(ajStrMatchCaseS(MAJTAGVALGETTAG(tv), tag))
8324 	{
8325 	    /* ajDebug("featTagval '%S' found value '%S'\n",
8326 	       tag, MAJTAGVALGETVALUE(tv)); */
8327 	    ret = tv;
8328 	    break;
8329 	}
8330     }
8331 
8332     ajListIterDel(&iter);
8333 
8334     /*
8335        if(!ret)
8336        ajDebug("featTagval '%S' not found\n", tag);
8337        */
8338 
8339 
8340     return ret;
8341 }
8342 
8343 
8344 
8345 
8346 /* @func ajFeattableNewFtable *************************************************
8347 **
8348 ** Makes a copy of a feature table.
8349 **
8350 ** For cases where we need a copy we can safely change and/or delete.
8351 **
8352 ** @param [r]   orig  [const AjPFeattable]  Original feature table
8353 ** @return [AjPFeattable] Feature table copy of the original
8354 **
8355 ** @release 6.2.0
8356 ** @@
8357 ******************************************************************************/
8358 
ajFeattableNewFtable(const AjPFeattable orig)8359 AjPFeattable ajFeattableNewFtable(const AjPFeattable orig)
8360 {
8361     AjPFeattable ret = NULL;
8362     AjIList iter;
8363     AjPFeature featorig;
8364     AjPFeature feat = NULL;
8365 
8366     if(!orig)
8367 	return NULL;
8368 
8369     ret = featTableNew();
8370 
8371     ajStrAssignS(&ret->Seqid, orig->Seqid);
8372     ajStrAssignS(&ret->Type, orig->Type);
8373 
8374     ajStrAssignS(&ret->Formatstr, orig->Formatstr);
8375     ret->Format    = orig->Format;
8376 
8377     ret->Groups    = orig->Groups;
8378     ret->Start     = orig->Start;
8379     ret->End       = orig->End;
8380     ret->Len       = orig->Len;
8381     ret->Offset    = orig->Offset;
8382     ret->Rev       = orig->Rev;
8383     ret->Reversed  = orig->Reversed;
8384     ret->Trimmed   = orig->Trimmed;
8385     ret->Circular  = orig->Circular;
8386 
8387     ret->Fpos      = orig->Fpos;
8388 
8389     ajStrAssignS(&ret->Db, orig->Db);
8390     ajStrAssignS(&ret->Setdb, orig->Setdb);
8391     ajStrAssignS(&ret->Full, orig->Full);
8392     ajStrAssignS(&ret->Qry, orig->Qry);
8393     ajStrAssignS(&ret->Filename, orig->Filename);
8394     ajStrAssignS(&ret->TextPtr, orig->TextPtr);
8395 
8396     iter = ajListIterNewread(orig->Features);
8397 
8398     while(!ajListIterDone(iter))
8399     {
8400 	featorig = ajListIterGet(iter);
8401 	feat = ajFeatNewFeat(featorig);
8402 	ajFeattableAdd(ret, feat);
8403     }
8404 
8405     ajListIterDel(&iter);
8406 
8407     return ret;
8408 }
8409 
8410 
8411 
8412 
8413 /* @func ajFeattableNewFtableLimit ********************************************
8414 **
8415 ** Makes a copy of a feature table using only a limited number of features.
8416 **
8417 ** For cases where we need a copy we can safely change and/or delete.
8418 **
8419 ** @param [r]   orig  [const AjPFeattable]  Original feature table
8420 ** @param [r]   limit  [ajint]  Limit to number of features copied
8421 ** @return [AjPFeattable] Feature table copy of the original
8422 **
8423 ** @release 6.2.0
8424 ** @@
8425 ******************************************************************************/
8426 
ajFeattableNewFtableLimit(const AjPFeattable orig,ajint limit)8427 AjPFeattable ajFeattableNewFtableLimit(const AjPFeattable orig, ajint limit)
8428 {
8429     AjPFeattable ret = NULL;
8430     AjIList iter;
8431     AjPFeature featorig;
8432     AjPFeature feat = NULL;
8433     ajint ift = 0;
8434 
8435     if(!orig)
8436 	return NULL;
8437 
8438     ret = featTableNew();
8439 
8440     ajStrAssignS(&ret->Seqid, orig->Seqid);
8441     ajStrAssignS(&ret->Type, orig->Type);
8442     ajStrAssignS(&ret->Formatstr, orig->Formatstr);
8443     ret->Format    = orig->Format;
8444     ret->Start     = orig->Start;
8445     ret->End       = orig->End;
8446     ret->Len       = orig->Len;
8447     ret->Groups    = orig->Groups;
8448 
8449     iter = ajListIterNewread(orig->Features);
8450 
8451     while(!ajListIterDone(iter) && (ift++ < limit))
8452     {
8453 	featorig = ajListIterGet(iter);
8454 	feat = ajFeatNewFeat(featorig);
8455 	ajFeattableAdd(ret, feat);
8456     }
8457 
8458     ajListIterDel(&iter);
8459 
8460     return ret;
8461 }
8462 
8463 
8464 
8465 
8466 /* @func ajFeatNewFeat ********************************************************
8467 **
8468 ** Makes a copy of a feature.
8469 **
8470 ** For cases where we need a copy we can safely change and/or delete.
8471 **
8472 ** @param [r]   orig  [const AjPFeature]  Original feature
8473 ** @return [AjPFeature] Feature  copy of the original
8474 ** @category new [AjPFeature] Copy constructor
8475 **
8476 ** @release 6.2.0
8477 ** @@
8478 ******************************************************************************/
8479 
ajFeatNewFeat(const AjPFeature orig)8480 AjPFeature ajFeatNewFeat(const AjPFeature orig)
8481 {
8482     AjPFeature ret;
8483     AjPFeature subfeat;
8484     AjIList iter;
8485     AjPTagval tvorig;
8486 
8487     ret = featFeatureNew();
8488 
8489     if(orig->Source)
8490         ajStrAssignS(&ret->Source, orig->Source);
8491     if(orig->Type)
8492         ajStrAssignS(&ret->Type, orig->Type);
8493     if(orig->Remote)
8494         ajStrAssignS(&ret->Remote, orig->Remote);
8495     if(orig->Label)
8496         ajStrAssignS(&ret->Label, orig->Label);
8497 
8498     ret->Protein = orig->Protein;
8499     ret->Start   = orig->Start;
8500     ret->End     = orig->End;
8501     ret->Start2  = orig->Start2;
8502     ret->End2    = orig->End2;
8503     ret->Score   = orig->Score;
8504     ret->Strand  = orig->Strand;
8505     ret->Frame   = orig->Frame;
8506     ret->Flags   = orig->Flags;
8507     ret->Group   = orig->Group;
8508     ret->Exon    = orig->Exon;
8509 
8510     if(orig->Subfeatures)
8511     {
8512         iter = ajListIterNewread(orig->Subfeatures);
8513 
8514         while(!ajListIterDone(iter))
8515         {
8516             subfeat = ajListIterGet(iter);
8517             ajListPushAppend(ret->Subfeatures, ajFeatNewFeat(subfeat));
8518         }
8519 
8520         ajListIterDel(&iter);
8521     }
8522 
8523     if(orig->Tags)
8524     {
8525         iter = ajListIterNewread(orig->Tags);
8526 
8527         while(!ajListIterDone(iter))
8528         {
8529             tvorig = ajListIterGet(iter);
8530             ajFeatTagAddTag(ret, tvorig);
8531         }
8532 
8533         ajListIterDel(&iter);
8534     }
8535 
8536     if(orig->GffTags)
8537     {
8538         iter = ajListIterNewread(orig->GffTags);
8539 
8540         while(!ajListIterDone(iter))
8541         {
8542             tvorig = ajListIterGet(iter);
8543             ajFeatGfftagAddTag(ret, tvorig);
8544         }
8545 
8546         ajListIterDel(&iter);
8547     }
8548 
8549     return ret;
8550 }
8551 
8552 
8553 
8554 
8555 /* @func ajFeatTrace **********************************************************
8556 **
8557 ** Traces (to the debug file) a feature object
8558 **
8559 ** @param [r]   thys  [const AjPFeature]  Feature
8560 ** @return [void]
8561 **
8562 ** @release 1.0.0
8563 ** @@
8564 ******************************************************************************/
8565 
ajFeatTrace(const AjPFeature thys)8566 void ajFeatTrace(const AjPFeature thys)
8567 {
8568     AjPStr flagstr = NULL;
8569     AjPFeature subft = NULL;
8570     AjIList iter = NULL;
8571     ajuint isub = 0;
8572 
8573     ajDebug("  address: %p\n", thys);
8574     ajDebug("  Source: '%S'\n", thys->Source);
8575     if(thys->Protein)
8576         ajDebug("  Type: '%S' protein: %B '%S'\n",
8577                 thys->Type, thys->Protein, ajFeatTypeProt(thys->Type));
8578     else
8579         ajDebug("  Type: '%S' protein: %B '%S'\n",
8580                 thys->Type, thys->Protein, ajFeatTypeNuc(thys->Type));
8581     ajDebug("  Location: %d..%d\n", thys->Start, thys->End);
8582     ajDebug("  Strand: '%c'\n", thys->Strand);
8583     ajDebug("  Frame: '%d'\n", thys->Frame);
8584     ajDebug("  Score: '%f'\n", thys->Score);
8585     ajDebug("  Start2: '%d'\n", thys->Start2);
8586     ajDebug("  End2: '%d'\n", thys->Start2);
8587     ajDebug("  RemoteId: '%S'\n", thys->Remote);
8588     ajDebug("  Label: '%S'\n", thys->Label);
8589 
8590     if(thys->Flags)
8591     {
8592         if(thys->Flags & AJFEATFLAG_START_BEFORE_SEQ)
8593             ajStrAppendC(&flagstr, "start_before ");
8594 
8595         if(thys->Flags & AJFEATFLAG_END_AFTER_SEQ)
8596             ajStrAppendC(&flagstr, "end_after ");
8597 
8598         if(thys->Flags & AJFEATFLAG_GENERATED)
8599             ajStrAppendC(&flagstr, "generated ");
8600 
8601         if(thys->Flags & AJFEATFLAG_BETWEEN_SEQ)
8602             ajStrAppendC(&flagstr, "between ");
8603 
8604         if(thys->Flags & AJFEATFLAG_START_TWO)
8605             ajStrAppendC(&flagstr, "start2 ");
8606 
8607         if(thys->Flags & AJFEATFLAG_END_TWO)
8608             ajStrAppendC(&flagstr, "end2 ");
8609 
8610         if(thys->Flags & AJFEATFLAG_POINT)
8611             ajStrAppendC(&flagstr, "point ");
8612 
8613         if(thys->Flags & AJFEATFLAG_COMPLEMENT_MAIN)
8614             ajStrAppendC(&flagstr, "overall_complement ");
8615 
8616         if(thys->Flags & AJFEATFLAG_MULTIPLE)
8617             ajStrAppendC(&flagstr, "multiple ");
8618 
8619         if(thys->Flags & AJFEATFLAG_ORDER)
8620             ajStrAppendC(&flagstr, "order ");
8621 
8622         if(thys->Flags & AJFEATFLAG_REMOTEID)
8623             ajStrAppendC(&flagstr, "remote_id ");
8624 
8625         if(thys->Flags & AJFEATFLAG_LABEL)
8626             ajStrAppendC(&flagstr, "label ");
8627 
8628         if(thys->Flags & AJFEATFLAG_START_UNSURE)
8629             ajStrAppendC(&flagstr, "start_unsure ");
8630 
8631         if(thys->Flags & AJFEATFLAG_END_UNSURE)
8632             ajStrAppendC(&flagstr, "end_unsure ");
8633 
8634         ajStrCutEnd(&flagstr, 1);
8635         ajDebug("  Flags: '%x' (%S)\n", thys->Flags, flagstr);
8636     }
8637     else
8638     {
8639         ajDebug("  Flags: '%x'\n", thys->Flags);
8640     }
8641 
8642     ajDebug("  Group: '%u' exon: %u\n", thys->Group, thys->Exon);
8643 
8644     ajFeatTagTrace(thys);
8645     ajStrDel(&flagstr);
8646 
8647     if(ajListGetLength(thys->Subfeatures))
8648     {
8649         ajDebug("  Subfeatures: %Lu\n\n", ajListGetLength(thys->Subfeatures));
8650         isub = 0;
8651         iter = ajListIterNewread(thys->Subfeatures);
8652         while(!ajListIterDone(iter))
8653         {
8654             ajDebug("Subfeature[%u] ...\n", ++isub);
8655             subft = ajListIterGet(iter);
8656             ajFeatTrace(subft);
8657         }
8658         ajListIterDel(&iter);
8659         ajDebug("  Sub %u done\n\n", isub);
8660     }
8661 
8662     return;
8663 }
8664 
8665 
8666 
8667 
8668 /* @func ajFeatTagTrace *******************************************************
8669 **
8670 ** Traces (to the debug file) the tag-value pairs of a feature object
8671 **
8672 ** @param [r]   thys  [const AjPFeature]  Feature
8673 ** @return [void]
8674 **
8675 ** @release 2.0.0
8676 ** @@
8677 ******************************************************************************/
8678 
ajFeatTagTrace(const AjPFeature thys)8679 void ajFeatTagTrace(const AjPFeature thys)
8680 {
8681     AjIList iter;
8682     ajint i = 0;
8683     AjPTagval tv = NULL;
8684 
8685     ajFeatGfftagTrace(thys);
8686 
8687     iter = ajListIterNewread(thys->Tags);
8688 
8689     while(!ajListIterDone(iter))
8690     {
8691 	tv = ajListIterGet(iter);
8692 	ajDebug(" %3d  %S : '%S'\n",
8693                 ++i, ajTagvalGetTag(tv), ajTagvalGetValue(tv));
8694     }
8695 
8696     ajListIterDel(&iter);
8697 
8698     return;
8699 }
8700 
8701 
8702 
8703 
8704 /* @func ajFeatGfftagTrace ****************************************************
8705 **
8706 ** Traces (to the debug file) the GFF tag-value pairs of a feature object
8707 **
8708 ** @param [r]   thys  [const AjPFeature]  Feature
8709 ** @return [void]
8710 **
8711 ** @release 6.5.0
8712 ** @@
8713 ******************************************************************************/
8714 
ajFeatGfftagTrace(const AjPFeature thys)8715 void ajFeatGfftagTrace(const AjPFeature thys)
8716 {
8717     AjIList iter;
8718     ajint i = 0;
8719     AjPTagval tv = NULL;
8720 
8721     iter = ajListIterNewread(thys->GffTags);
8722 
8723     while(!ajListIterDone(iter))
8724     {
8725 	tv = ajListIterGet(iter);
8726 	ajDebug(" %3d  %S : '%S'\n",
8727                 ++i, ajTagvalGetTag(tv), ajTagvalGetValue(tv));
8728     }
8729 
8730     ajListIterDel(&iter);
8731 
8732     return;
8733 }
8734 
8735 
8736 
8737 
8738 /* @func ajFeatGfftagsNew *****************************************************
8739 **
8740 ** Creates a structure holding GFF tag value pairs
8741 **
8742 ** @return [AjPFeatGfftags] GFF tag-values structure
8743 **
8744 ** @release 6.4.0
8745 ** @@
8746 ******************************************************************************/
8747 
ajFeatGfftagsNew(void)8748 AjPFeatGfftags ajFeatGfftagsNew(void)
8749 {
8750     AjPFeatGfftags ret = NULL;
8751 
8752     AJNEW0(ret);
8753 
8754     return ret;
8755 }
8756 
8757 
8758 
8759 
8760 /* @func ajFeatGfftagsDel *****************************************************
8761 **
8762 ** Destroys a structure holding GFF tag value pairs
8763 **
8764 ** @param [d] Pthys [AjPFeatGfftags*] GFF tag-values structure
8765 ** @return [void]
8766 **
8767 ** @release 6.4.0
8768 ** @@
8769 ******************************************************************************/
8770 
ajFeatGfftagsDel(AjPFeatGfftags * Pthys)8771 void ajFeatGfftagsDel(AjPFeatGfftags *Pthys)
8772 {
8773     AjPFeatGfftags thys;
8774 
8775     if(!Pthys)
8776         return;
8777     if(!*Pthys)
8778         return;
8779 
8780     thys = *Pthys;
8781 
8782     ajStrDel(&thys->Id);
8783     ajStrDel(&thys->Name);
8784     ajStrDel(&thys->Alias);
8785     ajStrDel(&thys->Parent);
8786     ajStrDel(&thys->Target);
8787     ajStrDel(&thys->Gap);
8788     ajStrDel(&thys->DerivesFrom);
8789     ajStrDel(&thys->Note);
8790     ajStrDel(&thys->Dbxref);
8791     ajStrDel(&thys->OntologyTerm);
8792     ajStrDel(&thys->IsCircular);
8793 
8794     AJFREE(*Pthys);
8795 
8796     return;
8797 }
8798 
8799 
8800 
8801 
8802 /* @func ajFeatGetGfftags *****************************************************
8803 **
8804 ** Returns an object with all feature GFF tag-value pairs
8805 **
8806 ** @param [r]   thys  [const AjPFeature]  Feature
8807 ** @return [AjPFeatGfftags] Gff tags object
8808 **
8809 ** @release 6.4.0
8810 ** @@
8811 ******************************************************************************/
8812 
ajFeatGetGfftags(const AjPFeature thys)8813 AjPFeatGfftags ajFeatGetGfftags(const AjPFeature thys)
8814 {
8815     AjPFeatGfftags ret = NULL;
8816     AjIList iter;
8817     AjPStr *Pvalstr = NULL;
8818     AjPStr tmpstr = NULL;
8819     AjPTagval tv = NULL;
8820     AjBool multivalues = ajFalse;
8821     const AjPStr tvtag = NULL;
8822 
8823     ret = ajFeatGfftagsNew();
8824 
8825     if(!thys)
8826         return ret;
8827 
8828     if(!ajListGetLength(thys->GffTags))
8829         return ret;
8830 
8831     iter = ajListIterNewread(thys->GffTags);
8832 
8833     while(!ajListIterDone(iter))
8834     {
8835         tv = ajListIterGet(iter);
8836         tvtag = ajTagvalGetTag(tv);
8837 
8838         Pvalstr = NULL;
8839         multivalues = ajFalse;
8840 
8841         if(ajStrMatchC(tvtag, "ID"))
8842             Pvalstr = &ret->Id;
8843         else if(ajStrMatchC(tvtag, "Name"))
8844             Pvalstr = &ret->Name;
8845         else if(ajStrMatchC(tvtag, "Alias"))
8846         {
8847             multivalues = ajTrue;
8848             Pvalstr = &ret->Alias;
8849         }
8850         else if(ajStrMatchC(tvtag, "Parent"))
8851         {
8852             multivalues = ajTrue;
8853             Pvalstr = &ret->Parent;
8854         }
8855         else if(ajStrMatchC(tvtag, "Target"))
8856             Pvalstr = &ret->Target;
8857         else if(ajStrMatchC(tvtag, "Gap"))
8858             Pvalstr = &ret->Gap;
8859         else if(ajStrMatchC(tvtag, "Derives_from"))
8860             Pvalstr = &ret->DerivesFrom;
8861         else if(ajStrMatchC(tvtag, "Note"))
8862         {
8863             multivalues = ajTrue;
8864             Pvalstr = &ret->Note;
8865         }
8866         else if(ajStrMatchC(tvtag, "Dbxref"))
8867         {
8868             multivalues = ajTrue;
8869             Pvalstr = &ret->Dbxref;
8870         }
8871         else if(ajStrMatchC(tvtag, "Ontology_term"))
8872         {
8873             multivalues = ajTrue;
8874             Pvalstr = &ret->OntologyTerm;
8875         }
8876         else if(ajStrMatchC(tvtag, "Is_circular"))
8877             Pvalstr = &ret->IsCircular;
8878 
8879         if(Pvalstr)
8880         {
8881             ajStrAssignS(&tmpstr, ajTagvalGetValue(tv));
8882             ajStrFmtPercentEncodeC(&tmpstr, ";=&%,");
8883             if(multivalues)
8884             {
8885                 if(ajStrGetLen(*Pvalstr))
8886                     ajStrAppendC(Pvalstr, ",");
8887                 ajStrAppendS(Pvalstr, tmpstr);
8888             }
8889             else
8890                 ajStrAssignS(Pvalstr, tmpstr);
8891         }
8892     }
8893 
8894     ajListIterDel(&iter);
8895     ajStrDel(&tmpstr);
8896 
8897     return ret;
8898 }
8899 
8900 
8901 
8902 
8903 /* @func ajFeatGetId **********************************************************
8904 **
8905 ** Returns the GFF ID tag of a feature with GFF tag-value pairs
8906 **
8907 ** @param [r]   thys  [const AjPFeature]  Feature
8908 ** @return [const AjPStr] ID tag
8909 **
8910 ** @release 6.5.0
8911 ** @@
8912 ******************************************************************************/
8913 
ajFeatGetId(const AjPFeature thys)8914 const AjPStr ajFeatGetId(const AjPFeature thys)
8915 {
8916     AjIList iter;
8917     AjPTagval tv = NULL;
8918 
8919     if(!thys)
8920         return NULL;
8921 
8922     if(!ajListGetLength(thys->GffTags))
8923         return NULL;
8924 
8925     iter = ajListIterNewread(thys->GffTags);
8926 
8927     while(!ajListIterDone(iter))
8928     {
8929         tv = ajListIterGet(iter);
8930 
8931         if(ajStrMatchC(MAJTAGVALGETTAG(tv), "Id"))
8932         {
8933             ajListIterDel(&iter);
8934             return MAJTAGVALGETVALUE(tv);
8935         }
8936     }
8937 
8938     return NULL;
8939 }
8940 
8941 
8942 
8943 
8944 /* @func ajFeatGetParent ******************************************************
8945 **
8946 ** Returns the GFF Parent tag of a feature with GFF tag-value pairs
8947 **
8948 ** @param [r]   thys  [const AjPFeature]  Feature
8949 ** @return [const AjPStr] Parent tag
8950 **
8951 ** @release 6.4.0
8952 ** @@
8953 ******************************************************************************/
8954 
ajFeatGetParent(const AjPFeature thys)8955 const AjPStr ajFeatGetParent(const AjPFeature thys)
8956 {
8957     AjIList iter;
8958     AjPTagval tv = NULL;
8959 
8960     if(!thys)
8961         return NULL;
8962 
8963     if(!ajListGetLength(thys->GffTags))
8964         return NULL;
8965 
8966     iter = ajListIterNewread(thys->GffTags);
8967 
8968     while(!ajListIterDone(iter))
8969     {
8970         tv = ajListIterGet(iter);
8971 
8972         if(ajStrMatchC(MAJTAGVALGETTAG(tv), "Parent"))
8973         {
8974             ajListIterDel(&iter);
8975             return MAJTAGVALGETVALUE(tv);
8976         }
8977     }
8978 
8979     return NULL;
8980 }
8981 
8982 
8983 
8984 
8985 /* @func ajFeatTagIter ********************************************************
8986 **
8987 ** Returns an iterator over all feature tag-value pairs
8988 **
8989 ** @param [r]   thys  [const AjPFeature]  Feature
8990 ** @return [AjIList] List iterator
8991 **
8992 ** @release 2.0.0
8993 ** @@
8994 ******************************************************************************/
8995 
ajFeatTagIter(const AjPFeature thys)8996 AjIList ajFeatTagIter(const AjPFeature thys)
8997 {
8998     return ajListIterNewread(thys->Tags);
8999 }
9000 
9001 
9002 
9003 
9004 /* @func ajFeatSubIter ********************************************************
9005 **
9006 ** Returns an iterator over all subfeaturers
9007 **
9008 ** @param [r]   thys  [const AjPFeature]  Feature
9009 ** @return [AjIList] List iterator
9010 **
9011 ** @release 6.4.0
9012 ** @@
9013 ******************************************************************************/
9014 
ajFeatSubIter(const AjPFeature thys)9015 AjIList ajFeatSubIter(const AjPFeature thys)
9016 {
9017     if(!ajListGetLength(thys->Subfeatures))
9018         return NULL;
9019 
9020     return ajListIterNewread(thys->Subfeatures);
9021 }
9022 
9023 
9024 
9025 
9026 /* @func ajFeatTagval *********************************************************
9027 **
9028 ** Returns the tag-value pairs of a feature object
9029 **
9030 ** @param [u]  iter  [AjIList] List iterator from ajFeatTagIter
9031 ** @param [w] Ptagnam [AjPStr*] Tag name
9032 ** @param [w] Ptagval [AjPStr*] Tag val
9033 ** @return [AjBool] ajTrue if another tag-value pair was returned
9034 **
9035 ** @release 2.0.0
9036 ** @@
9037 ******************************************************************************/
9038 
ajFeatTagval(AjIList iter,AjPStr * Ptagnam,AjPStr * Ptagval)9039 AjBool ajFeatTagval(AjIList iter, AjPStr* Ptagnam, AjPStr* Ptagval)
9040 {
9041     AjPTagval tv = NULL;
9042 
9043     tv = ajListIterGet(iter);
9044 
9045     if(!tv)
9046 	return ajFalse;
9047 
9048     ajStrAssignS(Ptagnam, MAJTAGVALGETTAG(tv));
9049     ajStrAssignS(Ptagval, MAJTAGVALGETVALUE(tv));
9050 
9051     return ajTrue;
9052 }
9053 
9054 
9055 
9056 
9057 /* @func ajFeattableTrace *****************************************************
9058 **
9059 ** Traces (to the debug file) a complete feature table
9060 **
9061 ** @param [r]   thys  [const AjPFeattable]  Feature table
9062 ** @return [void]
9063 **
9064 ** @release 2.0.0
9065 ** @@
9066 ******************************************************************************/
9067 
ajFeattableTrace(const AjPFeattable thys)9068 void ajFeattableTrace(const AjPFeattable thys)
9069 {
9070     AjIList iter  = NULL;
9071     AjPFeature ft = NULL;
9072     ajint i = 0;
9073 
9074     ajDebug("== ajFeattableTrace Start ==\n");
9075 
9076     if(!thys)
9077     {
9078 	ajDebug("NULL table\n");
9079 	return;
9080     }
9081 
9082     ajDebug("  Seqid: '%S'\n", thys->Seqid);
9083 
9084     iter = ajListIterNew(thys->Features);
9085 
9086     while(!ajListIterDone(iter))
9087     {
9088 	ft = ajListIterGet(iter);
9089 	ajDebug("Features[%d]\n", ++i);
9090 	ajFeatTrace(ft);
9091     }
9092 
9093     ajListIterDel(&iter);
9094 
9095     ajDebug("== ajFeattableTrace Done ==\n");
9096     return;
9097 }
9098 
9099 
9100 
9101 
9102 /* @func ajFeatTypeNuc ********************************************************
9103 **
9104 ** Given a feature type name,
9105 ** returns the valid feature type for the internal DNA feature table
9106 **
9107 ** @param [r]   type  [const AjPStr] Type name
9108 ** @return [const AjPStr] Valid feature type
9109 **
9110 ** @release 6.0.0
9111 ** @@
9112 ******************************************************************************/
9113 
ajFeatTypeNuc(const AjPStr type)9114 const AjPStr ajFeatTypeNuc(const AjPStr type)
9115 {
9116     if(!FeatInitDone)
9117 	featInit();
9118 
9119     return ajFeattypeGetExternal(type, FeatTypeTableDna);
9120 }
9121 
9122 
9123 
9124 
9125 /* @func ajFeatTypeProt *******************************************************
9126 **
9127 ** Given a feature type name,
9128 ** returns the valid feature type for the internal protein feature table
9129 **
9130 ** @param [r]   type  [const AjPStr] Type name
9131 ** @return [const AjPStr] Valid feature type
9132 **
9133 ** @release 6.0.0
9134 ** @@
9135 ******************************************************************************/
9136 
ajFeatTypeProt(const AjPStr type)9137 const AjPStr ajFeatTypeProt(const AjPStr type)
9138 {
9139     if(!FeatInitDone)
9140         featInit();
9141 
9142     return ajFeattypeGetExternal(type, FeatTypeTableProtein);
9143 }
9144 
9145 
9146 
9147 
9148 /* @funcstatic featTypeDna ****************************************************
9149 **
9150 ** Given a feature type name,
9151 ** returns the valid feature type for the internal DNA feature table
9152 **
9153 ** @param [r]   type  [const AjPStr] Type name
9154 ** @return [const AjPStr] Valid feature type
9155 **
9156 ** @release 2.0.0
9157 ** @@
9158 ******************************************************************************/
9159 
featTypeDna(const AjPStr type)9160 static const AjPStr featTypeDna(const AjPStr type)
9161 {
9162     if(!FeatInitDone)
9163         featInit();
9164 
9165     return featTableTypeInternal(type, FeatTypeTableDna);
9166 }
9167 
9168 
9169 
9170 
9171 /* @funcstatic featTypeProt ***************************************************
9172 **
9173 ** Given a feature type name,
9174 ** returns the valid feature type for the internal protein feature table
9175 **
9176 ** @param [r]   type  [const AjPStr] Type name
9177 ** @return [const AjPStr] Valid feature type
9178 **
9179 ** @release 2.0.0
9180 ** @@
9181 ******************************************************************************/
9182 
featTypeProt(const AjPStr type)9183 static const AjPStr featTypeProt(const AjPStr type)
9184 {
9185     if(!FeatInitDone)
9186         featInit();
9187 
9188     return featTableTypeInternal(type, FeatTypeTableProtein);
9189 }
9190 
9191 
9192 
9193 
9194 /* @funcstatic featTypeDnaLimit ***********************************************
9195 **
9196 ** Given a feature type name,
9197 ** returns the valid feature type for the internal DNA feature table
9198 ** following alternative names until a unique name is found
9199 **
9200 ** @param [r]   type  [const AjPStr] Type name
9201 ** @return [const AjPStr] Valid feature type
9202 **
9203 ** @release 6.1.0
9204 ** @@
9205 ******************************************************************************/
9206 
featTypeDnaLimit(const AjPStr type)9207 static const AjPStr featTypeDnaLimit(const AjPStr type)
9208 {
9209     if(!FeatInitDone)
9210         featInit();
9211 
9212     return featTableTypeInternalLimit(type, FeatTypeTableDna);
9213 }
9214 
9215 
9216 
9217 
9218 /* @funcstatic featTypeProtLimit **********************************************
9219 **
9220 ** Given a feature type name,
9221 ** returns the valid feature type for the internal protein feature table
9222 ** following alternative names until a unique name is found
9223 **
9224 ** @param [r]   type  [const AjPStr] Type name
9225 ** @return [const AjPStr] Valid feature type
9226 **
9227 ** @release 6.1.0
9228 ** @@
9229 ******************************************************************************/
9230 
featTypeProtLimit(const AjPStr type)9231 static const AjPStr featTypeProtLimit(const AjPStr type)
9232 {
9233     if(!FeatInitDone)
9234         featInit();
9235 
9236     return featTableTypeInternalLimit(type, FeatTypeTableProtein);
9237 }
9238 
9239 
9240 
9241 
9242 /* @funcstatic featTypeTestDnaWild ********************************************
9243 **
9244 ** Given a feature type name,
9245 ** returns the valid feature type for the internal DNA feature table
9246 ** following alternative names until a matching wildcard name is found
9247 **
9248 ** @param [r]   type  [const AjPStr] Type name
9249 ** @param [r]   str   [const AjPStr] Wildcard name
9250 ** @return [AjBool] True if a match is found
9251 **
9252 ** @release 6.2.0
9253 ** @@
9254 ******************************************************************************/
9255 
featTypeTestDnaWild(const AjPStr type,const AjPStr str)9256 static AjBool featTypeTestDnaWild(const AjPStr type, const AjPStr str)
9257 {
9258     if(!FeatInitDone)
9259         featInit();
9260 
9261     return featTableTypeTestWild(type, FeatTypeTableDna, str);
9262 }
9263 
9264 
9265 
9266 
9267 /* @funcstatic featTypeTestProtWild *******************************************
9268 **
9269 ** Given a feature type name,
9270 ** returns the valid feature type for the internal protein feature table
9271 ** following alternative names until a unique name is found
9272 **
9273 ** @param [r]   type  [const AjPStr] Type name
9274 ** @param [r]   str   [const AjPStr] Wildcard name
9275 ** @return [AjBool] True if a match is found
9276 **
9277 ** @release 6.2.0
9278 ** @@
9279 ******************************************************************************/
9280 
featTypeTestProtWild(const AjPStr type,const AjPStr str)9281 static AjBool featTypeTestProtWild(const AjPStr type, const AjPStr str)
9282 {
9283     if(!FeatInitDone)
9284         featInit();
9285 
9286     return featTableTypeTestWild(type, FeatTypeTableProtein, str);
9287 }
9288 
9289 
9290 
9291 
9292 /* @funcstatic featTagDna *****************************************************
9293 **
9294 ** Given a feature tag name,
9295 ** returns the valid feature tag for the internal DNA feature table
9296 **
9297 ** @param [r]   thys  [const AjPStr] Tag name
9298 ** @param [w]   knowntag  [AjBool*] ajTrue if the tag was found in the
9299 **                                  list of known tags
9300 ** @return [const AjPStr] Valid feature tag name
9301 **
9302 ** @release 2.0.0
9303 ** @@
9304 ******************************************************************************/
9305 
featTagDna(const AjPStr thys,AjBool * knowntag)9306 static const AjPStr featTagDna(const AjPStr thys, AjBool* knowntag)
9307 {
9308     featInit();
9309 
9310     return ajFeattagGetNameS(thys, FeatTagsTableDna, knowntag);
9311 }
9312 
9313 
9314 
9315 
9316 /* @funcstatic featTagProt ****************************************************
9317 **
9318 ** Given a feature tag name,
9319 ** returns the valid feature tag for the internal protein feature table
9320 **
9321 ** @param [r]   thys  [const AjPStr] Tag name
9322 ** @param [w]   knowntag  [AjBool*] ajTrue if the tag was found in the
9323 **                                  list of known tags
9324 ** @return [const AjPStr] Valid feature tag name
9325 **
9326 ** @release 2.0.0
9327 ** @@
9328 ******************************************************************************/
9329 
featTagProt(const AjPStr thys,AjBool * knowntag)9330 static const AjPStr featTagProt(const AjPStr thys, AjBool* knowntag)
9331 {
9332     featInit();
9333 
9334     return ajFeattagGetNameS(thys, FeatTagsTableProtein, knowntag);
9335 }
9336 
9337 
9338 
9339 
9340 /* @func ajFeattypeGetExternal ************************************************
9341 **
9342 ** Given a feature type name,
9343 ** returns the valid feature type for a feature table
9344 **
9345 ** @param [r]   type  [const AjPStr] Type name
9346 ** @param [r]   table [const AjPTable]  Feature table
9347 ** @return [const AjPStr] Valid feature type
9348 **
9349 ** @release 6.4.0
9350 ** @@
9351 ******************************************************************************/
9352 
ajFeattypeGetExternal(const AjPStr type,const AjPTable table)9353 const AjPStr ajFeattypeGetExternal(const AjPStr type,
9354                                    const AjPTable table)
9355 {
9356     static const AjPStr ret = NULL;
9357     static const AjPStr retkey = NULL;
9358     AjPStr defaultid = NULL;
9359     AjPStr tmpstr = NULL;
9360     ajlong i;
9361 
9362     retkey = ajTablestrFetchkeyS(table, type);
9363 
9364     if(!retkey)
9365     {
9366         defaultid = ajStrNew();
9367         retkey = ajTableFetchS(table, defaultid);
9368         ajStrDel(&defaultid);
9369         ajDebug("ajFeattypeGetExternal '%S' not in external table %x, "
9370                 "use default '%S'\n", type, table, retkey);
9371     }
9372 
9373     ret = ajTableFetchS(table, retkey);
9374     /*ajDebug("ajFeattypeGetExternal a '%S' found in internal table as"
9375       " '%S' = '%S\n", type, retkey, ret);*/
9376 
9377     if(ajStrGetCharLast(ret) != ';')
9378     {
9379         retkey = ret;
9380         ret = ajTableFetchS(table, retkey);
9381         ajDebug("ajFeattypeGetExternal b '%S' found in internal table"
9382                 " as '%S' = '%S\n", type, retkey, ret);
9383     }
9384 
9385     if(ajStrGetCharLast(ret) == ';')
9386     {
9387         if(ajStrGetCharFirst(ret) == ';')
9388         {
9389             ret = retkey;
9390         }
9391         else
9392         {
9393             i = ajStrFindAnyK(ret, ';');
9394             ajStrAssignSubS(&tmpstr, ret, 0, i-1);
9395             /*ajDebug("ajFeattypeGetExternal '%S' is an alias for '%S'\n",
9396               retkey, tmpstr);*/
9397             ret = ajTablestrFetchkeyS(table, tmpstr);
9398 
9399             if(!ret)	  /* oops, back to the previous one */
9400             {
9401                 ajFeatWarn("ajFeattypeGetExternal failed to find"
9402                          " '%S' alias '%S",
9403                          type, tmpstr);
9404                 ret = ajTableFetchS(table, retkey);
9405             }
9406 
9407             ajStrDel(&tmpstr);
9408         }
9409     }
9410 
9411     /*ajDebug("ajFeattypeGetExternal result '%S'\n",
9412       ret);*/
9413 
9414     return ret;
9415 }
9416 
9417 
9418 
9419 
9420 /* @func ajFeattypeGetInternal ************************************************
9421 **
9422 ** Given a feature type name,
9423 ** returns the valid feature type for an internal feature table
9424 **
9425 ** @param [r]   type  [const AjPStr] Type name
9426 ** @return [const AjPStr] Valid feature type
9427 **
9428 ** @release 6.4.0
9429 ** @@
9430 ******************************************************************************/
9431 
ajFeattypeGetInternal(const AjPStr type)9432 const AjPStr ajFeattypeGetInternal(const AjPStr type)
9433 {
9434     const AjPStr ret = NULL;
9435 
9436     if(!FeatInitDone)
9437         featInit();
9438 
9439     ret = featTableTypeInternal(type, FeatTypeTableDna);
9440     if(ret)
9441         return ret;
9442 
9443     return featTableTypeInternal(type, FeatTypeTableProtein);
9444 }
9445 
9446 
9447 
9448 
9449 /* @func ajFeattypeGetInternalEmbl ********************************************
9450 **
9451 ** Given a feature type name,
9452 ** returns the valid feature type for an EMBL format feature table
9453 **
9454 ** @param [r]   type  [const AjPStr] Type name
9455 ** @return [const AjPStr] Valid feature type
9456 **
9457 ** @release 6.4.0
9458 ** @@
9459 ******************************************************************************/
9460 
ajFeattypeGetInternalEmbl(const AjPStr type)9461 const AjPStr ajFeattypeGetInternalEmbl(const AjPStr type)
9462 {
9463     if(!FeatInitDone)
9464 	featInit();
9465 
9466     if(!FeatTypeTableEmbl)
9467         ajFeatVocabInitNuc("embl");
9468 
9469     return featTableTypeInternal(type, FeatTypeTableEmbl);
9470 }
9471 
9472 
9473 
9474 
9475 /* @func ajFeattypeGetInternalNuc *********************************************
9476 **
9477 ** Given a feature type name,
9478 ** returns the valid feature type for an internal feature table
9479 **
9480 ** @param [r]   type  [const AjPStr] Type name
9481 ** @return [const AjPStr] Valid feature type
9482 **
9483 ** @release 6.4.0
9484 ** @@
9485 ******************************************************************************/
9486 
ajFeattypeGetInternalNuc(const AjPStr type)9487 const AjPStr ajFeattypeGetInternalNuc(const AjPStr type)
9488 {
9489     if(!FeatInitDone)
9490 	featInit();
9491 
9492     return featTableTypeInternal(type, FeatTypeTableDna);
9493 }
9494 
9495 
9496 
9497 
9498 /* @func ajFeattypeGetInternalPir *********************************************
9499 **
9500 ** Given a feature type name,
9501 ** returns the valid feature type for an internal feature table
9502 **
9503 ** @param [r]   type  [const AjPStr] Type name
9504 ** @return [const AjPStr] Valid feature type
9505 **
9506 ** @release 6.4.0
9507 ** @@
9508 ******************************************************************************/
9509 
ajFeattypeGetInternalPir(const AjPStr type)9510 const AjPStr ajFeattypeGetInternalPir(const AjPStr type)
9511 {
9512     if(!FeatInitDone)
9513 	featInit();
9514 
9515     if(!FeatTypeTablePir)
9516         ajFeatVocabInitProt("pir");
9517 
9518     return featTableTypeInternal(type, FeatTypeTablePir);
9519 }
9520 
9521 
9522 
9523 
9524 /* @func ajFeattypeGetInternalProt ********************************************
9525 **
9526 ** Given a feature type name,
9527 ** returns the valid feature type for an internal feature table
9528 **
9529 ** @param [r]   type  [const AjPStr] Type name
9530 ** @return [const AjPStr] Valid feature type
9531 **
9532 ** @release 6.4.0
9533 ** @@
9534 ******************************************************************************/
9535 
ajFeattypeGetInternalProt(const AjPStr type)9536 const AjPStr ajFeattypeGetInternalProt(const AjPStr type)
9537 {
9538     if(!FeatInitDone)
9539 	featInit();
9540 
9541     return featTableTypeInternal(type, FeatTypeTableProtein);
9542 }
9543 
9544 
9545 
9546 
9547 /* @func ajFeattypeGetInternalRefseqp *****************************************
9548 **
9549 ** Given a feature type name,
9550 ** returns the valid feature type for a REFSEQP format feature table
9551 **
9552 ** @param [r]   type  [const AjPStr] Type name
9553 ** @return [const AjPStr] Valid feature type
9554 **
9555 ** @release 6.4.0
9556 ** @@
9557 ******************************************************************************/
9558 
ajFeattypeGetInternalRefseqp(const AjPStr type)9559 const AjPStr ajFeattypeGetInternalRefseqp(const AjPStr type)
9560 {
9561     if(!FeatInitDone)
9562 	featInit();
9563 
9564     if(!FeatTypeTableRefseqp)
9565         ajFeatVocabInitProt("refseqp");
9566 
9567     return featTableTypeInternal(type, FeatTypeTableRefseqp);
9568 }
9569 
9570 
9571 
9572 
9573 /* @funcstatic featTableTypeInternal ******************************************
9574 **
9575 ** Given a feature type name,
9576 ** returns the valid feature type for a feature table
9577 **
9578 ** @param [r]   type  [const AjPStr] Type name
9579 ** @param [r]   table [const AjPTable]  Feature table
9580 ** @return [const AjPStr] Valid feature type
9581 **
9582 ** @release 4.0.0
9583 ** @@
9584 ******************************************************************************/
9585 
featTableTypeInternal(const AjPStr type,const AjPTable table)9586 static const AjPStr featTableTypeInternal(const AjPStr type,
9587 					  const AjPTable table)
9588 {
9589     const AjPStr ret = NULL;
9590     const AjPStr retkey = NULL;
9591     const AjPStr tmpstr = NULL;
9592 
9593     retkey = ajTablestrFetchkeyS(table, type);
9594 
9595     if(retkey)
9596     {
9597 #if FEATDEBUG
9598 	ajDebug("featTableTypeInternal '%S' found in internal table"
9599 	  " as '%S'\n",type, retkey);
9600 #endif
9601 
9602 	tmpstr = ajTableFetchS(table, retkey);
9603 
9604 	if(ajStrGetCharLast(tmpstr) != ';')
9605 	{
9606 #if FEATDEBUG
9607 	    ajDebug("featTableTypeInternal '%S' is an alias for '%S'\n",
9608 		 retkey, tmpstr);
9609 #endif
9610 	    retkey = ajTablestrFetchkeyS(table, tmpstr);
9611 	}
9612 
9613 	ajDebug("featTableTypeInternal result '%S'\n",
9614 		 retkey);
9615 	return retkey;
9616     }
9617 
9618     ret = ajTableFetchS(table, ajStrNew());
9619 #if FEATDEBUG
9620     ajDebug("featTableTypeInternal '%S' not in internal table %x, "
9621 	    "default to '%S'\n", type, table, ret);
9622 
9623     /* ajTablestrTrace(table); */
9624 
9625     /*ajDebug("featTableTypeInternal result '%S'\n",
9626 	     ret);*/
9627 #endif
9628 
9629     return ret;
9630 }
9631 
9632 
9633 
9634 
9635 /* @funcstatic featTableTypeInternalLimit *************************************
9636 **
9637 ** Given a feature type name,
9638 ** returns the valid feature type for a feature table
9639 ** following alternative names which are common in the internal table
9640 ** which is a combination of multiple definitions
9641 **
9642 ** @param [r]   type  [const AjPStr] Type name
9643 ** @param [r]   table [const AjPTable]  Feature table
9644 ** @return [const AjPStr] Valid feature type or NULL if not found
9645 **
9646 ** @release 6.1.0
9647 ** @@
9648 ******************************************************************************/
9649 
featTableTypeInternalLimit(const AjPStr type,const AjPTable table)9650 static const AjPStr featTableTypeInternalLimit(const AjPStr type,
9651                                                const AjPTable table)
9652 {
9653     const AjPStr retkey = NULL;
9654     const AjPStr tmpstr = NULL;
9655     const AjPStr savekey = NULL;
9656     ajuint i = 0;
9657 
9658     retkey = ajTablestrFetchkeyS(table, type);
9659 
9660     while(retkey && i < 5)
9661     {
9662         savekey = retkey;
9663 	tmpstr = ajTableFetchS(table, retkey);
9664 
9665 #if FEATDEBUG
9666 	ajDebug("featTableTypeInternalLimit '%S' found in internal table"
9667                 " as '%S' (%S)\n",type, retkey, tmpstr);
9668 #endif
9669 
9670 	if(ajStrGetCharLast(tmpstr) != ';')
9671 	{
9672 #if FEATDEBUG
9673 	    ajDebug("featTableTypeInternalLimit '%S' is an alias for '%S'\n",
9674 		 retkey, tmpstr);
9675 #endif
9676 	    retkey = ajTablestrFetchkeyS(table, tmpstr);
9677 	}
9678         else
9679         {
9680            tmpstr = ajTableFetchS(table, retkey);
9681            retkey = ajTablestrFetchkeyS(table, tmpstr);
9682 
9683            if(ajStrMatchS(retkey, savekey))
9684                retkey = NULL;
9685 	}
9686 #if FEATDEBUG
9687 	ajDebug("featTableTypeInternalLimit result %u '%S'\n",
9688                 ++i, savekey);
9689 #endif
9690     }
9691 
9692     if(savekey)
9693         return savekey;
9694 
9695     ajDebug("featTableTypeInternalLimit '%S' not in internal table %x, "
9696 	    "default to NULL\n", type, table);
9697 
9698     /* ajTablestrTrace(table); */
9699 
9700     /*ajDebug("featTableTypeInternalLimit result '%S'\n",
9701 	     ret);*/
9702     return NULL;
9703 }
9704 
9705 
9706 
9707 
9708 /* @funcstatic featTableTypeTestWild ******************************************
9709 **
9710 ** Given a feature type name,
9711 ** returns the valid feature type for a feature table
9712 ** following alternative names which are common in the internal table
9713 ** which is a combination of multiple definitions
9714 **
9715 ** @param [r]   type  [const AjPStr] Type name
9716 ** @param [r]   table [const AjPTable]  Feature table
9717 ** @param [r]   str   [const AjPStr] Wildcard name
9718 ** @return [AjBool] True if a match is found
9719 **
9720 ** @release 6.2.0
9721 ** @@
9722 ******************************************************************************/
9723 
featTableTypeTestWild(const AjPStr type,const AjPTable table,const AjPStr str)9724 static AjBool featTableTypeTestWild(const AjPStr type,
9725                                     const AjPTable table,
9726                                     const AjPStr str)
9727 {
9728     const AjPStr retkey = NULL;
9729     const AjPStr tmpstr = NULL;
9730     AjPStr tmpkey = NULL;
9731     ajulong i = 0UL;
9732     ajulong nkeys;
9733     void **keys = NULL;
9734     AjPStr key = NULL;
9735 
9736     if(ajStrMatchWildS(type, str))
9737         return ajTrue;
9738 
9739     retkey = ajTablestrFetchkeyS(table, type);
9740 
9741     while(retkey && i < 5)
9742     {
9743 	tmpstr = ajTableFetchS(table, retkey);
9744 	ajDebug("featTableTypeTestWild '%S' found in internal table"
9745                 " as '%S' (%S)\n",type, retkey, tmpstr);
9746 
9747 	if(ajStrGetCharLast(tmpstr) != ';')
9748 	{
9749             if(ajStrMatchWildS(tmpstr, str))
9750                 return ajTrue;
9751 
9752             tmpstr = ajTableFetchS(table, retkey);
9753 	    retkey = ajTablestrFetchkeyS(table, tmpstr);
9754 	}
9755         else
9756         {
9757             ajStrAssignSubS(&tmpkey, tmpstr, 0, ajStrFindAnyK(tmpstr, ';')-1);
9758 
9759             if(ajStrMatchWildS(tmpkey, str))
9760             {
9761                 ajStrDel(&tmpkey);
9762                 return ajTrue;
9763             }
9764 
9765             ajStrDel(&tmpkey);
9766 
9767 	    ajDebug("featTableTypeTestWild '%S' is an alias for '%S'\n",
9768 		 retkey, tmpstr);
9769 
9770             retkey = ajTablestrFetchkeyS(table, tmpstr);
9771 
9772 	}
9773 
9774 	ajDebug("featTableTypeTestWild result %u '%S'\n",
9775                 ++i, retkey);
9776     }
9777 
9778     nkeys = ajTableToarrayKeys(table, &keys);
9779     for (i=0; i<nkeys; i++)
9780     {
9781         key = (AjPStr) keys[i];
9782         if(ajStrMatchWildS(key, str))
9783         {
9784             if(ajStrMatchS(featTableTypeInternalLimit(key,table),
9785                            featTableTypeInternalLimit(type,table)))
9786             {
9787                 AJFREE(keys);
9788                 return ajTrue;
9789             }
9790         }
9791     }
9792 
9793     AJFREE(keys);
9794     ajDebug("featTableTypeTestWild '%S' not in internal table %x, "
9795 	    "default to NULL\n", type, table);
9796 
9797     return ajFalse;
9798 }
9799 
9800 
9801 
9802 
9803 /* @func ajFeattagGetNameC ****************************************************
9804 **
9805 ** Given a feature tag name,
9806 ** returns the valid feature tag name for a feature table
9807 **
9808 ** @param [r]   tag  [const char*] Type name
9809 ** @param [r]   table [const AjPTable]  Feature table
9810 ** @param [w] knowntag [AjBool*] ajTrue if the tag name is known
9811 **                               ajFalse if the default name was substituted
9812 ** @return [const AjPStr] Valid feature tag name
9813 **
9814 ** @release 6.4.0
9815 ** @@
9816 ******************************************************************************/
9817 
ajFeattagGetNameC(const char * tag,const AjPTable table,AjBool * knowntag)9818 const AjPStr ajFeattagGetNameC(const char* tag, const AjPTable table,
9819                                AjBool* knowntag)
9820 {
9821     static const AjPStr ret    = NULL;
9822 
9823     static const AjPStr deftag  = NULL;
9824 
9825     deftag = ajTableFetchC(table, "");
9826 
9827     if(tag)
9828     {
9829 	ret = ajTablestrFetchkeyC(table, tag);
9830 
9831 	if(ret)
9832 	{
9833 	    *knowntag = ajTrue;
9834 #if FEATDEBUG
9835 	    if(ajStrMatchS(ret, deftag))
9836             {
9837                 ajDebug("featTag '%s' found in internal table as '%S' "
9838                         "(default)\n",
9839                         tag, ret);
9840             }
9841             else
9842             {
9843                 ajDebug("featTag '%s' found in internal table as '%S'\n",
9844                         tag, ret);
9845             }
9846 #endif
9847 	    return ret;
9848 	}
9849 	else
9850 	{
9851 	    *knowntag = ajFalse;
9852             ret = deftag;
9853 #if FEATDEBUG
9854 	    ajDebug("featTag '%s' not in internal table %x,"
9855 	       " default to '%S'\n",
9856 	       tag, table, deftag);
9857 	    /* ajTablestrTrace(table); */
9858 #endif
9859 	}
9860     }
9861     else
9862     {
9863 	*knowntag = ajFalse;
9864 	ret = deftag;
9865 #if FEATDEBUG
9866 	ajDebug("featTag '%s' use default '%S'\n",
9867                 tag, deftag);
9868 #endif
9869     }
9870 
9871     return ret;
9872 }
9873 
9874 
9875 
9876 
9877 /* @func ajFeattagGetNameS ****************************************************
9878 **
9879 ** Given a feature tag name,
9880 ** returns the valid feature tag name for a feature table
9881 **
9882 ** @param [r]   tag  [const AjPStr] Type name
9883 ** @param [r]   table [const AjPTable]  Feature table
9884 ** @param [w]   knowntag  [AjBool*] ajTrue if the tag was found in the
9885 **                                  list of known tags
9886 ** @return [const AjPStr] Valid feature tag name
9887 **
9888 ** @release 6.4.0
9889 ** @@
9890 ******************************************************************************/
9891 
ajFeattagGetNameS(const AjPStr tag,const AjPTable table,AjBool * knowntag)9892 const AjPStr ajFeattagGetNameS(const AjPStr tag, const AjPTable table,
9893                               AjBool* knowntag)
9894 {
9895     static const AjPStr ret     = NULL;
9896     static const AjPStr deftag  = NULL;
9897 
9898     deftag = ajTableFetchC(table, "");
9899 
9900     if(tag)
9901     {
9902 	ret = ajTablestrFetchkeyS(table, tag);
9903 
9904 	if(ret)
9905 	{
9906 	    *knowntag = ajTrue;
9907 #if FEATDEBUG
9908 	    if(ajStrMatchS(ret, deftag))
9909             {
9910                 ajDebug("featTag '%S' found in internal table as '%S' (default)\n",
9911                         tag, ret);
9912             }
9913             else
9914             {
9915                 ajDebug("featTag '%S' found in internal table as '%S'\n",
9916                         tag, ret);
9917             }
9918 #endif
9919 	    return ret;
9920 	}
9921 	else
9922 	{
9923 	    *knowntag = ajFalse;
9924             ret = deftag;
9925 #if FEATDEBUG
9926 	    ajDebug("featTag '%S' not in internal table %x,"
9927 	       " default to '%S'\n",
9928 	       tag, table, deftag);
9929 	    /* ajTablestrTrace(table); */
9930 #endif
9931 	}
9932     }
9933     else
9934     {
9935 	*knowntag = ajFalse;
9936 	ret = deftag;
9937 #if FEATDEBUG
9938 	ajDebug("featTag '%S' use default '%S'\n",
9939                 tag, deftag);
9940 #endif
9941     }
9942 
9943     return ret;
9944 }
9945 
9946 
9947 
9948 
9949 /* @func ajFeattagFormat ******************************************************
9950 **
9951 ** Converts a feature tag value into the correct format, after
9952 ** checking it is an acceptable value
9953 **
9954 ** @param [r] name  [const AjPStr] Tag name
9955 ** @param [r] table [const AjPTable] Tag table
9956 ** @param [w] retstr [AjPStr*] string with formatted value.
9957 ** @return [void]
9958 **
9959 ** @release 6.4.0
9960 ** @@
9961 ******************************************************************************/
9962 
ajFeattagFormat(const AjPStr name,const AjPTable table,AjPStr * retstr)9963 void ajFeattagFormat(const AjPStr name, const AjPTable table,
9964                      AjPStr* retstr)
9965 {
9966     const AjPStr tagstr    = NULL;
9967     const char* cp;
9968     const char* cq;
9969     ajint i;
9970 
9971     tagstr = ajTableFetchS(table, name);
9972 
9973     cp = ajStrGetPtr(tagstr);
9974 
9975     ajStrAssignClear(retstr);
9976 
9977     cq = cp;
9978     i=0;
9979 
9980     while(*cp && (*cp++ != ';'))
9981 	i++;
9982 
9983     ajStrAssignLenC(retstr, cq, i);
9984 
9985     /* ajDebug("ajFeattagFormat '%S' type '%S' (%S)\n",
9986        name, *retstr, tagstr); */
9987 
9988     return;
9989 }
9990 
9991 
9992 
9993 
9994 /* @func ajFeattagGetLimit ****************************************************
9995 **
9996 ** Returns the controlled vocabulary list for a limited value.
9997 **
9998 ** @param [r] name  [const AjPStr] Tag name
9999 ** @param [r] table [const AjPTable] Tag table
10000 ** @param [w] retstr [AjPStr*] string with formatted value.
10001 ** @return [void]
10002 **
10003 ** @release 6.4.0
10004 ** @@
10005 ******************************************************************************/
10006 
ajFeattagGetLimit(const AjPStr name,const AjPTable table,AjPStr * retstr)10007 void ajFeattagGetLimit(const AjPStr name, const AjPTable table,
10008                        AjPStr* retstr)
10009 {
10010     const AjPStr tagstr;
10011     const char* cp = NULL;
10012 
10013     ajStrAssignClear(retstr);
10014     tagstr = ajTableFetchS(table, name);
10015     cp = ajStrGetPtr(tagstr);
10016 
10017     while(*cp && (*cp != ';'))
10018 	cp++;
10019 
10020     if(!*cp)
10021 	return;
10022 
10023     ajStrAssignC(retstr, cp);
10024 
10025     return;
10026 }
10027 
10028 
10029 
10030 
10031 /* @func ajFeatUnused *********************************************************
10032 **
10033 ** Dummy function to prevent compiler warnings
10034 **
10035 ** @return [void]
10036 **
10037 ** @release 1.0.0
10038 ******************************************************************************/
10039 
ajFeatUnused(void)10040 void ajFeatUnused(void)
10041 {
10042     AjBool knowntag = ajTrue;
10043 
10044     featTagDna(NULL, &knowntag);
10045     featTagProt(NULL, &knowntag);
10046     ajFeattagGetNameC(NULL, NULL, &knowntag);
10047 }
10048 
10049 
10050 
10051 
10052 /* @funcstatic featFeatureNew *************************************************
10053 **
10054 ** Constructor for a feature
10055 **
10056 ** @return [AjPFeature] New empty feature
10057 **
10058 ** @release 2.1.0
10059 ******************************************************************************/
10060 
featFeatureNew(void)10061 static AjPFeature featFeatureNew(void)
10062 {
10063     AjPFeature ret;
10064 
10065     AJNEW0(ret);
10066 
10067     ret->Subfeatures = ajListNew() ; /* Assume empty until otherwise needed */
10068     ret->Tags = ajListNew() ; /* Assume empty until otherwise needed */
10069     ret->GffTags = ajListNew() ; /* Assume empty until otherwise needed */
10070 
10071     return ret;
10072 }
10073 
10074 
10075 
10076 
10077 /* @funcstatic featTableNew ***************************************************
10078 **
10079 ** Constructor for a feature table object.
10080 **
10081 ** The type is left uninitialised
10082 **
10083 ** @return [AjPFeattable] New empty feature table
10084 **
10085 ** @release 2.1.0
10086 ******************************************************************************/
10087 
featTableNew(void)10088 static AjPFeattable featTableNew(void)
10089 {
10090     AjPFeattable ret;
10091 
10092     AJNEW0(ret);
10093 
10094     ret->Features = ajListNew() ; /* assume empty until otherwise needed */
10095 
10096     return ret;
10097 }
10098 
10099 
10100 
10101 
10102 /* @funcstatic featTableNewS **************************************************
10103 **
10104 ** Constructor for a feature table object with a defined name
10105 **
10106 ** The type is left uninitialised
10107 **
10108 ** @param [r] name [const AjPStr] Name for new feature table
10109 **                                (or NULL for unnamed)
10110 ** @return [AjPFeattable] New empty feature table
10111 **
10112 ** @release 2.1.0
10113 ******************************************************************************/
10114 
featTableNewS(const AjPStr name)10115 static AjPFeattable featTableNewS(const AjPStr name)
10116 {
10117     AjPFeattable ret;
10118 
10119     ret = featTableNew();
10120     featTableInit(ret, name);
10121 
10122     return ret;
10123 }
10124 
10125 
10126 
10127 
10128 /* @func ajFeatTypeIsCds ******************************************************
10129 **
10130 ** Tests whether the feature is a CDS feature
10131 **
10132 ** @param [r] gf       [const AjPFeature]  Feature
10133 ** @return [AjBool] ajTrue on success
10134 **
10135 ** @release 6.0.0
10136 ** @@
10137 ******************************************************************************/
10138 
ajFeatTypeIsCds(const AjPFeature gf)10139 AjBool ajFeatTypeIsCds(const AjPFeature gf)
10140 {
10141     if(ajStrMatchC(gf->Type, "SO:0000316"))
10142 	return ajTrue;
10143 
10144     return ajFalse;
10145 }
10146 
10147 
10148 
10149 
10150 /* @func ajFeatTypeMatchC *****************************************************
10151 **
10152 ** Tests whether the feature type matches a given string
10153 ** including testing for alternative names
10154 **
10155 ** @param [r] gf       [const AjPFeature]  Feature
10156 ** @param [r] txt      [const char*]  Feature type name to test
10157 ** @return [AjBool] ajTrue on success
10158 **
10159 ** @release 6.1.0
10160 ** @@
10161 ******************************************************************************/
10162 
ajFeatTypeMatchC(const AjPFeature gf,const char * txt)10163 AjBool ajFeatTypeMatchC(const AjPFeature gf, const char* txt)
10164 {
10165     AjBool ret = ajFalse;
10166     AjPStr tmpstr;
10167     const AjPStr tmptype = NULL;
10168 
10169     if(ajStrMatchC(gf->Type, txt))
10170 	return ajTrue;
10171 
10172     tmpstr = ajStrNewC(txt);
10173 
10174     if(gf->Protein)
10175     {
10176         tmptype = featTypeProtLimit(tmpstr);
10177         if(tmptype)
10178             ret = ajStrMatchS(featTypeProtLimit(gf->Type),
10179                               tmptype);
10180         ajDebug("ajFeatTypeMatch: %B '%S' prot: '%S' <=> '%S'\n",
10181                 ret, tmpstr, tmptype, gf->Type);
10182     }
10183 
10184     else
10185     {
10186 	tmptype = featTypeDnaLimit(tmpstr);
10187         if(tmptype)
10188             ret = ajStrMatchS(featTypeDnaLimit(gf->Type),
10189                               tmptype);
10190         ajDebug("ajFeatTypeMatch: %B '%S' dna: '%S' <=> '%S'\n",
10191                 ret, tmpstr, tmptype, gf->Type);
10192     }
10193 
10194     ajStrDel(&tmpstr);
10195 
10196     return ret;
10197 }
10198 
10199 
10200 
10201 
10202 /* @func ajFeatTypeMatchS *****************************************************
10203 **
10204 ** Tests whether the feature type matches a given string
10205 ** including testing for alternative names
10206 **
10207 ** @param [r] gf       [const AjPFeature]  Feature
10208 ** @param [r] str      [const AjPStr]  Feature type name to test
10209 ** @return [AjBool] ajTrue on success
10210 **
10211 ** @release 6.1.0
10212 ** @@
10213 ******************************************************************************/
10214 
ajFeatTypeMatchS(const AjPFeature gf,const AjPStr str)10215 AjBool ajFeatTypeMatchS(const AjPFeature gf, const AjPStr str)
10216 {
10217     AjBool ret = ajFalse;
10218 
10219     if(ajStrMatchS(gf->Type, str))
10220 	return ajTrue;
10221 
10222     if(gf->Protein)
10223     {
10224 	ret =   ajStrMatchS(featTypeProtLimit(gf->Type),featTypeProtLimit(str));
10225         ajDebug("ajFeatTypeMatch: %B '%S' '%S' prot: '%S' <=> '%S'\n",
10226                 ret, str, gf->Type,
10227                 featTypeProtLimit(str), featTypeProtLimit(gf->Type));
10228     }
10229 
10230     else
10231     {
10232 	ret =   ajStrMatchS(featTypeDnaLimit(gf->Type),featTypeDnaLimit(str));
10233         ajDebug("ajFeatTypeMatch: %B '%S' '%S' dna: '%S' <=> '%S'\n",
10234                 ret, str, gf->Type,
10235                 featTypeDnaLimit(str), featTypeDnaLimit(gf->Type));
10236     }
10237 
10238     return ret;
10239 }
10240 
10241 
10242 
10243 
10244 /* @func ajFeatTypeMatchWildS *************************************************
10245 **
10246 ** Tests whether the feature type matches a given wildcard string
10247 ** including testing for alternative names
10248 **
10249 ** @param [r] gf       [const AjPFeature]  Feature
10250 ** @param [r] str      [const AjPStr]  Feature type name to test
10251 ** @return [AjBool] ajTrue on success
10252 **
10253 ** @release 6.2.0
10254 ** @@
10255 ******************************************************************************/
10256 
ajFeatTypeMatchWildS(const AjPFeature gf,const AjPStr str)10257 AjBool ajFeatTypeMatchWildS(const AjPFeature gf, const AjPStr str)
10258 {
10259     AjBool ret = ajFalse;
10260     AjPStr mystr = NULL;
10261 
10262     mystr = ajStrNewS(str);
10263     ajStrFmtLower(&mystr);
10264 
10265     if(gf->Protein)
10266     {
10267 	ret =  featTypeTestProtWild(gf->Type, mystr);
10268 
10269         if(!ret)
10270         {
10271             if(ajStrIsWild(mystr))
10272                 ajStrTrimEndC(&mystr, "*");
10273             ret = ajFeatTypeMatchS(gf, mystr);
10274         }
10275 
10276         ajDebug("ajFeatTypeMatchWildS: %B '%S' '%S' prot:'%S'\n",
10277                 ret, mystr, gf->Type,
10278                 featTypeProtLimit(gf->Type));
10279     }
10280 
10281     else
10282     {
10283 	ret =  featTypeTestDnaWild(gf->Type, mystr);
10284 
10285         if(!ret)
10286         {
10287             if(ajStrIsWild(mystr))
10288                 ajStrTrimEndC(&mystr, "*");
10289             ret = ajFeatTypeMatchS(gf, mystr);
10290         }
10291 
10292         ajDebug("ajFeatTypeMatchWildS: %B '%S' '%S' dna: '%S'\n",
10293                 ret, mystr, gf->Type,
10294                 featTypeDnaLimit(gf->Type));
10295     }
10296     ajStrDel(&mystr);
10297 
10298     return ret;
10299 }
10300 
10301 
10302 
10303 
10304 /* @func ajFeatIsLocal ********************************************************
10305 **
10306 ** Tests whether the feature is local to the sequence.
10307 ** Returns AJTRUE if it is local, AJFALSE if remote.
10308 **
10309 ** @param [r] gf       [const AjPFeature]  Feature
10310 ** @return [AjBool] ajTrue on success
10311 **
10312 ** @release 2.1.0
10313 ** @@
10314 ******************************************************************************/
10315 
ajFeatIsLocal(const AjPFeature gf)10316 AjBool ajFeatIsLocal(const AjPFeature gf)
10317 {
10318     return !(gf->Flags & AJFEATFLAG_REMOTEID);
10319 }
10320 
10321 
10322 
10323 
10324 /* @func ajFeatIsLocalRange ***************************************************
10325 **
10326 ** Tests whether the feature is local and in the specified range of the
10327 ** sequence.
10328 ** Returns AJTRUE if it is local and within the range.
10329 ** (Any label location is assumed to be outside the range.)
10330 **
10331 ** @param [r] gf       [const AjPFeature]  Feature
10332 ** @param [r] start    [ajuint]  start of range
10333 ** @param [r] end      [ajuint]  end of range
10334 ** @return [AjBool] ajTrue on success
10335 **
10336 ** @release 2.1.0
10337 ** @@
10338 ******************************************************************************/
10339 
ajFeatIsLocalRange(const AjPFeature gf,ajuint start,ajuint end)10340 AjBool ajFeatIsLocalRange(const AjPFeature gf, ajuint start, ajuint end)
10341 {
10342     if(gf->Flags & AJFEATFLAG_REMOTEID)
10343 	return AJFALSE;
10344 
10345     if(gf->Flags & AJFEATFLAG_LABEL)
10346 	return AJFALSE;
10347 
10348     if(gf->End < start || gf->Start > end)
10349 	return AJFALSE;
10350 
10351     return AJTRUE;
10352 }
10353 
10354 
10355 
10356 
10357 /* @func ajFeatIsMultiple *****************************************************
10358 **
10359 ** Tests whether the feature is a member of a join, group order or one_of
10360 **
10361 ** @param [r] gf       [const AjPFeature]  Feature
10362 ** @return [AjBool] Returns AJTRUE if it is a member
10363 **
10364 ** @release 2.5.0
10365 ** @@
10366 ******************************************************************************/
10367 
ajFeatIsMultiple(const AjPFeature gf)10368 AjBool ajFeatIsMultiple(const AjPFeature gf)
10369 {
10370     return (gf->Flags & AJFEATFLAG_MULTIPLE);
10371 }
10372 
10373 
10374 
10375 
10376 /* @func ajFeatIsCompMult *****************************************************
10377 **
10378 ** Tests whether the feature is a member of a complement around a
10379 ** multiple (join, etc.)
10380 **
10381 ** @param [r] gf       [const AjPFeature]  Feature
10382 ** @return [AjBool] Returns AJTRUE if it is a complemented multiple
10383 **
10384 ** @release 2.5.0
10385 ** @@
10386 ******************************************************************************/
10387 
ajFeatIsCompMult(const AjPFeature gf)10388 AjBool ajFeatIsCompMult(const AjPFeature gf)
10389 {
10390     return (gf->Flags & AJFEATFLAG_COMPLEMENT_MAIN);
10391 }
10392 
10393 
10394 
10395 
10396 /* @func ajFeattablePos *******************************************************
10397 **
10398 ** Converts a string position into a true position. If ipos is negative,
10399 ** it is counted from the end of the string rather than the beginning.
10400 **
10401 ** For strings, the result can go off the end to the terminating NULL.
10402 ** For sequences the maximum is the last base.
10403 **
10404 ** @param [r] thys [const AjPFeattable] Target feature table.
10405 ** @param [r] ipos [ajint] Position.
10406 ** @return [ajuint] string position between 1 and length.
10407 **
10408 ** @release 2.5.0
10409 ** @@
10410 ******************************************************************************/
10411 
ajFeattablePos(const AjPFeattable thys,ajint ipos)10412 ajuint ajFeattablePos(const AjPFeattable thys, ajint ipos)
10413 {
10414     return ajFeattablePosII(ajFeattableGetLen(thys), 1, ipos);
10415 }
10416 
10417 
10418 
10419 
10420 /* @func ajFeattablePosI ******************************************************
10421 **
10422 ** Converts a string position into a true position. If ipos is negative,
10423 ** it is counted from the end of the string rather than the beginning.
10424 **
10425 ** imin is a minimum relative position, also counted from the end
10426 ** if negative. Usually this is the start position when the end of a range
10427 ** is being tested.
10428 **
10429 ** @param [r] thys [const AjPFeattable] Target feature table.
10430 ** @param [r] imin [ajuint] Start position.
10431 ** @param [r] ipos [ajint] Position.
10432 ** @return [ajuint] string position between 1 and length.
10433 **
10434 ** @release 2.5.0
10435 ** @@
10436 ******************************************************************************/
10437 
ajFeattablePosI(const AjPFeattable thys,ajuint imin,ajint ipos)10438 ajuint ajFeattablePosI(const AjPFeattable thys, ajuint imin, ajint ipos)
10439 {
10440     return ajFeattablePosII(ajFeattableGetLen(thys), imin, ipos);
10441 }
10442 
10443 
10444 
10445 
10446 /* @func ajFeattablePosII *****************************************************
10447 **
10448 ** Converts a position into a true position. If ipos is negative,
10449 ** it is counted from the end of the sequence rather than the beginning.
10450 **
10451 ** imin is a minimum relative position, also counted from the end
10452 ** if negative. Usually this is the start position when the end of a range
10453 ** is being tested.
10454 **
10455 ** For strings, the result can go off the end to the terminating NULL.
10456 ** For sequences the maximum is the last base.
10457 **
10458 ** @param [r] ilen [ajuint] maximum length.
10459 ** @param [r] imin [ajuint] Start position.
10460 ** @param [r] ipos [ajint] Position.
10461 ** @return [ajuint] string position between 1 and length.
10462 **
10463 ** @release 2.5.0
10464 ** @@
10465 ******************************************************************************/
10466 
ajFeattablePosII(ajuint ilen,ajuint imin,ajint ipos)10467 ajuint ajFeattablePosII(ajuint ilen, ajuint imin, ajint ipos)
10468 {
10469     ajuint jpos;
10470 
10471     if(ipos < 0)
10472 	jpos = ilen + ipos + 1;
10473     else
10474     {
10475 	if(ipos)
10476 	    jpos = ipos;
10477 	else
10478 	    jpos = 1;
10479     }
10480 
10481     if(jpos > ilen)
10482 	jpos = ilen;
10483 
10484     if(jpos < imin)
10485 	jpos = imin;
10486 
10487     /*ajDebug("ajFeattablePosII(ilen: %d imin: %d ipos: %d) = %d\n",
10488 	    ilen, imin, ipos, jpos);*/
10489 
10490     return jpos;
10491 }
10492 
10493 
10494 
10495 
10496 /* @func ajFeattableTrimOff ***************************************************
10497 **
10498 ** Trim a feature table using the Begin and Ends.
10499 **
10500 ** Called where a sequence has been trimmed, so we have to allow for
10501 ** missing sequence positions at the start (ioffset) or at the end (ilen).
10502 **
10503 ** @param [u] thys [AjPFeattable] Target feature table.
10504 ** @param [r] ioffset [ajuint] Offset from start of sequence
10505 ** @param [r] ilen [ajuint] Length of sequence
10506 ** @return [AjBool] AjTrue returned if successful.
10507 **
10508 ** @release 2.7.0
10509 ** @@
10510 ******************************************************************************/
10511 
ajFeattableTrimOff(AjPFeattable thys,ajuint ioffset,ajuint ilen)10512 AjBool ajFeattableTrimOff(AjPFeattable thys, ajuint ioffset, ajuint ilen)
10513 {
10514     AjBool ok      = ajTrue;
10515     AjBool dobegin = ajFalse;
10516     AjBool doend   = ajFalse;
10517     ajuint begin    = 0;
10518     ajuint end      = 0;
10519     ajuint iseqlen;
10520     AjIList     iter = NULL ;
10521     AjPFeature  ft   = NULL ;
10522 
10523     /*ajDebug("ajFeattableTrimOff offset %d len %d\n", ioffset, ilen);*/
10524     /*ajDebug("ajFeattableTrimOff table Start %d End %d Len %d Features %Lu\n",
10525             thys->Start, thys->End, thys->Len,
10526             ajListGetLength(thys->Features));*/
10527 
10528     if(thys->Trimmed)
10529     {
10530         ajWarn("ajFeattableTrimOff: Features '%S' already trimmed",
10531                ajFeattableGetName(thys));
10532 
10533         return ajFalse;
10534     }
10535 
10536     iseqlen = ilen + ioffset;
10537 
10538     begin = ajFeattablePos(thys, thys->Start);
10539 
10540     if(thys->End)
10541 	end = ajFeattablePosI(thys, thys->End, iseqlen);
10542     else
10543 	end = thys->Len;
10544     if(end > iseqlen)
10545 	end = iseqlen;
10546 
10547     if(begin <= ioffset)
10548 	begin = ajFeattablePosI(thys, (ioffset+1), end);
10549 
10550     if(begin > 1)
10551 	dobegin = ajTrue;
10552 
10553     if(end < thys->Len)
10554 	doend = ajTrue;
10555 
10556     /*ajDebug("  ready to trim dobegin %B doend %B begin %d end %d\n",
10557 	     dobegin, doend, begin, end);*/
10558 
10559    iter = ajListIterNew(thys->Features) ;
10560 
10561     while(!ajListIterDone(iter))
10562     {
10563 	ft = (AjPFeature)ajListIterGet(iter);
10564 
10565 	if(!ajFeatTrimOffRange(ft, ioffset, begin, end, dobegin, doend))
10566 	{
10567 	    ajFeatDel(&ft);
10568 	    ajListIterRemove(iter);
10569 	}
10570     }
10571 
10572     ajListIterDel(&iter);
10573     thys->Offset = ioffset;
10574 
10575     if(thys->Rev)
10576         ajFeattableReverse(thys);
10577 
10578     thys->Trimmed = ajTrue;
10579 
10580     return ok;
10581 }
10582 
10583 
10584 
10585 
10586 /* @func ajFeattableTrim ******************************************************
10587 **
10588 ** Trim a feature table using the Begin and Ends.
10589 **
10590 ** @param [u] thys [AjPFeattable] Target feature table.
10591 ** @return [AjBool] AjTrue returned if successful.
10592 **
10593 ** @release 6.3.0
10594 ** @@
10595 ******************************************************************************/
10596 
ajFeattableTrim(AjPFeattable thys)10597 AjBool ajFeattableTrim(AjPFeattable thys)
10598 {
10599     AjBool ok      = ajTrue;
10600     AjBool dobegin = ajFalse;
10601     AjBool doend   = ajFalse;
10602     ajuint begin    = 0;
10603     ajuint end      = 0;
10604     AjIList     iter = NULL ;
10605     AjPFeature  ft   = NULL ;
10606 
10607     /*ajDebug("ajFeattableTrim table Start %d End %d Len %d Features %Lu\n",
10608 	     thys->Start, thys->End, thys->Len,
10609 	     ajListGetLength(thys->Features));*/
10610 
10611     if(thys->Trimmed)
10612     {
10613         ajWarn("Features '%S' already trimmed", ajFeattableGetName(thys));
10614 
10615         return ajFalse;
10616     }
10617 
10618     begin = ajFeattablePos(thys, thys->Start);
10619 
10620     if(thys->End)
10621 	end = ajFeattablePosI(thys, begin, thys->End);
10622     else
10623 	end = thys->Len;
10624 
10625     if(begin > 1)
10626 	dobegin = ajTrue;
10627 
10628     if(end < thys->Len)
10629 	doend = ajTrue;
10630 
10631     /*ajDebug("  ready to trim dobegin %B doend %B begin %d end %d\n",
10632 	     dobegin, doend, begin, end);*/
10633 
10634     iter = ajListIterNew(thys->Features) ;
10635 
10636     while(!ajListIterDone(iter))
10637     {
10638 	ft = (AjPFeature)ajListIterGet(iter);
10639 
10640 	if(!ajFeatTrimOffRange(ft, 0, begin, end, dobegin, doend))
10641 	{
10642 	    ajFeatDel(&ft);
10643 	    ajListIterRemove(iter);
10644 	}
10645     }
10646 
10647     ajListIterDel(&iter);
10648 
10649     thys->Offset = 0;
10650     thys->Len = 1 + thys->End - thys->Start;
10651 
10652     if(thys->Rev)
10653         ajFeattableReverse(thys);
10654 
10655     thys->Trimmed = ajTrue;
10656 
10657     return ok;
10658 }
10659 
10660 
10661 
10662 
10663 /* @func ajFeatTrimOffRange ***************************************************
10664 **
10665 ** Trim a feature table using the Begin and Ends.
10666 **
10667 ** Called where a sequence has been trimmed, so we have to allow for
10668 ** missing sequence positions at the start (ioffset)
10669 **
10670 ** @param [u] ft [AjPFeature] Target feature
10671 ** @param [r] ioffset [ajuint] Offset from start of sequence
10672 ** @param [r] begin [ajuint] Range start of sequence
10673 ** @param [r] end [ajuint] Range end of sequence
10674 ** @param [r] dobegin [AjBool] Reset begin
10675 ** @param [r] doend [AjBool] Reset end
10676 **
10677 ** @return [AjBool] AjTrue returned if successful.
10678 **                  ajFalse returned if feature could not be trimmed
10679 **
10680 ** @release 2.7.0
10681 ** @@
10682 ******************************************************************************/
10683 
ajFeatTrimOffRange(AjPFeature ft,ajuint ioffset,ajuint begin,ajuint end,AjBool dobegin,AjBool doend)10684 AjBool ajFeatTrimOffRange(AjPFeature ft, ajuint ioffset,
10685 			  ajuint begin, ajuint end,
10686 			  AjBool dobegin, AjBool doend)
10687 {
10688     AjBool ok = ajTrue;
10689     ajuint joffset;
10690     AjIList       iter = NULL;
10691     AjPFeature subfeat = NULL;
10692 
10693     ajDebug("ajFeatTrimOffRange ft flags %x %d..%d %d..%d\n",
10694 	     ft->Flags, ft->Start, ft->End, ft->Start2, ft->End2);
10695 
10696     joffset = ioffset;
10697     if(dobegin && begin)
10698         joffset += (begin - 1);
10699 
10700     if(ft->Flags & AJFEATFLAG_REMOTEID) /* feature in another sequence */
10701 	return ajTrue;
10702 
10703     if(ft->Flags & AJFEATFLAG_LABEL) /* label, no positions */
10704 	return ajTrue;
10705 
10706     if(doend)
10707     {
10708 	if(ft->Start > end)
10709 	    /* beyond the end - delete this feature */
10710 	    return ajFalse;
10711 
10712 	if(ft->Start2 > end)
10713 	    ft->Start2 = end;
10714 
10715 	if(ft->End > end)
10716 	{
10717 	    ft->End = end;
10718 	    ft->Flags |= AJFEATFLAG_END_AFTER_SEQ;
10719 	}
10720 
10721 	if(ft->End2 > end)
10722 	    ft->End2 = end;
10723     }
10724 
10725     if(dobegin)
10726     {
10727 	if(ft->End < begin)
10728 	    return ajFalse;
10729 
10730 	if(ft->End2 && begin > (ioffset + 1) && ft->End2 < begin)
10731 	    ft->End2 = begin;
10732 
10733 	if(ft->Start && ft->Start < begin)
10734 	{
10735 	    ft->Start = begin;
10736 	    ft->Flags |= AJFEATFLAG_START_BEFORE_SEQ;
10737 	}
10738 
10739 	if(ft->Start2 && ft->Start2 < begin)
10740 	    ft->Start2 = begin;
10741     }
10742 
10743     if(joffset)			/* shift to sequence offset */
10744     {
10745 	if(ft->Start)
10746 	    ft->Start -= joffset;
10747 	if(ft->Start2)
10748 	    ft->Start2 -= joffset;
10749 	if(ft->End)
10750 	    ft->End -= joffset;
10751 	if(ft->End2)
10752 	    ft->End2 -= joffset;
10753     }
10754 
10755     if(ft->Subfeatures)
10756     {
10757         iter = ajListIterNew(ft->Subfeatures);
10758 	while(!ajListIterDone(iter))
10759 	{
10760 	    subfeat = (AjPFeature)ajListIterGet(iter);
10761             if(!ajFeatTrimOffRange(subfeat, ioffset,
10762                                    begin, end, dobegin, doend))
10763                 ok = ajFalse;
10764         }
10765 	ajListIterDel(&iter);
10766     }
10767 
10768     return ok;
10769 }
10770 
10771 
10772 
10773 
10774 /* @func ajFeattagIsNote ******************************************************
10775 **
10776 ** Tests whether the feature tag is a note (the default feature tag)
10777 **
10778 ** @param [r] tag      [const AjPStr]  Feature tag
10779 ** @return [AjBool] ajTrue on success
10780 **
10781 ** @release 6.0.0
10782 ** @@
10783 ******************************************************************************/
10784 
ajFeattagIsNote(const AjPStr tag)10785 AjBool ajFeattagIsNote(const AjPStr tag)
10786 {
10787     if(ajStrMatchC(tag, "note"))
10788 	return ajTrue;
10789 
10790     return ajFalse;
10791 }
10792 
10793 
10794 
10795 
10796 /* @func ajFeatExit ***********************************************************
10797 **
10798 ** Cleans up feature table internal memory
10799 **
10800 ** @return [void]
10801 **
10802 ** @release 2.0.0
10803 ** @@
10804 ******************************************************************************/
10805 
ajFeatExit(void)10806 void ajFeatExit(void)
10807 {
10808 
10809     ajFeatreadExit();
10810     ajFeatwriteExit();
10811 
10812     ajRegFree(&featRegSpecialAnticodon);
10813     ajRegFree(&featRegSpecialBiomaterial);
10814     ajRegFree(&featRegSpecialCodon);
10815     ajRegFree(&featRegSpecialCodonBad);
10816     ajRegFree(&featRegSpecialColdate);
10817     ajRegFree(&featRegSpecialCompare);
10818     ajRegFree(&featRegSpecialConssplice);
10819     ajRegFree(&featRegSpecialEstlen);
10820     ajRegFree(&featRegSpecialInference);
10821     ajRegFree(&featRegSpecialLatlon);
10822     ajRegFree(&featRegSpecialMobile);
10823     ajRegFree(&featRegSpecialPrimer);
10824     ajRegFree(&featRegSpecialRptRange);
10825     ajRegFree(&featRegSpecialRptRangeLab);
10826     ajRegFree(&featRegSpecialRptRangeComp);
10827     ajRegFree(&featRegSpecialRptunitSeq);
10828     ajRegFree(&featRegSpecialRptunitSeqPos);
10829     ajRegFree(&featRegSpecialTrans);
10830     ajRegFree(&featRegSpecialTransBad);
10831     ajRegFree(&featRegSpecialTransComp);
10832     ajRegFree(&featRegSpecialTransBadComp);
10833     ajRegFree(&featRegTagReplace);
10834 
10835     ajTablestrFree(&FeatTypeTableEmbl);
10836     ajTablestrFree(&FeatTagsTableEmbl);
10837 
10838     ajTablestrFree(&FeatTypeTableGff2);
10839     ajTablestrFree(&FeatTagsTableGff2);
10840 
10841     ajTablestrFree(&FeatTypeTableGff3);
10842     ajTablestrFree(&FeatTagsTableGff3);
10843 
10844     ajTablestrFree(&FeatTypeTablePir);
10845     ajTablestrFree(&FeatTagsTablePir);
10846 
10847     ajTablestrFree(&FeatTypeTableGff2protein);
10848     ajTablestrFree(&FeatTagsTableGff2protein);
10849 
10850     ajTablestrFree(&FeatTypeTableGff3protein);
10851     ajTablestrFree(&FeatTagsTableGff3protein);
10852 
10853     ajTablestrFree(&FeatTypeTableSwiss);
10854     ajTablestrFree(&FeatTagsTableSwiss);
10855 
10856     ajTablestrFree(&FeatTypeTableDna);
10857     ajTablestrFree(&FeatTagsTableDna);
10858 
10859     ajTablestrFree(&FeatTypeTableProtein);
10860     ajTablestrFree(&FeatTagsTableProtein);
10861 
10862     ajTablestrFree(&FeatTypeTableRefseqp);
10863     ajTablestrFree(&FeatTagsTableRefseqp);
10864 
10865     ajTablestrFree(&FeatCategoryTable);
10866 
10867     ajStrDel(&featTypeMiscfeat);
10868     ajStrDel(&featTypeEmpty);
10869     ajStrDel(&featDefSource);
10870     ajStrDel(&featFmtTmp);
10871     ajStrDel(&featTagTmp);
10872     ajStrDel(&featTagTmp2);
10873     ajStrDel(&featValTmp);
10874     ajStrDel(&featValTmp2);
10875     ajStrDel(&featTmpStr);
10876     ajStrDel(&featTagNote);
10877 
10878     ajStrDel(&featTransBegStr);
10879     ajStrDel(&featTransEndStr);
10880     ajStrDel(&featTransAaStr);
10881     ajStrDel(&featTempQry);
10882 
10883     ajStrTokenDel(&featVocabSplit);
10884 
10885     return;
10886 }
10887 
10888 
10889 
10890 
10891 /* @func ajFeatWarn ***********************************************************
10892 **
10893 ** Formatted write as a warning message.
10894 **
10895 ** @param [r] fmt [const char*] Format string
10896 ** @param [v] [...] Format arguments.
10897 ** @return [void]
10898 **
10899 ** @release 6.4.0
10900 ** @@
10901 ******************************************************************************/
10902 
ajFeatWarn(const char * fmt,...)10903 void ajFeatWarn(const char* fmt, ...)
10904 {
10905     va_list args;
10906     static AjBool dowarn = AJTRUE;
10907     AjPStr tmpstr = NULL;
10908     AjPStr errstr = NULL;
10909 
10910     if(!featWarnCount)
10911     {
10912 	if(ajNamGetValueC("featwarn", &tmpstr))
10913 	{
10914 	    ajStrToBool(tmpstr, &dowarn);
10915 	}
10916 
10917 	ajStrDel(&tmpstr);
10918     }
10919 
10920     featWarnCount++;
10921 
10922     if(!dowarn)
10923 	return;
10924 
10925     va_start(args, fmt) ;
10926     ajFmtVPrintS(&errstr, fmt, args);
10927     va_end(args) ;
10928 
10929     ajWarn("%S", errstr);
10930     ajStrDel(&errstr);
10931 
10932     return;
10933 }
10934 
10935 
10936 
10937 
10938 #ifdef AJ_COMPILE_DEPRECATED_BOOK
10939 #endif
10940 
10941 
10942 
10943 
10944 #ifdef AJ_COMPILE_DEPRECATED
10945 /* @obsolete ajFeattableBegin
10946 ** @rename ajFeattableGetBegin
10947 */
10948 
ajFeattableBegin(const AjPFeattable thys)10949 __deprecated ajint ajFeattableBegin(const AjPFeattable thys)
10950 {
10951     return ajFeattableGetBegin(thys);
10952 }
10953 
10954 
10955 
10956 
10957 /* @obsolete ajFeattableEnd
10958 ** @rename ajFeattableGetEnd
10959 */
10960 
ajFeattableEnd(const AjPFeattable thys)10961 __deprecated ajint ajFeattableEnd(const AjPFeattable thys)
10962 {
10963     return ajFeattableGetEnd(thys);
10964 }
10965 
10966 
10967 
10968 
10969 /* @obsolete ajFeattableLen
10970 ** @rename ajFeattableGetLen
10971 */
10972 
ajFeattableLen(const AjPFeattable thys)10973 __deprecated ajint ajFeattableLen(const AjPFeattable thys)
10974 {
10975     return ajFeattableGetLen(thys);
10976 }
10977 
10978 
10979 
10980 
10981 /* @obsolete ajFeattableSize
10982 ** @rename ajFeattableGetSize
10983 */
10984 
ajFeattableSize(const AjPFeattable thys)10985 __deprecated ajint ajFeattableSize(const AjPFeattable thys)
10986 {
10987     return ajFeattableGetSize(thys);
10988 }
10989 
10990 
10991 
10992 
10993 /* @obsolete ajFeatGetNoteI
10994 ** @rename ajFeatGetNoteSI
10995 */
ajFeatGetNoteI(const AjPFeature thys,const AjPStr name,ajint count,AjPStr * val)10996 __deprecated AjBool ajFeatGetNoteI(const AjPFeature thys,
10997                                    const AjPStr name, ajint count,
10998                                    AjPStr* val)
10999 {
11000     return ajFeatGetNoteSI(thys, name, count, val);
11001 }
11002 
11003 
11004 
11005 
11006 /* @obsolete ajFeatGetNote
11007 ** @rename ajFeatGetNoteS
11008 */
11009 
ajFeatGetNote(const AjPFeature thys,const AjPStr name,AjPStr * val)11010 __deprecated AjBool ajFeatGetNote(const AjPFeature thys, const AjPStr name,
11011                                   AjPStr* val)
11012 {
11013     return ajFeatGetNoteS(thys, name, val);
11014 }
11015 
11016 
11017 
11018 
11019 /* @obsolete ajFeatTagAddC
11020 ** @rename ajFeatTagAddCS
11021 */
11022 
ajFeatTagAddC(AjPFeature thys,const char * tag,const AjPStr value)11023 __deprecated AjBool ajFeatTagAddC(AjPFeature thys, const char* tag,
11024                                   const AjPStr value)
11025 {
11026     return ajFeatTagAddCS(thys, tag, value);
11027 }
11028 
11029 
11030 
11031 
11032 /* @obsolete ajFeatTagAdd
11033 ** @rename ajFeatTagAddS
11034 */
11035 
ajFeatTagAdd(AjPFeature thys,const AjPStr tag,const AjPStr value)11036 __deprecated AjBool ajFeatTagAdd(AjPFeature thys,
11037                                  const AjPStr tag, const AjPStr value)
11038 {
11039     return ajFeatTagAddSS(thys, tag, value);
11040 }
11041 
11042 
11043 
11044 
11045 /* @obsolete ajFeatDefName
11046 ** @rename ajFeattableSetDefname
11047 */
11048 
ajFeatDefName(AjPFeattable thys,const AjPStr setname)11049 __deprecated void ajFeatDefName(AjPFeattable thys, const AjPStr setname)
11050 {
11051     ajFeattableSetDefname(thys, setname);
11052     return;
11053 }
11054 
11055 
11056 
11057 
11058 /* @obsolete ajFeatGfftagAddC
11059 ** @rename ajFeatGfftagAddCS
11060 */
11061 
ajFeatGfftagAddC(AjPFeature thys,const char * tag,const AjPStr value)11062 __deprecated ajuint ajFeatGfftagAddC(AjPFeature thys,
11063                                      const char* tag, const AjPStr value)
11064 {
11065     return ajFeatGfftagAddCS(thys, tag, value);
11066 }
11067 
11068 
11069 
11070 
11071 /* @obsolete ajFeatGfftagAdd
11072 ** @rename ajFeatGfftagAddSS
11073 */
11074 
ajFeatGfftagAdd(AjPFeature thys,const AjPStr tag,const AjPStr value)11075 __deprecated ajuint ajFeatGfftagAdd(AjPFeature thys,
11076                        const AjPStr tag, const AjPStr value)
11077 {
11078     return ajFeatGfftagAddSS(thys, tag, value);
11079 }
11080 
11081 
11082 
11083 
11084 /* @obsolete ajFeattableCopy
11085 ** @rename ajFeattableNewFtable
11086 */
11087 
ajFeattableCopy(const AjPFeattable orig)11088 __deprecated AjPFeattable ajFeattableCopy(const AjPFeattable orig)
11089 {
11090     return ajFeattableNewFtable(orig);
11091 }
11092 
11093 
11094 
11095 
11096 /* @obsolete ajFeattableCopyLimit
11097 ** @rename ajFeattableNewFtableLimit
11098 */
11099 
ajFeattableCopyLimit(const AjPFeattable orig,ajint limit)11100 __deprecated AjPFeattable ajFeattableCopyLimit(const AjPFeattable orig,
11101                                                ajint limit)
11102 {
11103     return ajFeattableNewFtableLimit(orig, limit);
11104 }
11105 
11106 
11107 
11108 
11109 /* @obsolete ajFeatCopy
11110 ** @rename ajFeatNewFeat
11111 */
11112 
ajFeatCopy(const AjPFeature orig)11113 __deprecated AjPFeature ajFeatCopy(const AjPFeature orig)
11114 {
11115     return ajFeatNewFeat(orig);
11116 }
11117 
11118 
11119 
11120 
11121 /* @obsolete ajFeatIsChild
11122 ** @remove Always returns false, AJFEATFLAG_CHILD was no longer set
11123 */
11124 
ajFeatIsChild(const AjPFeature gf)11125 __deprecated AjBool ajFeatIsChild(const AjPFeature gf)
11126 {
11127     (void) gf;
11128     /*return (gf->Flags & AJFEATFLAG_CHILD);*/
11129     return ajFalse;
11130 }
11131 #endif
11132