/* * Copyright (c) 2002 Jessica L. Parsons. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgement: * * This product includes software developed by Jessica L. Parsons * (orc@pell.chi.il.us) * * 4. My name may not be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID PARSONS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID * PARSONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * jot: print sequential or random data * * Done as a programming exercise 5/Oct/2002 (7:45pm->1:25am 6/Oct/2002) * * usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision] [r[b[e[s]]]] */ #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H # include #endif int rflag = 0; /* random data */ int nflag = 0; /* don't print a trailing newline */ char *bstr = 0; /* -b option */ char *wstr = 0; /* -w option */ char *fsep = "\n"; /* -s option */ int precision = -1; /* -p option */ int iflag = 0; /* -w format is integral */ int fflag = 0; /* -w format has a conversion */ int dft_precision = 0; /* default precision if no -p flag */ int prec_shift = 1; /* for -r; shifting the long result from random down * into the fractional part of the result */ double roundoff = 0.0; int count = 100; /* how many things to display */ int r_set = 0; double begin = 1; /* starting at this number */ int b_set = 0; double end = 100; /* and ending here */ int e_set = 0; double step = 1; /* with this step */ int s_set = 0; long seed; /* or this random seed */ double drand(); long lrand(); /* * complain, then die. */ void fail(char *what) { perror(what); exit(1); } /* * string -> int, complaining on error */ int xatoi(char *str, char *what, int dft, int *set) { int r; if (strcmp(str, "-") == 0) return dft; r = atoi(str); if (errno == ERANGE) fail(what); if (set) *set = 1; return r; } /* * string -> double, complaining on error */ double xatod(char *str, char *what, double dft, int *set) { double r; if (strcmp(str, "-") == 0) return dft; r = strtod(str, 0); if (errno == ERANGE) fail(what); if (set) *set = 1; return r; } /* * string -> sequence number, which is either a real number * or an ascii digit picked off the start of a string. */ double xseq(char *str, char *what, double dft, int *set) { double r; int i; int prec; char *p; char *endptr; if (strcmp(str, "-") == 0) return dft; if (set) *set = 1; r = strtod(str, &endptr); if (*endptr) { /* not a string, so return the first character */ return (double)(str[0]); } /* floating point number -- need to figure out how precise it is. */ prec = 0; if ( (p = strchr(str, '.')) != 0) { while (isdigit(*++p)) ++prec; } if (prec > dft_precision) dft_precision = prec; return r; } /* * say whether a number is positive, zero, or negative */ int sign(double d) { if (d < 0.0) return -1; if (d > 0.0) return 1; return 0; } /* * spit out a usage message, then die */ void usage(int ret) { fprintf(stderr, "usage: jot [-cnr] [-b word] [-w word] [-s string]" " [count [begin [end [s]]]]\n"); exit(ret); } /* * validate a format string for -w */ char * xfmtstr(char *arg) { char *ret; int needifmt = 0; char *sfmt; int prec=0; fflag = iflag = 0; for (ret = arg; *arg; ++arg) { if (*arg == '%') if (arg[1] == '%') ++arg; else if (fflag) { fprintf(stderr, "too many conversions\n"); exit(1); } else { fflag = 1; sfmt = arg++; if (*arg == '#') ++arg; if (*arg == ' ') ++arg; if (*arg == '+' || *arg == '-') ++arg; while (isdigit(*arg)) ++arg; if (*arg == '.') { ++arg; while (isdigit(*arg)) { ++prec; ++arg; } if (prec > dft_precision) dft_precision = prec; } if (*arg == 'l') { needifmt = 1; ++arg; } switch(*arg) { case 'd': case 'i': case 'o': case 'u': case 'x': /* okay! */ iflag = 1; break; case 'X': case 'O': case 'U': case 'D': case 'c': iflag = 1; case 'e': case 'f': case 'g': case 'E': case 'G': if (!needifmt) break; default: arg[1] = 0; fprintf(stderr, "illegal or unsupported format '%s'\n", sfmt); exit(1); } } } return ret; } /* * display an item */ void display(double value) { value += roundoff; if (bstr) fputs(bstr, stdout); else if (iflag) printf(wstr, (long)(value)); else printf(wstr, value); } /* * we were called as ``seq begin end'' or ``seq end'' */ void initialize_seq(int argc, char **argv) { switch (argc) { case 3: begin = xseq(argv[1], "begin", begin, &b_set); end = xseq(argv[2], "end", end, &e_set); break; case 2: end = xseq(argv[1], "end", end, &e_set); break; default: fprintf(stderr, "usage: seq start end\n" " seq end\n"); exit(1); } s_set = 1; wstr = xfmtstr(isalpha(argv[1][0]) ? "%c" : "%d"); } /* * we were called as ``yes [assertion]'' */ void initialize_yes(int argc, char **argv) { count = 0; r_set = 1; bstr = (argc > 1) ? argv[1] : "y"; } /* * we were called as ourselves, so initialize in the expected way */ void initialize_jot(int argc, char **argv) { int opt; char *p; char *wfmt; time(&seed); seed |= (getpid()<<16); while ( (opt = getopt(argc, argv, "?cnrb:w:s:p:")) != EOF) { switch (opt) { case 'p': precision = xatoi(optarg, "precision", 0, 0); break; case 'c': wstr = xfmtstr("%c"); break; case 'n': nflag = 1; break; case 'r': rflag = 1; break; case 'b': bstr = optarg; break; case 's': fsep = optarg; break; case 'w': wstr = xfmtstr(optarg); break; default: usage( ! (opt == '?') ); } } argc -= optind; argv += optind; /* need at least one of count begin end s */ if (argc == 0) usage(1); count = xatoi(argv[0], "count", count, &r_set); if (argc > 1) begin = xseq(argv[1], "begin", begin, &b_set); if (argc > 2) end = xseq(argv[2], "end", end, &e_set); if (rflag) { if (argc > 3) seed = xatoi(argv[3], "seed", seed, 0); } else { if (argc > 3) step = xatod(argv[3], "step", step, &s_set); if ( r_set && !e_set) end = begin + (count * step); } if (precision < 0) precision = dft_precision; roundoff = 0.49999/pow(10,precision); /* fix up the wstr if it doesn't exist or doesn't have a * conversion in it. */ if ( !(wstr && fflag) ) { char *arg; if (precision) { static char floatfmt[40]; sprintf(floatfmt, "%%.%df", precision); arg = xfmtstr(floatfmt); } else arg = xfmtstr("%d"); if (wstr) { wfmt = malloc(strlen(wstr) + strlen(arg) + 1); strcpy(wfmt, wstr); strcat(wfmt, arg); wstr = wfmt; } else wstr = arg; } } /* * get options and set default values */ void getoptions(int argc, char **argv) { char *p, *pgm; #ifndef HAVE_BASENAME p = strrchr(argv[0], '/'); pgm = p ? (1+p) : argv[0]; #else pgm = basename(argv[0]); #endif if (strcasecmp(pgm, "yes") == 0) initialize_yes(argc, argv); else if (strcasecmp(pgm, "seq") == 0) initialize_seq(argc, argv); else initialize_jot(argc, argv); } /* * display random data */ void babble() { double interval; /* get the interval to work in, and, if necessary, * reorder begin .. end to be in ascending order. */ if (end < begin) { interval = (begin - end); begin = end; } else interval = (end - begin); initrand(seed); if (count == 0) { while (1) { display(begin + (drand() * interval)); fputs(fsep, stdout); } } while (count-- > 0) { display(begin + (drand() * interval)); if (count > 0) fwrite(fsep, strlen(fsep), 1, stdout); } } /* * display sequential data */ void iterate() { double interval; if ((count != 0) && (sign(end-begin) != sign(step)) ) { fprintf(stderr, "impossible stepsize\n"); exit(1); } if (count == 0) { /* simple case: count set to 0, so just go charging off into * the hills. */ while (1) { display(begin); fputs(fsep, stdout); begin += step; } } else { int need = 0; int up = (begin < end); if (s_set == 0) { /* step not set, so fabricate one */ step = (end-begin)/count; } else if (r_set == 0) { /* count not set, so fabricate it */ if ( fabs(step) < 0.0000000001) count = 1; else count = (end-begin) / step; } do { if (need) fputs(fsep, stdout); display(begin); begin += step; need = 1; } while ( count-- > 0 && (up ? (begin < end) : (begin > end)) ); } } /* * jot */ int main(int argc, char **argv) { double interval; getoptions(argc, argv); if (rflag) babble(); else iterate(); if (!nflag) putchar('\n'); }