Annotation of src/usr.bin/jot/jot.c, Revision 1.33
1.32 tb 1: /* $OpenBSD: jot.c,v 1.31 2016/08/05 13:43:38 tb 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.7 aaron 39: #include <err.h>
1.15 otto 40: #include <stdbool.h>
1.1 deraadt 41: #include <ctype.h>
42: #include <limits.h>
1.27 tb 43: #include <math.h>
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:
50: #define REPS_DEF 100
51: #define BEGIN_DEF 1
52: #define ENDER_DEF 100
53: #define STEP_DEF 1
54:
1.32 tb 55: #define STEP 1
56: #define ENDER 2
57: #define BEGIN 4
58: #define REPS 8
59:
1.8 pjanzen 60: #define is_default(s) (strcmp((s), "-") == 0)
1.1 deraadt 61:
1.29 tb 62: static double begin = BEGIN_DEF;
63: static double ender = ENDER_DEF;
1.32 tb 64: static double step = STEP_DEF;
1.29 tb 65: static long reps = REPS_DEF;
1.15 otto 66: static bool randomize;
67: static bool infinity;
68: static bool boring;
69: static int prec = -1;
1.17 otto 70: static bool intdata;
71: static bool longdata;
1.15 otto 72: static bool chardata;
1.17 otto 73: static bool nosign;
1.15 otto 74: static bool finalnl = true;
75: static char sepstring[BUFSIZ] = "\n";
76: static char format[BUFSIZ];
77:
78: static void getformat(void);
79: static int getprec(char *);
1.17 otto 80: static int putdata(double, bool);
1.33 ! tb 81: static void __dead usage(void);
1.1 deraadt 82:
83: int
1.13 deraadt 84: main(int argc, char *argv[])
1.1 deraadt 85: {
1.15 otto 86: double x;
87: double y;
88: long i;
1.8 pjanzen 89: unsigned int mask = 0;
1.15 otto 90: int n = 0;
91: int ch;
1.19 jdixon 92: const char *errstr;
1.25 deraadt 93:
1.26 deraadt 94: if (pledge("stdio", NULL) == -1)
95: err(1, "pledge");
1.1 deraadt 96:
1.8 pjanzen 97: while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1)
1.15 otto 98: switch (ch) {
1.1 deraadt 99: case 'r':
1.15 otto 100: randomize = true;
1.1 deraadt 101: break;
102: case 'c':
1.15 otto 103: chardata = true;
1.1 deraadt 104: break;
105: case 'n':
1.15 otto 106: finalnl = false;
1.1 deraadt 107: break;
108: case 'b':
1.15 otto 109: boring = true;
1.8 pjanzen 110: if (strlcpy(format, optarg, sizeof(format)) >=
111: sizeof(format))
112: errx(1, "-b word too long");
113: break;
1.1 deraadt 114: case 'w':
1.8 pjanzen 115: if (strlcpy(format, optarg, sizeof(format)) >=
116: sizeof(format))
117: errx(1, "-w word too long");
1.1 deraadt 118: break;
119: case 's':
1.8 pjanzen 120: if (strlcpy(sepstring, optarg, sizeof(sepstring)) >=
121: sizeof(sepstring))
1.21 okan 122: errx(1, "-s string too long");
1.1 deraadt 123: break;
124: case 'p':
1.19 jdixon 125: prec = strtonum(optarg, 0, INT_MAX, &errstr);
126: if (errstr != NULL)
1.24 jasper 127: errx(1, "bad precision value, %s: %s", errstr,
1.19 jdixon 128: optarg);
1.1 deraadt 129: break;
130: default:
1.7 aaron 131: usage();
1.1 deraadt 132: }
1.8 pjanzen 133: argc -= optind;
134: argv += optind;
1.1 deraadt 135:
1.8 pjanzen 136: switch (argc) { /* examine args right to left, falling thru cases */
1.1 deraadt 137: case 4:
1.8 pjanzen 138: if (!is_default(argv[3])) {
1.32 tb 139: if (!sscanf(argv[3], "%lf", &step))
1.8 pjanzen 140: errx(1, "Bad s value: %s", argv[3]);
1.32 tb 141: mask |= STEP;
1.16 otto 142: if (randomize)
143: warnx("random seeding not supported");
1.1 deraadt 144: }
145: case 3:
1.8 pjanzen 146: if (!is_default(argv[2])) {
147: if (!sscanf(argv[2], "%lf", &ender))
148: ender = argv[2][strlen(argv[2])-1];
1.32 tb 149: mask |= ENDER;
1.15 otto 150: if (prec == -1)
1.8 pjanzen 151: n = getprec(argv[2]);
1.1 deraadt 152: }
153: case 2:
1.8 pjanzen 154: if (!is_default(argv[1])) {
155: if (!sscanf(argv[1], "%lf", &begin))
156: begin = argv[1][strlen(argv[1])-1];
1.32 tb 157: mask |= BEGIN;
1.15 otto 158: if (prec == -1)
1.8 pjanzen 159: prec = getprec(argv[1]);
1.1 deraadt 160: if (n > prec) /* maximum precision */
161: prec = n;
162: }
163: case 1:
1.8 pjanzen 164: if (!is_default(argv[0])) {
165: if (!sscanf(argv[0], "%ld", &reps))
166: errx(1, "Bad reps value: %s", argv[0]);
1.32 tb 167: mask |= REPS;
1.15 otto 168: if (prec == -1)
169: prec = 0;
1.1 deraadt 170: }
171: break;
172: case 0:
1.8 pjanzen 173: usage();
174: break;
1.1 deraadt 175: default:
1.15 otto 176: errx(1, "Too many arguments. What do you mean by %s?",
177: argv[4]);
1.1 deraadt 178: }
179: getformat();
1.32 tb 180: /* If random output is requested, use defaults for omitted values. */
181: if (!randomize) {
182: /*
183: * Consolidate the values of reps, begin, ender, step:
184: * The formula ender - begin == (reps - 1) * step shows that any
185: * three determine the fourth (unless reps == 1 or step == 0).
186: * The manual states the following rules:
187: * 1. If four are specified, compare the given and the computed
188: * value of reps and take the smaller of the two.
189: * 2. If steps was omitted, it takes the default, unless both
190: * begin and ender were specified.
191: * 3. Assign defaults to omitted values for reps, begin, ender,
192: * from left to right.
193: * 4. reps == 0 means infinite output
194: */
195: switch (mask) { /* Four cases involve both begin and ender. */
196: case REPS | BEGIN | ENDER | STEP:
197: if (reps == 0)
198: errx(1,
199: "Can't specify end of infinite sequence");
200: if (step != 0.0) {
201: long t = (ender - begin + step) / step;
202: if (t <= 0)
203: errx(1, "Impossible stepsize");
204: if (t < reps)
205: reps = t;
206: }
207: break;
208: case REPS | BEGIN | ENDER:
209: if (reps == 0)
210: errx(1,
211: "Can't specify end of infinite sequence");
212: if (reps == 1)
213: step = 0.0;
214: else
215: step = (ender - begin) / (reps - 1);
216: break;
217: case BEGIN | ENDER:
218: step = ender > begin ? 1 : -1; /* FreeBSD's behavior. */
1.31 tb 219: /* FALLTHROUGH */
1.32 tb 220: case BEGIN | ENDER | STEP:
221: if (step == 0.0) {
1.1 deraadt 222: reps = 0;
223: break;
224: }
1.32 tb 225: reps = (ender - begin + step) / step;
1.1 deraadt 226: if (reps <= 0)
1.7 aaron 227: errx(1, "Impossible stepsize");
1.1 deraadt 228: break;
1.32 tb 229: case ENDER: /* Four cases involve only ender. */
230: case ENDER | STEP:
231: case REPS | ENDER:
232: case REPS | ENDER | STEP:
1.16 otto 233: if (reps == 0)
1.32 tb 234: errx(1,
235: "Must specify start of infinite sequence");
236: begin = ender - reps * step + step;
1.1 deraadt 237: break;
1.32 tb 238: default:
239: /*
240: * The remaining eight cases omit ender. We don't need
241: * to compute anything because only reps, begin, step
242: * are used for producing output below. Rules 2. and 3.
243: * together imply that ender will be set last.
244: */
1.1 deraadt 245: break;
246: }
1.32 tb 247: }
1.1 deraadt 248: if (reps == 0)
1.15 otto 249: infinity = true;
1.8 pjanzen 250: if (randomize) {
1.27 tb 251: bool use_unif;
252: uint32_t pow10 = 1;
253: uint32_t uintx = 0; /* Initialized to make gcc happy. */
254:
255: if (prec > 9) /* pow(10, prec) > UINT32_MAX */
256: errx(1, "requested precision too large");
257:
258: if (ender < begin) {
259: x = begin;
260: begin = ender;
261: ender = x;
262: }
263: x = ender - begin;
264:
1.28 tb 265: if (prec == 0 && (fmod(ender, 1) != 0 || fmod(begin, 1) != 0))
266: use_unif = 0;
267: else {
268: while (prec-- > 0)
269: pow10 *= 10;
270: /*
271: * If pow10 * (ender - begin) is an integer, use
272: * arc4random_uniform().
273: */
274: use_unif = fmod(pow10 * (ender - begin), 1) == 0;
275: if (use_unif) {
276: uintx = pow10 * (ender - begin);
277: if (uintx >= UINT32_MAX)
278: errx(1, "requested range too large");
279: uintx++;
280: }
1.27 tb 281: }
282:
1.15 otto 283: for (i = 1; i <= reps || infinity; i++) {
1.17 otto 284: double v;
1.27 tb 285:
286: if (use_unif) {
287: y = arc4random_uniform(uintx) / (double)pow10;
288: v = y + begin;
289: } else {
290: y = arc4random() / ((double)0xffffffff + 1);
291: v = y * x + begin;
292: }
1.17 otto 293: if (putdata(v, reps == i && !infinity))
294: errx(1, "range error in conversion: %f", v);
1.8 pjanzen 295: }
1.32 tb 296: } else {
297: for (i = 1, x = begin; i <= reps || infinity; i++, x += step)
1.17 otto 298: if (putdata(x, reps == i && !infinity))
299: errx(1, "range error in conversion: %f", x);
1.32 tb 300: }
1.15 otto 301: if (finalnl)
1.8 pjanzen 302: putchar('\n');
1.32 tb 303: return (0);
1.1 deraadt 304: }
305:
1.17 otto 306: static int
1.15 otto 307: putdata(double x, bool last)
1.1 deraadt 308: {
1.17 otto 309: if (boring)
1.1 deraadt 310: printf("%s", format);
1.17 otto 311: else if (longdata && nosign) {
312: if (x <= (double)ULONG_MAX && x >= 0.0)
313: printf(format, (unsigned long)x);
314: else
315: return (1);
316: } else if (longdata) {
317: if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
318: printf(format, (long)x);
319: else
320: return (1);
321: } else if (chardata || (intdata && !nosign)) {
322: if (x <= (double)INT_MAX && x >= (double)INT_MIN)
323: printf(format, (int)x);
324: else
325: return (1);
326: } else if (intdata) {
327: if (x <= (double)UINT_MAX && x >= 0.0)
328: printf(format, (unsigned int)x);
329: else
330: return (1);
331: } else
1.1 deraadt 332: printf(format, x);
1.15 otto 333: if (!last)
1.1 deraadt 334: fputs(sepstring, stdout);
1.17 otto 335:
336: return (0);
1.1 deraadt 337: }
338:
1.33 ! tb 339: static void __dead
1.7 aaron 340: usage(void)
1.1 deraadt 341: {
1.14 jmc 342: (void)fprintf(stderr, "usage: jot [-cnr] [-b word] [-p precision] "
343: "[-s string] [-w word]\n"
344: " [reps [begin [end [s]]]]\n");
1.1 deraadt 345: exit(1);
346: }
347:
1.15 otto 348: static int
1.13 deraadt 349: getprec(char *s)
1.1 deraadt 350: {
1.8 pjanzen 351: char *p;
352: char *q;
1.1 deraadt 353:
1.15 otto 354: for (p = s; *p != '\0'; p++)
1.1 deraadt 355: if (*p == '.')
356: break;
1.15 otto 357: if (*p == '\0')
1.1 deraadt 358: return (0);
1.15 otto 359: for (q = ++p; *p != '\0'; p++)
1.23 deraadt 360: if (!isdigit((unsigned char)*p))
1.1 deraadt 361: break;
362: return (p - q);
363: }
364:
1.15 otto 365: static void
1.13 deraadt 366: getformat(void)
1.1 deraadt 367: {
1.17 otto 368: char *p, *p2;
369: int dot, hash, space, sign, numbers = 0;
1.8 pjanzen 370: size_t sz;
1.1 deraadt 371:
372: if (boring) /* no need to bother */
373: return;
1.15 otto 374: for (p = format; *p != '\0'; p++) /* look for '%' */
1.30 tb 375: if (*p == '%') {
376: if (*(p+1) != '%')
377: break;
378: p++; /* leave %% alone */
379: }
1.8 pjanzen 380: sz = sizeof(format) - strlen(format) - 1;
1.15 otto 381: if (*p == '\0' && !chardata) {
1.18 deraadt 382: int n;
383:
384: n = snprintf(p, sz, "%%.%df", prec);
385: if (n == -1 || n >= (int)sz)
1.8 pjanzen 386: errx(1, "-w word too long");
1.15 otto 387: } else if (*p == '\0' && chardata) {
1.8 pjanzen 388: if (strlcpy(p, "%c", sz) >= sz)
389: errx(1, "-w word too long");
1.17 otto 390: intdata = true;
1.15 otto 391: } else if (*(p+1) == '\0') {
1.8 pjanzen 392: if (sz <= 0)
393: errx(1, "-w word too long");
1.15 otto 394: /* cannot end in single '%' */
395: strlcat(format, "%", sizeof format);
1.8 pjanzen 396: } else {
1.17 otto 397: /*
398: * Allow conversion format specifiers of the form
399: * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
400: * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u}
401: */
402: p2 = p++;
403: dot = hash = space = sign = numbers = 0;
1.23 deraadt 404: while (!isalpha((unsigned char)*p)) {
405: if (isdigit((unsigned char)*p)) {
1.17 otto 406: numbers++;
407: p++;
408: } else if ((*p == '#' && !(numbers|dot|sign|space|
409: hash++)) ||
410: (*p == ' ' && !(numbers|dot|space++)) ||
411: ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
412: || (*p == '.' && !(dot++)))
413: p++;
414: else
415: goto fmt_broken;
416: }
417: if (*p == 'l') {
418: longdata = true;
419: if (*++p == 'l') {
420: if (p[1] != '\0')
421: p++;
422: goto fmt_broken;
423: }
424: }
1.1 deraadt 425: switch (*p) {
1.17 otto 426: case 'o': case 'u': case 'x': case 'X':
427: intdata = nosign = true;
1.1 deraadt 428: break;
1.17 otto 429: case 'd': case 'i':
430: intdata = true;
1.1 deraadt 431: break;
1.17 otto 432: case 'D':
433: if (!longdata) {
434: intdata = true;
435: break;
436: }
437: case 'O': case 'U':
438: if (!longdata) {
439: intdata = nosign = true;
440: break;
441: }
442: case 'c':
443: if (!(intdata | longdata)) {
444: chardata = true;
445: break;
446: }
447: case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
448: case '$': case '*':
449: goto fmt_broken;
450: case 'f': case 'e': case 'g': case 'E': case 'G':
451: if (!longdata)
452: break;
453: /* FALLTHROUGH */
1.8 pjanzen 454: default:
1.17 otto 455: fmt_broken:
456: *++p = '\0';
457: errx(1, "illegal or unsupported format '%s'", p2);
458: /* NOTREACHED */
1.1 deraadt 459: }
1.17 otto 460: while (*++p != '\0')
461: if (*p == '%' && *(p+1) != '\0' && *(p+1) != '%')
462: errx(1, "too many conversions");
463: else if (*p == '%' && *(p+1) == '%')
464: p++;
465: else if (*p == '%' && *(p+1) == '\0') {
466: strlcat(format, "%", sizeof format);
467: break;
1.8 pjanzen 468: }
1.1 deraadt 469: }
470: }