Home | History | Annotate | Download | only in lsb
      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