1 /* @source embgroup ***********************************************************
2 **
3 ** Group Routines.
4 **
5 ** @author Copyright (c) 1999 Alan Bleasby
6 ** @version $Revision: 1.60 $
7 ** @modified $Date: 2012/12/07 10:23:51 $ by $Author: rice $
8 ** @@
9 **
10 ** This library is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU Lesser General Public
12 ** License as published by the Free Software Foundation; either
13 ** version 2.1 of the License, or (at your option) any later version.
14 **
15 ** This library is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** Lesser General Public License for more details.
19 **
20 ** You should have received a copy of the GNU Lesser General Public
21 ** License along with this library; if not, write to the Free Software
22 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 ** MA 02110-1301, USA.
24 **
25 ******************************************************************************/
26
27
28 #include "ajlib.h"
29
30 #include "embgroup.h"
31 #include "ajlist.h"
32 #include "ajfile.h"
33 #include "ajtable.h"
34 #include "ajobo.h"
35 #include "ajoboread.h"
36 #include "ajsys.h"
37 #include "ajnam.h"
38 #include "ajfileio.h"
39 #include "ajacd.h"
40
41 #include <sys/types.h> /* for opendir etc. */
42 #ifndef WIN32
43 #include <dirent.h> /* for readdir */
44 #else
45 #include "win32.h"
46 #include "dirent_w32.h"
47 #endif
48 #include <string.h>
49 #include <sys/stat.h> /* for stat */
50
51
52
53 static void grpProgClear(EmbPGroupProg gl);
54 static void grpGroupsListClear(AjPList groupslist);
55 static void grpRelationsListClear(AjPList relslist);
56 static EmbPGroupProg grpCopyPnode(const EmbPGroupProg pnode);
57 static EmbPGroupRelation grpRelationsCopy(const EmbPGroupRelation gr);
58 static void grpGetAcdFiles(AjPList glist, AjPList alpha, char * const env[],
59 const AjPStr acddir, AjBool explode, AjBool colon,
60 AjBool gui, AjBool embassy,
61 const AjPStr embassyname);
62 static void grpGetAcdDirs(AjPList glist, AjPList alpha, char * const env[],
63 const AjPStr acddir, AjBool explode, AjBool colon,
64 AjBool gui, AjBool embassy,
65 const AjPStr embassyname);
66 static void grpParse(AjPFile file, AjPList groups,
67 AjBool explode, AjBool colon,
68 AjBool *gui, AjBool* embassy,
69 EmbPGroupProg *Pprognode);
70 static void grpParseEmbassy(AjPFile file, AjPStr* embassyname);
71 static void grpNoComment(AjPStr* text);
72 static AjPStr grpParseValueRB(AjPStrTok tokenhandle, const char* delim);
73 static void grpSplitList(AjPList groups, const AjPStr value, AjBool explode,
74 AjBool colon, AjPStr* keywords);
75 static void grpSubSplitList(AjPList groups, AjPList sublist);
76 static void grpAddGroupsToList(const AjPList alpha, AjPList glist,
77 const AjPList groups,
78 EmbPGroupProg *Pprognode);
79 static AjBool grpGetAcdByname(const AjPStr appname, const AjPStr acddir,
80 AjPStr* embassyname);
81
82 static AjPStr grpStr1 = NULL;
83 static AjPStr grpStr2 = NULL;
84
85
86
87
88 /* @func embGrpGetProgGroups **************************************************
89 **
90 ** Optionally constructs a path to the directory of normal EMBOSS or
91 ** embassy ACD files. Calls grpGetAcdFiles to construct lists of the
92 ** group, doc and program name information.
93 **
94 ** @param [w] glist [AjPList] List of groups of programs
95 ** @param [w] alpha [AjPList] Alphabetic list of programs
96 ** @param [r] env [char* const[]] Environment passed in from C main()
97 ** parameters
98 ** @param [r] emboss [AjBool] Read in EMBOSS ACD data
99 ** @param [r] embassy [AjBool] Read in EMBASSY ACD data
100 ** @param [r] embassyname [const AjPStr] Name of embassy package.
101 ** default is to search for all
102 ** @param [r] explode [AjBool] Expand group names around ':'
103 ** @param [r] colon [AjBool] Retain ':' in group names
104 ** @param [r] gui [AjBool] Only report programs that are OK in GUIs
105 ** @return [void]
106 **
107 ** @release 1.0.0
108 ** @@
109 ******************************************************************************/
110
embGrpGetProgGroups(AjPList glist,AjPList alpha,char * const env[],AjBool emboss,AjBool embassy,const AjPStr embassyname,AjBool explode,AjBool colon,AjBool gui)111 void embGrpGetProgGroups(AjPList glist, AjPList alpha, char * const env[],
112 AjBool emboss, AjBool embassy,
113 const AjPStr embassyname,
114 AjBool explode, AjBool colon, AjBool gui)
115 {
116
117 AjPStr acdroot = NULL;
118 AjPStr acdrootdir = NULL;
119 AjPStr acdrootinst = NULL;
120 AjPStr acdpack = NULL;
121 AjPStr alphaname = NULL;
122 EmbPGroupTop gpnode; /* new member (first & only) of alpha being added */
123 AjBool doneinstall = ajFalse;
124
125 /* set up alpha programs group list */
126 ajStrAssignC(&alphaname, "Alphabetic list of programs");
127 gpnode = embGrpMakeNewGnode(alphaname);
128 ajListPushAppend(alpha, gpnode);
129 ajStrDel(&alphaname);
130
131
132 /* look at all EMBOSS ACD files */
133 acdpack = ajStrNew();
134 acdroot = ajStrNew();
135 acdrootdir = ajStrNew();
136 acdrootinst = ajStrNew();
137 alphaname = ajStrNew();
138
139 ajStrAssignS(&acdpack, ajNamValuePackage());
140 ajStrAssignS(&acdrootinst, ajNamValueInstalldir());
141
142 if(emboss)
143 {
144 if(ajNamGetValueC("acdroot", &acdroot))
145 {
146 ajDirnameFix(&acdroot);
147 /*ajStrAppendC(&acdroot, "acd/");*/
148 }
149 else
150 {
151 ajDirnameFix(&acdrootinst);
152 ajFmtPrintS(&acdroot, "%Sshare/%S/acd/", acdrootinst, acdpack);
153
154 if(ajDirnameFixExists(&acdroot))
155 doneinstall = ajTrue;
156 else
157 {
158 ajStrAssignS(&acdrootdir, ajNamValueRootdir());
159 ajDirnameFix(&acdrootdir);
160 ajFmtPrintS(&acdroot, "%Sacd/", acdrootdir);
161 }
162 }
163
164 /* normal EMBOSS ACD */
165 grpGetAcdFiles(glist, alpha, env, acdroot, explode, colon,
166 gui, embassy, embassyname);
167 }
168
169 if(embassy && !doneinstall)
170 {
171 ajDirnameFix(&acdroot);
172
173 /* EMBOSS install directory */
174 ajFmtPrintS(&acdroot, "%Sshare/%S/acd/",
175 acdrootinst, acdpack);
176
177 if(ajDirnameFixExists(&acdroot))
178 /* embassadir ACD files */
179 grpGetAcdFiles(glist, alpha, env, acdroot, explode, colon,
180 gui, embassy, embassyname);
181 else
182 {
183 /* look for all source directories */
184 ajStrAssignS(&acdrootdir, ajNamValueRootdir());
185 ajDirnameUp(&acdrootdir);
186 ajFmtPrintS(&acdroot, "%Sembassy/", acdrootdir);
187 /* embassadir ACD files */
188 grpGetAcdDirs(glist, alpha, env, acdroot, explode, colon,
189 gui, embassy, embassyname);
190 }
191
192 }
193
194 /* sort the groups and alpha lists */
195 embGrpSortGroupsList(glist);
196 embGrpSortGroupsList(alpha);
197
198 ajStrDel(&acdroot);
199 ajStrDel(&acdrootdir);
200 ajStrDel(&acdrootinst);
201 ajStrDel(&alphaname);
202 ajStrDel(&acdpack);
203
204 return;
205 }
206
207
208
209
210 /* @func embGrpGetEmbassy *****************************************************
211 **
212 ** Optionally constructs a path to the directory of normal EMBOSS or
213 ** embassy ACD files. Calls grpGetAcdFiles to construct lists of the
214 ** group, doc and program name information.
215 **
216 ** @param [r] appname [const AjPStr] Application name
217 ** @param [w] embassyname [AjPStr*] Embassy package attribute value,
218 ** or an empty string if in the main package
219 ** @return [AjBool] ajTrue if an ACD file was found
220 **
221 ** @release 4.1.0
222 ** @@
223 ******************************************************************************/
224
embGrpGetEmbassy(const AjPStr appname,AjPStr * embassyname)225 AjBool embGrpGetEmbassy(const AjPStr appname, AjPStr* embassyname)
226 {
227
228 AjPStr acdroot = NULL;
229 AjPStr acdrootdir = NULL;
230 AjPStr acdrootinst = NULL;
231 AjPStr acdpack = NULL;
232 AjPFile acdfile = NULL;
233 AjPStr filename = NULL;
234 AjBool ok = ajFalse;
235
236 /* look at all EMBOSS ACD files */
237 acdpack = ajStrNew();
238 acdroot = ajStrNew();
239 acdrootdir = ajStrNew();
240 acdrootinst = ajStrNew();
241
242 ajStrAssignS(&acdpack, ajNamValuePackage());
243 ajStrAssignS(&acdrootinst, ajNamValueInstalldir());
244
245 ajStrAssignC(embassyname, "");
246
247 if(ajNamGetValueC("acdroot", &acdroot))
248 {
249 ajDirnameFix(&acdroot);
250 /*ajStrAppendC(&acdroot, "acd/");*/
251 }
252 else
253 {
254 ajDirnameFix(&acdrootinst);
255 ajFmtPrintS(&acdroot, "%Sshare/%S/acd/", acdrootinst, acdpack);
256
257 if(!ajDirnameFixExists(&acdroot))
258 {
259 ajStrAssignS(&acdrootdir, ajNamValueRootdir());
260 ajDirnameFix(&acdrootdir);
261 ajFmtPrintS(&acdroot, "%Sacd/", acdrootdir);
262 }
263 }
264
265 /* normal EMBOSS ACD */
266 ajFmtPrintS(&filename, "%S%S.acd", acdroot, appname);
267 acdfile = ajFileNewInNameS(filename);
268
269 if(acdfile)
270 {
271 grpParseEmbassy(acdfile, embassyname);
272 ajFileClose(&acdfile);
273 ok = ajTrue;
274 }
275
276 if(!ok)
277 {
278 /* look for all source directories */
279 ajStrAssignS(&acdrootdir, ajNamValueRootdir());
280 ajDirnameUp(&acdrootdir);
281 ajFmtPrintS(&acdroot, "%Sembassy/", acdrootdir);
282 /* embassadir ACD files */
283 ok = grpGetAcdByname(appname, acdroot, embassyname);
284 }
285
286 ajStrDel(&acdroot);
287 ajStrDel(&acdrootdir);
288 ajStrDel(&acdrootinst);
289 ajStrDel(&acdpack);
290 ajStrDel(&filename);
291
292 ajDebug("embGrpGetEmbassy ok:%B embassy '%S'\n",
293 ok, *embassyname);
294 return ok;
295 }
296
297
298
299
300 /* @funcstatic grpGetAcdByname ************************************************
301 **
302 ** Given a directory from main package or EMBASSY sources, it searches
303 ** for directories of ACD files and passes processing on to
304 ** grpGetAcdFiles
305 **
306 ** @param [r] appname [const AjPStr] Application name
307 ** @param [r] acddir [const AjPStr] Path of directory holding ACD files
308 ** to read in
309 ** @param [w] embassyname [AjPStr*] Embassy package name
310 ** or empty string for main package
311 ** @return [AjBool] ajTrue if an ACD file was found
312 **
313 ** @release 4.1.0
314 ** @@
315 ******************************************************************************/
316
grpGetAcdByname(const AjPStr appname,const AjPStr acddir,AjPStr * embassyname)317 static AjBool grpGetAcdByname(const AjPStr appname, const AjPStr acddir,
318 AjPStr* embassyname)
319 {
320 DIR *dirp;
321 DIR *dirpa;
322 struct dirent *dp;
323 AjPStr dirname = NULL;
324 AjPStr filename = NULL;
325 AjPFile acdfile = NULL;
326 AjBool ok = ajFalse;
327
328 /* go through all the directories in this directory */
329 dirp = opendir(ajStrGetPtr(acddir));
330
331 if(!dirp)
332 return ajFalse; /* could be no embassy installed */
333
334 ajDebug("grpGetAcdbyName '%S' '%S'\n", acddir, appname);
335
336 for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
337 {
338 if(dp->d_name[0] == '.')
339 continue; /* don't want hidden files */
340
341 ajFmtPrintS(&dirname, "%S%s/emboss_acd/", acddir, dp->d_name);
342 dirpa = opendir(ajStrGetPtr(dirname));
343
344 if(dirpa)
345 {
346 closedir(dirpa);
347 ajFmtPrintS(&filename, "%S%S.acd", dirname, appname);
348 acdfile = ajFileNewInNameS(filename);
349
350 if(acdfile)
351 {
352 grpParseEmbassy(acdfile, embassyname);
353 ajFileClose(&acdfile);
354 ok = ajTrue;
355 }
356 }
357
358 if(ok)
359 break;
360 }
361
362 ajStrDel(&dirname);
363 ajStrDel(&filename);
364 closedir(dirp);
365
366 return ok;
367 }
368
369
370
371
372 /* @funcstatic grpGetAcdDirs **************************************************
373 **
374 ** Given a directory from EMBASSY sources, it searches for directories
375 ** of ACD files and passes processing on to grpGetAcdFiles
376 **
377 ** @param [w] glist [AjPList] List of groups of programs
378 ** @param [w] alpha [AjPList] Alphabetic list of programs
379 ** @param [r] env [char* const[]] Environment passed in from C main()
380 ** parameters
381 ** @param [r] acddir [const AjPStr] path of directory holding ACD files
382 ** to read in
383 ** @param [r] explode [AjBool] Expand group names around ':'
384 ** @param [r] colon [AjBool] Retain ':' in group names
385 ** @param [r] gui [AjBool] Report only those applications OK in GUIs
386 ** @param [r] embassy [AjBool] Report only those applications not in
387 ** an EMBASSY package (embassy attribute in ACD)
388 ** @param [r] embassyname [const AjPStr] Name of embassy package.
389 ** default is to search for all
390 ** @return [void]
391 **
392 ** @release 2.5.0
393 ** @@
394 ******************************************************************************/
395
grpGetAcdDirs(AjPList glist,AjPList alpha,char * const env[],const AjPStr acddir,AjBool explode,AjBool colon,AjBool gui,AjBool embassy,const AjPStr embassyname)396 static void grpGetAcdDirs(AjPList glist, AjPList alpha, char * const env[],
397 const AjPStr acddir, AjBool explode, AjBool colon,
398 AjBool gui, AjBool embassy,
399 const AjPStr embassyname)
400 {
401 DIR *dirp;
402 DIR *dirpa;
403 struct dirent *dp;
404 static AjPStr dirname = NULL;
405
406
407 /* go through all the directories in this directory */
408 if((dirp = opendir(ajStrGetPtr(acddir))) == NULL)
409 return; /* could be no embassy installed */
410
411
412 for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
413 {
414 if(dp->d_name[0] == '.')
415 continue; /* don't want hidden files */
416
417 ajFmtPrintS(&dirname, "%S%s/emboss_acd/", acddir, dp->d_name);
418
419 if((dirpa = opendir(ajStrGetPtr(dirname))))
420 {
421 grpGetAcdFiles(glist, alpha, env, dirname, explode, colon,
422 gui, embassy, embassyname);
423 closedir(dirpa);
424 }
425 }
426
427 closedir(dirp);
428
429 return;
430 }
431
432
433
434
435 /* @funcstatic grpGetAcdFiles *************************************************
436 **
437 ** Given a directory, it searches for ACD files which describe an
438 ** existing program on the path,
439 ** parses out the documentation and groups from these ACD files,
440 ** returns a list of program names and documentation grouped by group names,
441 ** and returns an alphabetic list of program names and documentation.
442 **
443 ** @param [w] glist [AjPList] List of groups of programs
444 ** @param [w] alpha [AjPList] Alphabetic list of programs
445 ** @param [r] env [char* const[]] Environment passed in from C main()
446 ** parameters
447 ** @param [r] acddir [const AjPStr] path of directory holding ACD files
448 ** to read in
449 ** @param [r] explode [AjBool] Expand group names around ':'
450 ** @param [r] colon [AjBool] Retain ':' in group names
451 ** @param [r] gui [AjBool] Report only those applications OK in GUIs
452 ** @param [r] embassy [AjBool] Report only those applications not in
453 ** an EMBASSY package (embassy attribute in ACD)
454 ** @param [r] embassyname [const AjPStr] Name of embassy package.
455 ** default is to search for all
456 ** @return [void]
457 **
458 ** @release 2.5.0
459 ** @@
460 ******************************************************************************/
461
grpGetAcdFiles(AjPList glist,AjPList alpha,char * const env[],const AjPStr acddir,AjBool explode,AjBool colon,AjBool gui,AjBool embassy,const AjPStr embassyname)462 static void grpGetAcdFiles(AjPList glist, AjPList alpha, char * const env[],
463 const AjPStr acddir, AjBool explode, AjBool colon,
464 AjBool gui, AjBool embassy,
465 const AjPStr embassyname)
466 {
467 DIR *dirp;
468 struct dirent *dp;
469 AjPStr progpath = NULL;
470 AjPFile file = NULL;
471 AjPStr appl = NULL;
472 AjPStr applpath = NULL; /* path of application */
473 AjPStr doc = NULL;
474 AjPList groups = NULL;
475 AjPStr keywords = NULL;
476 AjBool guiresult;
477 AjBool isembassy;
478 EmbPGroupProg prognode = NULL;
479
480 prognode = embGrpMakeNewPnode(NULL, NULL, NULL, NULL);
481
482 /* go through all the files in this directory */
483 if((dirp = opendir(ajStrGetPtr(acddir))) == NULL)
484 ajFatal("You do not have read permission on the directory '%S'",
485 acddir);
486
487 for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
488 {
489 if(dp->d_name[0] != '.')
490 {
491 ajStrAssignResS(&progpath,
492 ajStrGetLen(acddir)+strlen(dp->d_name)+3,
493 acddir);
494 ajStrAppendC(&progpath, dp->d_name);
495
496 /* does it end with ".acd" ? */
497 if(ajStrSuffixC(progpath, ".acd"))
498 {
499 /* see if it is a normal file */
500 if(ajFilenameExistsRead(progpath))
501 {
502 /* open the file and parse it */
503 if((file = ajFileNewInNameS(progpath)) != NULL)
504 {
505 groups = ajListstrNew();
506 grpParse(file, groups,
507 explode, colon, &guiresult,
508 &isembassy, &prognode);
509
510 /* see if the appl is the name of a real program */
511 ajStrAssignS(&appl,prognode->name);
512 ajStrAssignS(&applpath, appl);
513
514 if(ajSysFileWhichEnv(&applpath, env))
515 {
516 /*
517 ** see if the appl is OK in GUIs or we don't
518 ** want just GUI apps
519 */
520 if(gui && !guiresult)
521 ajDebug("%S is not a OK in GUIs\n", appl);
522 else if(!embassy && isembassy)
523 ajDebug("%S is in EMBASSY\n", appl);
524 else if (ajStrGetLen(embassyname) &&
525 prognode &&
526 !ajStrMatchCaseS(embassyname,
527 prognode->package))
528 ajDebug("%S is in not in EMBASSY %S\n",
529 appl, embassyname);
530 else
531 grpAddGroupsToList(alpha, glist, groups,
532 &prognode);
533 }
534
535 ajFileClose(&file);
536 ajListstrFreeData(&groups);
537 ajStrDel(&appl);
538 ajStrDel(&doc);
539 }
540 }
541 }
542
543 ajStrDel(&progpath);
544 }
545 }
546
547 closedir(dirp);
548 ajStrDel(&applpath);
549 ajStrDel(&keywords);
550
551 embGrpProgDel(&prognode);
552
553 return;
554 }
555
556
557
558
559 /* @funcstatic grpParse *******************************************************
560 **
561 ** parse the acd file.
562 **
563 ** @param [u] file [AjPFile] ACD file
564 ** @param [w] groups [AjPList] Program groups list
565 ** @param [r] explode [AjBool] Expand group names around ':'
566 ** @param [r] colon [AjBool] Retain ':' in group names
567 ** @param [w] gui [AjBool*] returns ajTrue if application is OK in GUIs
568 ** @param [w] embassy [AjBool*] returns ajTrue if application has
569 ** an EMBASSY package definition
570 **
571 ** @param [w] Pprognode [EmbPGroupProg*] Program node
572 ** @return [void]
573 **
574 ** @release 2.5.0
575 ** @@
576 ******************************************************************************/
577
grpParse(AjPFile file,AjPList groups,AjBool explode,AjBool colon,AjBool * gui,AjBool * embassy,EmbPGroupProg * Pprognode)578 static void grpParse(AjPFile file, AjPList groups,
579 AjBool explode, AjBool colon,
580 AjBool *gui, AjBool* embassy,
581 EmbPGroupProg *Pprognode)
582 {
583
584 AjPStr line = NULL;
585 AjPStr text = NULL;
586
587 AjPStrTok tokenhandle;
588 char white[] = " \t\n\r";
589 char whiteplus[] = " \t\n\r:=";
590 AjPStr tmpstr = NULL;
591 AjPStr token = NULL;
592 AjPStr value = NULL;
593 AjBool done = 0;
594 AjPStr nullgroup = NULL;
595 AjPStr newstr = NULL;
596 AjPStr tmpvalue = NULL;
597 AjPStr type = NULL;
598 AjPStr qual = NULL;
599 AjPStr edamid = NULL;
600 AjPStr edamspace = NULL;
601 AjPStr edamname = NULL;
602 EmbPGroupRelation gprel = NULL;
603 EmbPGroupProg ppnode = NULL;
604
605 if(!*Pprognode)
606 *Pprognode = embGrpMakeNewPnode(NULL, NULL, NULL, NULL);
607 else
608 grpProgClear(*Pprognode);
609
610 ppnode = *Pprognode;
611
612 /* initialise a name for programs with no assigned group */
613 ajStrAppendC(&nullgroup, "ASSORTED");
614
615 ajStrAssignC(&ppnode->keywords, "");
616
617 /* if 'gui' not defined in ACD, default is 'gui: Y' */
618 *gui = ajTrue;
619 *embassy = ajFalse;
620
621 /* read file into one line, stripping out comment lines and blanks */
622 while(ajReadlineTrim(file, &line))
623 {
624 grpNoComment(&line);
625 if(ajStrGetLen(line))
626 {
627 ajStrAppendS(&text, line);
628 ajStrAppendC(&text, " ");
629 }
630 }
631
632 tokenhandle = ajStrTokenNewC(text, white);
633
634 /* find application token */
635 while(ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr))
636 if(ajStrPrefixCaseC(tmpstr, "application"))
637 break;
638
639 /* next token is the application name */
640 ajStrTokenNextParseC(tokenhandle, white, &ppnode->name);
641
642 /* if next token is '[' */
643 ajStrTokenNextParseC(tokenhandle, white, &tmpstr);
644
645 if(ajStrCmpC(tmpstr, "[") == 0)
646 {
647 token=ajStrNew();
648
649 /* is the next token 'doc' or 'groups' or 'gui' */
650 while(ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr))
651 {
652 while(!ajStrMatchC(tmpstr, "]"))
653 {
654 ajStrAssignS(&token, tmpstr);
655 value = grpParseValueRB(tokenhandle, white);
656 done = ajStrMatchC(value, "]");
657
658 if(!done)
659 {
660 ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr);
661 ajStrFmtLower(&tmpstr);
662 done = ajStrMatchC(tmpstr, "]");
663 }
664
665 if(ajStrPrefixCaseC(token, "documentation"))
666 {
667 ajStrAssignS(&ppnode->doc, value);
668 ajStrTrimWhite(&ppnode->doc);
669 ajStrTrimC(&ppnode->doc, ".,");
670
671 }
672 else if(ajStrPrefixCaseC(token, "gui"))
673 {
674 ajStrAssignS(&tmpvalue, value);
675 ajStrTrimWhite(&tmpvalue);
676 ajDebug("gui value '%S'\n", tmpvalue);
677
678 /* test for '[Nn]*' */
679 if(tolower((int)(ajStrGetPtr(tmpvalue))[0]) == 'n')
680 *gui = ajFalse;
681
682 ajStrDel(&tmpvalue);
683 }
684 else if(ajStrPrefixCaseC(token, "groups"))
685 {
686 grpSplitList(groups, value, explode, colon,
687 &ppnode->keywords);
688 }
689 else if(ajStrPrefixCaseC(token, "keywords"))
690 {
691 ajStrExchangeKK(&value, ' ', '_');
692
693 if(ajStrGetLen(ppnode->keywords))
694 ajStrAppendK(&ppnode->keywords, ' ');
695
696 ajStrAppendS(&ppnode->keywords, value);
697 }
698 else if(ajStrPrefixCaseC(token, "embassy"))
699 {
700 *embassy = ajTrue;
701 ajStrAssignS(&ppnode->package, value);
702 }
703 if(ajStrPrefixCaseC(token, "relation"))
704 {
705 /*ajDebug("+++ done:%B '%S' '%S'\n", done, token, value);*/
706 if(ajAcdedamParse(value, &edamid, &edamspace, &edamname))
707 {
708 AJNEW0(gprel);
709 ajStrAssignC(&gprel->type, "application");
710 ajStrAssignS(&gprel->qual, ppnode->name);
711 ajStrAssignC(&gprel->acdgroup, "application");
712 ajStrAssignS(&gprel->id, edamid);
713 ajStrAssignS(&gprel->namespace, edamspace);
714 ajStrAssignS(&gprel->name, edamname);
715 if(ajStrMatchC(edamspace, "topic"))
716 ajListPushAppend(ppnode->acdtopics, gprel);
717 else if(ajStrMatchC(edamspace, "operation"))
718 ajListPushAppend(ppnode->acdoperations, gprel);
719 else
720 ajListPushAppend(ppnode->acdparams, gprel);
721 }
722 else
723 {
724 ajErr("%F: bad ACD relation '%S'", file, value);
725 }
726 }
727 }
728
729 if(done)
730 break;
731 }
732 }
733
734 /* check that we got the doc, keywords and groups descriptions */
735 if(!ajStrGetLen(ppnode->doc))
736 ajStrAssignC(&ppnode->doc, "");
737
738 if(!ajStrGetLen(ppnode->keywords))
739 ajStrAssignC(&ppnode->keywords, "");
740
741 if(!ajListGetLength(groups))
742 {
743 newstr = ajStrNewRef(nullgroup);
744 ajListstrPushAppend(groups, newstr);
745 }
746
747 ajStrAssignEmptyC(&ppnode->package, "");
748
749
750 /* now process the qualifiers */
751
752 ajDebug("appl: '%S'\n", ppnode->name);
753
754 while(ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr))
755 {
756 ajStrAssignS(&type, tmpstr);
757 ajStrTokenNextParseC(tokenhandle, white, &tmpstr);
758 ajStrAssignS(&qual, tmpstr);
759
760 /*ajDebug("qual: '%S' '%S'\n", type, qual);*/
761
762 if(ajStrMatchC(type, "endsection"))
763 continue;
764
765 while(!ajStrMatchC(tmpstr, "["))
766 ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr);
767
768 while(ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr))
769 {
770 while(!ajStrMatchC(tmpstr, "]"))
771 {
772 ajStrAssignS(&token, tmpstr);
773 value = grpParseValueRB(tokenhandle, white);
774 done = ajStrMatchC(value, "]");
775
776 if(!done)
777 {
778 ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr);
779 ajStrFmtLower(&tmpstr);
780 done = ajStrMatchC(tmpstr, "]");
781 }
782 if(ajStrPrefixCaseC(token, "relation"))
783 {
784 if(ajAcdedamParse(value, &edamid, &edamspace, &edamname))
785 {
786 AJNEW0(gprel);
787 ajStrAssignS(&gprel->type, type);
788 ajStrAssignS(&gprel->qual, qual);
789 ajStrAssignC(&gprel->acdgroup, ajAcdtypeGetGroup(type));
790 ajStrAssignS(&gprel->id, edamid);
791 ajStrAssignS(&gprel->namespace, edamspace);
792 ajStrAssignS(&gprel->name, edamname);
793 if(ajStrMatchC(gprel->acdgroup, "input"))
794 ajListPushAppend(ppnode->acdinputs, gprel);
795 else if(ajStrMatchC(gprel->acdgroup, "output"))
796 ajListPushAppend(ppnode->acdoutputs, gprel);
797 else
798 ajListPushAppend(ppnode->acdparams, gprel);
799 /*ajDebug("+++ done:%B %S: %S (%S) edam:%S '%S'\n",
800 done, type, qual, gprel->acdgroup,
801 edamid, edamname);*/
802 }
803 else
804 {
805 ajErr("%F: bad ACD relation '%S'", file, value);
806 }
807 }
808 /*
809 else
810 ajDebug(" done:%B '%S' '%S'\n", done, token, value);
811 */
812 }
813 if(done)
814 break;
815 }
816 }
817
818
819 ajStrDel(&nullgroup);
820 ajStrDel(&tmpstr);
821 ajStrDel(&line);
822 ajStrDel(&text);
823 ajStrTokenDel(&tokenhandle);
824 ajStrDel(&type);
825 ajStrDel(&edamid);
826 ajStrDel(&edamspace);
827 ajStrDel(&edamname);
828 ajStrDel(&qual);
829 ajStrDel(&token);
830 ajStrDel(&nullgroup);
831
832 return;
833 }
834
835
836
837
838 /* @funcstatic grpParseEmbassy ************************************************
839 **
840 ** parse the acd file to get the EMBASSY application attribute
841 **
842 ** @param [u] file [AjPFile] ACD file
843 ** @param [w] embassyname [AjPStr*] EMBASSY package name from
844 ** embassy attribute
845 ** @return [void]
846 **
847 ** @release 4.1.0
848 ** @@
849 ******************************************************************************/
850
grpParseEmbassy(AjPFile file,AjPStr * embassyname)851 static void grpParseEmbassy(AjPFile file, AjPStr* embassyname)
852 {
853
854 AjPStr line = NULL;
855 AjPStr text = NULL;
856
857 AjPStrTok tokenhandle;
858 char white[] = " \t\n\r";
859 char whiteplus[] = " \t\n\r:=";
860 AjPStr tmpstr = NULL;
861 AjPStr token = NULL;
862 AjPStr value = NULL;
863 ajint done = 0;
864
865 ajStrAssignC(embassyname, "");
866
867 /* read file into one line, stripping out comment lines and blanks */
868 while(ajReadlineTrim(file, &line))
869 {
870 grpNoComment(&line);
871
872 if(ajStrGetLen(line))
873 {
874 ajStrAppendS(&text, line);
875 ajStrAppendC(&text, " ");
876 }
877 }
878
879 tokenhandle = ajStrTokenNewC(text, white);
880
881 /* find appl token */
882 while(ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr))
883 if(ajStrPrefixCaseC(tmpstr, "application"))
884 break;
885
886 /* next token is the application name */
887 ajStrTokenNextParseC(tokenhandle, white, &tmpstr);
888
889 /* if next token is '[' */
890 ajStrTokenNextParseC(tokenhandle, white, &tmpstr);
891 if(ajStrCmpC(tmpstr, "[") == 0)
892 {
893 token=ajStrNew();
894
895 /* is the next token 'doc' or 'groups' or 'gui' */
896 while(ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr))
897 {
898 while(!ajStrMatchC(tmpstr, "]"))
899 {
900 ajStrAssignS(&token, tmpstr);
901 value = grpParseValueRB(tokenhandle, white);
902 done = ajStrMatchC(value, "]");
903
904 if(!done)
905 {
906 ajStrTokenNextParseC(tokenhandle, whiteplus, &tmpstr);
907 ajStrFmtLower(&tmpstr);
908 done = ajStrMatchC(tmpstr, "]");
909 }
910
911 if(ajStrPrefixCaseC(token, "embassy"))
912 {
913 ajStrAssignS(embassyname, value);
914 }
915 }
916
917 if(done)
918 break;
919 }
920 }
921
922 ajStrDel(&tmpstr);
923 ajStrDel(&line);
924 ajStrDel(&text);
925 ajStrTokenDel(&tokenhandle);
926
927 return;
928 }
929
930
931
932
933 /* @funcstatic grpNoComment ***************************************************
934 **
935 ** Strips comments from a character string (a line from an trn file).
936 ** Comments are blank lines or any text following a "#" character.
937 ** Whitespace characters can be included in a blank line.
938 **
939 ** @param [u] text [AjPStr*] Line of text from input file
940 ** @return [void]
941 **
942 ** @release 2.5.0
943 ** @@
944 ******************************************************************************/
945
grpNoComment(AjPStr * text)946 static void grpNoComment(AjPStr* text)
947 {
948 ajint i;
949 char *cp;
950
951 ajStrTrimWhite(text);
952 i = ajStrGetLen(*text);
953
954 if(!i) /* empty string */
955 return;
956
957 cp = strchr(ajStrGetPtr(*text), '#');
958
959 if(cp)
960 { /* comment found */
961 *cp = '\0';
962 ajStrSetValid(text);
963 }
964
965 return;
966 }
967
968
969
970
971 /* @funcstatic grpParseValueRB ************************************************
972 **
973 ** Copied from ajacd.c
974 **
975 ** Uses ajStrTok to complete a (possibly) quoted value.
976 ** Note that the AjPStrTok object has a stored internal copy of the text string
977 ** which is set up in the calling function and is being used here.
978 **
979 ** Quotes can be single or double, or any kind of parentheses,
980 ** depending on the first character of the next token examined.
981 **
982 ** @param [u] tokenhandle [AjPStrTok] Current parsing handle for input text
983 ** @param [r] delim [const char*] Delimiter string
984 ** @return [AjPStr] String containing next value using acdStrTok
985 **
986 ** @release 1.0.0
987 ** @@
988 ******************************************************************************/
989
grpParseValueRB(AjPStrTok tokenhandle,const char * delim)990 static AjPStr grpParseValueRB(AjPStrTok tokenhandle, const char* delim)
991 {
992 char endq[] = " ";
993 char endqbr[] = " ]";
994 ajint iquote;
995 char *cq;
996 AjBool done = ajFalse;
997 AjBool rightb = ajFalse;
998
999 const char *quotes = "\"";
1000 const char *endquotes = "\"";
1001
1002 if(!ajStrTokenNextParseC(tokenhandle, delim, &grpStr1))
1003 return NULL;
1004
1005 cq = strchr(quotes, ajStrGetCharFirst(grpStr1));
1006
1007 if(!cq)
1008 return grpStr1;
1009
1010
1011 /* quote found: parse up to closing quote then strip white space */
1012
1013 ajStrDelStatic(&grpStr2);
1014
1015 iquote = (ajint) (cq - quotes);
1016 endq[0] = endqbr[0] = endquotes[iquote];
1017 ajStrCutStart(&grpStr1, 1);
1018
1019 while(!done)
1020 {
1021 if(ajStrSuffixC(grpStr1, endq))
1022 {
1023 ajStrCutEnd(&grpStr1, 1);
1024 done = ajTrue;
1025 }
1026
1027 if(ajStrSuffixC(grpStr1, endqbr))
1028 {
1029 ajStrCutEnd(&grpStr1, 2);
1030 rightb = ajTrue;
1031 done = ajTrue;
1032 }
1033
1034 if(ajStrGetLen(grpStr1))
1035 {
1036 if(ajStrGetLen(grpStr2))
1037 ajStrAppendC(&grpStr2, " ");
1038
1039 ajStrAppendS(&grpStr2, grpStr1);
1040 }
1041
1042 if(!done)
1043 if(!ajStrTokenNextParseC(tokenhandle, delim, &grpStr1))
1044 return NULL;
1045 }
1046
1047 if(rightb)
1048 ajStrAppendC(&grpStr2, "]");
1049
1050 return grpStr2;
1051 }
1052
1053
1054
1055
1056 /* @funcstatic grpSplitList ***************************************************
1057 **
1058 ** Split a string containing group names into a list on the delimiters
1059 ** ',' or ';' or '|' to form the primary names of the groups.
1060 ** Any names containing a colon ':' are optionally expanded in a call to
1061 ** grpSubSplitList() to form many combinations of group names.
1062 **
1063 ** The group names are returned as a list.
1064 **
1065 ** @param [u] groups [AjPList] List of groups
1066 ** @param [r] value [const AjPStr] Groups string from ACD file
1067 ** @param [r] explode [AjBool] Expand group names around ':'
1068 ** @param [r] colon [AjBool] Retain ':' in group names
1069 ** @param [u] keywords [AjPStr*] List of keywords
1070 **
1071 ** @return [void]
1072 **
1073 ** @release 2.5.0
1074 ** @@
1075 ******************************************************************************/
1076
grpSplitList(AjPList groups,const AjPStr value,AjBool explode,AjBool colon,AjPStr * keywords)1077 static void grpSplitList(AjPList groups, const AjPStr value, AjBool explode,
1078 AjBool colon, AjPStr *keywords)
1079 {
1080 AjPStrTok colontokenhandle;
1081 AjPStrTok tokenhandle;
1082 char delim[] = ",;|";
1083 char colonstring[] = ":";
1084 AjPList subnames;
1085 AjPStr tmpstr = NULL;
1086 AjPStr substr = NULL;
1087 AjPStr copystr = NULL;
1088 AjPStr keystr = NULL;
1089
1090 tokenhandle = ajStrTokenNewC(value, delim);
1091
1092 while(ajStrTokenNextParse(tokenhandle, &tmpstr))
1093 {
1094 ajStrTrimWhite(&tmpstr);
1095 ajStrTrimC(&tmpstr, ".");
1096
1097 ajStrAssignS(&keystr, tmpstr);
1098 ajStrExchangeKK(&keystr, ':', '_');
1099 ajStrExchangeKK(&keystr, ' ', '_');
1100
1101 if(ajStrGetLen(*keywords))
1102 ajStrAppendK(keywords, ' ');
1103
1104 ajStrAppendS(keywords, keystr);
1105
1106 /*
1107 ** split the group name on colons and expand the sub-names into several
1108 ** combinations of name
1109 */
1110 if(explode)
1111 {
1112 subnames = ajListstrNew();
1113 colontokenhandle = ajStrTokenNewC(tmpstr, colonstring);
1114
1115 while(ajStrTokenNextParse(colontokenhandle, &substr))
1116 {
1117 copystr = ajStrNewS(substr); /* make new copy of the string
1118 for the list to hold */
1119 ajStrTrimWhite(©str);
1120 ajListstrPushAppend(subnames, copystr);
1121 }
1122
1123 /*
1124 ** make the combinations of sub-names and add them to the list of
1125 ** group names
1126 */
1127 grpSubSplitList(groups, subnames);
1128
1129 ajStrTokenDel(&colontokenhandle);
1130 ajStrDel(&substr);
1131 ajListstrFreeData(&subnames);
1132 /*
1133 ** don't free up copystr - because ajListstrFreeData()
1134 ** then tries to free
1135 ** it as well ajStrDel(©str);
1136 */
1137
1138 }
1139 else
1140 {
1141 /*
1142 ** don't explode, just remove ':'s and excess spaces and add to
1143 ** 'groups' list
1144 */
1145 copystr = ajStrNewRef(tmpstr); /* make new copy of the string
1146 for the list to hold */
1147 /*
1148 ** we might want to retain the ':' in the output
1149 ** if it is being parsed by
1150 ** other programs that create 2-level menus for an interface etc.
1151 */
1152 if(!colon)
1153 {
1154 ajStrExchangeSetCC(©str, ":", " ");
1155 ajStrRemoveWhiteExcess(©str);
1156 }
1157 else
1158 {
1159 /* tidy up spurious spaces around the colon */
1160 ajStrRemoveWhiteExcess(©str);
1161 ajStrExchangeCC(©str, " :", ":");
1162 ajStrExchangeCC(©str, ": ", ":");
1163 }
1164
1165 ajListstrPushAppend(groups, copystr);
1166 }
1167 }
1168
1169 ajStrTokenDel(&tokenhandle);
1170 ajStrDel(&tmpstr);
1171 ajStrDel(&substr);
1172 ajStrDel(&keystr);
1173
1174 return;
1175 }
1176
1177
1178
1179
1180 /* @funcstatic grpSubSplitList ************************************************
1181 **
1182 ** Takes a list of words and makes several combinations of them to
1183 ** construct the expanded group constructs made from the ':' operator in
1184 ** the group names.
1185 **
1186 ** For example, the group name 'aaa:bbb:ccc' will be passed over to this
1187 ** routine as the list 'aaa', 'bbb', 'ccc' and the group names:
1188 ** 'aaa bbb ccc'
1189 ** 'ccc bbb aaa'
1190 ** 'aaa bbb'
1191 ** 'bbb aaa'
1192 ** 'bbb ccc'
1193 ** 'ccc bbb'
1194 ** 'ccc'
1195 ** 'bbb'
1196 ** 'aaa'
1197 ** will be constructed and added to the list of group names in 'groups'
1198 **
1199 ** @param [u] groups [AjPList] List of groups
1200 ** @param [u] sublist [AjPList] (Sub)-names of groups string from ACD file
1201 **
1202 ** @return [void]
1203 **
1204 ** @release 2.5.0
1205 ** @@
1206 ******************************************************************************/
1207
grpSubSplitList(AjPList groups,AjPList sublist)1208 static void grpSubSplitList(AjPList groups, AjPList sublist)
1209 {
1210 AjPStr *sub; /* array of sub-names */
1211 ajint len; /* length of array of sub-names */
1212 ajint i;
1213 ajint j;
1214 AjPStr head; /* constructed group names */
1215 AjPStr tail;
1216 AjPStr revhead;
1217 AjPStr revtail;
1218 AjPStr dummy = NULL; /* dummy string for ajListstrPop() */
1219
1220
1221 len = (ajuint) ajListstrToarray(sublist, &sub);
1222
1223 for(i=0; i<len; i++)
1224 {
1225 /* do head of list */
1226 head = ajStrNew();
1227
1228 for(j=0; j<=i; j++)
1229 {
1230 if(ajStrGetLen(head) > 0)
1231 ajStrAppendC(&head, " ");
1232
1233 ajStrAppendS(&head, sub[j]);
1234 }
1235
1236 ajListstrPushAppend(groups, head);
1237
1238 /*
1239 ** do reverse head of list if there is more than
1240 ** one name in the head
1241 */
1242 if(i)
1243 {
1244 revhead = ajStrNew();
1245
1246 for(j=i; j>=0; j--)
1247 {
1248 if(ajStrGetLen(revhead) > 0)
1249 ajStrAppendC(&revhead, " ");
1250
1251 ajStrAppendS(&revhead, sub[j]);
1252 }
1253
1254 ajListstrPushAppend(groups, revhead);
1255 }
1256
1257 /* do tail of list, if there is any tail left */
1258 if(i < len-1)
1259 {
1260 tail = ajStrNew();
1261
1262 for(j=i+1; j<len; j++)
1263 {
1264 if(ajStrGetLen(tail) > 0)
1265 ajStrAppendC(&tail, " ");
1266
1267 ajStrAppendS(&tail, sub[j]);
1268 }
1269
1270 ajListstrPushAppend(groups, tail);
1271 }
1272
1273 /*
1274 ** do reverse tail of list if there is more than
1275 ** one name in the tail
1276 */
1277 if(i < len-2)
1278 {
1279 revtail = ajStrNew();
1280
1281 for(j=len-1; j>i; j--)
1282 {
1283 if(ajStrGetLen(revtail) > 0)
1284 ajStrAppendC(&revtail, " ");
1285
1286 ajStrAppendS(&revtail, sub[j]);
1287 }
1288
1289 ajListstrPushAppend(groups, revtail);
1290 }
1291
1292 }
1293
1294 AJFREE(sub);
1295
1296 /* if list length is greater than 2, pop off head and tail and recurse */
1297 if(len > 2)
1298 {
1299 ajListstrPop(sublist, &dummy); /* remove first node */
1300 ajStrDel(&dummy);
1301
1302 /* remove last node of list. */
1303
1304 ajListstrReverse(sublist);
1305 ajListstrPop(sublist, &dummy); /* remove first node */
1306 ajStrDel(&dummy);
1307 ajListstrReverse(sublist);
1308
1309 /* recurse */
1310 grpSubSplitList(groups, sublist);
1311 }
1312
1313 return;
1314 }
1315
1316
1317
1318
1319 /* @funcstatic grpAddGroupsToList *********************************************
1320 **
1321 ** Add application to applications list and its groups to the full groups list
1322 ** Results are alpha list and glist.
1323 **
1324 ** alpha is a list of application with sub-lists of their groups
1325 ** glist is a list of groups with sub-lists of their applications
1326 **
1327 ** @param [r] alpha [const AjPList] Alphabetic list of programs
1328 ** @param [u] glist [AjPList] List of all known groups
1329 ** @param [r] groups [const AjPList] List of groups for this application
1330 ** @param [u] Pprognode [EmbPGroupProg*] Program node by reference
1331 **
1332 ** @return [void]
1333 **
1334 ** @release 2.5.0
1335 ** @@
1336 ******************************************************************************/
1337
grpAddGroupsToList(const AjPList alpha,AjPList glist,const AjPList groups,EmbPGroupProg * Pprognode)1338 static void grpAddGroupsToList(const AjPList alpha, AjPList glist,
1339 const AjPList groups,
1340 EmbPGroupProg *Pprognode)
1341 {
1342 AjPStr g = NULL; /* temporary value of member of groups list */
1343 AjIList aiter; /* 'alpha' iterator */
1344 AjIList iter; /* 'groups' iterator */
1345 AjIList giter; /* 'glist' iterator */
1346 AjIList niter; /* 'nlist' iterator */
1347 EmbPGroupTop al; /* next (first) member of alpha */
1348 EmbPGroupTop gl; /* next member of glist */
1349 EmbPGroupTop nl; /* next member of nlist */
1350 EmbPGroupTop gpnode; /* new member of glist being added */
1351 EmbPGroupProg ppnode; /* new member of plist list being added */
1352 EmbPGroupProg apnode; /* new member of alpha list being added */
1353 AjPList nlist=NULL; /* list of programs in a group - used to check
1354 name is unique */
1355 AjBool foundit; /* flag for found the program name */
1356
1357 ppnode = *Pprognode;
1358
1359 /* add this program to the alphabetic list of programs */
1360 apnode = embGrpMakeNewPnode(ppnode->name, ppnode->doc,
1361 ppnode->keywords, ppnode->package);
1362 aiter = ajListIterNewread(alpha);
1363 al = ajListIterGet(aiter);
1364 ajListPushAppend(al->progs, apnode);
1365 ajListIterDel(&aiter);
1366
1367 /*
1368 ** Now step through all groups that this program belongs to and add this
1369 ** program to the groups
1370 */
1371 iter = ajListIterNewread(groups);
1372
1373 while((g = ajListIterGet(iter)) != NULL)
1374 {
1375 /* add the group name to the program node in alpha list */
1376 gpnode = embGrpMakeNewGnode(g);
1377 ajListPushAppend(apnode->groups, gpnode);
1378
1379 /* add the application to the appropriate groups list in glist */
1380 giter = ajListIterNewread(glist);
1381
1382 while((gl = ajListIterGet(giter)) != NULL)
1383 {
1384 /* is this our group ? */
1385 if(!ajStrCmpCaseS(gl->name, g))
1386 {
1387 /*
1388 ** found the group.
1389 ** look through the program names in this group
1390 ** and only add if name is
1391 ** not already there
1392 */
1393 foundit = ajFalse;
1394 nlist = gl->progs;
1395 niter = ajListIterNewread(nlist);
1396
1397 while((nl = ajListIterGet(niter)) != NULL)
1398 if(ajStrMatchCaseS(nl->name, ppnode->name))
1399 {
1400 /* found the program name */
1401 foundit = ajTrue;
1402 break;
1403 }
1404
1405 ajListIterDel(&niter);
1406
1407 if(!foundit)
1408 {
1409 ajListPushAppend(gl->progs, grpCopyPnode(ppnode));
1410 }
1411
1412 break;
1413 }
1414 }
1415
1416 if(gl == NULL)
1417 {
1418 /* went past the end of the group list - new group */
1419 gpnode = embGrpMakeNewGnode(g);
1420 ajListPushAppend(glist, gpnode);
1421 ajListPushAppend(gpnode->progs, grpCopyPnode(ppnode));
1422 }
1423 ajListIterDel(&giter);
1424 }
1425
1426 embGrpProgDel(Pprognode);
1427
1428 ajListIterDel(&iter);
1429 ajStrDel(&g);
1430
1431 /* sort the groups for this application in alpha list */
1432 embGrpSortGroupsList(apnode->groups);
1433
1434 return;
1435 }
1436
1437
1438
1439
1440 /* @func embGrpMakeNewGnode ***************************************************
1441 **
1442 ** Creates a new pointer to a Gnode struct for holding a group's
1443 ** name and pointer to a list of programs (also held in Gnodes).
1444 **
1445 ** @param [r] name [const AjPStr] Name of the group
1446 ** @return [EmbPGroupTop] pointer to a new GPnode struct
1447 **
1448 ** @release 2.0.0
1449 ** @@
1450 ******************************************************************************/
1451
embGrpMakeNewGnode(const AjPStr name)1452 EmbPGroupTop embGrpMakeNewGnode(const AjPStr name)
1453 {
1454 EmbPGroupTop gpnode;
1455 AjPStr newstr = NULL;
1456 AjPStr dummy = NULL;
1457
1458
1459 /* ajDebug("New groups gnode name=%S\n", name); */
1460 AJNEW0(gpnode);
1461
1462 newstr = ajStrNewS(name);
1463 ajStrFmtUpper(&newstr);
1464
1465 gpnode->name = newstr;
1466 ajStrAssignC(&dummy, "");
1467 gpnode->doc = dummy;
1468 gpnode->progs = ajListNew();
1469
1470 return gpnode;
1471 }
1472
1473
1474
1475
1476 /* @func embGrpMakeNewPnode ***************************************************
1477 **
1478 ** Creates a new pointer to a Gnode struct for holding a program's
1479 ** name and documentation.
1480 **
1481 ** @param [r] name [const AjPStr] Name of the program
1482 ** @param [r] doc [const AjPStr] Description of the program
1483 ** @param [r] keywords [const AjPStr] Keywords for this program
1484 ** with underscores for spaces and
1485 ** with spaces as separators
1486 ** @param [r] package [const AjPStr] Name of the package
1487 ** @return [EmbPGroupProg] pointer to a new gnode struct
1488 **
1489 ** @release 2.0.0
1490 ** @@
1491 ******************************************************************************/
1492
embGrpMakeNewPnode(const AjPStr name,const AjPStr doc,const AjPStr keywords,const AjPStr package)1493 EmbPGroupProg embGrpMakeNewPnode(const AjPStr name, const AjPStr doc,
1494 const AjPStr keywords, const AjPStr package)
1495 {
1496 EmbPGroupProg gpnode;
1497
1498 AJNEW0(gpnode);
1499 gpnode->name = ajStrNewS(name);
1500 gpnode->doc = ajStrNewS(doc);
1501 gpnode->keywords= ajStrNewS(keywords);
1502 gpnode->package = ajStrNewS(package);
1503 gpnode->groups = ajListNew();
1504 gpnode->acdtopics = ajListNew();
1505 gpnode->acdoperations = ajListNew();
1506 gpnode->acdinputs = ajListNew();
1507 gpnode->acdoutputs = ajListNew();
1508 gpnode->acdparams = ajListNew();
1509
1510 return gpnode;
1511 }
1512
1513
1514
1515
1516 /* @funcstatic grpCopyPnode ***************************************************
1517 **
1518 ** Creates a new pointer to a Pnode struct for holding a program's
1519 ** name and documentation.
1520 **
1521 ** @param [r] pnode [const EmbPGroupProg] Source program node
1522 ** @return [EmbPGroupProg] pointer to a new pnode struct
1523 **
1524 ** @release 6.4.0
1525 ** @@
1526 ******************************************************************************/
1527
grpCopyPnode(const EmbPGroupProg pnode)1528 static EmbPGroupProg grpCopyPnode(const EmbPGroupProg pnode)
1529 {
1530 EmbPGroupProg gpnode;
1531 EmbPGroupTop gl;
1532 EmbPGroupTop newgl;
1533 EmbPGroupRelation gr;
1534 AjIList iter = NULL;
1535
1536 AJNEW0(gpnode);
1537 gpnode->name = ajStrNewS(pnode->name);
1538 gpnode->doc = ajStrNewS(pnode->doc);
1539 gpnode->keywords= ajStrNewS(pnode->keywords);
1540 gpnode->package = ajStrNewS(pnode->package);
1541
1542 if(pnode->groups)
1543 {
1544 gpnode->groups = ajListNew();
1545 iter = ajListIterNewread(pnode->groups);
1546 while(!ajListIterDone(iter))
1547 {
1548 gl = ajListIterGet(iter);
1549 AJNEW0(newgl);
1550 newgl->name = ajStrNewS(gl->name);
1551 newgl->doc = ajStrNewS(gl->doc);
1552 ajListPushAppend(gpnode->groups, newgl);
1553 }
1554 ajListIterDel(&iter);
1555 }
1556
1557 if(pnode->acdtopics)
1558 {
1559 gpnode->acdtopics = ajListNew();
1560 iter = ajListIterNewread(pnode->acdtopics);
1561 while(!ajListIterDone(iter))
1562 {
1563 gr = ajListIterGet(iter);
1564 ajListPushAppend(gpnode->acdtopics, grpRelationsCopy(gr));
1565 }
1566 ajListIterDel(&iter);
1567 }
1568
1569 if(pnode->acdoperations)
1570 {
1571 gpnode->acdoperations = ajListNew();
1572 iter = ajListIterNewread(pnode->acdoperations);
1573 while(!ajListIterDone(iter))
1574 {
1575 gr = ajListIterGet(iter);
1576 ajListPushAppend(gpnode->acdoperations, grpRelationsCopy(gr));
1577 }
1578 ajListIterDel(&iter);
1579 }
1580
1581 if(pnode->acdinputs)
1582 {
1583 gpnode->acdinputs = ajListNew();
1584 iter = ajListIterNewread(pnode->acdinputs);
1585 while(!ajListIterDone(iter))
1586 {
1587 gr = ajListIterGet(iter);
1588 ajListPushAppend(gpnode->acdinputs, grpRelationsCopy(gr));
1589 }
1590 ajListIterDel(&iter);
1591 }
1592
1593 if(pnode->acdoutputs)
1594 {
1595 gpnode->acdoutputs = ajListNew();
1596 iter = ajListIterNewread(pnode->acdoutputs);
1597 while(!ajListIterDone(iter))
1598 {
1599 gr = ajListIterGet(iter);
1600 ajListPushAppend(gpnode->acdoutputs, grpRelationsCopy(gr));
1601 }
1602 ajListIterDel(&iter);
1603 }
1604
1605 if(pnode->acdparams)
1606 {
1607 gpnode->acdparams = ajListNew();
1608 iter = ajListIterNewread(pnode->acdparams);
1609 while(!ajListIterDone(iter))
1610 {
1611 gr = ajListIterGet(iter);
1612 ajListPushAppend(gpnode->acdparams, grpRelationsCopy(gr));
1613 }
1614 ajListIterDel(&iter);
1615 }
1616
1617 return gpnode;
1618 }
1619
1620
1621
1622
1623 /* @func embGrpSortGroupsList *************************************************
1624 **
1625 ** Sort a list of GPnodes by their name.
1626 **
1627 ** @param [u] groupslist [AjPList] List to sort
1628 ** @return [void]
1629 **
1630 ** @release 2.0.0
1631 ** @@
1632 ******************************************************************************/
1633
embGrpSortGroupsList(AjPList groupslist)1634 void embGrpSortGroupsList(AjPList groupslist)
1635 {
1636 EmbPGroupTop gl;
1637 AjIList giter;
1638
1639 /* sort the programs for each group */
1640 giter = ajListIterNewread(groupslist);
1641
1642 while((gl = ajListIterGet(giter)) != NULL)
1643 ajListSort(gl->progs, &embGrpCompareTwoPnodes);
1644
1645
1646 ajListIterDel(&giter);
1647
1648 /* sort the groups themselves */
1649 ajListSort(groupslist, &embGrpCompareTwoGnodes);
1650
1651 return;
1652 }
1653
1654
1655
1656
1657 /* @func embGrpSortProgsList **************************************************
1658 **
1659 ** Sort a list of Pnodes by their name.
1660 **
1661 ** @param [u] progslist [AjPList] List to sort
1662 ** @return [void]
1663 **
1664 ** @release 4.0.0
1665 ** @@
1666 ******************************************************************************/
1667
embGrpSortProgsList(AjPList progslist)1668 void embGrpSortProgsList(AjPList progslist)
1669 {
1670 EmbPGroupProg pl;
1671 AjIList piter;
1672
1673 /* sort the groups for each program */
1674 piter = ajListIterNewread(progslist);
1675
1676 while((pl = ajListIterGet(piter)) != NULL)
1677 ajListSort(pl->groups, &embGrpCompareTwoGnodes);
1678
1679
1680 ajListIterDel(&piter);
1681
1682 /* sort the groups themselves */
1683 ajListSort(progslist, &embGrpCompareTwoPnodes);
1684
1685 return;
1686 }
1687
1688
1689
1690
1691 /* @func embGrpCompareTwoGnodes ***********************************************
1692 **
1693 ** Compare two Gnodes as case-insensitive strings.
1694 **
1695 ** @param [r] a [const void *] First node
1696 ** @param [r] b [const void *] Second node
1697 **
1698 ** @return [ajint] Compare value (-1, 0, +1)
1699 **
1700 ** @release 2.0.0
1701 ** @@
1702 ******************************************************************************/
1703
embGrpCompareTwoGnodes(const void * a,const void * b)1704 ajint embGrpCompareTwoGnodes(const void * a, const void * b)
1705 {
1706 return ajStrCmpCaseS((*(EmbPGroupTop const *)a)->name,
1707 (*(EmbPGroupTop const *)b)->name);
1708 }
1709
1710
1711
1712
1713 /* @func embGrpCompareTwoPnodes ***********************************************
1714 **
1715 ** Compare two Pnodes as case-insensitive strings.
1716 **
1717 ** @param [r] a [const void *] First node
1718 ** @param [r] b [const void *] Second node
1719 **
1720 ** @return [ajint] Compare value (-1, 0, +1)
1721 **
1722 ** @release 4.0.0
1723 ** @@
1724 ******************************************************************************/
1725
embGrpCompareTwoPnodes(const void * a,const void * b)1726 ajint embGrpCompareTwoPnodes(const void * a, const void * b)
1727 {
1728 return ajStrCmpCaseS((*(EmbPGroupProg const *)a)->name,
1729 (*(EmbPGroupProg const *)b)->name);
1730 }
1731
1732
1733
1734
1735 /* @func embGrpOutputGroupsList ***********************************************
1736 **
1737 ** Displays a list of groups to an output file handle.
1738 **
1739 ** @param [u] outfile [AjPFile] Output file handle
1740 ** @param [r] groupslist [const AjPList] List of groups to be displayed
1741 ** @param [r] showprogs [AjBool] If True, display the programs in each group
1742 ** @param [r] html [AjBool] If True, format for HTML, else make a simple list
1743 ** @param [r] showkey [AjBool] If True, show keywords
1744 ** @param [r] package [const AjPStr] Name of current package
1745 ** @return [void]
1746 **
1747 ** @release 2.0.0
1748 ** @@
1749 ******************************************************************************/
1750
embGrpOutputGroupsList(AjPFile outfile,const AjPList groupslist,AjBool showprogs,AjBool html,AjBool showkey,const AjPStr package)1751 void embGrpOutputGroupsList(AjPFile outfile, const AjPList groupslist,
1752 AjBool showprogs, AjBool html,
1753 AjBool showkey, const AjPStr package)
1754 {
1755 EmbPGroupTop gl;
1756 AjIList giter; /* 'groupslist' iterator */
1757
1758 /* output the programs for each group */
1759 if(!showprogs && html)
1760 ajFmtPrintF(outfile,"<ul>\n");
1761
1762 giter = ajListIterNewread(groupslist);
1763 while((gl = ajListIterGet(giter)) != NULL)
1764 {
1765 if(html)
1766 {
1767 if(showprogs)
1768 ajFmtPrintF(outfile,"<h2><a name=\"%S\">%S</a></h2>\n",
1769 gl->name, gl->name);
1770 else
1771 {
1772 ajFmtPrintF(outfile,"<li><a href=\"%S.html\">%S</a></li>\n",
1773 gl->name,gl->name);
1774 }
1775 }
1776 else
1777 ajFmtPrintF(outfile,"%S\n", gl->name);
1778
1779 if(showprogs)
1780 {
1781 if(html) ajFmtPrintF(outfile,"<table border cellpadding=4 "
1782 "bgcolor=\"#FFFFF0\">\n");
1783
1784 embGrpOutputProgsList(outfile, gl->progs, html, showkey, package);
1785
1786 if(html)
1787 ajFmtPrintF(outfile,"</table>\n");
1788 else
1789 ajFmtPrintF(outfile,"\n");
1790 }
1791 }
1792
1793 if(!showprogs && html)
1794 ajFmtPrintF(outfile,"</ul>\n");
1795
1796 ajListIterDel(&giter);
1797
1798 return;
1799 }
1800
1801
1802
1803
1804 /* @func embGrpOutputProgsList ************************************************
1805 **
1806 ** Displays a list of programs and their descriptions to an output file handle.
1807 **
1808 ** @param [u] outfile [AjPFile] Output file handle
1809 ** @param [r] progslist [const AjPList] List of programs to be displayed
1810 ** @param [r] html [AjBool] If True, format for HTML, else make a simple list
1811 ** @param [r] showkey [AjBool] Show keywords in output
1812 ** @param [r] package [const AjPStr] Name of current package
1813 ** @return [void]
1814 **
1815 ** @release 2.0.0
1816 ** @@
1817 ******************************************************************************/
1818
embGrpOutputProgsList(AjPFile outfile,const AjPList progslist,AjBool html,AjBool showkey,const AjPStr package)1819 void embGrpOutputProgsList(AjPFile outfile, const AjPList progslist,
1820 AjBool html, AjBool showkey, const AjPStr package)
1821 {
1822 EmbPGroupProg pl;
1823 AjIList piter; /* 'progslist' iterator */
1824 AjPStr keystr = NULL;
1825 ajint maxwidth = 6;
1826 AjBool isembassy = ajFalse;
1827
1828 if(ajStrGetLen(package))
1829 isembassy = ajTrue;
1830
1831 /* output the programs for each group */
1832 if(!html)
1833 {
1834 piter = ajListIterNewread(progslist);
1835
1836 while((pl = ajListIterGet(piter)) != NULL)
1837 {
1838 if(ajStrGetLen(pl->name) > (ajuint) maxwidth)
1839 maxwidth = ajStrGetLen(pl->name);
1840 }
1841
1842 ajListIterDel(&piter);
1843 }
1844
1845 piter = ajListIterNewread(progslist);
1846
1847 if(html) ajFmtPrintF(outfile,
1848 "<tr><th>Program name</th>\n"
1849 "<th>Description</th></tr>\n");
1850
1851 while((pl = ajListIterGet(piter)) != NULL)
1852 {
1853 if(showkey && ajStrGetLen(pl->keywords)) {
1854 ajFmtPrintS(&keystr, "(%S)", pl->keywords);
1855 ajStrExchangeKK(&keystr, ' ', ',');
1856 ajStrExchangeKK(&keystr, '_', ' ');
1857 ajStrInsertK(&keystr, 0, ' ');
1858 }
1859 else
1860 {
1861 ajStrAssignC(&keystr, "");
1862 }
1863
1864 if(html)
1865 {
1866 ajFmtPrintF(outfile, "<tr>\n");
1867
1868 if(ajStrMatchCaseS(package, pl->package))
1869 ajFmtPrintF(outfile,
1870 "<td><a href=\"%S.html\">%S</a></td>\n",
1871 pl->name, pl->name);
1872 else if(isembassy && ajStrGetLen(pl->package))
1873 ajFmtPrintF(outfile,
1874 "<td><a href=\"../%S/%S.html\">%S</a></td>\n",
1875 pl->package, pl->name, pl->name);
1876 else if(ajStrGetLen(pl->package))
1877 ajFmtPrintF(outfile,
1878 "<td><a href=\"/embassy/%S/%S.html\">%S</a></td>\n",
1879 pl->package, pl->name, pl->name);
1880 else
1881 ajFmtPrintF(outfile,
1882 "<td><a href=\"../../emboss/apps/%S.html\">%S"
1883 "</a></td>\n",
1884 pl->name, pl->name);
1885 ajFmtPrintF(outfile,
1886 "<td>%S%S</td>\n</tr>\n\n",
1887 pl->doc, keystr);
1888 }
1889 else
1890 ajFmtPrintF(outfile, "%-*S %S%S\n",
1891 maxwidth, pl->name, pl->doc, keystr);
1892 }
1893
1894 ajListIterDel(&piter);
1895
1896 ajStrDel(&keystr);
1897
1898 return;
1899 }
1900
1901
1902
1903
1904 /* @funcstatic grpGroupsListClear *********************************************
1905 **
1906 ** Clear a groups list
1907 **
1908 ** @param [d] groupslist [AjPList] List of groups to be cleared
1909 ** @return [void]
1910 **
1911 ** @release 6.4.0
1912 ** @@
1913 ******************************************************************************/
1914
grpGroupsListClear(AjPList groupslist)1915 static void grpGroupsListClear(AjPList groupslist)
1916 {
1917 EmbPGroupTop gl;
1918 AjIList giter;
1919
1920 giter = ajListIterNew(groupslist);
1921
1922 while((gl = ajListIterGet(giter)) != NULL)
1923 {
1924 ajStrDel(&(gl->doc));
1925 ajStrDel(&(gl->name));
1926 embGrpProgsListDel(&(gl->progs));
1927 AJFREE(gl);
1928 }
1929
1930 ajListIterDel(&giter);
1931
1932 return;
1933 }
1934
1935
1936
1937
1938 /* @func embGrpGroupsListDel **************************************************
1939 **
1940 ** Destructor for a groups list
1941 **
1942 ** @param [d] groupslist [AjPList*] List of groups to be destroyed
1943 ** @return [void]
1944 **
1945 ** @release 2.0.0
1946 ** @@
1947 ******************************************************************************/
1948
embGrpGroupsListDel(AjPList * groupslist)1949 void embGrpGroupsListDel(AjPList *groupslist)
1950 {
1951 grpGroupsListClear(*groupslist);
1952 ajListFree(groupslist);
1953
1954 return;
1955 }
1956
1957
1958
1959
1960 /* @func embGrpProgsListDel ***************************************************
1961 **
1962 ** Destructor for a groups list
1963 **
1964 ** @param [d] progslist [AjPList*] List of programs to be destroyed
1965 ** @return [void]
1966 **
1967 ** @release 4.0.0
1968 ** @@
1969 ******************************************************************************/
1970
embGrpProgsListDel(AjPList * progslist)1971 void embGrpProgsListDel(AjPList *progslist)
1972 {
1973 EmbPGroupProg gl;
1974 AjIList piter;
1975
1976 if(!*progslist)
1977 return;
1978
1979 piter = ajListIterNew(*progslist);
1980
1981 while((gl = ajListIterGet(piter)) != NULL)
1982 {
1983 embGrpProgDel(&gl);
1984 }
1985
1986 ajListIterDel(&piter);
1987 ajListFree(progslist);
1988
1989 return;
1990 }
1991
1992
1993
1994
1995 /* @funcstatic grpProgClear ***************************************************
1996 **
1997 ** Reset a program node
1998 **
1999 ** @param [d] gl [EmbPGroupProg] Program node
2000 ** @return [void]
2001 **
2002 ** @release 6.4.0
2003 ** @@
2004 ******************************************************************************/
2005
grpProgClear(EmbPGroupProg gl)2006 static void grpProgClear(EmbPGroupProg gl)
2007 {
2008 ajStrSetClear(&(gl->name));
2009 ajStrSetClear(&(gl->doc));
2010 ajStrSetClear(&(gl->package));
2011 ajStrSetClear(&(gl->keywords));
2012 grpGroupsListClear((gl->groups));
2013 grpRelationsListClear((gl->acdtopics));
2014 grpRelationsListClear((gl->acdoperations));
2015 grpRelationsListClear((gl->acdinputs));
2016 grpRelationsListClear((gl->acdoutputs));
2017 grpRelationsListClear((gl->acdparams));
2018
2019 return;
2020 }
2021
2022
2023
2024
2025 /* @func embGrpProgDel ********************************************************
2026 **
2027 ** Destructor for a program node
2028 **
2029 ** @param [d] Pgl [EmbPGroupProg*] Program node
2030 ** @return [void]
2031 **
2032 ** @release 6.4.0
2033 ** @@
2034 ******************************************************************************/
2035
embGrpProgDel(EmbPGroupProg * Pgl)2036 void embGrpProgDel(EmbPGroupProg *Pgl)
2037 {
2038 EmbPGroupProg gl = *Pgl;
2039
2040 if(!*Pgl)
2041 return;
2042
2043 ajStrDel(&(gl->name));
2044 ajStrDel(&(gl->doc));
2045 ajStrDel(&(gl->package));
2046 ajStrDel(&(gl->keywords));
2047 embGrpGroupsListDel(&(gl->groups));
2048 embGrpRelationsListDel(&(gl->acdtopics));
2049 embGrpRelationsListDel(&(gl->acdoperations));
2050 embGrpRelationsListDel(&(gl->acdinputs));
2051 embGrpRelationsListDel(&(gl->acdoutputs));
2052 embGrpRelationsListDel(&(gl->acdparams));
2053
2054 AJFREE(*Pgl);
2055
2056 return;
2057 }
2058
2059
2060
2061
2062 /* @funcstatic grpRelationsListClear ******************************************
2063 **
2064 ** Clear a relations list
2065 **
2066 ** @param [d] relslist [AjPList] List of relations to be cleared
2067 ** @return [void]
2068 **
2069 ** @release 6.4.0
2070 ** @@
2071 ******************************************************************************/
2072
grpRelationsListClear(AjPList relslist)2073 static void grpRelationsListClear(AjPList relslist)
2074 {
2075 EmbPGroupRelation gl;
2076
2077 while(ajListGetLength(relslist))
2078 {
2079 ajListPop(relslist, (void**) &gl);
2080 ajStrDel(&(gl->type));
2081 ajStrDel(&(gl->qual));
2082 ajStrDel(&(gl->acdgroup));
2083 ajStrDel(&(gl->id));
2084 ajStrDel(&(gl->namespace));
2085 ajStrDel(&(gl->name));
2086 AJFREE(gl);
2087 }
2088
2089 return;
2090 }
2091
2092
2093
2094
2095 /* @func embGrpRelationsListDel ***********************************************
2096 **
2097 ** Destructor for a relations list
2098 **
2099 ** @param [d] relslist [AjPList*] List of relations to be destroyed
2100 ** @return [void]
2101 **
2102 ** @release 6.4.0
2103 ** @@
2104 ******************************************************************************/
2105
embGrpRelationsListDel(AjPList * relslist)2106 void embGrpRelationsListDel(AjPList *relslist)
2107 {
2108 EmbPGroupRelation gl;
2109 AjIList piter;
2110
2111 piter = ajListIterNew(*relslist);
2112
2113 while((gl = ajListIterGet(piter)) != NULL)
2114 {
2115 ajStrDel(&(gl->type));
2116 ajStrDel(&(gl->qual));
2117 ajStrDel(&(gl->acdgroup));
2118 ajStrDel(&(gl->id));
2119 ajStrDel(&(gl->namespace));
2120 ajStrDel(&(gl->name));
2121 AJFREE(gl);
2122 }
2123
2124 ajListIterDel(&piter);
2125 ajListFree(relslist);
2126
2127 return;
2128 }
2129
2130
2131
2132
2133 /* @funcstatic grpRelationsCopy ***********************************************
2134 **
2135 ** Copy constructor for a relation
2136 **
2137 ** @param [r] gr [const EmbPGroupRelation] Source relation
2138 ** @return [EmbPGroupRelation] Relation object
2139 **
2140 ** @release 6.4.0
2141 ** @@
2142 ******************************************************************************/
2143
grpRelationsCopy(const EmbPGroupRelation gr)2144 static EmbPGroupRelation grpRelationsCopy(const EmbPGroupRelation gr)
2145 {
2146 EmbPGroupRelation ret;
2147
2148 AJNEW0(ret);
2149 ret->type = ajStrNewS(gr->type);
2150 ret->qual = ajStrNewS(gr->qual);
2151 ret->acdgroup = ajStrNewS(gr->acdgroup);
2152 ret->id = ajStrNewS(gr->id);
2153 ret->namespace = ajStrNewS(gr->namespace);
2154 ret->name = ajStrNewS(gr->name);
2155
2156 return ret;
2157 }
2158
2159
2160
2161
2162 /* @func embGrpKeySearchProgs *************************************************
2163 **
2164 ** Searches a list of groups and programs for (partial) matches to a keyword
2165 **
2166 ** @param [w] newlist [AjPList] List of matching EmbPGroupProg struct returned
2167 ** @param [r] glist [const AjPList] List of EmbPGroupProg struct to
2168 ** search through
2169 ** @param [r] key [const AjPStr] String to search for
2170 ** @param [r] all [AjBool] Match all words in key search string
2171 ** @return [void]
2172 **
2173 ** @release 2.0.0
2174 ** @@
2175 ******************************************************************************/
2176
embGrpKeySearchProgs(AjPList newlist,const AjPList glist,const AjPStr key,AjBool all)2177 void embGrpKeySearchProgs(AjPList newlist,
2178 const AjPList glist, const AjPStr key, AjBool all)
2179 {
2180 AjIList giter; /* 'glist' iterator */
2181 AjIList piter; /* 'plist' iterator */
2182 EmbPGroupTop gl; /* next member of glist */
2183 EmbPGroupTop gpnode; /* new member of glist being added */
2184 EmbPGroupProg pl; /* next member of plist */
2185 EmbPGroupProg ppnode; /* new member of plist being added */
2186 AjPStr gname = NULL;
2187 AjPStr name = NULL;
2188 AjPStr doc = NULL;
2189 AjPStr keywords= NULL;
2190 AjPStr keystr = NULL;
2191
2192 /*
2193 ** compare case independently - so use upper case of both key
2194 ** and name/doc
2195 */
2196 keystr = ajStrNewS(key);
2197 ajStrFmtUpper(&keystr);
2198
2199 /* make new group */
2200 ajStrAssignC(&gname, "Search for '");
2201 ajStrAppendS(&gname, keystr);
2202 ajStrAppendC(&gname, "'");
2203 gpnode = embGrpMakeNewGnode(gname);
2204 ajListPushAppend(newlist, gpnode);
2205
2206 giter = ajListIterNewread(glist); /* iterate through existing groups list */
2207
2208 while((gl = ajListIterGet(giter)) != NULL)
2209 {
2210 piter = ajListIterNewread(gl->progs);
2211
2212 while((pl = ajListIterGet(piter)) != NULL)
2213 {
2214 ajStrAssignS(&name, pl->name);
2215 ajStrAssignS(&doc, pl->doc);
2216 ajStrAssignS(&keywords, pl->keywords);
2217 ajStrFmtUpper(&name);
2218 ajStrFmtUpper(&doc);
2219 ajStrFmtUpper(&keywords);
2220
2221 if (all)
2222 {
2223 if(ajStrMatchWordAllS(doc,keystr) ||
2224 ajStrMatchWordAllS(keywords, keystr) ||
2225 ajStrMatchWordAllS(name, keystr))
2226 {
2227 ajDebug("Search '%S' in name:'%S' doc:'%S' key:'%S'\n",
2228 keystr, pl->name, pl->doc, pl->keywords);
2229 ppnode = grpCopyPnode(pl);
2230 ajListPushAppend(gpnode->progs, ppnode);
2231 }
2232 }
2233 else
2234 {
2235 if(ajStrMatchWordOneS(doc,keystr) ||
2236 ajStrMatchWordOneS(keywords, keystr) ||
2237 ajStrMatchWordOneS(name, keystr))
2238 {
2239 ajDebug("Search '%S' in name:'%S' doc:'%S' key:'%S'\n",
2240 keystr, pl->name, pl->doc, pl->keywords);
2241 ppnode = grpCopyPnode(pl);
2242 ajListPushAppend(gpnode->progs, ppnode);
2243 }
2244 }
2245
2246 ajStrDel(&name);
2247 ajStrDel(&doc);
2248 }
2249
2250 ajListIterDel(&piter);
2251 }
2252
2253 ajListIterDel(&giter);
2254
2255 /* sort the results */
2256 embGrpSortGroupsList(newlist);
2257
2258 ajStrDel(&gname);
2259 ajStrDel(&name);
2260 ajStrDel(&doc);
2261 ajStrDel(&keystr);
2262 ajStrDel(&keywords);
2263
2264 return;
2265 }
2266
2267
2268
2269
2270 /* @func embGrpSearchProgsEdam ************************************************
2271 **
2272 ** Searches a list of groups and programs for (partial) matches to
2273 ** EDAM topic terms
2274 **
2275 ** @param [w] newlist [AjPList] List of matching EmbPGroupProg struct returned
2276 ** @param [r] glist [const AjPList] List of EmbPGroupProg struct to
2277 ** search through
2278 ** @param [r] query [const AjPStr] String(s) to search for
2279 ** @param [r] namespace [const char*] EDAM namespace to search
2280 ** @param [r] sensitive [AjBool] Match EDAM definitions
2281 ** @param [r] subclasses [AjBool] Match EDAM subclasses
2282 ** @param [r] obsolete [AjBool] Match EDAM obsolete terms
2283 ** @return [void]
2284 **
2285 ** @release 6.4.0
2286 ** @@
2287 ******************************************************************************/
2288
embGrpSearchProgsEdam(AjPList newlist,const AjPList glist,const AjPStr query,const char * namespace,AjBool sensitive,AjBool subclasses,AjBool obsolete)2289 void embGrpSearchProgsEdam(AjPList newlist, const AjPList glist,
2290 const AjPStr query, const char* namespace,
2291 AjBool sensitive, AjBool subclasses,
2292 AjBool obsolete)
2293 {
2294 AjIList giter; /* 'glist' iterator */
2295 AjIList piter; /* 'plist' iterator */
2296 AjIList eiter; /* 'relations' iterator */
2297 EmbPGroupTop gl; /* next member of glist */
2298 EmbPGroupTop gpnode; /* new member of glist being added */
2299 EmbPGroupProg pl; /* next member of plist */
2300 EmbPGroupProg ppnode; /* new member of plist being added */
2301 EmbPGroupRelation rl; /* next relation for program */
2302 AjPStr gname = NULL;
2303
2304 AjPStr qrystr = NULL;
2305
2306 AjPOboin oboin = NULL;
2307 AjPObo obo = NULL;
2308 AjPObo obotest = NULL;
2309
2310 AjPStr oboqry = NULL;
2311 AjPTable obotable = NULL;
2312 AjPTable apptable = NULL;
2313
2314 AjPStrTok handle = NULL;
2315 AjPList obolist = NULL;
2316 AjBool dotopics = ajFalse;
2317 AjBool dooperations = ajFalse;
2318 AjBool doinputs = ajFalse;
2319 AjBool dooutputs = ajFalse;
2320 AjBool doparams = ajFalse;
2321
2322 AjBool matched = ajFalse;
2323
2324 AjPStr edamNamespace = NULL;
2325
2326 ajuint i;
2327 ajuint imax = 3;
2328
2329 const char* fields[] = {"id", "acc", "nam", "des"};
2330
2331 ajDebug("embGrpSearchProgsEdam '%S' namespace '%s' sens %B sub %B obs %B\n",
2332 query, namespace, sensitive, subclasses, obsolete);
2333 oboin = ajOboinNew();
2334 obo = ajOboNew();
2335
2336 obolist = ajListNew();
2337 obotable = ajTablestrNew(600);
2338 apptable = ajTablestrNew(600);
2339
2340 if(sensitive)
2341 imax++;
2342
2343 if(ajCharMatchC(namespace, "topic"))
2344 {
2345 dotopics = ajTrue;
2346 edamNamespace = ajStrNewC("topic");
2347 }
2348 else if (ajCharMatchC(namespace, "operation"))
2349 {
2350 dooperations = ajTrue;
2351 edamNamespace = ajStrNewC("operation");
2352 }
2353 else if (ajCharMatchC(namespace, "input"))
2354 {
2355 doinputs = ajTrue;
2356 edamNamespace = ajStrNewC("data");
2357 }
2358 else if (ajCharMatchC(namespace, "output"))
2359 {
2360 dooutputs = ajTrue;
2361 edamNamespace = ajStrNewC("data");
2362 }
2363 else if (ajCharMatchC(namespace, "param"))
2364 {
2365 doparams = ajTrue;
2366 edamNamespace = ajStrNewC("data");
2367 }
2368 else if (ajCharMatchC(namespace, "data"))
2369 {
2370 doinputs = ajTrue;
2371 doparams = ajTrue;
2372 dooutputs = ajTrue;
2373 edamNamespace = ajStrNewC("data");
2374 }
2375 else
2376 {
2377 ajErr("Unknown namespace '%s' for embGrpSearchProgsEdam", namespace);
2378 return;
2379 }
2380
2381 handle = ajStrTokenNewC(query, ",");
2382 while(ajStrTokenNextParse(handle, &qrystr))
2383 {
2384 for(i=0;i<imax;i++)
2385 {
2386 ajFmtPrintS(&oboqry, "edam-%s:%S", fields[i], qrystr);
2387
2388 ajOboinQryS(oboin, oboqry);
2389
2390 while(ajOboinRead(oboin, obo))
2391 {
2392 if(!ajStrMatchS(ajOboGetNamespace(obo), edamNamespace))
2393 continue;
2394
2395 if(!obsolete && ajOboIsObsolete(obo))
2396 continue;
2397
2398 ajListPushAppend(obolist, ajOboNewObo(obo));
2399 if(subclasses)
2400 ajOboGetTree(obo, obolist);
2401
2402 ajDebug("%S '%S' %Lu\n",
2403 qrystr, obo->Id, ajListGetLength(obolist));
2404
2405 while(ajListGetLength(obolist))
2406 {
2407 ajListPop(obolist, (void**) &obotest);
2408
2409 if(!ajStrMatchS(ajOboGetNamespace(obotest), edamNamespace))
2410 {
2411 ajOboDel(&obotest);
2412 continue;
2413 }
2414
2415 if(!obsolete && ajOboIsObsolete(obotest))
2416 {
2417 ajOboDel(&obotest);
2418 continue;
2419 }
2420
2421 if(!ajTableMatchS(obotable, obotest->Id))
2422 {
2423 ajDebug("edam id '%S' namespace '%S' %d '%S'\n",
2424 obotest->Id, obotest->Namespace,
2425 fields[i], obotest->Name);
2426 ajTablePut(obotable, ajStrNewS(obotest->Id),
2427 (void *) 1);
2428 }
2429
2430 ajOboDel(&obotest);
2431 }
2432 }
2433 }
2434 }
2435
2436 /*
2437 ** compare case independently - so use upper case of both key
2438 ** and name/doc
2439 */
2440
2441 /* make new group */
2442 ajFmtPrintS(&gname, "Search for %s '%S'", namespace, query);
2443 gpnode = embGrpMakeNewGnode(gname);
2444 ajListPushAppend(newlist, gpnode);
2445
2446 giter = ajListIterNewread(glist); /* iterate through existing groups list */
2447
2448 while((gl = ajListIterGet(giter)) != NULL)
2449 {
2450 piter = ajListIterNewread(gl->progs);
2451
2452 while((pl = ajListIterGet(piter)) != NULL)
2453 {
2454 if(!ajTableMatchS(apptable, pl->name))
2455 {
2456 matched = ajFalse;
2457 rl = NULL;
2458
2459 if(dotopics)
2460 {
2461 eiter = ajListIterNewread(pl->acdtopics);
2462
2463 while(!matched && (rl = ajListIterGet(eiter)) != NULL)
2464 {
2465 if(ajTableMatchS(obotable, rl->id))
2466 matched = ajTrue;
2467 }
2468 ajListIterDel(&eiter);
2469 }
2470
2471 if(!matched && dooperations)
2472 {
2473 eiter = ajListIterNewread(pl->acdoperations);
2474
2475 while(!matched && (rl = ajListIterGet(eiter)) != NULL)
2476 {
2477 if(ajTableMatchS(obotable, rl->id))
2478 matched = ajTrue;
2479 }
2480 ajListIterDel(&eiter);
2481 }
2482
2483 if(!matched && doinputs)
2484 {
2485 eiter = ajListIterNewread(pl->acdinputs);
2486
2487 while(!matched && (rl = ajListIterGet(eiter)) != NULL)
2488 {
2489 if(ajTableMatchS(obotable, rl->id))
2490 matched = ajTrue;
2491 }
2492 ajListIterDel(&eiter);
2493 }
2494
2495 if(!matched && dooutputs)
2496 {
2497 eiter = ajListIterNewread(pl->acdoutputs);
2498
2499 while(!matched && (rl = ajListIterGet(eiter)) != NULL)
2500 {
2501 if(ajTableMatchS(obotable, rl->id))
2502 matched = ajTrue;
2503 }
2504 ajListIterDel(&eiter);
2505 }
2506
2507 if(!matched && doparams)
2508 {
2509 eiter = ajListIterNewread(pl->acdparams);
2510
2511 while(!matched && (rl = ajListIterGet(eiter)) != NULL)
2512 {
2513 if(ajTableMatchS(obotable, rl->id))
2514 matched = ajTrue;
2515 }
2516 ajListIterDel(&eiter);
2517 }
2518 if(matched && rl)
2519 {
2520 ajDebug("program %S edam:%S '%S' namespace '%S'\n",
2521 pl->name, rl->id, rl->name, rl->namespace);
2522 ppnode = grpCopyPnode(pl);
2523 ajListPushAppend(gpnode->progs, ppnode);
2524 ajTablePut(apptable, ajStrNewS(pl->name),
2525 (void *) 1);
2526 }
2527 }
2528 }
2529
2530 ajListIterDel(&piter);
2531 }
2532
2533 ajListIterDel(&giter);
2534
2535 /* sort the results */
2536 embGrpSortGroupsList(newlist);
2537
2538 ajListFree(&obolist);
2539 ajTablestrFreeKey(&obotable);
2540 ajTablestrFreeKey(&apptable);
2541
2542 ajOboinDel(&oboin);
2543 ajOboDel(&obo);
2544
2545 ajStrDel(&edamNamespace);
2546 ajStrDel(&qrystr);
2547 ajStrDel(&oboqry);
2548 ajStrDel(&gname);
2549
2550 ajStrTokenDel(&handle);
2551
2552 return;
2553 }
2554
2555
2556
2557
2558 /* @func embGrpKeySearchSeeAlso ***********************************************
2559 **
2560 ** Takes an application name and returns a list of the groups that the
2561 ** application belongs to and a list of the applications that are in
2562 ** those groups.
2563 **
2564 ** If the program we are searching for is not found, it returns *appgroups
2565 ** as NULL.
2566 **
2567 ** @param [u] newlist [AjPList] List of application groups EmbPGroupTop
2568 ** returned
2569 ** @param [w] appgroups [AjPList *] List of EmbPGroupTop groups of programs
2570 ** returned
2571 ** @param [w] package [AjPStr *] List of EmbPGroupTop groups of programs
2572 ** @param [r] alpha [const AjPList] List of EmbPGroupProg struct to
2573 ** search through
2574 ** @param [r] glist [const AjPList] List of EmbPGroupTop struct to
2575 ** search through
2576 ** @param [r] key [const AjPStr] program name to search for
2577 ** @return [void]
2578 **
2579 ** @release 2.0.0
2580 ** @@
2581 ******************************************************************************/
2582
embGrpKeySearchSeeAlso(AjPList newlist,AjPList * appgroups,AjPStr * package,const AjPList alpha,const AjPList glist,const AjPStr key)2583 void embGrpKeySearchSeeAlso(AjPList newlist, AjPList *appgroups,
2584 AjPStr* package,
2585 const AjPList alpha, const AjPList glist,
2586 const AjPStr key)
2587 {
2588
2589 AjIList giter; /* 'glist' iterator */
2590 AjIList piter; /* 'plist' iterator */
2591 AjIList griter; /* iterator through list of groups we have found */
2592 EmbPGroupTop gl; /* next member of glist */
2593 EmbPGroupTop gpnode; /* new member of newlist being added */
2594 EmbPGroupProg ppnode; /* new member of glist being added */
2595 EmbPGroupProg pl; /* next member of plist */
2596 EmbPGroupTop gr; /* next member of list of groups we have found */
2597 AjPStr tmp = NULL;
2598 AjPList base;
2599
2600 /* make initial group node and push on newlist */
2601 tmp = ajStrNewC("See also");
2602 gpnode = embGrpMakeNewGnode(tmp);
2603 base = gpnode->progs;
2604 ajListPushAppend(newlist, gpnode);
2605
2606
2607 /*
2608 ** set *appgroups to NULL initially - test to see if still NULL after
2609 ** we have searched for the application name
2610 **/
2611 *appgroups = NULL;
2612
2613 /*
2614 ** initially look for our application in list 'alpha' to get its list of
2615 ** groups
2616 **/
2617
2618 /* iterate through existing applications list */
2619 giter = ajListIterNewread(alpha);
2620
2621 while((gl = ajListIterGet(giter)) != NULL)
2622 {
2623 piter = ajListIterNewread(gl->progs);
2624
2625 while((pl = ajListIterGet(piter)) != NULL)
2626 if(ajStrMatchCaseS(pl->name, key))
2627 {
2628 *appgroups = pl->groups;
2629 ajStrAssignS(package, pl->package);
2630 }
2631
2632 ajListIterDel(&piter);
2633 }
2634
2635 ajListIterDel(&giter);
2636
2637 /* If application not found */
2638 if(*appgroups == NULL)
2639 return;
2640
2641 /*
2642 ** go through each group in glist finding those that are
2643 ** used by the application
2644 */
2645
2646 /* iterate through existing applications list */
2647 giter = ajListIterNewread(glist);
2648
2649 while((gl = ajListIterGet(giter)) != NULL)
2650 {
2651 /* iterate through groups found */
2652 griter = ajListIterNewread(*appgroups);
2653
2654 while((gr = ajListIterGet(griter)) != NULL)
2655 {
2656 if(!ajStrCmpCaseS(gr->name, gl->name))
2657 {
2658 /*
2659 ** found one of the groups - pull out
2660 ** the applications
2661 **/
2662 piter = ajListIterNewread(gl->progs);
2663
2664 while((pl = ajListIterGet(piter)) != NULL)
2665 {
2666 /* don't want to include our key program */
2667 if(!ajStrCmpS(pl->name, key))
2668 continue;
2669
2670 /* make new application node and push on base */
2671 ppnode = grpCopyPnode(pl);
2672 ajListPushAppend(base, ppnode);
2673
2674 }
2675
2676 ajListIterDel(&piter);
2677 }
2678 }
2679
2680 ajListIterDel(&griter);
2681 }
2682
2683 ajListIterDel(&giter);
2684
2685 /* sort the results and remove duplicates */
2686 embGrpSortProgsList(base);
2687 embGrpProgsMakeUnique(base);
2688
2689 ajStrDel(&tmp);
2690
2691 return;
2692 }
2693
2694
2695
2696
2697 /* @func embGrpProgsMakeUnique ************************************************
2698 **
2699 ** Takes a sorted EmbPGroupProg list and ensures that there are no duplicate
2700 ** group or application names in that list.
2701 **
2702 ** @param [u] list [AjPList] List of application GPnode returned
2703 ** @return [void]
2704 **
2705 ** @release 4.0.0
2706 ** @@
2707 ******************************************************************************/
2708
embGrpProgsMakeUnique(AjPList list)2709 void embGrpProgsMakeUnique(AjPList list)
2710 {
2711 AjIList iter;
2712 EmbPGroupProg l; /* next member of list */
2713 AjPStr old = NULL; /* previous name */
2714
2715 old = ajStrNewC("");
2716
2717 iter = ajListIterNew(list);
2718
2719 while((l = ajListIterGet(iter)) != NULL)
2720 {
2721 if(!ajStrCmpCaseS(l->name, old))
2722 {
2723
2724 /* delete this GPnode's lists and data */
2725 embGrpGroupsListDel(&l->groups);
2726 ajStrDel(&(l->name));
2727 ajStrDel(&(l->doc));
2728 ajStrDel(&(l->package));
2729 AJFREE(l);
2730
2731 /* delete this element of the list */
2732 ajListIterRemove(iter);
2733
2734 }
2735 else
2736 {
2737 ajStrDel(&old);
2738 old = ajStrNewRef(l->name);
2739 embGrpGroupMakeUnique(l->groups);
2740 }
2741
2742 }
2743
2744 ajListIterDel(&iter);
2745 ajStrDel(&old);
2746
2747 return;
2748 }
2749
2750
2751
2752
2753 /* @func embGrpGroupMakeUnique ************************************************
2754 **
2755 ** Takes a sorted EmbPGroupTop list and ensures that there are no duplicate
2756 ** group or application names in that list.
2757 **
2758 ** @param [u] list [AjPList] List of application GPnode returned
2759 ** @return [void]
2760 **
2761 ** @release 4.0.0
2762 ** @@
2763 ******************************************************************************/
2764
embGrpGroupMakeUnique(AjPList list)2765 void embGrpGroupMakeUnique(AjPList list)
2766 {
2767 AjIList iter;
2768 EmbPGroupTop l; /* next member of list */
2769 AjPStr old = NULL; /* previous name */
2770
2771 old = ajStrNewC("");
2772
2773 iter = ajListIterNew(list);
2774
2775 while((l = ajListIterGet(iter)) != NULL)
2776 {
2777
2778 if(!ajStrCmpCaseS(l->name, old))
2779 {
2780
2781 /* delete this GPnode's lists and data */
2782 embGrpProgsListDel(&l->progs);
2783 ajStrDel(&(l->doc));
2784 ajStrDel(&(l->name));
2785 AJFREE(l);
2786
2787 /* delete this element of the list */
2788 ajListIterRemove(iter);
2789
2790 }
2791 else
2792 {
2793 ajStrDel(&old);
2794 old = ajStrNewRef(l->name);
2795 embGrpProgsMakeUnique(l->progs);
2796 }
2797
2798 }
2799
2800 ajListIterDel(&iter);
2801 ajStrDel(&old);
2802
2803 return;
2804 }
2805
2806
2807
2808
2809 /* @func embGrpExit ***********************************************************
2810 **
2811 ** Cleanup program group internals on exit
2812 **
2813 ** @return [void]
2814 **
2815 ** @release 4.0.0
2816 ******************************************************************************/
2817
embGrpExit(void)2818 void embGrpExit(void)
2819 {
2820 ajStrDel(&grpStr1);
2821 ajStrDel(&grpStr2);
2822
2823 return;
2824 }
2825