Annotation of src/usr.bin/jot/jot.c, Revision 1.47
1.47 ! cheloha 1: /* $OpenBSD: jot.c,v 1.46 2018/06/24 18:39:57 schwarze Exp $ */
1.1 deraadt 2: /* $NetBSD: jot.c,v 1.3 1994/12/02 20:29:43 pk Exp $ */
3:
4: /*-
5: * Copyright (c) 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.12 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * jot - print sequential or random data
35: *
36: * Author: John Kunze, Office of Comp. Affairs, UCB
37: */
38:
1.36 tb 39: #include <ctype.h>
1.7 aaron 40: #include <err.h>
1.1 deraadt 41: #include <limits.h>
1.27 tb 42: #include <math.h>
1.36 tb 43: #include <stdbool.h>
1.27 tb 44: #include <stdint.h>
1.1 deraadt 45: #include <stdio.h>
46: #include <stdlib.h>
47: #include <string.h>
1.22 millert 48: #include <unistd.h>
1.1 deraadt 49:
1.36 tb 50: #define REPS 1
51: #define BEGIN 2
52: #define ENDER 4
53: #define STEP 8
1.32 tb 54:
1.8 pjanzen 55: #define is_default(s) (strcmp((s), "-") == 0)
1.1 deraadt 56:
1.36 tb 57: static long reps = 100;
58: static double begin = 1;
59: static double ender = 100;
60: static double step = 1;
61:
1.42 tb 62: static char *format = "";
63: static char *sepstring = "\n";
1.36 tb 64: static int prec = -1;
65: static bool boring;
66: static bool chardata;
67: static bool finalnl = true;
1.15 otto 68: static bool infinity;
1.17 otto 69: static bool intdata;
70: static bool longdata;
71: static bool nosign;
1.36 tb 72: static bool randomize;
1.15 otto 73:
74: static void getformat(void);
75: static int getprec(char *);
1.17 otto 76: static int putdata(double, bool);
1.33 tb 77: static void __dead usage(void);
1.1 deraadt 78:
79: int
1.13 deraadt 80: main(int argc, char *argv[])
1.1 deraadt 81: {
1.15 otto 82: double x;
83: double y;
84: long i;
1.8 pjanzen 85: unsigned int mask = 0;
1.15 otto 86: int n = 0;
87: int ch;
1.42 tb 88: const char *errstr;
1.25 deraadt 89:
1.26 deraadt 90: if (pledge("stdio", NULL) == -1)
91: err(1, "pledge");
1.1 deraadt 92:
1.36 tb 93: while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1) {
1.15 otto 94: switch (ch) {
1.36 tb 95: case 'b':
96: boring = true;
1.42 tb 97: format = optarg;
1.1 deraadt 98: break;
99: case 'c':
1.15 otto 100: chardata = true;
1.1 deraadt 101: break;
102: case 'n':
1.15 otto 103: finalnl = false;
1.1 deraadt 104: break;
1.36 tb 105: case 'p':
106: prec = strtonum(optarg, 0, INT_MAX, &errstr);
107: if (errstr != NULL)
108: errx(1, "bad precision value, %s: %s", errstr,
109: optarg);
1.8 pjanzen 110: break;
1.36 tb 111: case 'r':
112: randomize = true;
1.1 deraadt 113: break;
114: case 's':
1.42 tb 115: sepstring = optarg;
1.1 deraadt 116: break;
1.36 tb 117: case 'w':
1.42 tb 118: format = optarg;
1.1 deraadt 119: break;
120: default:
1.7 aaron 121: usage();
1.1 deraadt 122: }
1.36 tb 123: }
1.8 pjanzen 124: argc -= optind;
125: argv += optind;
1.1 deraadt 126:
1.8 pjanzen 127: switch (argc) { /* examine args right to left, falling thru cases */
1.1 deraadt 128: case 4:
1.8 pjanzen 129: if (!is_default(argv[3])) {
1.32 tb 130: if (!sscanf(argv[3], "%lf", &step))
1.8 pjanzen 131: errx(1, "Bad s value: %s", argv[3]);
1.32 tb 132: mask |= STEP;
1.16 otto 133: if (randomize)
134: warnx("random seeding not supported");
1.1 deraadt 135: }
136: case 3:
1.8 pjanzen 137: if (!is_default(argv[2])) {
138: if (!sscanf(argv[2], "%lf", &ender))
139: ender = argv[2][strlen(argv[2])-1];
1.32 tb 140: mask |= ENDER;
1.15 otto 141: if (prec == -1)
1.8 pjanzen 142: n = getprec(argv[2]);
1.1 deraadt 143: }
144: case 2:
1.8 pjanzen 145: if (!is_default(argv[1])) {
146: if (!sscanf(argv[1], "%lf", &begin))
147: begin = argv[1][strlen(argv[1])-1];
1.32 tb 148: mask |= BEGIN;
1.15 otto 149: if (prec == -1)
1.8 pjanzen 150: prec = getprec(argv[1]);
1.1 deraadt 151: if (n > prec) /* maximum precision */
152: prec = n;
153: }
154: case 1:
1.8 pjanzen 155: if (!is_default(argv[0])) {
1.47 ! cheloha 156: reps = strtonum(argv[0], 0, LONG_MAX, &errstr);
! 157: if (errstr != NULL)
! 158: errx(1, "Bad reps value, %s: %s", errstr,
! 159: argv[0]);
1.32 tb 160: mask |= REPS;
1.35 tb 161: if (reps == 0)
162: infinity = true;
1.15 otto 163: if (prec == -1)
164: prec = 0;
1.1 deraadt 165: }
166: case 0:
1.8 pjanzen 167: break;
1.1 deraadt 168: default:
1.15 otto 169: errx(1, "Too many arguments. What do you mean by %s?",
170: argv[4]);
1.1 deraadt 171: }
1.35 tb 172:
1.42 tb 173: if (!boring)
174: getformat();
1.35 tb 175:
1.32 tb 176: if (!randomize) {
177: /*
178: * Consolidate the values of reps, begin, ender, step:
179: * The formula ender - begin == (reps - 1) * step shows that any
180: * three determine the fourth (unless reps == 1 or step == 0).
181: * The manual states the following rules:
182: * 1. If four are specified, compare the given and the computed
183: * value of reps and take the smaller of the two.
184: * 2. If steps was omitted, it takes the default, unless both
185: * begin and ender were specified.
186: * 3. Assign defaults to omitted values for reps, begin, ender,
187: * from left to right.
188: */
189: switch (mask) { /* Four cases involve both begin and ender. */
190: case REPS | BEGIN | ENDER | STEP:
1.35 tb 191: if (infinity)
1.32 tb 192: errx(1,
193: "Can't specify end of infinite sequence");
194: if (step != 0.0) {
195: long t = (ender - begin + step) / step;
196: if (t <= 0)
197: errx(1, "Impossible stepsize");
198: if (t < reps)
199: reps = t;
200: }
201: break;
202: case REPS | BEGIN | ENDER:
1.35 tb 203: if (infinity)
1.32 tb 204: errx(1,
205: "Can't specify end of infinite sequence");
206: if (reps == 1)
207: step = 0.0;
208: else
209: step = (ender - begin) / (reps - 1);
210: break;
211: case BEGIN | ENDER:
212: step = ender > begin ? 1 : -1; /* FreeBSD's behavior. */
1.31 tb 213: /* FALLTHROUGH */
1.32 tb 214: case BEGIN | ENDER | STEP:
215: if (step == 0.0) {
1.1 deraadt 216: reps = 0;
1.35 tb 217: infinity = true;
1.1 deraadt 218: break;
219: }
1.32 tb 220: reps = (ender - begin + step) / step;
1.1 deraadt 221: if (reps <= 0)
1.7 aaron 222: errx(1, "Impossible stepsize");
1.1 deraadt 223: break;
1.32 tb 224: case ENDER: /* Four cases involve only ender. */
225: case ENDER | STEP:
226: case REPS | ENDER:
227: case REPS | ENDER | STEP:
1.35 tb 228: if (infinity)
1.32 tb 229: errx(1,
230: "Must specify start of infinite sequence");
231: begin = ender - reps * step + step;
1.1 deraadt 232: break;
1.32 tb 233: default:
234: /*
235: * The remaining eight cases omit ender. We don't need
236: * to compute anything because only reps, begin, step
237: * are used for producing output below. Rules 2. and 3.
238: * together imply that ender will be set last.
239: */
1.1 deraadt 240: break;
241: }
1.35 tb 242:
243: for (i = 1, x = begin; i <= reps || infinity; i++, x += step)
244: if (putdata(x, reps == i && !infinity))
245: errx(1, "range error in conversion: %f", x);
246: } else { /* Random output: use defaults for omitted values. */
1.27 tb 247: bool use_unif;
248: uint32_t pow10 = 1;
249: uint32_t uintx = 0; /* Initialized to make gcc happy. */
250:
251: if (prec > 9) /* pow(10, prec) > UINT32_MAX */
252: errx(1, "requested precision too large");
253:
254: if (ender < begin) {
255: x = begin;
256: begin = ender;
257: ender = x;
258: }
259: x = ender - begin;
260:
1.28 tb 261: if (prec == 0 && (fmod(ender, 1) != 0 || fmod(begin, 1) != 0))
262: use_unif = 0;
263: else {
264: while (prec-- > 0)
265: pow10 *= 10;
266: /*
267: * If pow10 * (ender - begin) is an integer, use
268: * arc4random_uniform().
269: */
270: use_unif = fmod(pow10 * (ender - begin), 1) == 0;
271: if (use_unif) {
272: uintx = pow10 * (ender - begin);
273: if (uintx >= UINT32_MAX)
274: errx(1, "requested range too large");
275: uintx++;
276: }
1.27 tb 277: }
278:
1.15 otto 279: for (i = 1; i <= reps || infinity; i++) {
1.17 otto 280: double v;
1.27 tb 281:
282: if (use_unif) {
283: y = arc4random_uniform(uintx) / (double)pow10;
284: v = y + begin;
285: } else {
286: y = arc4random() / ((double)0xffffffff + 1);
287: v = y * x + begin;
288: }
1.17 otto 289: if (putdata(v, reps == i && !infinity))
290: errx(1, "range error in conversion: %f", v);
1.8 pjanzen 291: }
1.32 tb 292: }
1.35 tb 293:
1.15 otto 294: if (finalnl)
1.8 pjanzen 295: putchar('\n');
1.35 tb 296:
1.36 tb 297: return 0;
1.1 deraadt 298: }
299:
1.17 otto 300: static int
1.15 otto 301: putdata(double x, bool last)
1.1 deraadt 302: {
1.17 otto 303: if (boring)
1.1 deraadt 304: printf("%s", format);
1.17 otto 305: else if (longdata && nosign) {
306: if (x <= (double)ULONG_MAX && x >= 0.0)
307: printf(format, (unsigned long)x);
308: else
1.36 tb 309: return 1;
1.17 otto 310: } else if (longdata) {
311: if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
312: printf(format, (long)x);
313: else
1.36 tb 314: return 1;
1.17 otto 315: } else if (chardata || (intdata && !nosign)) {
316: if (x <= (double)INT_MAX && x >= (double)INT_MIN)
317: printf(format, (int)x);
318: else
1.36 tb 319: return 1;
1.17 otto 320: } else if (intdata) {
321: if (x <= (double)UINT_MAX && x >= 0.0)
322: printf(format, (unsigned int)x);
323: else
1.36 tb 324: return 1;
1.17 otto 325: } else
1.1 deraadt 326: printf(format, x);
1.15 otto 327: if (!last)
1.1 deraadt 328: fputs(sepstring, stdout);
1.17 otto 329:
1.36 tb 330: return 0;
1.1 deraadt 331: }
332:
1.33 tb 333: static void __dead
1.7 aaron 334: usage(void)
1.1 deraadt 335: {
1.14 jmc 336: (void)fprintf(stderr, "usage: jot [-cnr] [-b word] [-p precision] "
337: "[-s string] [-w word]\n"
338: " [reps [begin [end [s]]]]\n");
1.1 deraadt 339: exit(1);
340: }
341:
1.15 otto 342: static int
1.13 deraadt 343: getprec(char *s)
1.1 deraadt 344: {
1.34 tb 345: if ((s = strchr(s, '.')) == NULL)
1.36 tb 346: return 0;
347: return strspn(s + 1, "0123456789");
1.1 deraadt 348: }
349:
1.15 otto 350: static void
1.13 deraadt 351: getformat(void)
1.1 deraadt 352: {
1.42 tb 353: char *p;
354:
355: p = format;
356: while ((p = strchr(p, '%')) != NULL && p[1] == '%')
357: p += 2;
358:
359: if (p == NULL && !chardata) {
360: if (asprintf(&format, "%s%%.%df", format, prec) < 0)
361: err(1, NULL);
362: } else if (p == NULL && chardata) {
363: if (asprintf(&format, "%s%%c", format) < 0)
364: err(1, NULL);
365: } else if (p[1] == '\0') {
1.39 tb 366: /* cannot end in single '%' */
1.42 tb 367: if (asprintf(&format, "%s%%", format) < 0)
368: err(1, NULL);
1.8 pjanzen 369: } else {
1.17 otto 370: /*
371: * Allow conversion format specifiers of the form
372: * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
1.45 tb 373: * [l]{d,i,o,u,x} or {f,e,g,F,E,G,d,o,x,D,O,U,X,c,u}
1.17 otto 374: */
1.42 tb 375: char *fmt;
376: int dot, hash, space, sign, numbers;
377:
378: fmt = p++;
1.17 otto 379: dot = hash = space = sign = numbers = 0;
1.23 deraadt 380: while (!isalpha((unsigned char)*p)) {
381: if (isdigit((unsigned char)*p)) {
1.17 otto 382: numbers++;
383: p++;
384: } else if ((*p == '#' && !(numbers|dot|sign|space|
385: hash++)) ||
386: (*p == ' ' && !(numbers|dot|space++)) ||
387: ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
388: || (*p == '.' && !(dot++)))
389: p++;
390: else
391: goto fmt_broken;
392: }
393: if (*p == 'l') {
394: longdata = true;
395: if (*++p == 'l') {
1.40 tb 396: p++;
1.17 otto 397: goto fmt_broken;
398: }
399: }
1.1 deraadt 400: switch (*p) {
1.43 tb 401: case 'd':
402: case 'i':
403: intdata = true;
404: break;
405: case 'o':
406: case 'u':
407: case 'x':
408: case 'X':
1.17 otto 409: intdata = nosign = true;
1.1 deraadt 410: break;
1.43 tb 411: case 'D':
412: if (longdata)
413: goto fmt_broken;
414: longdata = intdata = true; /* same as %ld */
415: break;
416: case 'O':
417: case 'U':
418: if (longdata)
419: goto fmt_broken;
420: longdata = intdata = nosign = true; /* same as %l[ou] */
1.1 deraadt 421: break;
1.17 otto 422: case 'c':
1.43 tb 423: if (longdata)
424: goto fmt_broken;
425: chardata = true;
426: break;
427: case 'e':
428: case 'E':
429: case 'f':
1.44 tb 430: case 'F':
1.43 tb 431: case 'g':
432: case 'G':
433: if (longdata)
434: goto fmt_broken;
435: /* No cast needed for printing in putdata() */
436: break;
1.8 pjanzen 437: default:
1.17 otto 438: fmt_broken:
1.42 tb 439: errx(1, "illegal or unsupported format '%.*s'",
440: (int)(p + 1 - fmt), fmt);
1.1 deraadt 441: }
1.42 tb 442:
443: while ((p = strchr(p, '%')) != NULL && p[1] == '%')
444: p += 2;
445:
446: if (p != NULL) {
447: if (p[1] != '\0')
1.17 otto 448: errx(1, "too many conversions");
1.42 tb 449: /* cannot end in single '%' */
450: if (asprintf(&format, "%s%%", format) < 0)
451: err(1, NULL);
452: }
1.1 deraadt 453: }
454: }