1 /* seq.c - Count from first to last, by increment. 2 * 3 * Copyright 2006 Rob Landley <rob (at) landley.net> 4 * 5 * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/seq.html 6 7 USE_SEQ(NEWTOY(seq, "<1>3?f:s:w[!fw]", TOYFLAG_USR|TOYFLAG_BIN)) 8 9 config SEQ 10 bool "seq" 11 depends on TOYBOX_FLOAT 12 default y 13 help 14 usage: seq [-w|-f fmt_str] [-s sep_str] [first] [increment] last 15 16 Count from first to last, by increment. Omitted arguments default 17 to 1. Two arguments are used as first and last. Arguments can be 18 negative or floating point. 19 20 -f Use fmt_str as a printf-style floating point format string 21 -s Use sep_str as separator, default is a newline character 22 -w Pad to equal width with leading zeroes 23 */ 24 25 #define FOR_seq 26 #include "toys.h" 27 28 GLOBALS( 29 char *sep; 30 char *fmt; 31 ) 32 33 // Ensure there's one %f escape with correct attributes 34 static void insanitize(char *f) 35 { 36 char *s = next_printf(f, 0); 37 38 if (!s) error_exit("bad -f no %%f"); 39 if (-1 == stridx("aAeEfFgG", *s) || (s = next_printf(s, 0))) { 40 // The @ is a byte offset, not utf8 chars. Waiting for somebody to complain. 41 error_exit("bad -f '%s'@%d", f, (int)(s-f+1)); 42 } 43 } 44 45 void seq_main(void) 46 { 47 double first, increment, last, dd; 48 char *sep_str = "\n", *fmt_str = "%g"; 49 int i; 50 51 // Parse command line arguments, with appropriate defaults. 52 // Note that any non-numeric arguments are treated as zero. 53 first = increment = 1; 54 switch (toys.optc) { 55 case 3: increment = atof(toys.optargs[1]); 56 case 2: first = atof(*toys.optargs); 57 default: last = atof(toys.optargs[toys.optc-1]); 58 } 59 60 // Pad to largest width 61 if (toys.optflags & FLAG_w) { 62 char *s; 63 int len, dot, left = 0, right = 0; 64 65 for (i=0; i<3; i++) { 66 dd = (double []){first, increment, last}[i]; 67 68 len = sprintf(toybuf, "%g", dd); 69 if ((s = strchr(toybuf, '.'))) { 70 dot = s-toybuf; 71 if (left<dot) left = dot; 72 dot = len-dot-1; 73 if (right<dot) right = dot; 74 } else if (len>left) left = len; 75 } 76 77 sprintf(fmt_str = toybuf, "%%0%d.%df", left+right+!!right, right); 78 } 79 if (toys.optflags & FLAG_f) insanitize(fmt_str = TT.fmt); 80 if (toys.optflags & FLAG_s) sep_str = TT.sep; 81 82 i = 0; 83 dd = first; 84 if (increment) for (;;) { 85 // avoid accumulating rounding errors from increment 86 dd = first+i*increment; 87 if ((increment<0 && dd<last) || (increment>0 && dd>last)) break; 88 if (i++) printf("%s", sep_str); 89 printf(fmt_str, dd); 90 } 91 92 if (i) printf("\n"); 93 } 94