1 /* @Source acdrelations application
2 **
3 ** Add relations: attribute to ACD files
4 ** Any existing relations: attributes are replaced.
5 **
6 ** @author: Copyright (C) Jon Ison (jison@ebi.ac.uk)
7 ** @@
8 **
9 ** This program is free software; you can redistribute it and/or
10 ** modify it under the terms of the GNU General Public License
11 ** as published by the Free Software Foundation; either version 2
12 ** of the License, or (at your option) any later version.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 **
23 *******************************************************************************
24 **
25 **  ACDRELATIONS documentation
26 **  See http://wwww.emboss.org
27 **
28 **  Please cite the authors and EMBOSS.
29 **
30 **  Email jison@ebi.ac.uk.
31 **
32 **  acdrelations reads ACD files and writes exact copies but (depending on the
33 **  mode it is run in) with relations: attributes either modified (mode 1) or
34 **  added (mode 2).
35 **  Mode 1
36 **  relations: lines in this format:
37 **  relations: "/edam/data/0001773 Tool-specific parameter"
38 **  are replaced with this format:
39 **  relations: "EDAM:0001773 data Tool-specific parameter"
40 **
41 **
42 **  Mode 2
43 **  acdrelations reads ACD files and writes exact copies but with a relations:
44 **  attribute added to each data definition.  Any existing relations: attributes
45 **  are replaced.  Text for relations: is from the EDAM ontology.
46 **
47 **  acdrelations parameters:
48 **  knowntypes.standards      (EMBOSS data file)
49 **  edamtoacd.dat             (acdrelations data file)
50 **  ACD file input directory
51 **  ACD file output directory
52 **
53 **  knowntypes.standards and edamtoacd.dat define the relations: value.
54 **  Values given in knowntypes.standards take precedence over edamtoacd.dat
55 **
56 **  knowntypes.standards is the standard EMBOSS data file of known types which is annotated with EDAM terms.
57 **  An excerpt:
58 **  aaindex_data                        | file           |  "EDAM: Amino acid index"                               | AAINDEX entry
59 **  aaindex_database                    | file           |  "EDAM: AAindex database"                               | AAINDEX database
60 **  abi_trace                           | file           |  "EDAM: ABI sequencing trace"                           | ABI sequencing trace
61 **
62 **  edamtoacd.dat is a data file defining terms from the EDAM ontology to use
63 **  as values for relations: attribute in ACD files, for different combinations
64 **  of ACD datatypes / attributes.
65 **  For example:
66 **  #
67 **  align          | "EDAM: Sequence alignment data"                             |
68 **  align          | "EDAM: Nucleotide sequence alignment data"                  | type:"nucleotide"
69 **  align          | "EDAM: Protein sequence alignment data"                     | type:"protein"
70 **  align          | "EDAM: Multiple sequence alignment data"                    | minseqs:"3"
71 **  align          | "EDAM: Pairwise sequence alignment data"                    | minseqs:"2"; maxseqs:"2"
72 **  align          | "EDAM: Multiple protein sequence alignment data"            | type:"protein"; minseqs:"3"
73 **  align          | "EDAM: Multiple nucleotide sequence alignment data"         | type:"nucleotide"; minseqs:"3"
74 **  align          | "EDAM: Pairwise nucleotide sequence alignment data"         | type:"nucleotide"; minseqs:"2"; maxseqs:"2"
75 **  align          | "EDAM: Pairwise protein sequence alignment data"            | type:"protein"; minseqs:"2"; maxseqs:"2"
76 **  array          | "EDAM: Generic float array"                                 |
77 **  #
78 **  arraychar      | "EDAM: Generic character array"                             |
79 **  #
80 **  arrayword      | "EDAM: Generic string array"                                |
81 **  #
82 **
83 **
84 **  Meaning of columns is:
85 **  ACD datatype | Attributes that must be specified | Value of relation: attribute | Note
86 **
87 **  IMPORTANT
88 **  For acdrelations to work correctly, edamtoacd.dat must be correctly formatted and laid out:
89 **  1. Lines for a given datatype *must* be given in order of number of attributes in the third column (lowest number first)
90 **  2. The first line for each datatype gives the default value of the relations: attribute and should have no attributes defined.
91 **  3. The attribute:value pairs must be delimited by ';'.
92 **
93 ******************************************************************************/
94 
95 #include "emboss.h"
96 
97 
98 
99 
100 
101 /******************************************************************************
102 **
103 ** DATA STRUCTURES
104 **
105 ******************************************************************************/
106 
107 
108 
109 
110 /* @datastatic PEdamdat *******************************************************
111 **
112 ** edamdat object
113 ** Holds a single line from the data file edamtoacd.dat
114 **
115 ** @alias SEdamdat
116 ** @alias OEdamdat
117 **
118 ** @attr acdtype [AjPStr]  ACD datatype, e.g. "align"
119 ** @attr acdattr [AjPStr*] Array of ACD attribute:value strings e.g. minseqs:"3"
120 **                         Strings must contain no whitespace!
121 ** @attr edam    [AjPStr]  Text to be given after relations: attribute,
122 **                         e.g. "EDAM: Multiple sequence alignment data"
123 **                         if all relations in acdattr are defined for acdtype.
124 ** @attr n       [ajint]   Size of acdattr array
125 ** @attr Padding [ajint] Padding to alignment boundaty
126 ******************************************************************************/
127 typedef struct SEdamdat
128 {
129   AjPStr  acdtype;
130   AjPStr* acdattr;
131   AjPStr  edam;
132   ajint   n;
133   ajint Padding;
134 } OEdamdat;
135 #define PEdamdat OEdamdat*
136 
137 
138 
139 
140 /* @datastatic PEdam **********************************************************
141 **
142 ** edam object
143 ** Holds all lines from the data file edamtoacd.dat
144 **
145 ** @alias SEdam
146 ** @alias OEdam
147 **
148 ** @attr dat    [PEdamdat*] Array of PEdamdat objects
149 ** @attr n      [ajint]     Size of dat array
150 ** @attr Padding [ajint] Padding to alignment boundaty
151 ******************************************************************************/
152 typedef struct SEdam
153 {
154   PEdamdat *dat;
155   ajint  n;
156   ajint Padding;
157 } OEdam;
158 #define PEdam OEdam*
159 
160 
161 
162 
163 /* @datastatic PKtypedat ******************************************************
164 **
165 ** ktypedat object
166 ** Holds a single line from the data file knowntypes.standard
167 **
168 ** @alias SKtypedat
169 ** @alias OKtypedat
170 **
171 ** @attr acdtype [AjPStr]  ACD datatype, e.g. "align"
172 ** @attr ktype   [AjPStr]  Value of knowntype: attribute: no whitespace!
173 ** @attr edam    [AjPStr]  Text to be given after relations: attribute,
174 **                         e.g. "EDAM: Multiple sequence alignment data"
175 **                         if ktype is defined for acdtype.
176 ******************************************************************************/
177 typedef struct SKtypedat
178 {
179   AjPStr acdtype;
180   AjPStr ktype;
181   AjPStr edam;
182 } OKtypedat;
183 #define PKtypedat OKtypedat*
184 
185 
186 
187 
188 /* @datastatic PKtype *********************************************************
189 **
190 ** ktype object
191 ** Holds all lines from the data file knowntypes.standard
192 **
193 ** @alias SKtype
194 ** @alias OKtype
195 **
196 ** @attr dat [PKtypedat*]  Array of PKtypedat objects
197 ** @attr n   [ajint]       Size of dat array
198 ** @attr Padding [ajint] Padding to alignment boundaty
199 ******************************************************************************/
200 typedef struct SKtype
201 {
202   PKtypedat *dat;
203   ajint n;
204   ajint Padding;
205 } OKtype;
206 #define PKtype OKtype*
207 
208 
209 
210 
211 
212 /******************************************************************************
213 **
214 ** PROTOTYPES
215 **
216 ******************************************************************************/
217 
218 static void acdrelations_writerelations
219             (AjPFile  outf,
220 	     AjPStr   acdtype,
221 	     AjPStr  *strarr,
222              ajint    n,
223 	     PEdam  P,
224 	     PKtype T);
225 
226 static void acdrelations_readdatfile
227             (AjPFile inf,
228 	     PEdam *P);
229 
230 static void acdrelations_readtypefile
231             (AjPFile inf,
232 	     PKtype *P);
233 
234 static void acdrelations_procacdfile1
235             (AjPFile inf,
236 	     AjPFile outf);
237 
238 static void acdrelations_procacdfile2
239             (AjPFile inf,
240 	     AjPFile outf,
241 	     PEdam P,
242              PKtype T);
243 
244 
245 static PEdamdat  acdrelations_EdamdatNew(void);
246 static PEdam     acdrelations_EdamNew(void);
247 
248 static void      acdrelations_EdamdatDel(PEdamdat *P);
249 static void      acdrelations_EdamDel(PEdam *P);
250 
251 static PKtypedat acdrelations_KtypedatNew(void);
252 static PKtype    acdrelations_KtypeNew(void);
253 
254 static void      acdrelations_KtypedatDel(PKtypedat *P);
255 static void      acdrelations_KtypeDel(PKtype *P);
256 
257 
258 
259 
260 /* @prog acdrelations ********************************************************
261 **
262 ** Add relations: attribute to ACD files.
263 **
264 *****************************************************************************/
265 
main(ajint argc,char ** argv)266 int main(ajint argc, char **argv)
267 {
268   /* Variable declarations */
269   AjPFile   inf_edam   = NULL;  /* Name of EDAM data (input) file   */
270   AjPFile   acdoutf    = NULL;  /* Name of ACD (output) file        */
271   AjPStr    mode       = NULL;
272 
273   ajint     modei;
274   AjPList   acdinlist  = NULL;  /* List of ACD file names (input)   */
275   AjPFile   acdinf     = NULL;  /* Name of ACD (input) file         */
276   AjPStr    acdname    = NULL;  /* Name of current acd file         */
277   AjPDirout acdoutdir  = NULL;  /* Directory for ACD files (output) */
278 
279   AjPFile   inf_ktype  = NULL;  /* Name of knowntypes.standard file */
280 
281   PEdam   edam         = NULL;  /* EDAM relations data              */
282   PKtype  ktype        = NULL;  /* Data from knowntype.standard     */
283 
284 
285 
286   /* Read data from acd. */
287 /*  embInitP("acdrelations",argc,argv,"MYEMBOSS"); */
288   embInit("acdrelations",argc,argv);
289 
290   /* ACD data handling */
291   mode = ajAcdGetListSingle("mode");
292   inf_edam   = ajAcdGetDatafile("inedamfile");
293   inf_ktype  = ajAcdGetInfile("intypefile");
294   acdinlist  = ajAcdGetDirlist("indir");
295   acdoutdir  = ajAcdGetOutdir("outdir");
296 
297   ajStrToInt(mode, &modei);
298 
299   /* Read data file */
300   if(modei==2)
301   {
302       edam  = acdrelations_EdamNew();
303       ktype = acdrelations_KtypeNew();
304       acdrelations_readdatfile(inf_edam, &edam);
305       acdrelations_readtypefile(inf_ktype, &ktype);
306   }
307 
308 
309   /*  Main application loop. Process each ACD file in turn.  */
310   while(ajListPop(acdinlist,(void **)&acdname))
311   {
312       if(!(acdinf = ajFileNewInNameS(acdname)))
313           ajFatal("Cannot open input ACD file %S\n", acdname);
314 
315       ajFilenameTrimPath(&acdname);
316 
317       if(!(acdoutf = ajFileNewOutNameDirS(acdname, acdoutdir)))
318           ajFatal("Cannot open output ACD file %S\n", acdname);
319 
320       if(modei==1)
321           acdrelations_procacdfile1(acdinf, acdoutf);
322       else if(modei==2)
323           acdrelations_procacdfile2(acdinf, acdoutf, edam, ktype);
324       else
325           ajFatal("Unknown mode");
326 
327       ajFileClose(&acdinf);
328       ajFileClose(&acdoutf);
329   }
330 
331   /* Clean up and exit */
332   ajStrDel(&mode);
333 
334   if(modei==2)
335   {
336       ajFileClose(&inf_edam);
337       ajFileClose(&inf_ktype);
338       acdrelations_EdamDel(&edam);
339       acdrelations_KtypeDel(&ktype);
340   }
341 
342   ajListFree(&acdinlist);
343   ajDiroutDel(&acdoutdir);
344 
345 
346 
347   ajExit();
348   return 0;
349 }
350 
351 
352 
353 
354 /******************************************************************************
355 **
356 ** FUNCTIONS
357 **
358 ******************************************************************************/
359 
360 
361 
362 
363 /* @funcstatic acdrelations_readdatfile ***************************************
364 **
365 ** Read the data file edamtoacd.dat and write edam object.
366 **
367 ** @param [u] inf [AjPFile] Handle on edamtoacd.dat
368 ** @param [u] P   [PEdam*]  edam object to write
369 ** @return [void]
370 ** @@
371 ******************************************************************************/
372 
acdrelations_readdatfile(AjPFile inf,PEdam * P)373 static void acdrelations_readdatfile
374             (AjPFile inf,
375 	     PEdam *P)
376 {
377   AjPStr  line           = NULL;
378   const AjPStr  tok      = NULL;
379   const AjPStr  subtok   = NULL;
380   AjPStr  strtmp         = NULL;
381   AjPList strlist        = NULL;
382 
383   AjPStr  acdtype        = NULL;
384   AjPStr  relations      = NULL;
385 
386   PEdamdat dattmp        = NULL;
387   AjPList  datlist       = NULL;
388 
389   if(!P)
390     ajFatal("Null arg error 1 in acdrelations_readdatfile");
391   if(!inf)
392     ajFatal("Null arg error 3 in acdrelations_readdatfile");
393 
394 
395   /* Allocate memory */
396   line      = ajStrNew();
397   acdtype   = ajStrNew();
398   relations = ajStrNew();
399   datlist   = ajListNew();
400 
401   /* Read data from file */
402   while(ajReadline(inf,&line))
403     {
404       /* Discard comment lines */
405       if(ajStrPrefixC(line,"#"))
406 	continue;
407 
408 
409 
410       /* Tokenise line, delimited by '|'.
411          Parse first token (ACD datatype ) */
412       ajStrAssignS(&acdtype, ajStrParseC(line, "|"));
413 
414       /* Parse second token (EDAM relations: value ) */
415       ajStrAssignS(&relations, ajStrParseC(NULL, "|"));
416 
417       /* Parse third token (attribute:value strings block) */
418       tok = ajStrParseC(NULL, "|");
419 
420 
421       /* Create new string list */
422       strlist = ajListstrNew();
423 
424       /* Tokenise third token itself into tokens delimited by ' ' (space)
425          Parse tokens (individual attribute:value strings)*/
426       if((subtok=ajStrParseC(tok, ";")))
427       {
428           strtmp = ajStrNew();
429           ajStrAssignS(&strtmp, subtok);
430           ajStrRemoveWhite(&strtmp);
431           ajListstrPushAppend(strlist, strtmp);
432 
433           while((subtok=ajStrParseC(NULL, ";")))
434           {
435               strtmp = ajStrNew();
436               ajStrAssignS(&strtmp, subtok);
437               ajStrRemoveWhite(&strtmp);
438               ajListstrPushAppend(strlist, strtmp);
439           }
440       }
441 
442       /* Write PEdamdat structure & push onto list */
443       dattmp = acdrelations_EdamdatNew();
444       ajStrRemoveWhite(&acdtype);
445       ajStrAssignS(&dattmp->acdtype, acdtype);
446       ajStrAssignS(&dattmp->edam, relations);
447       dattmp->n = (ajuint) ajListstrToarray(strlist, &dattmp->acdattr);
448       ajListPushAppend(datlist, dattmp);
449 
450       /* Clear nodes (but not strings) from string list */
451       ajListstrFree(&strlist);
452     }
453 
454 
455   /* Write PEdam structure */
456   ((*P)->n) = (ajuint) ajListToarray(datlist, (void***) &((*P)->dat));
457 
458   /* Free memory */
459   ajStrDel(&line);
460   ajStrDel(&acdtype);
461   ajStrDel(&relations);
462   ajListFree(&datlist);
463 
464   return;
465 }
466 
467 
468 
469 
470 
471 /* @funcstatic acdrelations_readtypefile **************************************
472 **
473 ** Read the data file knowntypes.standard and write ktype object
474 **
475 ** @param [u] inf [AjPFile]  Handle on knowntypes.standard
476 ** @param [u] T   [PKtype*]  ktype object to write
477 ** @return [void]
478 ** @@
479 ******************************************************************************/
480 
acdrelations_readtypefile(AjPFile inf,PKtype * T)481 static void acdrelations_readtypefile
482             (AjPFile inf,
483 	     PKtype *T)
484 {
485     AjPStr     line    = NULL;
486     PKtypedat  dattmp  = NULL;
487     AjPList    datlist = NULL;
488 
489     if(!T)
490         ajFatal("Null arg error 1 in acdrelations_readtypefile");
491     if(!inf)
492         ajFatal("Null arg error 3 in acdrelations_readtypefile");
493 
494 
495     /* Allocate memory */
496     line           = ajStrNew();
497     datlist        = ajListNew();
498 
499 
500     /* Read data from file */
501     while(ajReadline(inf,&line))
502     {
503         /* Discard comment lines */
504         if(ajStrPrefixC(line,"#"))
505             continue;
506 
507         /* Create object for holding line */
508         dattmp = acdrelations_KtypedatNew();
509 
510         /* Tokenise line delimited by '|'
511            Parse first token (value of knowntype: attribute) */
512         ajStrAssignS(&dattmp->ktype, ajStrParseC(line, "|"));
513         ajStrRemoveSetC(&dattmp->ktype, "_");
514         ajStrRemoveWhite(&dattmp->ktype);
515 
516         /* Parse second token (ACD datatype) */
517         ajStrAssignS(&dattmp->acdtype, ajStrParseC(NULL, "|"));
518 
519         /* Parse third token (EDAM relations: value ) */
520         ajStrAssignS(&dattmp->edam, ajStrParseC(NULL, "|"));
521 
522         /* Push line onto list */
523         ajListPushAppend(datlist, dattmp);
524     }
525 
526 
527     /* Write PKtype structure */
528     ((*T)->n) = (ajuint) ajListToarray(datlist, (void***) &((*T)->dat));
529 
530 
531     /* Free memory */
532     ajStrDel(&line);
533     ajListFree(&datlist);
534 
535     return;
536 }
537 
538 
539 
540 
541 
542 /* @funcstatic acdrelations_procacdfile1 ***************************************
543 **
544 ** Process ACD file and write new ACD file with relations: attributes in new
545 ** format (mode '1' operation).
546 **
547 ** @param [u] inf  [AjPFile] ACD input file
548 ** @param [u] outf [AjPFile] ACD output file
549 ** @return [void]
550 ** @@
551 ******************************************************************************/
acdrelations_procacdfile1(AjPFile inf,AjPFile outf)552 static void acdrelations_procacdfile1
553             (AjPFile inf,
554 	     AjPFile outf)
555 {
556   AjPStr    line      = NULL;
557   AjPStr    tmp       = NULL;
558   AjPStr    tok       = NULL;
559   AjPStr    id        = NULL;
560   AjPStr    name      = NULL;
561   AjPStr    namespace = NULL;
562   AjPStrTok parse     = NULL;
563   ajint     pos;
564 
565 
566   /* Allocate memory */
567   line        = ajStrNew();
568   tmp         = ajStrNew();
569   tok         = ajStrNew();
570   id          = ajStrNew();
571   name        = ajStrNew();
572   namespace   = ajStrNew();
573 
574 
575   /*  Read next line */
576   while(ajReadline(inf,&line))
577   {
578       ajFmtScanS(line, "%S", &tok);
579 
580       /* Write reformatted relations: line */
581       if(ajStrMatchC(tok, "relations:"))
582       {
583           /* Tokenise line segment (from after "relations:") by '"', ' ' and '/'
584              Discard unwanted tokens */
585           pos = (ajuint) ajStrFindAnyK(line, ':');
586           ajStrAssignC(&tmp, line->Ptr+pos);
587 
588           parse = ajStrTokenNewC(tmp, "\" /");
589           ajStrTokenNextParse(parse, &tok);
590           ajStrTokenNextParse(parse, &tok);
591 
592           /* Get namespace and id tokens */
593           ajStrTokenNextParse(parse, &namespace);
594           ajStrTokenNextParse(parse, &id);
595 
596           /* Get rest of string (name)
597              Strip whitespace at start and trailing " from name. */
598           ajStrTokenRestParse(parse, &name);
599           ajStrRemoveWhiteExcess(&name);
600           ajStrRemoveSetC(&name, "\"\n");
601           ajStrTokenDel(&parse);
602 
603           /* Position of last '/' and last '"' characters respectively. */
604           ajFmtPrintF(outf, "    relations: \"EDAM:%S %S %S\"\n", id, namespace, name);
605       }
606 
607       /* Write other lines out as-is */
608       else
609           ajFmtPrintF(outf, "%S", line);
610   }
611 
612 
613   /* Free memory */
614   ajStrDel(&line);
615   ajStrDel(&tmp);
616   ajStrDel(&tok);
617   ajStrDel(&id);
618   ajStrDel(&name);
619   ajStrDel(&namespace);
620 
621   return;
622 }
623 
624 
625 
626 
627 /* @funcstatic acdrelations_procacdfile2 ***************************************
628 **
629 ** Process ACD file and write new ACD file with new relations: attributes
630 ** added (replaced if necessary) using mode '2' operation.
631 **
632 ** @param [u] inf  [AjPFile] ACD input file
633 ** @param [u] outf [AjPFile] ACD output file
634 ** @param [u] P    [PEdam]   edam object
635 ** @param [u] T    [PKtype]  ktype object
636 ** @return [void]
637 ** @@
638 ******************************************************************************/
acdrelations_procacdfile2(AjPFile inf,AjPFile outf,PEdam P,PKtype T)639 static void acdrelations_procacdfile2
640             (AjPFile inf,
641 	     AjPFile outf,
642 	     PEdam P,
643     	     PKtype T)
644 {
645   AjPStr   line     = NULL;
646   AjPStr   tok      = NULL;
647   AjPStr   acdtype  = NULL;
648   AjPStr   strtmp   = NULL;
649   AjPList  strlist  = NULL;
650   AjPStr  *strarr   = NULL;
651   ajint    nstr     = 0;
652 
653 
654   /* Allocate memory */
655   line        = ajStrNew();
656   tok         = ajStrNew();
657   acdtype     = ajStrNew();
658   strlist     = ajListstrNew();
659 
660 
661   /*  Read next line */
662   while(ajReadline(inf,&line))
663     {
664       ajFmtScanS(line, "%S", &tok);
665 
666       /* Write application definition or section definition out as-is */
667       if(ajStrMatchC(tok, "application:")  ||
668 	 ajStrMatchC(tok, "section:"))
669       {
670 	  ajFmtPrintF(outf, "%S", line);
671 	  while(ajReadline(inf,&line))
672           {
673 	      ajFmtPrintF(outf, "%S", line);
674 	      ajFmtScanS(line, "%S", &tok);
675 	      if(ajStrMatchC(tok, "]"))
676                   break;
677           }
678       }
679       /* Write variables, endsection definitions and comments out as-is */
680       else if(ajStrMatchC(tok, "variable:")   ||
681 	      ajStrMatchC(tok, "endsection:") ||
682               ajStrMatchC(tok, "#"))
683           ajFmtPrintF(outf, "%S", line);
684 
685       /* Write out blank lines as-is */
686       else if (!ajFmtScanS(line, "%S", &tok))
687           ajFmtPrintF(outf, "%S", line);
688       /* Process data definition */
689       else
690           /* First line of data definition */
691       {
692           /* Process and write datatype line */
693           ajFmtPrintF(outf, "%S", line);
694           ajFmtScanS(line, "%S", &acdtype);
695 	  ajStrRemoveSetC(&acdtype, ":");
696 
697           /* Process subsequent (attribute) lines */
698 	  while(ajReadline(inf,&line))
699 	    {
700 	      strtmp = ajStrNew();
701 	      ajStrAssignS(&strtmp, line);
702 	      ajStrRemoveWhite(&strtmp);
703 	      ajListstrPushAppend(strlist, strtmp);
704 
705 	      ajFmtScanS(line, "%S", &tok);
706 
707               /* Reached end of data definition */
708               if(ajStrMatchC(tok, "]"))
709               {
710                   nstr = (ajuint) ajListstrToarray(strlist, &strarr);
711 
712                   /* Write relations: line */
713                   acdrelations_writerelations(outf, acdtype, strarr, nstr, P, T);
714 
715                   AJFREE(strarr);
716                   ajListstrFreeData(&strlist);
717 		  strlist = ajListstrNew();
718 
719 		  ajFmtPrintF(outf, "%S", line);
720 		  break;
721 		}
722               /* Ignore existing relations: lines */
723               else if(ajStrMatchC(tok, "relations:"))
724                   continue;
725 
726 	      ajFmtPrintF(outf, "%S", line);
727 	    }
728 	}
729     }
730 
731 
732   /* Free memory */
733   ajStrDel(&line);
734   ajStrDel(&tok);
735   ajStrDel(&acdtype);
736   ajListstrFreeData(&strlist);
737 
738   return;
739 }
740 
741 
742 
743 
744 
745 /* @funcstatic acdrelations_writerelations ************************************
746 **
747 ** Writes relations: attribute for an ACD data definition
748 ** The relations: values given in knowntypes.standard have highest precedence,
749 ** then the values given in edamtoacd.dat
750 ** Attribute values for a given datatype in edamtoacd.dat are in order of
751 ** increasing precedence, i.e. the last line is highest and the relations:
752 ** value will be used if all conditions are met.
753 **
754 ** @param [u] outf    [AjPFile] ACD output file
755 ** @param [u] acdtype [AjPStr] ACD datatype, e.g. "align"
756 ** @param [u] strarr  [AjPStr*] All ACD attribute lines (whitespace removed)
757 **                              for the the current ACD data item (of type
758 **                              acdtype).  One line per array element.
759 ** @param [r] n       [ajint]   Size of strarr
760 ** @param [u] P       [PEdam]   edam object to write
761 ** @param [u] T       [PKtype]  ktype object to read
762 ** @return [void]
763 ** @@
764 ******************************************************************************/
acdrelations_writerelations(AjPFile outf,AjPStr acdtype,AjPStr * strarr,ajint n,PEdam P,PKtype T)765 static void acdrelations_writerelations
766             (AjPFile outf,
767 	     AjPStr  acdtype,
768 	     AjPStr *strarr,
769              ajint   n,
770 	     PEdam   P,
771     	     PKtype  T)
772 {
773     ajint  i         = 0;
774     ajint  j         = 0;
775     ajint  k         = 0;
776     ajint  nmatch    = 0;
777     AjPStr relations = NULL;
778     AjPStr ktype     = NULL;     /* Value of knowntype: attribute */
779     AjBool done      = ajFalse;
780     AjBool donetype  = ajFalse;
781     AjPStr tmpstr    = NULL;
782 
783 
784     if(!outf || !acdtype || !strarr || !n || !P)
785         ajFatal("NULL args passed to acdrelations_writerelations");
786 
787     /* Memory allocation */
788     relations = ajStrNew();
789     ktype     = ajStrNew();
790     tmpstr    = ajStrNew();
791 
792 
793     /* Loop through all lines in edamtoacd.dat */
794     for(i=0; i<P->n ;i++)
795     {
796         /* Found matching datatype */
797         if(ajStrMatchS(acdtype, P->dat[i]->acdtype))
798         {
799             /* Copy first relations: string defined for this datatype (default) */
800             ajStrAssignS(&relations, P->dat[i]->edam);
801             done = ajTrue;
802             i++;
803 
804             /* Check next line in edamtoacd.dat */
805             for( ; i<P->n; i++)
806             {
807                 /* Datatype still matches */
808                 if(ajStrMatchS(acdtype, P->dat[i]->acdtype))
809                 {
810                     /* Loop through all required attributes for this datatype */
811                     for(nmatch=0, j=0; j<P->dat[i]->n; j++)
812                     {
813                         /* Loop through all attribute lines for the data defininition */
814                         for(k=0; k<n; k++)
815                             if(ajStrMatchS(P->dat[i]->acdattr[j], strarr[k]))
816                             {
817                                 nmatch++;
818                                 break;
819                             }
820                     }
821                     /* All attribute values match */
822                     if(nmatch == P->dat[i]->n)
823                         ajStrAssignS(&relations, P->dat[i]->edam);
824                     /* Should never happen */
825                     else if (nmatch > P->dat[i]->n)
826                         ajFatal("Terminal weirdness in acdrelations_writerelations");
827                 }
828                 else
829                     break;
830             }
831             break;
832         }
833     }
834 
835     /* Check for match of knowntype: attribute against knowntypes.standard.
836        These have higher precedence than the rules defined in edamtoacd.dat */
837     for(donetype=ajFalse, i=0; i<n; i++)
838     {
839         if(ajStrPrefixC(strarr[i], "knowntype:"))
840         {
841 
842             for(j=0;j<T->n; j++)
843             {
844                 /* No check is made on the "Type" column in knowntypes.standard
845                    as these are not proper ACD datatype names
846                    To check these add
847                    if(ajStrMatchS(acdtype, T->dat[j]->acdtype)) */
848 
849                 ajFmtPrintS(&tmpstr, "knowntype:\"%S\"", T->dat[j]->ktype);
850 
851                     if(ajStrMatchS(tmpstr, strarr[i]))
852                     {
853                         ajStrAssignS(&relations, T->dat[j]->edam);
854                         donetype=ajTrue;
855                         break;
856                     }
857             }
858             if(donetype)
859                 break;
860         }
861         else
862             continue;
863     }
864 
865 
866     if(!done)
867         ajFatal("No matching datatype (%S) in acdrelations_writerelations", acdtype);
868 
869 
870     /* Write relations: attribute line to file */
871     ajFmtPrintF(outf, "    relations:%S\n", relations);
872 
873 
874     /* Free memory */
875     ajStrDel(&relations);
876     ajStrDel(&ktype);
877     ajStrDel(&tmpstr);
878 
879     return;
880 }
881 
882 
883 
884 
885 
886 /* @funcstatic acdrelations_EdamdatNew ****************************************
887 **
888 ** edamdat constructor
889 ** The array is NOT allocated
890 **
891 ** @return [PEdamdat] New object
892 ** @@
893 ******************************************************************************/
acdrelations_EdamdatNew(void)894 static PEdamdat  acdrelations_EdamdatNew(void)
895 {
896   PEdamdat ret;
897 
898   AJNEW0(ret);
899   ret->acdtype  = ajStrNew();
900   ret->edam     = ajStrNew();
901   ret->acdattr  = NULL;
902   ret->n        = 0;
903 
904   return ret;
905 }
906 
907 
908 
909 
910 
911 /* @funcstatic acdrelations_EdamNew *******************************************
912 **
913 ** edam constructor
914 ** The array is NOT allocated
915 **
916 ** @return [PEdam] New object
917 ** @@
918 ******************************************************************************/
acdrelations_EdamNew(void)919 static PEdam     acdrelations_EdamNew(void)
920 {
921   PEdam ret;
922 
923   AJNEW0(ret);
924 
925   ret->dat = NULL;
926   ret->n = 0;
927 
928   return ret;
929 }
930 
931 
932 
933 
934 
935 /* @funcstatic acdrelations_EdamdatDel ****************************************
936 **
937 ** edamdat destructor
938 **
939 ** @param [d] P       [PEdamdat*]  edamdat object to delete
940 ** @return [void]
941 ** @@
942 ******************************************************************************/
acdrelations_EdamdatDel(PEdamdat * P)943 static void        acdrelations_EdamdatDel(PEdamdat *P)
944 {
945   int i;
946 
947   if(!P)
948     ajFatal("Null arg error 1 in acdrelations_EdamdatDel");
949   else if(!(*P))
950     ajFatal("Null arg error 2 in acdrelations_EdamdatDel");
951 
952   ajStrDel(&(*P)->acdtype);
953   ajStrDel(&(*P)->edam);
954 
955   if((*P)->n)
956     {
957         for(i=0;i<(*P)->n;i++)
958             ajStrDel(&(*P)->acdattr[i]);
959         AJFREE((*P)->acdattr);
960     }
961 
962   AJFREE(*P);
963   *P=NULL;
964 
965   return;
966 }
967 
968 
969 
970 
971 
972 /* @funcstatic acdrelations_EdamDel *******************************************
973 **
974 ** edam destructor
975 **
976 ** @param [d] P       [PEdam*]  edam object to delete
977 ** @return [void]
978 ** @@
979 ******************************************************************************/
acdrelations_EdamDel(PEdam * P)980 static void        acdrelations_EdamDel(PEdam *P)
981 {
982   int i;
983 
984   if(!P)
985     ajFatal("Null arg error 1 in acdrelations_EdamDel");
986   else if(!(*P))
987     ajFatal("Null arg error 2 in acdrelations_EdamDel");
988 
989   if((*P)->n)
990     {
991         for(i=0;i<(*P)->n;i++)
992             acdrelations_EdamdatDel(&(*P)->dat[i]);
993         AJFREE((*P)->dat);
994     }
995 
996   AJFREE(*P);
997   *P=NULL;
998 
999   return;
1000 }
1001 
1002 
1003 
1004 
1005 
1006 /* @funcstatic acdrelations_KtypedatNew ***************************************
1007 **
1008 ** ktypedat constructor
1009 **
1010 ** @return [PKtypedat] New object
1011 ** @@
1012 ******************************************************************************/
1013 
acdrelations_KtypedatNew(void)1014 static PKtypedat  acdrelations_KtypedatNew(void)
1015 {
1016   PKtypedat ret;
1017 
1018   AJNEW0(ret);
1019   ret->acdtype = ajStrNew();
1020   ret->edam    = ajStrNew();
1021   ret->ktype   = ajStrNew();
1022 
1023   return ret;
1024 }
1025 
1026 
1027 
1028 
1029 
1030 /* @funcstatic acdrelations_KtypeNew ******************************************
1031 **
1032 ** ktype constructor
1033 **
1034 ** @return [PKtype] New object
1035 ** @@
1036 ******************************************************************************/
acdrelations_KtypeNew(void)1037 static PKtype     acdrelations_KtypeNew(void)
1038 {
1039   PKtype ret;
1040 
1041   AJNEW0(ret);
1042 
1043   ret->dat = NULL;
1044   ret->n = 0;
1045 
1046   return ret;
1047 }
1048 
1049 
1050 
1051 
1052 
1053 /* @funcstatic acdrelations_KtypedatDel ***************************************
1054 **
1055 ** ktypedat destructor
1056 **
1057 ** @param [d] P       [PKtypedat*] ktypedat object to delete
1058 ** @return [void]
1059 ** @@
1060 ******************************************************************************/
acdrelations_KtypedatDel(PKtypedat * P)1061 static void        acdrelations_KtypedatDel(PKtypedat *P)
1062 {
1063   if(!P)
1064     ajFatal("Null arg error 1 in acdrelations_KtypedatDel");
1065   else if(!(*P))
1066     ajFatal("Null arg error 2 in acdrelations_KtypedatDel");
1067 
1068   ajStrDel(&(*P)->acdtype);
1069   ajStrDel(&(*P)->edam);
1070   ajStrDel(&(*P)->ktype);
1071 
1072   AJFREE(*P);
1073   *P=NULL;
1074 
1075   return;
1076 }
1077 
1078 
1079 
1080 
1081 
1082 /* @funcstatic acdrelations_KtypeDel ******************************************
1083 **
1084 ** ktype destructor
1085 **
1086 ** @param [d] P       [PKtype*] ktype object to delete
1087 ** @return [void]
1088 ** @@
1089 ******************************************************************************/
acdrelations_KtypeDel(PKtype * P)1090 static void        acdrelations_KtypeDel(PKtype *P)
1091 {
1092   int i;
1093 
1094   if(!P)
1095     ajFatal("Null arg error 1 in acdrelations_KtypeDel");
1096   else if(!(*P))
1097     ajFatal("Null arg error 2 in acdrelations_KtypeDel");
1098 
1099   if((*P)->n)
1100     {
1101         for(i=0;i<(*P)->n;i++)
1102             acdrelations_KtypedatDel(&(*P)->dat[i]);
1103         AJFREE((*P)->dat);
1104     }
1105 
1106   AJFREE(*P);
1107   *P=NULL;
1108 
1109   return;
1110 }
1111