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