1 /* @source showpep application
2 **
3 ** Display a sequence with translations, features and other bits
4 **
5 ** @author Copyright (C) Gary Williams (gwilliam@hgmp.mrc.ac.uk)
6 ** 14 Sept 1999 - GWW - written
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 #include "emboss.h"
25
26
27
28
29 static void showpep_FormatShow(EmbPShow ss,
30 const AjPStr format,
31 const AjPRange uppercase,
32 const AjPRange highlight, AjBool threeletter,
33 AjBool numberseq, const AjPFeattable feat,
34 const AjPRange annotation);
35
36 static AjBool showpep_MatchFeature(const AjPFeature gf,
37 AjPFeature newgf,
38 const AjPStr matchsource,
39 const AjPStr matchtype, AjBool testscore,
40 float minscore,
41 float maxscore, const AjPStr matchtag,
42 const AjPStr matchvalue, AjBool *tagsmatch,
43 AjBool stricttags);
44 static AjBool showpep_MatchPatternTags(const AjPFeature gf,
45 AjPFeature newgf,
46 const AjPStr tpattern,
47 const AjPStr vpattern,
48 AjBool stricttags);
49 static void showpep_FeatureFilter(const AjPFeattable featab,
50 AjPFeattable newfeatab,
51 const AjPStr matchsource,
52 const AjPStr matchtype,
53 AjBool testscore, float minscore,
54 float maxscore, const AjPStr matchtag,
55 const AjPStr matchvalue, AjBool stricttags);
56 static AjPFeature showpep_FeatCopy(const AjPFeature orig);
57
58
59
60
61
62 /* @prog showpep **************************************************************
63 **
64 ** Display a sequence with features, translation etc
65 **
66 ******************************************************************************/
67
main(int argc,char ** argv)68 int main(int argc, char **argv)
69 {
70
71 ajint begin;
72 ajint end;
73 AjPSeqall seqall;
74 AjPSeq seq;
75 EmbPShow ss;
76 AjPFile outfile;
77 AjPStr formatname;
78 AjPStr *thinglist;
79 AjPRange uppercase;
80 AjPRange highlight;
81 AjBool threeletter;
82 AjBool numberseq;
83 AjBool nameseq;
84 ajint width;
85 ajint length;
86 ajint margin;
87 AjBool description;
88 ajint offset;
89 AjBool html;
90 AjBool stricttags;
91
92 AjPStr descriptionline;
93 AjPFeattable feattab;
94 AjPFeattable newfeattab;/* feature table copy, unwanted features removed */
95 AjPRange annotation;
96
97 /* holds ACD or constructed format for output */
98 AjPStr format;
99 ajint i;
100
101 /* feature filter criteria */
102 AjPStr matchsource = NULL;
103 AjPStr matchtype = NULL;
104 float minscore;
105 float maxscore;
106 AjPStr matchtag = NULL;
107 AjPStr matchvalue = NULL;
108 AjBool testscore = AJFALSE;
109
110
111 embInit("showpep", argc, argv);
112
113 seqall = ajAcdGetSeqall("sequence");
114 outfile = ajAcdGetOutfile("outfile");
115 formatname = ajAcdGetListSingle("format");
116 thinglist = ajAcdGetList("things");
117 uppercase = ajAcdGetRange("uppercase");
118 highlight = ajAcdGetRange("highlight");
119 annotation = ajAcdGetRange("annotation");
120 threeletter = ajAcdGetBoolean("threeletter");
121 numberseq = ajAcdGetBoolean("number");
122 width = ajAcdGetInt("width");
123 length = ajAcdGetInt("length");
124 margin = ajAcdGetInt("margin");
125 nameseq = ajAcdGetBoolean("name");
126 description = ajAcdGetBoolean("description");
127 offset = ajAcdGetInt("offset");
128 html = ajAcdGetBoolean("html");
129
130 /* feature filter criteria */
131 matchsource = ajAcdGetString("sourcematch");
132 matchtype = ajAcdGetString("typematch");
133 minscore = ajAcdGetFloat("minscore");
134 maxscore = ajAcdGetFloat("maxscore");
135 matchtag = ajAcdGetString("tagmatch");
136 matchvalue = ajAcdGetString("valuematch");
137 stricttags = ajAcdGetBoolean("stricttags");
138
139 testscore = (minscore || maxscore);
140 if(minscore && !maxscore)
141 if(minscore > maxscore)
142 maxscore = minscore;
143 if(!minscore && maxscore)
144 if(minscore > maxscore)
145 minscore = maxscore;
146
147 format = ajStrNew();
148
149 /* get the format to use */
150 if(ajStrMatchC(formatname, "0"))
151 for(i=0; thinglist[i]; i++)
152 {
153 ajStrAppendS(&format, thinglist[i]);
154 ajStrAppendC(&format, " ");
155 }
156 else if(ajStrMatchC(formatname, "1"))
157 ajStrAssignC(&format, "S A ");
158 else if(ajStrMatchC(formatname, "2"))
159 ajStrAssignC(&format, "B N T S A F ");
160 else if(ajStrMatchC(formatname, "3"))
161 ajStrAssignC(&format, "B N T S A ");
162 else if(ajStrMatchC(formatname, "4"))
163 ajStrAssignC(&format, "B N T S T C T A F ");
164 else
165 ajFatal("Invalid format type: %S", formatname);
166
167
168 /* make the format upper case */
169 ajStrFmtUpper(&format);
170
171 while(ajSeqallNext(seqall, &seq))
172 {
173 begin = ajSeqGetBegin(seq)-1;
174 end = ajSeqGetEnd(seq)-1;
175
176 /* do the name and description */
177 if(nameseq)
178 {
179 if(html)
180 ajFmtPrintF(outfile, "<H2>%S</H2>\n",
181 ajSeqGetNameS(seq));
182 else
183 ajFmtPrintF(outfile, "%S\n", ajSeqGetNameS(seq));
184 }
185
186 if(description)
187 {
188 /*
189 ** wrap the description line at the width of the sequence
190 ** plus margin
191 */
192 if(html)
193 ajFmtPrintF(outfile, "<H3>%S</H3>\n",
194 ajSeqGetDescS(seq));
195 else
196 {
197 descriptionline = ajStrNew();
198 ajStrAssignS(&descriptionline, ajSeqGetDescS(seq));
199 ajStrFmtWrap(&descriptionline, width+margin);
200 ajFmtPrintF(outfile, "%S\n", descriptionline);
201 ajStrDel(&descriptionline);
202 }
203 }
204
205
206 /* get the feature table of the sequence */
207 feattab = ajSeqGetFeatCopy(seq);
208
209 /* new feature table to hold the filetered features */
210 newfeattab = ajFeattableNew(NULL);
211 ajDebug("created newfeattab %x\n", newfeattab);
212
213 /* only copy features in the table that match our criteria */
214 showpep_FeatureFilter(feattab, newfeattab, matchsource, matchtype,
215 testscore, minscore, maxscore, matchtag,
216 matchvalue, stricttags);
217
218
219 /* make the Show Object */
220 ss = embShowNew(seq, begin, end, width, length, margin, html, offset);
221
222 if(html)
223 ajFmtPrintF(outfile, "<PRE>");
224
225 showpep_FormatShow(ss, format,
226 uppercase, highlight, threeletter,
227 numberseq, newfeattab,
228 annotation);
229
230 embShowPrint(outfile, ss);
231
232 embShowDel(&ss);
233
234 ajFeattableDel(&newfeattab);
235 ajFeattableDel(&feattab);
236
237 /* add a newline at the end of the sequence */
238 ajFmtPrintF(outfile, "\n");
239
240 if(html)
241 ajFmtPrintF(outfile, "</PRE>\n");
242 }
243
244
245 ajStrDel(&format);
246 ajFileClose(&outfile);
247 ajSeqallDel(&seqall);
248 ajSeqDel(&seq);
249 ajStrDelarray(&thinglist);
250 ajStrDel(&formatname);
251 ajStrDel(&matchsource);
252 ajStrDel(&matchtype);
253 ajStrDel(&matchtag);
254 ajStrDel(&matchvalue);
255 ajRangeDel(&uppercase);
256 ajRangeDel(&highlight);
257 ajRangeDel(&annotation);
258
259 embExit();
260
261 return 0;
262 }
263
264
265
266
267 /* @funcstatic showpep_FormatShow *********************************************
268 **
269 ** Set up the EmbPShow object, according to the required format
270 **
271 ** @param [u] ss [EmbPShow] Show sequence object
272 ** @param [r] format [const AjPStr] format codes for the required
273 ** things to display
274 ** @param [r] uppercase [const AjPRange] ranges to uppercase
275 ** @param [r] highlight [const AjPRange] ranges to colour in HTML
276 ** @param [r] threeletter [AjBool] use 3-letter code
277 ** @param [r] numberseq [AjBool] put numbers on sequences
278 ** @param [r] feat [const AjPFeattable] sequence's feature table
279 ** NULL after - pointer stored internally
280 ** @param [r] annotation [const AjPRange] ranges to annotate
281 ** @return [void]
282 ** @@
283 ******************************************************************************/
284
showpep_FormatShow(EmbPShow ss,const AjPStr format,const AjPRange uppercase,const AjPRange highlight,AjBool threeletter,AjBool numberseq,const AjPFeattable feat,const AjPRange annotation)285 static void showpep_FormatShow(EmbPShow ss,
286 const AjPStr format,
287 const AjPRange uppercase,
288 const AjPRange highlight, AjBool threeletter,
289 AjBool numberseq, const AjPFeattable feat,
290 const AjPRange annotation)
291 {
292 AjPStrTok tok;
293 char white[] = " \t\n\r";
294 char whiteplus[] = " \t,.!@#$%^&*()_+|~`\\={}[]:;\"'<>,.?/";
295 AjPStr code = NULL;
296
297 /* start token to parse format */
298 tok = ajStrTokenNewC(format, white);
299 while(ajStrTokenNextParseC(tok, whiteplus, &code))
300 {
301 ajStrFmtUpper(&code);
302
303 if(!ajStrCmpC(code, "S"))
304 embShowAddSeq(ss, numberseq, threeletter, uppercase,
305 highlight);
306 else if(!ajStrCmpC(code, "B"))
307 embShowAddBlank(ss);
308 else if(!ajStrCmpC(code, "T"))
309 embShowAddTicks(ss);
310 else if(!ajStrCmpC(code, "N"))
311 embShowAddTicknum(ss);
312 else if(!ajStrCmpC(code, "C"))
313 embShowAddComp(ss, numberseq);
314 else if(!ajStrCmpC(code, "F"))
315 embShowAddFT(ss, feat);
316 else if(!ajStrCmpC(code, "A"))
317 embShowAddNote(ss, annotation);
318 else
319 ajFatal("Formatting code not recognised: '%S'", code);
320 }
321
322 ajStrDel(&code);
323 ajStrTokenDel(&tok);
324
325 return;
326 }
327
328
329
330
331 /* @funcstatic showpep_FeatureFilter ******************************************
332 **
333 ** Removes unwanted features from a feature table
334 **
335 ** @param [r] featab [const AjPFeattable] Feature table to filter
336 ** @param [u] newfeatab [AjPFeattable] Retured table of filtered features
337 ** @param [r] matchsource [const AjPStr] Required Source pattern
338 ** @param [r] matchtype [const AjPStr] Required Type pattern
339 ** @param [r] testscore [AjBool] Filter by score values
340 ** @param [r] minscore [float] Min required Score pattern
341 ** @param [r] maxscore [float] Max required Score pattern
342 ** @param [r] matchtag [const AjPStr] Required Tag pattern
343 ** @param [r] matchvalue [const AjPStr] Required Value pattern
344 ** @param [r] stricttags [AjBool] If false then only display tag/values
345 ** that match the criteria
346 ** @return [void]
347 ** @@
348 ******************************************************************************/
349
showpep_FeatureFilter(const AjPFeattable featab,AjPFeattable newfeatab,const AjPStr matchsource,const AjPStr matchtype,AjBool testscore,float minscore,float maxscore,const AjPStr matchtag,const AjPStr matchvalue,AjBool stricttags)350 static void showpep_FeatureFilter(const AjPFeattable featab,
351 AjPFeattable newfeatab,
352 const AjPStr matchsource,
353 const AjPStr matchtype, AjBool testscore,
354 float minscore,
355 float maxscore, const AjPStr matchtag,
356 const AjPStr matchvalue, AjBool stricttags)
357 {
358
359 AjIList iter = NULL;
360 AjPFeature gf = NULL;
361 AjPFeature newgf = NULL;
362 AjBool tagsmatch;
363
364 tagsmatch = ajFalse;
365
366 /* foreach feature in the feature table */
367 if(featab)
368 {
369 iter = ajListIterNewread(featab->Features);
370 while(!ajListIterDone(iter))
371 {
372 gf = (AjPFeature)ajListIterGet(iter);
373 newgf = showpep_FeatCopy(gf); /* copy of gf that we can add */
374 /* required tags to */
375 if(showpep_MatchFeature(gf, newgf, matchsource, matchtype,
376 testscore, minscore, maxscore, matchtag,
377 matchvalue, &tagsmatch, stricttags))
378 /*
379 ** There's a match, so add the copy of gf
380 ** to the new feature table
381 */
382 ajFeattableAdd(newfeatab, newgf);
383 else
384 ajFeatDel(&newgf);
385 }
386 ajListIterDel(&iter);
387 }
388
389 return;
390 }
391
392
393
394
395 /* @funcstatic showpep_MatchFeature *******************************************
396 **
397 ** Test if a feature matches a set of criteria
398 **
399 ** @param [r] gf [const AjPFeature] Feature to test
400 ** @param [u] newgf [AjPFeature] Copy of feature with filtered
401 ** Tag/Value list
402 ** @param [r] source [const AjPStr] Required Source pattern
403 ** @param [r] type [const AjPStr] Required Type pattern
404 ** @param [r] testscore [AjBool] Filter by score values
405 ** @param [r] minscore [float] Min required Score pattern
406 ** @param [r] maxscore [float] Max required Score pattern
407 ** @param [r] tag [const AjPStr] Required Tag pattern
408 ** @param [r] value [const AjPStr] Required Value pattern
409 ** @param [u] tagsmatch [AjBool *] true if a join has matching tag/values
410 ** @param [r] stricttags [AjBool] If false then only display tag/values
411 ** that match the criteria
412 ** @return [AjBool] True if feature matches criteria
413 ** @@
414 ******************************************************************************/
415
showpep_MatchFeature(const AjPFeature gf,AjPFeature newgf,const AjPStr source,const AjPStr type,AjBool testscore,float minscore,float maxscore,const AjPStr tag,const AjPStr value,AjBool * tagsmatch,AjBool stricttags)416 static AjBool showpep_MatchFeature(const AjPFeature gf, AjPFeature newgf,
417 const AjPStr source, const AjPStr type,
418 AjBool testscore,
419 float minscore, float maxscore,
420 const AjPStr tag, const AjPStr value,
421 AjBool *tagsmatch, AjBool stricttags)
422 {
423 AjPStrTok tokens = NULL;
424 AjPStr key = NULL;
425 AjBool val = ajFalse;
426
427 /*
428 ** is this a child of a join() ?
429 ** if it is a child, then we use the previous result of MatchPatternTags
430 */
431 if(!ajFeatIsMultiple(gf))
432 *tagsmatch = showpep_MatchPatternTags(gf, newgf, tag, value,
433 stricttags);
434
435 /* ignore remote IDs */
436 if(!ajFeatIsLocal(gf))
437 return ajFalse;
438
439 /* check source, type, sense, score, tags, values
440 ** Match anything:
441 ** for strings, '*'
442 ** for sense, 0
443 ** for score, maxscore <= minscore
444 */
445 if(!embMiscMatchPatternDelimC(ajFeatGetSource(gf), source,",;|") ||
446 (testscore && ajFeatGetScore(gf) < minscore) ||
447 (testscore && ajFeatGetScore(gf) > maxscore) ||
448 !*tagsmatch)
449 return ajFalse;
450
451 if(ajStrGetLen(type))
452 {
453 val = ajFalse;
454 tokens = ajStrTokenNewC(type, " \t\n\r,;|");
455
456 while (ajStrTokenNextParse(tokens, &key))
457 {
458 if (ajFeatTypeMatchWildS(gf, key))
459 {
460 val = ajTrue;
461 break;
462 }
463 }
464
465 ajStrTokenDel( &tokens);
466 ajStrDel(&key);
467 if(!val)
468 return ajFalse;
469 }
470
471 return ajTrue;
472 }
473
474
475
476
477 /* @funcstatic showpep_MatchPatternTags ***************************************
478 **
479 ** Checks for a match of the tagpattern and valuepattern to at least one
480 ** tag=value pair
481 **
482 ** @param [r] gf [const AjPFeature] Feature to process
483 ** @param [u] newgf [AjPFeature] Copy of feature returned
484 ** with filtered Tag/Value list
485 ** @param [r] tpattern [const AjPStr] tags pattern to match with
486 ** @param [r] vpattern [const AjPStr] values pattern to match with
487 ** @param [r] stricttags [AjBool] If false then only display tag/values
488 ** that match the criteria
489 **
490 ** @return [AjBool] ajTrue = found a match
491 ** @@
492 ******************************************************************************/
493
showpep_MatchPatternTags(const AjPFeature gf,AjPFeature newgf,const AjPStr tpattern,const AjPStr vpattern,AjBool stricttags)494 static AjBool showpep_MatchPatternTags(const AjPFeature gf,
495 AjPFeature newgf,
496 const AjPStr tpattern,
497 const AjPStr vpattern,
498 AjBool stricttags)
499 {
500 AjIList titer; /* iterator for feat */
501 AjPStr tagnam = NULL; /* tag name from tag structure */
502 AjPStr tagval = NULL; /* tag value from tag structure */
503 AjBool val = ajFalse; /* returned value */
504 AjBool tval; /* tags result */
505 AjBool vval; /* value result */
506
507 /*
508 ** If there are no tags to match, but the patterns are
509 ** both '*', then allow this as a match
510 */
511 if(ajListGetLength(gf->Tags) == 0 &&
512 !ajStrCmpC(tpattern, "*") &&
513 !ajStrCmpC(vpattern, "*"))
514 return ajTrue;
515
516
517 /* iterate through the tags and test for match to patterns */
518 titer = ajFeatTagIter(gf);
519 while(ajFeatTagval(titer, &tagnam, &tagval))
520 {
521 tval = embMiscMatchPatternDelimC(tagnam, tpattern,",;|");
522 /*
523 ** If tag has no value then
524 ** If vpattern is '*' the value pattern is a match
525 ** Else check vpattern
526 */
527 if(!ajStrGetLen(tagval))
528 {
529 if(!ajStrCmpC(vpattern, "*"))
530 vval = ajTrue;
531 else
532 vval = ajFalse;
533 }
534 else
535 /*
536 ** The value can be one or more words and the vpattern could
537 ** be the whole phrase, so test not only each word in vpattern
538 ** against the value, but also test to see if there is a match
539 ** of the whole of vpattern without spitting it up into words.
540 */
541 vval = (ajStrMatchS(tagval, vpattern) ||
542 embMiscMatchPatternDelimC(tagval, vpattern,",;|"));
543
544
545 if(tval && vval)
546 {
547 val = ajTrue;
548 /*
549 ** if strict tags then only want to see the tags
550 ** that match the criteria
551 */
552 if(stricttags)
553 ajFeatTagAddSS(newgf, tagnam, tagval);
554 }
555
556 /* if not strict tags then need to see all the tags */
557 if(!stricttags)
558 ajFeatTagAddSS(newgf, tagnam, tagval);
559 }
560 ajListIterDel(&titer);
561
562 ajStrDel(&tagnam);
563 ajStrDel(&tagval);
564
565 return val;
566 }
567
568
569
570
571 /* @funcstatic showpep_FeatCopy ***********************************************
572 **
573 ** Makes a copy of a feature, except for the Tags list which is added later.
574 ** This is mostly copied from the original in ajFeatCopy,
575 ** but without the Tags stuff.
576 **
577 ** @param [r] orig [const AjPFeature] Original feature
578 ** @return [AjPFeature] New copy of feature
579 ** @@
580 ******************************************************************************/
581
showpep_FeatCopy(const AjPFeature orig)582 static AjPFeature showpep_FeatCopy(const AjPFeature orig)
583 {
584
585 AjPFeature ret;
586
587 AJNEW0(ret);
588
589 ret->Tags = ajListNew();
590
591 ajStrAssignS(&ret->Source, orig->Source);
592 ajStrAssignS(&ret->Type, orig->Type);
593 ajStrAssignS(&ret->Remote, orig->Remote);
594 ajStrAssignS(&ret->Label, orig->Label);
595
596 ret->Protein = orig->Protein;
597 ret->Start = orig->Start;
598 ret->End = orig->End;
599 ret->Start2 = orig->Start2;
600 ret->End2 = orig->End2;
601 ret->Score = orig->Score;
602 ret->Strand = orig->Strand;
603 ret->Frame = orig->Frame;
604 ret->Flags = orig->Flags;
605 ret->Group = orig->Group;
606 ret->Exon = orig->Exon;
607
608 return ret;
609 }
610