1 /* @source ajrange ************************************************************
2 **
3 ** AJAX range functions
4 **
5 ** @author Copyright (C) 1999 Alan Bleasby
6 ** @version $Revision: 1.46 $
7 ** @modified Aug 21 ajb First version
8 ** @modified 7 Sept 1999 GWW - String range edit functions added
9 ** @modified 5 Nov 1999 GWW - store text after pairs of numbers
10 ** @modified $Date: 2013/02/07 10:24:39 $ by $Author: rice $
11 ** @@
12 **
13 ** This library is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU Lesser General Public
15 ** License as published by the Free Software Foundation; either
16 ** version 2.1 of the License, or (at your option) any later version.
17 **
18 ** This library is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 ** Lesser General Public License for more details.
22 **
23 ** You should have received a copy of the GNU Lesser General Public
24 ** License along with this library; if not, write to the Free Software
25 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 ** MA  02110-1301,  USA.
27 **
28 ******************************************************************************/
29 
30 /* ==================================================================== */
31 /* ========================== include files =========================== */
32 /* ==================================================================== */
33 
34 
35 #include "ajlib.h"
36 
37 #include "ajrange.h"
38 #include "ajsys.h"
39 #include "ajseq.h"
40 #include "ajfileio.h"
41 
42 #include <stdlib.h>
43 #include <string.h>
44 #include <ctype.h>
45 #include <limits.h>
46 
47 
48 
49 
50 /* ==================================================================== */
51 /* ========================== private data ============================ */
52 /* ==================================================================== */
53 
54 
55 
56 /* ==================================================================== */
57 /* ======================== private functions ========================= */
58 /* ==================================================================== */
59 
60 
61 
62 /* ==================================================================== */
63 /* ========================= constructors ============================= */
64 /* ==================================================================== */
65 
66 
67 
68 
69 /* @section Range Constructors ************************************************
70 **
71 ** All constructors return a new object by pointer. It is the responsibility
72 ** of the user to first destroy any previous object. The target pointer
73 ** does not need to be initialised to NULL, but it is good programming practice
74 ** to do so anyway.
75 **
76 ******************************************************************************/
77 
78 
79 
80 
81 /* @func ajRangeNewI **********************************************************
82 **
83 ** Default constructor for AJAX range objects.
84 **
85 ** @param [r] n [ajuint] number of ranges
86 **
87 ** @return [AjPRange] Pointer to a range object
88 ** @category new [AjPRange] Default constructor for range objects
89 **
90 ** @release 1.0.0
91 ** @@
92 ******************************************************************************/
93 
ajRangeNewI(ajuint n)94 AjPRange ajRangeNewI(ajuint n)
95 {
96     AjPRange thys;
97 
98     AJNEW0(thys);
99 
100     thys->n = n;
101 
102     if(n > 0)
103     {
104         thys->start = AJALLOC0(n * sizeof (ajuint));
105         thys->end   = AJALLOC0(n * sizeof (ajuint));
106         thys->text  = AJALLOC0(n * sizeof (AjPStr *));
107     }
108 
109     return thys;
110 }
111 
112 
113 
114 
115 /* @func ajRangeNewFilename ***************************************************
116 **
117 ** Load a range object from a file
118 **
119 ** The format of the range file is:
120 ** Comment lines start with '#' in the first column.
121 ** Comment lines and blank lines are ignored.
122 ** The line may start with white-space.
123 ** There are two positive numbers per line separated by white-space.
124 ** The second number must be greater or equal to the first number.
125 ** There is optional text after the two numbers.
126 ** White-space before or after the text is removed.
127 **
128 ** e.g.:
129 **
130 ** # this is my set of ranges
131 ** 12   23
132 **  4   5       this is like 12-23, but smaller
133 ** 67   10348   interesting region
134 **
135 ** @param [r] name [const AjPStr] range file name
136 **
137 ** @return [AjPRange] range object
138 ** @category new [AjPRange] Create a range object from a file
139 **
140 ** @release 6.2.0
141 ** @@
142 ******************************************************************************/
143 
ajRangeNewFilename(const AjPStr name)144 AjPRange ajRangeNewFilename(const AjPStr name)
145 {
146     return ajRangeNewFilenameLimits(name, 1, UINT_MAX, 0, 0);
147 }
148 
149 
150 
151 
152 /* @func ajRangeNewFilenameLimits *********************************************
153 **
154 ** Load a range object from a file
155 **
156 ** The format of the range file is:
157 ** Comment lines start with '#' in the first column.
158 ** Comment lines and blank lines are ignored.
159 ** The line may start with white-space.
160 ** There are two positive numbers per line separated by white-space.
161 ** The second number must be greater or equal to the first number.
162 ** There is optional text after the two numbers.
163 ** White-space before or after the text is removed.
164 **
165 ** e.g.:
166 **
167 ** # this is my set of ranges
168 ** 12   23
169 **  4   5       this is like 12-23, but smaller
170 ** 67   10348   interesting region
171 **
172 ** @param [r] name [const AjPStr] range file name
173 ** @param [r] imin [ajuint] Minimum value
174 ** @param [r] imax [ajuint] Maximum value
175 ** @param [r] minsize [ajuint] Minimum number of values
176 ** @param [r] size [ajuint] Required number of values, zero for unlimited
177 **
178 ** @return [AjPRange] range object
179 ** @category new [AjPRange] Create a range object from a file
180 **
181 ** @release 6.2.0
182 ** @@
183 ******************************************************************************/
184 
ajRangeNewFilenameLimits(const AjPStr name,ajuint imin,ajuint imax,ajuint minsize,ajuint size)185 AjPRange ajRangeNewFilenameLimits(const AjPStr name, ajuint imin, ajuint imax,
186                                   ajuint minsize, ajuint size)
187 {
188     AjPRange ret = NULL;
189     AjPFile infile = NULL;
190     AjPStr line   = NULL;
191     char whiteSpace[] = "- \t\n\r";
192     char notSpace[]   = "\n\r";
193     AjPStrTok tokens;
194     ajuint n = 0U;                       /* ranges found so far */
195     ajuint k;
196     ajuint numone;
197     ajuint numtwo;
198 
199     AjPStr one = NULL;
200     AjPStr two = NULL;
201     AjPStr text = NULL;
202 
203     AjPList onelist;
204     AjPList twolist;
205     AjPList textlist;
206 
207 
208     onelist  = ajListstrNew();
209     twolist  = ajListstrNew();
210     textlist = ajListstrNew();
211 
212 
213     if((infile = ajFileNewInNameS(name)) == NULL)
214         return NULL;
215 
216     while(ajReadlineTrim(infile, &line))
217     {
218         ajStrTrimWhite(&line);
219 
220         if(!ajStrFindC(line, "#")) /* starts with # (comment line) */
221             continue;
222 
223         if(!ajStrGetLen(line))  /* empty line */
224             continue;
225 
226         /*
227         ** parse the numbers out of the line and store in temporary
228         ** list (we may be reading data from stdin, so we can't read
229         ** in once to count the number of ajRange elements, close
230         ** file, open it again and read the data again to populate
231         ** ajRange)
232         */
233 
234         tokens = ajStrTokenNewC(line, whiteSpace);
235 
236         one = ajStrNew();
237         ajStrTokenNextParse(tokens, &one);
238         ajListstrPushAppend(onelist, one);
239         one = NULL;
240 
241         two = ajStrNew();
242         ajStrTokenNextParse(tokens, &two);
243 
244         if(ajStrGetLen(two))
245         {
246             ajListstrPushAppend(twolist, two);
247             two = NULL;
248         }
249         else
250         {
251             ajWarn("Odd integer(s) in range specification:\n%S\n", line);
252 
253             return NULL;
254         }
255 
256         /* get any remaining text and store in temporary list */
257         text = ajStrNew();
258         ajStrTokenNextParseC(tokens, notSpace, &text);
259         ajStrTrimWhite(&text);
260         ajListstrPushAppend(textlist, text);
261         text = NULL;
262 
263         ajStrTokenDel( &tokens);
264     }
265 
266     ajFileClose(&infile);
267     ajStrDel(&line);
268 
269     /* now we know how many pairs of numbers to store, create ajRange object */
270     n  = (ajuint) ajListstrGetLength(onelist);
271     if(size)
272     {
273         if(n != size)
274         {
275             ajWarn("Range specification requires exactly %d pairs",
276                    size);
277 
278             return NULL;
279         }
280     }
281     else if (n < minsize)
282     {
283         ajWarn("Range specification requires at least %d pairs",
284                minsize);
285 
286         return NULL;
287     }
288 
289     ret = ajRangeNewI(n);
290 
291 
292     /* populate ajRange object from lists and check numbers are valid */
293     for(k = 0; k < n; k++)
294     {
295         ajListstrPop(onelist, &one);
296         if(!ajStrToUint(one, &numone))
297         {
298             ajWarn("Bad range value [%S]",one);
299             ajRangeDel(&ret);
300 
301             return NULL;
302         }
303 
304         ajListstrPop(twolist, &two);
305         if(!ajStrToUint(two, &numtwo))
306         {
307             ajWarn("Bad range value [%S]",two);
308             ajRangeDel(&ret);
309 
310             return NULL;
311         }
312 
313         ajStrDel(&one);
314         ajStrDel(&two);
315 
316         if(numone > numtwo)
317         {
318             ajWarn("From range [%d] greater than To range [%d]",
319                    numone, numtwo);
320             ajRangeDel(&ret);
321 
322             return NULL;
323         }
324 
325         if (numone < imin)
326         {
327             ajWarn("From range [%d] less than minimum [%d]",
328                    numone,imin);
329             ajRangeDel(&ret);
330 
331             return NULL;
332         }
333 
334         if (numtwo > imax)
335         {
336             ajWarn("To range [%d] greater than maximum [%d]",
337                    numtwo,imax);
338             ajRangeDel(&ret);
339 
340             return NULL;
341         }
342 
343         ret->start[k] = numone;
344         ret->end[k]   = numtwo;
345 
346         /* do the text */
347         ajListstrPop(textlist, &text);
348         ret->text[k] = text;
349         text = NULL;
350     }
351 
352 
353     ajListstrFreeData(&onelist);
354     ajListstrFreeData(&twolist);
355     ajListstrFreeData(&textlist);
356 
357     return ret;
358 }
359 
360 
361 
362 
363 /* @func ajRangeNewRange ******************************************************
364 **
365 ** Copy constructor for AJAX range objects.
366 **
367 ** @param [r] src [const AjPRange] Source range
368 **
369 ** @return [AjPRange] Pointer to a range object
370 ** @category new [AjPRange] Copy constructor for range objects
371 **
372 ** @release 6.2.0
373 ** @@
374 ******************************************************************************/
375 
ajRangeNewRange(const AjPRange src)376 AjPRange ajRangeNewRange(const AjPRange src)
377 {
378     AjPRange thys;
379     ajuint i;
380     ajuint n;
381 
382     AJNEW0(thys);
383 
384     n = src->n;
385 
386     thys->n = n;
387 
388     if(src->n > 0)
389     {
390         thys->start = AJALLOC0(n * sizeof (ajuint));
391         thys->end   = AJALLOC0(n * sizeof (ajuint));
392         thys->text  = AJALLOC0(n * sizeof (AjPStr *));
393 
394         for(i = 0; i < n; i++)
395         {
396             thys->start[i] = src->start[i];
397             thys->end[i] = src->end[i];
398             ajStrAssignS(&thys->text[i], src->text[i]);
399         }
400     }
401 
402     return thys;
403 }
404 
405 
406 
407 
408 /* @func ajRangeNewString *****************************************************
409 **
410 ** Create a range object from a string
411 **
412 ** @param [r] str [const AjPStr] range string
413 **
414 ** @return [AjPRange] range object
415 ** @category new [AjPRange] Create a range object from a string
416 **
417 ** @release 6.2.0
418 ** @@
419 ******************************************************************************/
420 
ajRangeNewString(const AjPStr str)421 AjPRange ajRangeNewString(const AjPStr str)
422 {
423     return ajRangeNewStringLimits(str, 1, UINT_MAX, 0, 0);
424 }
425 
426 
427 
428 
429 /* @func ajRangeNewStringLimits ***********************************************
430 **
431 ** Create a range object from a string
432 **
433 ** @param [r] str [const AjPStr] range string
434 ** @param [r] imin [ajuint] Minimum value
435 ** @param [r] imax [ajuint] Maximum value
436 ** @param [r] minsize [ajuint] Minimum number of values
437 ** @param [r] size [ajuint] Required number of values, zero for unlimited
438 **
439 ** @return [AjPRange] range object
440 ** @category new [AjPRange] Create a range object from a string
441 **
442 ** @release 6.2.0
443 ** @@
444 ******************************************************************************/
445 
ajRangeNewStringLimits(const AjPStr str,ajuint imin,ajuint imax,ajuint minsize,ajuint size)446 AjPRange ajRangeNewStringLimits(const AjPStr str, ajuint imin, ajuint imax,
447                                 ajuint minsize, ajuint size)
448 {
449     AjPRange ret = NULL;
450     AjPStr c1 = NULL;
451     AjPStr c2 = NULL;
452     AjPStr c3 = NULL;
453     static AjPStr s   =NULL;
454     const char *cp;
455     char *p;
456     ajuint n;
457     ajuint e;
458     ajuint f;
459     ajuint t;
460     ajuint i;
461     AjBool doneone = ajFalse;
462 
463     const char *nondigit="abcdefghijklmnopqrstuvwxyz"
464         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
465         " \t\n\r!@#$%^&*()_-=|\\~`{[}]:;\"'<,>.?/+";
466     const char *nondigitplus="abcdefghijklmnopqrstuvwxyz"
467         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
468         " \t\n\r!@#$%^&*()_-=|\\~`{[}]:;\"'<,>.?/";
469     const char *digit="0123456789";
470 
471     ajStrAssignS(&s, str);
472 
473     /* clean up the ranges string */
474     ajStrTrimWhite(&s);
475 
476     /* is this a file of ranges? (does it start with a '@' ?) */
477     if(*(ajStrGetPtr(s)) == '@')
478     {
479         /* knock off the '@' */
480         ajStrKeepRange(&s, 1, ajStrGetLen(s));
481         ret = ajRangeNewFilenameLimits(s, imin, imax, minsize, size);
482     }
483     else
484     {
485         /* get some copies of the string for parsing with strtok */
486         ajStrAssignS(&c1, s);
487         ajStrAssignS(&c2, s);
488         ajStrAssignS(&c3, s);
489 
490         cp = ajStrGetPtr(c1);
491         p = ajSysFuncStrtok(cp, nondigit);
492 
493         n = 0;
494 
495         if(p)
496         {
497             /*
498              *  count the pairs of numbers so that we know the size of
499              *  arrays to create
500              */
501             ++n;
502             while((p = ajSysFuncStrtok(NULL, nondigit)))
503                 ++n;
504 
505             if(n % 2)
506             {
507                 ajWarn("Odd integer(s) in range specification [%d]",n);
508 
509                 return NULL;
510             }
511 
512             if(size)
513             {
514                 if(n != size)
515                 {
516                     ajWarn("Range specification requires exactly %d pairs",
517                            size);
518 
519                     return NULL;
520                 }
521             }
522             else if (n < minsize)
523             {
524                 ajWarn("Range specification requires at least %d pairs",
525                        minsize);
526 
527                 return NULL;
528             }
529             ret = ajRangeNewI((e = n >> 1));
530 
531             /* get the pairs of numbers and put them in the AjPRange object */
532             cp = ajStrGetPtr(c2);
533             p = ajSysFuncStrtok(cp, nondigitplus);
534 
535             if(2 == sscanf(p,"%u+%u",&f, &t))
536             {
537                 if(t)
538                     t = (f + t - 1);
539                 else
540                     t = f;
541 
542             }
543             else
544             {
545                 if(!sscanf(p,"%u",&f))
546                 {
547                     ajWarn("Bad range value [%s]",p);
548                     ajRangeDel(&ret);
549 
550                     return NULL;
551                 }
552 
553                 p = ajSysFuncStrtok(NULL, nondigitplus);
554 
555                 if(sscanf(p, "+%u", &t))
556                 {
557                     if(t)
558                         t = (f + t - 1);
559                     else
560                         t = f;
561                 }
562                 else if(!sscanf(p, "%u", &t))
563                 {
564                     ajWarn("Bad range value [%s]",p);
565                     ajRangeDel(&ret);
566 
567                     return NULL;
568                 }
569             }
570 
571             if(f>t)
572             {
573                 ajWarn("From range [%d] greater than To range [%d]", f, t);
574                 ajRangeDel(&ret);
575 
576                 return NULL;
577             }
578 
579             if (f < imin)
580             {
581                 ajWarn("From range [%d] less than minimum [%d]", f, imin);
582                 ajRangeDel(&ret);
583 
584                 return NULL;
585             }
586 
587             if (t > imax)
588             {
589                 ajWarn("To range [%d] greater than maximum [%d]", t, imax);
590                 ajRangeDel(&ret);
591 
592                 return NULL;
593             }
594 
595             ret->start[0] = f;
596             ret->end[0] = t;
597 
598             for(i = 1; i < e; ++i)
599             {
600                 p = ajSysFuncStrtok(NULL, nondigitplus);
601 
602                 if(2 == sscanf(p,"%u+%u",&f, &t))
603                 {
604                     if(t)
605                         t = (f + t - 1);
606                     else
607                         t = f;
608                 }
609                 else
610                 {
611                     if(!sscanf(p, "%u", &f))
612                     {
613                         ajWarn("Bad range value [%s]", p);
614                         ajRangeDel(&ret);
615 
616                         return NULL;
617                     }
618 
619                     p = ajSysFuncStrtok(NULL, nondigitplus);
620 
621                     if(sscanf(p, "+%u", &t))
622                     {
623                         if(t)
624                             t = (f + t - 1);
625                         else
626                             t = f;
627                     }
628                     else if(!sscanf(p, "%u", &t))
629                     {
630                         ajWarn("Bad range value [%s]", p);
631                         ajRangeDel(&ret);
632 
633                         return NULL;
634                     }
635                 }
636 
637                 if(f > t)
638                 {
639                     ajWarn("From range [%d] greater than To range [%d]", f, t);
640                     ajRangeDel(&ret);
641 
642                     return NULL;
643                 }
644 
645                 ret->start[i] = f;
646                 ret->end[i]   = t;
647             }
648 
649             /* now get any strings after the pairs of ranges */
650             cp = ajStrGetPtr(c3);
651 
652             if(!isdigit((ajint) *cp))
653             {
654                 doneone = ajTrue;
655                 p = ajSysFuncStrtok(cp, digit);
656             }
657 
658             for(i = 0; i < e; ++i)
659             {
660                 /* ignore anything between the two numbers */
661                 if(!doneone)
662                 {
663                     p = ajSysFuncStrtok(cp, digit);
664                     doneone = ajTrue;
665                 }
666                 else
667                     p = ajSysFuncStrtok(NULL, digit);
668 
669                 /* this must be the text after the pair of numbers */
670                 /* get the string after the two numbers */
671                 p = ajSysFuncStrtok(NULL, digit);
672 
673                 if(p)
674                 {
675                     ajStrAssignC(&(ret->text[i]), p);
676                     ajStrTrimWhite(&(ret->text[i]));
677                 }
678             }
679         }
680         else
681         {
682             if(size)
683             {
684                 ajWarn("Range specification requires exactly %d pairs",
685                        size);
686 
687                 return NULL;
688             }
689             else if (0 < minsize)
690             {
691                 ajWarn("Range specification requires at least %d pairs",
692                        minsize);
693 
694                 return NULL;
695             }
696             ret = ajRangeNewI(0);
697         }
698 
699         ajStrDel(&c1);
700         ajStrDel(&c2);
701         ajStrDel(&c3);
702     }
703 
704     ajStrDel(&s);
705 
706     return ret;
707 }
708 
709 
710 
711 
712 /* @section Range Destructors ************************************************
713 **
714 ** Default destructor for AJAX range objects
715 **
716 ******************************************************************************/
717 
718 
719 
720 
721 /* @func ajRangeDel ***********************************************************
722 **
723 ** Default destructor for AJAX range objects.
724 **
725 ** @param [d] thys [AjPRange *] range structure
726 **
727 ** @return [void]
728 ** @category delete [AjPRange] Default destructor for range objects
729 **
730 ** @release 1.0.0
731 ** @@
732 ******************************************************************************/
733 
ajRangeDel(AjPRange * thys)734 void ajRangeDel(AjPRange *thys)
735 {
736     ajuint i;
737 
738     if(!*thys) return;
739 
740     if((*thys)->n > 0)
741     {
742         AJFREE((*thys)->start);
743         AJFREE((*thys)->end);
744 
745         for(i = 0; i < (*thys)->n; i++)
746             ajStrDel(&(*thys)->text[i]);
747     }
748 
749     AJFREE((*thys)->text);
750     AJFREE(*thys);
751 
752     return;
753 }
754 
755 
756 
757 
758 /* @section Range Functions ************************************************
759 **
760 ** Other functions for AJAX range objects
761 **
762 ******************************************************************************/
763 
764 
765 
766 
767 /* @func ajRangeGetSize *******************************************************
768 **
769 ** Return the number of ranges in a range object
770 **
771 ** @param [r] thys [const AjPRange] range object
772 **
773 ** @return [ajuint] number of ranges
774 ** @category use [AjPRange] Return the number of ranges in a range object
775 **
776 ** @release 6.2.0
777 ** @@
778 ******************************************************************************/
779 
ajRangeGetSize(const AjPRange thys)780 ajuint ajRangeGetSize(const AjPRange thys)
781 {
782     return thys->n;
783 }
784 
785 
786 
787 
788 /* @func ajRangeElementGetText ************************************************
789 **
790 ** Return (as parameters) text value of a range element
791 **
792 ** The text value of a range is any non-digit after the pair of range numbers
793 ** e.g. in a pair of range '10-20 potential exon 50-60 repeat'
794 ** the text values of the two ranges are: 'potential exon' and 'repeat'
795 **
796 ** @param [r] thys [const AjPRange] range object
797 ** @param [r] element [ajuint] range element (0 to n-1)
798 ** @param [w] text [AjPStr *] text value
799 **
800 ** @return [AjBool] true if range exists
801 ** @category use [AjPRange] Return (as parameters) text value of a range
802 **
803 ** @release 6.2.0
804 ** @@
805 ******************************************************************************/
806 
ajRangeElementGetText(const AjPRange thys,ajuint element,AjPStr * text)807 AjBool ajRangeElementGetText(const AjPRange thys, ajuint element, AjPStr * text)
808 {
809     if(element >= thys->n)
810         return ajFalse;
811 
812     if(thys->text[element])
813         ajStrAssignS(text, thys->text[element]);
814     else
815         ajStrAssignClear(text);
816 
817     return ajTrue;
818 }
819 
820 
821 
822 
823 /* @func ajRangeElementGetValues **********************************************
824 **
825 ** Return (as parameters) start and end values in a range
826 **
827 ** @param [r] thys [const AjPRange] range object
828 ** @param [r] element [ajuint] range element (0 to n-1)
829 ** @param [w] start [ajuint *] start value
830 ** @param [w] end [ajuint *] end value
831 **
832 ** @return [AjBool] true if range exists
833 ** @category use [AjPRange] Return (as parameters) start and end values
834 **                          in a range
835 **
836 ** @release 6.2.0
837 ** @@
838 ******************************************************************************/
839 
ajRangeElementGetValues(const AjPRange thys,ajuint element,ajuint * start,ajuint * end)840 AjBool ajRangeElementGetValues(const AjPRange thys, ajuint element,
841                                ajuint *start, ajuint *end)
842 {
843     if(element >= thys->n)
844         return ajFalse;
845 
846     if(thys->start[element] < 1)
847         return ajFalse;
848 
849     if(thys->end[element] < 1)
850         return ajFalse;
851 
852     if(thys->start[element] > thys->end[element])
853         return ajFalse;
854 
855     *start = thys->start[element];
856     *end   = thys->end[element];
857 
858     return ajTrue;
859 }
860 
861 
862 
863 
864 /* @func ajRangeElementSet ****************************************************
865 **
866 ** Set the values of a start and end in a (pre-existing) range element
867 **
868 ** @param [w] thys [AjPRange] range object
869 ** @param [r] element [ajuint] range element (0 to n-1)
870 ** @param [r] start [ajuint] start value
871 ** @param [r] end [ajuint] end value
872 **
873 ** @return [AjBool] true if range exists
874 ** @category modify [AjPRange] Set the values of a start and end in a
875 **                              range element
876 **
877 ** @release 6.2.0
878 ** @@
879 ******************************************************************************/
880 
ajRangeElementSet(AjPRange thys,ajuint element,ajuint start,ajuint end)881 AjBool ajRangeElementSet(AjPRange thys, ajuint element,
882                          ajuint start, ajuint end)
883 {
884     if(element >= thys->n)
885         return ajFalse;
886 
887     thys->start[element] = start;
888     thys->end[element]   = end;
889 
890     return ajTrue;
891 }
892 
893 
894 
895 
896 /* @func ajRangeSetOffset *****************************************************
897 **
898 ** Sets the range values offset relative to the Begin value.
899 **
900 ** Used when a sequence has -sbegin= and -send= parameters set
901 ** and we have extracted the specified subsequence.
902 ** So if -sbeg 11 has been set and the range is 11-12
903 ** the resulting range is changed to 1-2
904 **
905 ** @param [u] thys [AjPRange] range object
906 ** @param [r] begin [ajuint] begin parameter obtained from ajSeqGetBegin(seq)
907 **
908 ** @return [AjBool] true if region values modified
909 ** @category modify [AjPRange] Sets the range values relative to the
910 **                             Begin value
911 **
912 ** @release 6.2.0
913 ** @@
914 ******************************************************************************/
915 
ajRangeSetOffset(AjPRange thys,ajuint begin)916 AjBool ajRangeSetOffset(AjPRange thys, ajuint begin)
917 {
918     ajuint nr;
919     ajuint i;
920     ajuint st;
921     ajuint en;
922     AjBool result = ajFalse;
923 
924 
925     nr = thys->n;
926 
927     for(i = 0; i < nr; i++)
928     {
929         if(begin > 1)
930             result = ajTrue;
931 
932         ajRangeElementGetValues(thys, i, &st, &en);
933         st -= begin - 1;
934         en -= begin - 1;
935         ajRangeElementSet(thys, i, st, en);
936     }
937 
938     return result;
939 }
940 
941 
942 
943 
944 /* @func ajRangeSeqExtractList ************************************************
945 **
946 ** Extract the range from a sequence and place the resulting text in a
947 ** list of strings.
948 **
949 ** N.B. the resulting list will be regions of the input sequence listed
950 ** in the order specified in the set of ranges. If these are not in ascending
951 ** order, the resulting list of strings will not be in ascending order either.
952 **
953 ** @param [r] thys [const AjPRange] range object
954 ** @param [r] seq [const AjPSeq] sequence to extract from
955 ** @param [w] outliststr [AjPList] resulting list of strings
956 **
957 ** @return [AjBool] true if result is not the whole sequence
958 ** @category use [AjPRange] PushApp substrings defined by range onto list
959 **
960 ** @release 3.0.0
961 ** @@
962 ******************************************************************************/
963 
ajRangeSeqExtractList(const AjPRange thys,const AjPSeq seq,AjPList outliststr)964 AjBool ajRangeSeqExtractList(const AjPRange thys,
965                              const AjPSeq seq, AjPList outliststr)
966 {
967 
968     ajuint nr;
969     ajuint i;
970     ajuint st;
971     ajuint en;
972     AjBool result = ajFalse;
973     AjPStr str;
974 
975     nr = thys->n;
976 
977     if(nr)
978     {
979         for(i = 0; i < nr; i++)
980         {
981             result = ajTrue;
982 
983             if(!ajRangeElementGetValues(thys, i, &st, &en))
984                 continue;
985 
986             str = ajStrNew();
987             ajStrAppendSubS(&str, ajSeqGetSeqS(seq), st - 1, en - 1);
988             ajListstrPushAppend(outliststr, str);
989         }
990     }
991     else
992     {
993         str = ajSeqGetSeqCopyS(seq);
994         ajListstrPushAppend(outliststr, str);
995     }
996 
997     return result;
998 }
999 
1000 
1001 
1002 
1003 /* @func ajRangeSeqExtract ****************************************************
1004 **
1005 ** Extract the range from a sequence (Remove regions not in the range(s))
1006 ** N.B. the resulting sequence will be regions of the original concatenated
1007 ** in the order specified in the set of ranges. If these are not in ascending
1008 ** order, the resulting sequence will not be in position order either.
1009 **
1010 ** @param [r] thys [const AjPRange] range object
1011 ** @param [u] seq [AjPSeq] Sequence
1012 **
1013 ** @return [AjBool] true if sequence was modified
1014 ** @category use [AjPRange] Extract substrings defined by range
1015 **
1016 ** @release 3.0.0
1017 ** @@
1018 ******************************************************************************/
1019 
ajRangeSeqExtract(const AjPRange thys,AjPSeq seq)1020 AjBool ajRangeSeqExtract(const AjPRange thys, AjPSeq seq)
1021 {
1022     ajuint nr;
1023     ajuint i;
1024     ajuint st;
1025     ajuint en;
1026     AjBool result = ajFalse;
1027     AjPStr outstr = NULL;
1028 
1029     nr = thys->n;
1030 
1031     ajDebug("ajRangeSeqExtract Number:%d\n", nr);
1032 
1033     if (nr)
1034     {
1035         for(i = 0; i < nr; i++)
1036         {
1037             result = ajTrue;
1038 
1039             if(!ajRangeElementGetValues(thys, i, &st, &en))
1040                 continue;
1041 
1042             ajStrAppendSubS(&outstr, ajSeqGetSeqS(seq), st - 1, en - 1);
1043             ajDebug("Range [%d] %d..%d '%S'\n", i, st, en, outstr);
1044         }
1045         ajSeqAssignSeqS(seq, outstr);
1046         ajStrDel(&outstr);
1047     }
1048 
1049     return result;
1050 }
1051 
1052 
1053 
1054 
1055 /* @func ajRangeSeqExtractPep *************************************************
1056 **
1057 ** Extract the range from a sequence (Remove regions not in the range(s))
1058 ** and translate to protein.
1059 **
1060 ** N.B. the resulting sequence will be regions of the original concatenated
1061 ** in the order specified in the set of ranges. If these are not in ascending
1062 ** order, the resulting sequence will not be in position order either.
1063 **
1064 ** @param [r] thys [const AjPRange] range object
1065 ** @param [u] seq [AjPSeq] Sequence
1066 ** @param [r] trntable [const AjPTrn] Translation table
1067 ** @param [r] frame [ajint] Reading frame 1..3 or -1..-3
1068 **
1069 ** @return [AjPSeq] Translated protein sequence
1070 ** @category use [AjPRange] Extract substrings defined by range
1071 **
1072 ** @release 6.1.0
1073 ** @@
1074 ******************************************************************************/
1075 
ajRangeSeqExtractPep(const AjPRange thys,AjPSeq seq,const AjPTrn trntable,ajint frame)1076 AjPSeq ajRangeSeqExtractPep(const AjPRange thys, AjPSeq seq,
1077                             const AjPTrn trntable, ajint frame)
1078 {
1079     ajuint nr;
1080     ajuint i;
1081     ajuint st;
1082     ajuint en;
1083     AjPStr outstr = NULL;
1084     AjPSeq pepseq = NULL;
1085     AjPStr pepstr = NULL;
1086     ajuint pos = 0;
1087     ajuint lastpos = 0;
1088     ajuint npos = 0;
1089     ajuint rlen = 0;
1090     ajuint shift = 0;
1091 
1092     nr = thys->n;
1093 
1094     if (!nr)
1095         return NULL;
1096 
1097     if(frame > 0)
1098     {
1099         for(i = 0; i < nr; i++)
1100         {
1101             if(!ajRangeElementGetValues(thys, i, &st, &en))
1102                 continue;
1103 
1104             ajStrAppendSubS(&outstr, ajSeqGetSeqS(seq), st - 1, en - 1);
1105         }
1106 
1107         ajSeqAssignSeqS(seq, outstr);
1108         ajStrAssignClear(&outstr);
1109         pepseq = ajTrnSeqOrig(trntable, seq, 1);
1110         ajStrAssignS(&pepstr, ajSeqGetSeqS(pepseq));
1111 
1112         for(i = 0; i < nr; i++)
1113         {
1114             if(!ajRangeElementGetValues(thys, i, &st, &en))
1115                 continue;
1116 
1117             shift = npos % 3;
1118 
1119             rlen = (en - st) + 1;
1120             npos += rlen;
1121             pos = (npos - 1) / 3;
1122 
1123             if(frame % 3 == (((ajint) st - (ajint) shift) % 3))
1124             {
1125                 if(pos >= lastpos)
1126                     ajStrAppendSubS(&outstr, pepstr, lastpos, pos);
1127             }
1128 
1129             if(pos >= lastpos)
1130                 lastpos = pos + 1;
1131             else
1132                 lastpos = pos;
1133         }
1134 
1135         ajSeqAssignSeqS(pepseq, outstr);
1136         ajStrDel(&pepstr);
1137         ajStrDel(&outstr);
1138     }
1139     else if (frame < 0)
1140     {
1141         for(i = nr; i > 0; i--)
1142         {
1143             if(!ajRangeElementGetValues(thys, i - 1, &st, &en))
1144                 continue;
1145 
1146             ajStrAppendSubS(&outstr, ajSeqGetSeqS(seq), st - 1, en - 1);
1147         }
1148 
1149         ajSeqAssignSeqS(seq, outstr);
1150         ajStrAssignClear(&outstr);
1151         pepseq = ajTrnSeqOrig(trntable, seq, -1);
1152         ajStrAssignS(&pepstr, ajSeqGetSeqS(pepseq));
1153 
1154         for(i = 0; i < nr; i++)
1155         {
1156             if(!ajRangeElementGetValues(thys, i, &st, &en))
1157                 continue;
1158 
1159             rlen = (en - st) + 1;
1160             npos += rlen;
1161             pos = (npos - 1) / 3;
1162 
1163             if((-frame) % 3 == (((ajint) st) % 3))
1164             {
1165                 if(pos >= lastpos)
1166                     ajStrAppendSubS(&outstr, pepstr, lastpos, pos);
1167             }
1168 
1169             if(pos >= lastpos)
1170                 lastpos = pos + 1;
1171             else
1172                 lastpos = pos;
1173         }
1174 
1175         ajSeqAssignSeqS(pepseq, outstr);
1176         ajStrDel(&outstr);
1177     }
1178 
1179     return pepseq;
1180 }
1181 
1182 
1183 
1184 
1185 /* @func ajRangeSeqStuff ******************************************************
1186 **
1187 ** The opposite of ajRangeSeqExtract()
1188 ** Stuff space characters into a string to pad out to the range.
1189 **
1190 ** It takes a string and an ordered, non-overlapping set of ranges and puts
1191 ** spaces into the string between the ranges.
1192 ** So starting with the string 'abcde' and the ranges 3-5,7-8 it will produce:
1193 ** '  abc de'
1194 **
1195 ** @param [r] thys [const AjPRange] range object
1196 ** @param [u] seq [AjPSeq] Sequence to be modified
1197 **
1198 ** @return [AjBool] true if sequence was modified
1199 ** @category use [AjPRange] The opposite of ajRangeSeqExtract
1200 **
1201 ** @release 3.0.0
1202 ** @@
1203 ******************************************************************************/
1204 
ajRangeSeqStuff(const AjPRange thys,AjPSeq seq)1205 AjBool ajRangeSeqStuff(const AjPRange thys, AjPSeq seq)
1206 {
1207     ajuint nr;
1208     ajuint i;
1209     ajuint j;
1210     ajuint lasten = 0;
1211     ajuint lastst = 0;
1212     ajuint len;
1213     ajuint st;
1214     ajuint en;
1215     AjBool result = ajFalse;
1216     AjPStr outstr = NULL;
1217 
1218     nr = thys->n;
1219 
1220     if(nr)
1221     {
1222         for(i = 0; i < nr; i++)
1223         {
1224             result = ajTrue;
1225 
1226             if(!ajRangeElementGetValues(thys, i, &st, &en))
1227                 continue;
1228 
1229             /* change range positions to string positions */
1230             --st;
1231             --en;
1232             len = en - st;
1233 
1234             for(j = lasten; j < st; j++)
1235                 ajStrAppendC(&outstr, " ");
1236 
1237             ajStrAppendSubS(&outstr, ajSeqGetSeqS(seq), lastst, lastst + len);
1238             lastst = lastst + len + 1;
1239             lasten = en + 1;
1240         }
1241 
1242         ajSeqAssignSeqS(seq, outstr);
1243         ajStrDel(&outstr);
1244     }
1245 
1246     return result;
1247 }
1248 
1249 
1250 
1251 
1252 /* @func ajRangeSeqStuffPep ***************************************************
1253 **
1254 ** The opposite of ajRangeSeqExtractPep()
1255 ** Stuff space characters into a translated string to pad out to the range.
1256 **
1257 ** It takes a string and an ordered, non-overlapping set of ranges and puts
1258 ** spaces into the string between the ranges.
1259 ** So starting with the string 'abcde' and the ranges 3-5,7-8 it will produce:
1260 ** '  abc de'
1261 **
1262 ** @param [r] thys [const AjPRange] range object
1263 ** @param [u] seq [AjPSeq] Sequence to be modified
1264 ** @param [r] frame [ajint] Reading frame 1..3 or -1..-3
1265 **
1266 ** @return [AjBool] true if sequence was modified
1267 ** @category use [AjPRange] The opposite of ajRangeSeqExtract
1268 **
1269 ** @release 6.1.0
1270 ** @@
1271 ******************************************************************************/
1272 
ajRangeSeqStuffPep(const AjPRange thys,AjPSeq seq,ajint frame)1273 AjBool ajRangeSeqStuffPep(const AjPRange thys, AjPSeq seq, ajint frame)
1274 {
1275     ajuint nr;
1276     ajuint i;
1277     ajuint j;
1278     ajuint lasten = 0;
1279     ajuint lastst = 0;
1280     ajuint len;
1281     ajuint st;
1282     ajuint en;
1283     ajuint nbases = 0;
1284     ajuint shift = 0;
1285     AjBool result = ajFalse;
1286     AjPStr outstr = NULL;
1287     ajint lastframe = 0;
1288 
1289     nr = thys->n;
1290 
1291     if(!nr)
1292         return ajFalse;
1293 
1294     if(frame > 0)
1295     {
1296         for(i = 0; i < nr; i++)
1297         {
1298             result = ajTrue;
1299 
1300             if(!ajRangeElementGetValues(thys, i, &st, &en))
1301                 continue;
1302 
1303             shift = nbases%3;
1304             nbases += en - st + 1;
1305 
1306             if((frame) % 3 != (((ajint) st - (ajint) shift) % 3))
1307                 continue;
1308 
1309             /* change range positions to string positions */
1310             --st;
1311             --en;
1312             len = en - st;
1313 
1314             ajDebug("lasten:%u st:%u shift:%u frame:%d lastframe:%d\n",
1315                     lasten, st, shift, frame, lastframe);
1316             for(j = lasten; j < st; j++)
1317                 ajStrAppendC(&outstr, " ");
1318 
1319             if(shift && (frame != lastframe))
1320                 for(j = 3; j > shift; j--)
1321                     ajStrAppendC(&outstr, " ");
1322 
1323             ajStrAppendSubS(&outstr, ajSeqGetSeqS(seq), lastst, lastst + len);
1324             lastst = lastst + len + 1;
1325             lasten = en + 1;
1326             lastframe = frame;
1327         }
1328 
1329         ajSeqAssignSeqS(seq, outstr);
1330         ajStrDel(&outstr);
1331     }
1332     else if (frame < 0)
1333     {
1334         ajSeqReverseOnly(seq);
1335 
1336         for(i = nr; i > 0; i--)
1337         {
1338             result = ajTrue;
1339             if(!ajRangeElementGetValues(thys, i - 1, &st, &en))
1340                 continue;
1341 
1342             if((-frame) % 3 != (((ajint) st) % 3))
1343                 continue;
1344 
1345             /* change range positions to string positions */
1346             --st;
1347             --en;
1348             len = en - st;
1349 
1350             for(j = lasten; j < st; j++)
1351                 ajStrAppendC(&outstr, " ");
1352 
1353             ajStrAppendSubS(&outstr, ajSeqGetSeqS(seq), lastst, lastst + len);
1354             lastst = lastst + len + 1;
1355             lasten = en + 1;
1356         }
1357 
1358         ajSeqAssignSeqS(seq, outstr);
1359         ajStrDel(&outstr);
1360     }
1361 
1362 
1363     return result;
1364 }
1365 
1366 
1367 
1368 
1369 /* @func ajRangeSeqMask *******************************************************
1370 **
1371 ** Mask the range in a String
1372 **
1373 ** @param [r] thys [const AjPRange] range object
1374 ** @param [r] maskchar [const AjPStr] character to mask with
1375 ** @param [u] seq [AjPSeq] sequence to be masked
1376 **
1377 ** @return [AjBool] true if string modified
1378 ** @category use [AjPRange] Mask the range in a String
1379 **
1380 ** @release 3.0.0
1381 ** @@
1382 ******************************************************************************/
1383 
ajRangeSeqMask(const AjPRange thys,const AjPStr maskchar,AjPSeq seq)1384 AjBool ajRangeSeqMask(const AjPRange thys, const AjPStr maskchar, AjPSeq seq)
1385 {
1386     ajuint nr;
1387     ajuint i;
1388     ajuint j;
1389     ajuint jj;
1390     ajuint st;
1391     ajuint en;
1392     AjBool result = ajFalse;
1393     AjPStr str = NULL;
1394 
1395     nr = thys->n;
1396 
1397     if (nr)
1398     {
1399         for(i = 0; i < nr; ++i)
1400         {
1401             result = ajTrue;
1402             if(!ajRangeElementGetValues(thys, i, &st, &en))
1403                 continue;
1404 
1405             /* change range positions to string positions */
1406             --st;
1407             --en;
1408 
1409             /* cut out the region */
1410             ajStrCutRange(&str, st, en);
1411 
1412             /* replace the region with the mask character */
1413             for(j = st; j <= en; ++j)
1414                 ajStrInsertS(&str, st, maskchar);
1415         }
1416         ajSeqAssignSeqS(seq, str);
1417         ajStrDel(&str);
1418     }
1419     else
1420     {
1421         str = ajStrNew();
1422 
1423         for(jj = 0; jj <= ajStrGetLen(str); ++jj)
1424             ajStrInsertS(&str, jj, maskchar);
1425 
1426         ajSeqAssignSeqS(seq, str);
1427         ajStrDel(&str);
1428     }
1429 
1430     return result;
1431 }
1432 
1433 
1434 
1435 
1436 /* @func ajRangeSeqToLower ****************************************************
1437 **
1438 ** Change the range in a String to lower-case
1439 **
1440 ** @param [r] thys [const AjPRange] range object
1441 ** @param [u] seq [AjPSeq] sequence to be lower-cased
1442 **
1443 ** @return [AjBool] true if sequence was modified
1444 ** @category use [AjPRange] Change to lower-case the range in a sequence
1445 **
1446 ** @release 3.0.0
1447 ** @@
1448 ******************************************************************************/
1449 
ajRangeSeqToLower(const AjPRange thys,AjPSeq seq)1450 AjBool ajRangeSeqToLower(const AjPRange thys, AjPSeq seq)
1451 {
1452     ajuint nr;
1453     ajuint i;
1454     ajuint st;
1455     ajuint en;
1456     AjBool result = ajFalse;
1457     AjPStr substr = NULL;
1458     AjPStr str = NULL;
1459     const AjPStr seqstr;
1460 
1461 
1462     nr = thys->n;
1463 
1464     if (nr)
1465     {
1466         substr = ajStrNew();
1467         str = ajStrNew();
1468         seqstr = ajSeqGetSeqS(seq);
1469 
1470         for(i = 0; i < nr; ++i)
1471         {
1472             if(!ajRangeElementGetValues(thys, i, &st, &en))
1473                 continue;
1474 
1475             /* change range positions to string positions */
1476             --st;
1477             --en;
1478 
1479             /* extract the region and lowercase */
1480             ajStrAppendSubS(&substr, seqstr, st, en);
1481             ajStrFmtLower(&substr);
1482 
1483             /* remove and replace the lowercased region */
1484             ajStrCutRange(&str, st, en);
1485             ajStrInsertS(&str, st, substr);
1486             ajStrSetClear(&substr);
1487         }
1488 
1489         ajStrDel(&substr);
1490     }
1491     else
1492         ajSeqFmtLower(seq);
1493 
1494     return result;
1495 }
1496 
1497 
1498 
1499 
1500 /* @func ajRangeStrExtractList ************************************************
1501 **
1502 ** Extract the range from a String and place the resulting text in a
1503 ** list of strings.
1504 **
1505 ** N.B. the resulting list will be regions of the input string listed
1506 ** in the order specified in the set of ranges. If these are not in ascending
1507 ** order, the resulting list of strings will not be in ascending order either.
1508 **
1509 ** @param [r] thys [const AjPRange] range object
1510 ** @param [r] instr [const AjPStr] string to extract from
1511 ** @param [w] outliststr [AjPList] resulting list of strings
1512 **
1513 ** @return [AjBool] true if string modified
1514 ** @category use [AjPRange] PushApp substrings defined by range onto list
1515 **
1516 ** @release 1.0.0
1517 ** @@
1518 ******************************************************************************/
1519 
ajRangeStrExtractList(const AjPRange thys,const AjPStr instr,AjPList outliststr)1520 AjBool ajRangeStrExtractList(const AjPRange thys,
1521                              const AjPStr instr, AjPList outliststr)
1522 {
1523     ajuint nr;
1524     ajuint i;
1525     ajuint st;
1526     ajuint en;
1527     AjBool result = ajFalse;
1528     AjPStr str;
1529 
1530     nr = thys->n;
1531 
1532     for(i = 0; i < nr; i++)
1533     {
1534         result = ajTrue;
1535         ajRangeElementGetValues(thys, i, &st, &en);
1536         str = ajStrNew();
1537         ajStrAppendSubS(&str, instr, st - 1, en - 1);
1538         ajListstrPushAppend(outliststr, str);
1539     }
1540 
1541     return result;
1542 }
1543 
1544 
1545 
1546 
1547 /* @func ajRangeStrExtract ****************************************************
1548 **
1549 ** Extract the range from a String (Remove regions not in the range(s))
1550 **
1551 ** N.B. the resulting string will be regions of the input string appended
1552 ** in the order specified in the set of ranges. If these are not in ascending
1553 ** order, the resulting string will not be in ascending order either.
1554 **
1555 ** Intended for use in extracting exon ranges from the sequence of
1556 ** a transcript.
1557 **
1558 ** @param [r] thys [const AjPRange] range object
1559 ** @param [r] instr [const AjPStr] string to extract from
1560 ** @param [w] outstr [AjPStr *] resulting extracted string
1561 **
1562 ** @return [AjBool] true if string modified
1563 ** @category use [AjPRange] Extract substrings defined by range
1564 **
1565 ** @release 1.0.0
1566 ** @@
1567 ******************************************************************************/
1568 
ajRangeStrExtract(const AjPRange thys,const AjPStr instr,AjPStr * outstr)1569 AjBool ajRangeStrExtract(const AjPRange thys, const AjPStr instr,
1570                          AjPStr *outstr)
1571 {
1572     ajuint nr;
1573     ajuint i;
1574     ajuint st;
1575     ajuint en;
1576     AjBool result = ajFalse;
1577 
1578     nr = thys->n;
1579 
1580     ajDebug("ajRangeStrExtract Number:%d\n", nr);
1581 
1582     if (nr)
1583         for(i = 0; i < nr; i++)
1584         {
1585             result = ajTrue;
1586             ajRangeElementGetValues(thys, i, &st, &en);
1587             ajStrAppendSubS(outstr, instr, st - 1, en - 1);
1588             ajDebug("Range [%d] %d..%d '%S'\n", i, st, en, *outstr);
1589         }
1590     else
1591         ajStrAssignS(outstr, instr);
1592 
1593     return result;
1594 }
1595 
1596 
1597 
1598 
1599 /* @func ajRangeStrStuff ******************************************************
1600 **
1601 ** The opposite of ajRangeStrExtract()
1602 ** Stuff space characters into a string to pad out to the range.
1603 **
1604 ** It takes a string and an ordered, non-overlapping set of ranges and puts
1605 ** spaces into the string between the ranges.
1606 ** So starting with the string 'abcde' and the ranges 3-5,7-8 it will produce:
1607 ** '  abc de'
1608 **
1609 ** @param [r] thys [const AjPRange] range object
1610 ** @param [r] instr [const AjPStr] string to stuff
1611 ** @param [w] outstr [AjPStr *] resulting stuffed string
1612 **
1613 ** @return [AjBool] true if string modified
1614 ** @category use [AjPRange] The opposite of ajRangeStrExtract
1615 **
1616 ** @release 1.0.0
1617 ** @@
1618 ******************************************************************************/
1619 
ajRangeStrStuff(const AjPRange thys,const AjPStr instr,AjPStr * outstr)1620 AjBool ajRangeStrStuff(const AjPRange thys, const AjPStr instr, AjPStr *outstr)
1621 {
1622     ajuint nr;
1623     ajuint i;
1624     ajuint j;
1625     ajuint lasten = 0;
1626     ajuint lastst = 0;
1627     ajuint len;
1628     ajuint st;
1629     ajuint en;
1630     AjBool result = ajFalse;
1631 
1632     nr = thys->n;
1633 
1634     for(i = 0; i < nr; i++)
1635     {
1636         result = ajTrue;
1637         ajRangeElementGetValues(thys, i, &st, &en);
1638         /* change range positions to string positions */
1639         --st;
1640         --en;
1641         len = en - st;
1642 
1643         for(j = lasten; j < st; j++)
1644             ajStrAppendC(outstr, " ");
1645 
1646         ajStrAppendSubS(outstr, instr, lastst, lastst + len);
1647         lastst = lastst + len + 1;
1648         lasten = en + 1;
1649     }
1650 
1651     return result;
1652 }
1653 
1654 
1655 
1656 
1657 /* @func ajRangeStrMask *******************************************************
1658 **
1659 ** Mask the positions defined by a range in a string
1660 **
1661 ** @param [r] thys [const AjPRange] range object
1662 ** @param [r] maskchar [const AjPStr] character to mask with
1663 ** @param [w] str [AjPStr *] string to be masked
1664 **
1665 ** @return [AjBool] true if string modified
1666 ** @category use [AjPRange] Mask the range in a String
1667 **
1668 ** @release 1.0.0
1669 ** @@
1670 ******************************************************************************/
1671 
ajRangeStrMask(const AjPRange thys,const AjPStr maskchar,AjPStr * str)1672 AjBool ajRangeStrMask(const AjPRange thys, const AjPStr maskchar, AjPStr *str)
1673 {
1674     ajuint nr;
1675     ajuint i;
1676     ajuint j;
1677     ajuint st;
1678     ajuint en;
1679     AjBool result = ajFalse;
1680 
1681     nr = thys->n;
1682 
1683     for(i = 0; i < nr; ++i)
1684     {
1685         result = ajTrue;
1686         ajRangeElementGetValues(thys, i, &st, &en);
1687 
1688         /* change range positions to string positions */
1689         --st;
1690         --en;
1691 
1692         /* cut out the region */
1693         ajStrCutRange(str, st, en);
1694 
1695         /* replace the region with the mask character */
1696         for(j = st; j <= en; ++j)
1697             ajStrInsertS(str, st, maskchar);
1698     }
1699 
1700     return result;
1701 }
1702 
1703 
1704 
1705 
1706 /* @func ajRangeStrToLower ****************************************************
1707 **
1708 ** Change positions defined by the range in a string to lower-case
1709 **
1710 ** @param [r] thys [const AjPRange] range object
1711 ** @param [w] str [AjPStr *] string to be lower-cased
1712 **
1713 ** @return [AjBool] true if string modified
1714 ** @category use [AjPRange] Change to lower-case the range in a String
1715 **
1716 ** @release 2.7.0
1717 ** @@
1718 ******************************************************************************/
1719 
ajRangeStrToLower(const AjPRange thys,AjPStr * str)1720 AjBool ajRangeStrToLower(const AjPRange thys, AjPStr *str)
1721 {
1722     ajuint nr;
1723     ajuint i;
1724     ajuint st;
1725     ajuint en;
1726     AjBool result = ajFalse;
1727     AjPStr substr;
1728 
1729     substr = ajStrNew();
1730 
1731     nr = thys->n;
1732 
1733     for(i = 0; i < nr; ++i)
1734     {
1735         result = ajTrue;
1736         ajRangeElementGetValues(thys, i, &st, &en);
1737 
1738         /* change range positions to string positions */
1739         --st;
1740         --en;
1741 
1742         /* extract the region and lowercase */
1743         ajStrAppendSubS(&substr, *str, st, en);
1744         ajStrFmtLower(&substr);
1745 
1746         /* remove and replace the lowercased region */
1747         ajStrCutRange(str, st, en);
1748         ajStrInsertS(str, st, substr);
1749         ajStrSetClear(&substr);
1750     }
1751 
1752     ajStrDel(&substr);
1753 
1754     return result;
1755 }
1756 
1757 
1758 
1759 
1760 /* @func ajRangeElementTypeOverlap ********************************************
1761 **
1762 ** Detect an overlap of a single range element to a region of a sequence
1763 **
1764 ** @param [r] thys [const AjPRange] range object
1765 ** @param [r] element [ajuint] range element (0 to n-1)
1766 ** @param [r] pos [ajuint] position in sequence of start of region of sequence
1767 ** @param [r] length [ajuint] length of region of sequence
1768 **
1769 ** @return [ajuint] 0=no overlap 1=internal 2=complete 3=at left 4=at right
1770 **
1771 ** @release 6.2.0
1772 ** @@
1773 ******************************************************************************/
1774 
ajRangeElementTypeOverlap(const AjPRange thys,ajuint element,ajuint pos,ajuint length)1775 ajuint ajRangeElementTypeOverlap(const AjPRange thys, ajuint element,
1776                                  ajuint pos, ajuint length)
1777 {
1778     ajuint start;
1779     ajuint end;
1780     ajuint posend;
1781 
1782     if(element >= thys->n)
1783         return 0;
1784 
1785     if(thys->start[element] < 1)
1786         return 0;
1787 
1788     if(thys->end[element] < 1)
1789         return 0;
1790 
1791     if(thys->start[element] > thys->end[element])
1792         return 0;
1793 
1794     start = thys->start[element];
1795     end   = thys->end[element];
1796 
1797     /* end position of region in sequence */
1798     posend = pos + length - 1;
1799 
1800     /* convert range positions to sequence positions */
1801     start--;
1802     end--;
1803 
1804     if(end < pos || start > posend)
1805         return 0;
1806 
1807     /* no overlap       ~~~~ |--------|         */
1808     if(start >= pos && end <= posend)
1809         return 1;
1810 
1811     /* internal overlap      |-~~~~~--|         */
1812     if(start < pos && end > posend)
1813         return 2;
1814 
1815     /* complete overlap ~~~~~|~~~~~~~~|~~       */
1816     if(start < pos && end >= pos )
1817         return 3;
1818 
1819     /* overlap at left  ~~~~~|~~~-----|         */
1820     if(start >= pos && end > posend )
1821         return 4;
1822 
1823     /* overlap at right      |----~~~~|~~~      */
1824 
1825     ajFatal("ajRangeElementTypeOverlap error");
1826 
1827     return -1;
1828 }
1829 
1830 
1831 
1832 
1833 /* @func ajRangeCountOverlaps *************************************************
1834 **
1835 ** Detect overlaps of a set of ranges to a region of a sequence
1836 ** @param [r] thys [const AjPRange] range object
1837 ** @param [r] pos [ajuint] position in sequence of start of region of sequence
1838 ** @param [r] length [ajuint] length of region of sequence
1839 **
1840 ** @return [ajuint] Number of ranges in range object with overlaps
1841 **                  to the region
1842 ** @category use [AjPRange] Detect overlaps of a set of ranges to a seq region
1843 **
1844 ** @release 6.2.0
1845 ** @@
1846 ******************************************************************************/
1847 
ajRangeCountOverlaps(const AjPRange thys,ajuint pos,ajuint length)1848 ajuint ajRangeCountOverlaps(const AjPRange thys, ajuint pos, ajuint length)
1849 {
1850     ajuint nr;
1851     ajuint i;
1852     ajuint result = 0;
1853 
1854     nr = thys->n;
1855 
1856     for(i = 0; i < nr; i++)
1857     {
1858         if(ajRangeElementTypeOverlap(thys, i, pos, length))
1859             result++;
1860     }
1861 
1862     return result;
1863 }
1864 
1865 
1866 
1867 
1868 /* @func ajRangeIsOrdered *****************************************************
1869 **
1870 ** Tests to see if the set of ranges are in ascending non-overlapping order
1871 ** @param [r] thys [const AjPRange] range object
1872 **
1873 ** @return [AjBool] ajTrue if in ascending non-overlapping order
1874 ** @category use [AjPRange] Test if ranges are in ascending non-overlapping
1875 **                          order
1876 **
1877 ** @release 6.2.0
1878 ** @@
1879 ******************************************************************************/
1880 
ajRangeIsOrdered(const AjPRange thys)1881 AjBool ajRangeIsOrdered(const AjPRange thys)
1882 {
1883     ajuint nr;
1884     ajuint i;
1885     ajuint st;
1886     ajuint en;
1887     ajuint last = 0;
1888 
1889     nr = thys->n;
1890 
1891     for(i = 0; i < nr; i++)
1892     {
1893         ajRangeElementGetValues(thys, i, &st, &en);
1894         ajDebug("ajRangeOrdered [%u] st:%u en:%u (last:%u)\n",
1895                 i, st, en, last);
1896 
1897         if(st <= last || en <= st)
1898             return ajFalse;
1899 
1900         last = en;
1901     }
1902 
1903     return ajTrue;
1904 }
1905 
1906 
1907 
1908 
1909 /* @func ajRangeIsWhole *******************************************************
1910 **
1911 ** Test whether the default range is used for a sequence
1912 **
1913 ** The test is whether the given range is defined or left at the
1914 ** default of zero to zero.
1915 **
1916 ** @param [r] thys [const AjPRange] range object
1917 ** @param [r] s [const AjPSeq] sequence
1918 **
1919 ** @return [AjBool] true if default range
1920 ** @category use [AjPRange] Test if the default range has been set
1921 **
1922 ** @release 6.2.0
1923 ** @@
1924 ******************************************************************************/
1925 
ajRangeIsWhole(const AjPRange thys,const AjPSeq s)1926 AjBool ajRangeIsWhole(const AjPRange thys, const AjPSeq s)
1927 {
1928     /* test the range - 1..end or empty means whole sequence */
1929 
1930     if(thys->n == 0)
1931     {
1932         ajDebug("ajRangeDefault n:%d begin:%u end:%u\n",
1933                 thys->n,
1934                 ajSeqGetBegin(s), ajSeqGetEnd(s));
1935 
1936         return ajTrue;
1937     }
1938 
1939     ajDebug("ajRangeDefault n:%d start:%d end:%d begin:%u end:%u\n",
1940             thys->n, thys->start[0], thys->end[0],
1941             ajSeqGetBegin(s), ajSeqGetEnd(s));
1942 
1943 /*
1944 ** Changed to be true only if range is not set
1945 ** transeq needs to distinguish undefed from specific 1..end
1946 */
1947 
1948 /*
1949 //    if(thys->n == 1 &&
1950 //       thys->start[0] == ajSeqGetBegin(s) &&
1951 //       thys->end[0] == ajSeqGetEnd(s))
1952 //        return ajTrue;
1953 */
1954     return ajFalse;
1955 }
1956 
1957 
1958 
1959 
1960 #ifdef AJ_COMPILE_DEPRECATED_BOOK
1961 #endif
1962 
1963 
1964 
1965 
1966 #ifdef AJ_COMPILE_DEPRECATED
1967 /* @obsolete ajRangeFile
1968 ** @rename ajRangeNewFilename
1969 */
1970 
ajRangeFile(const AjPStr name)1971 __deprecated AjPRange ajRangeFile(const AjPStr name)
1972 {
1973     return ajRangeNewFilename(name);
1974 }
1975 
1976 
1977 
1978 
1979 /* @obsolete ajRangeFileLimits
1980 ** @rename ajRangeNewFilenameLimits
1981 */
1982 
ajRangeFileLimits(const AjPStr name,ajuint imin,ajuint imax,ajuint minsize,ajuint size)1983 __deprecated AjPRange ajRangeFileLimits(const AjPStr name,
1984                                         ajuint imin, ajuint imax,
1985                                         ajuint minsize, ajuint size)
1986 {
1987     return ajRangeNewFilenameLimits(name, imin, imax, minsize, size);
1988 }
1989 
1990 
1991 
1992 
1993 /* @obsolete ajRangeCopy
1994 ** @rename ajRangeNewRange
1995 */
1996 
ajRangeCopy(const AjPRange src)1997 __deprecated AjPRange ajRangeCopy(const AjPRange src)
1998 {
1999     return ajRangeNewRange(src);
2000 }
2001 
2002 
2003 
2004 
2005 /* @obsolete ajRangeGet
2006 ** @rename ajRangeNewString
2007 */
2008 
ajRangeGet(const AjPStr str)2009 __deprecated AjPRange ajRangeGet(const AjPStr str)
2010 {
2011     return ajRangeNewString(str);
2012 }
2013 
2014 
2015 
2016 
2017 /* @obsolete ajRangeGetLimits
2018 ** @rename ajRangeNewStringLimits
2019 */
2020 
ajRangeGetLimits(const AjPStr str,ajuint imin,ajuint imax,ajuint minsize,ajuint size)2021 __deprecated AjPRange ajRangeGetLimits(const AjPStr str,
2022                                        ajuint imin, ajuint imax,
2023                                        ajuint minsize, ajuint size)
2024 {
2025     return ajRangeNewStringLimits(str, imin, imax, minsize, size);
2026 }
2027 
2028 
2029 
2030 
2031 /* @obsolete ajRangeNumber
2032 ** @rename ajRangeGetSize
2033 */
2034 
ajRangeNumber(const AjPRange thys)2035 __deprecated ajuint ajRangeNumber(const AjPRange thys)
2036 {
2037     return thys->n;
2038 }
2039 
2040 
2041 
2042 
2043 /* @obsolete ajRangeText
2044 ** @rename ajRangeElementGetText
2045 */
2046 
ajRangeText(const AjPRange thys,ajuint element,AjPStr * text)2047 __deprecated AjBool ajRangeText(const AjPRange thys, ajuint element,
2048                                 AjPStr * text)
2049 {
2050     return ajRangeElementGetText(thys, element, text);
2051 }
2052 
2053 
2054 
2055 
2056 /* @obsolete ajRangeValues
2057 ** @rename ajRangeElementGetValues
2058 */
2059 
ajRangeValues(const AjPRange thys,ajuint element,ajuint * start,ajuint * end)2060 __deprecated AjBool ajRangeValues(const AjPRange thys, ajuint element,
2061                                   ajuint *start, ajuint *end)
2062 {
2063     return ajRangeElementGetValues(thys, element, start, end);
2064 }
2065 
2066 
2067 
2068 
2069 /* @obsolete ajRangeChange
2070 ** @rename ajRangeElementSet
2071 */
ajRangeChange(AjPRange thys,ajuint element,ajuint start,ajuint end)2072 __deprecated AjBool ajRangeChange(AjPRange thys, ajuint element,
2073                                   ajuint start, ajuint end)
2074 {
2075     return ajRangeElementSet(thys, element, start, end);
2076 }
2077 
2078 
2079 
2080 
2081 /* @obsolete ajRangeBegin
2082 ** @rename ajRangeSetOffset
2083 */
2084 
ajRangeBegin(AjPRange thys,ajuint begin)2085 __deprecated AjBool ajRangeBegin(AjPRange thys, ajuint begin)
2086 {
2087     return ajRangeSetOffset(thys, begin);
2088 }
2089 
2090 
2091 
2092 
2093 /* @obsolete ajRangeOverlapSingle
2094 ** @remove Use ajRangeElementTypeOverlap
2095 */
2096 
ajRangeOverlapSingle(ajuint start,ajuint end,ajuint pos,ajuint length)2097 __deprecated ajuint ajRangeOverlapSingle(ajuint start, ajuint end,
2098                                          ajuint pos, ajuint length)
2099 {
2100     ajuint posend;
2101 
2102     /* end position of region in sequence */
2103     posend = pos + length - 1;
2104 
2105     /* convert range positions to sequence positions */
2106     start--;
2107     end--;
2108 
2109     if(end < pos || start > posend)
2110         return 0;
2111 
2112     /* no overlap               ~~~~ |--------| */
2113     if(start >= pos && end <= posend)
2114         return 1;
2115 
2116     /* internal overlap      |-~~~~~--|         */
2117     if(start < pos && end > posend)
2118         return 2;
2119 
2120     /* complete overlap ~~~~~|~~~~~~~~|~~       */
2121     if(start < pos && end >= pos )
2122         return 3;
2123 
2124     /* overlap at left  ~~~~~|~~~-----|         */
2125     if(start >= pos && end > posend )
2126         return 4;
2127 
2128     /* overlap at right      |----~~~~|~~~      */
2129 
2130     ajFatal("ajrangeoverlapsingle error");
2131 
2132     return -1;
2133 }
2134 
2135 
2136 
2137 
2138 /* @obsolete ajRangeOverlaps
2139 ** @rename ajRangeCountOverlaps
2140 */
2141 
ajRangeOverlaps(const AjPRange thys,ajuint pos,ajuint length)2142 __deprecated ajuint ajRangeOverlaps(const AjPRange thys,
2143                                     ajuint pos, ajuint length)
2144 {
2145     return ajRangeCountOverlaps(thys, pos, length);
2146 }
2147 
2148 
2149 
2150 
2151 /* @obsolete ajRangeOrdered
2152 ** @rename ajRangeIsOrdered
2153 */
2154 
ajRangeOrdered(const AjPRange thys)2155 __deprecated AjBool ajRangeOrdered(const AjPRange thys)
2156 {
2157     return ajRangeIsOrdered(thys);
2158 }
2159 
2160 
2161 
2162 
2163 /* @obsolete ajRangeDefault
2164 ** @rename ajRangeIsWhole
2165 */
2166 
ajRangeDefault(const AjPRange thys,const AjPSeq s)2167 __deprecated AjBool ajRangeDefault(const AjPRange thys, const AjPSeq s)
2168 {
2169     return ajRangeIsWhole(thys, s);
2170 }
2171 #endif
2172