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