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