Annotation of src/usr.bin/jot/jot.c, Revision 1.36
1.36 ! tb 1: /* $OpenBSD: jot.c,v 1.35 2016/08/16 16:49:24 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.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:
! 62: static char format[BUFSIZ];
! 63: static char sepstring[BUFSIZ] = "\n";
! 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.19 jdixon 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;
! 97: if (strlcpy(format, optarg, sizeof(format)) >=
! 98: sizeof(format))
! 99: errx(1, "-b word too long");
1.1 deraadt 100: break;
101: case 'c':
1.15 otto 102: chardata = true;
1.1 deraadt 103: break;
104: case 'n':
1.15 otto 105: finalnl = false;
1.1 deraadt 106: break;
1.36 ! tb 107: case 'p':
! 108: prec = strtonum(optarg, 0, INT_MAX, &errstr);
! 109: if (errstr != NULL)
! 110: errx(1, "bad precision value, %s: %s", errstr,
! 111: optarg);
1.8 pjanzen 112: break;
1.36 ! tb 113: case 'r':
! 114: randomize = true;
1.1 deraadt 115: break;
116: case 's':
1.8 pjanzen 117: if (strlcpy(sepstring, optarg, sizeof(sepstring)) >=
118: sizeof(sepstring))
1.21 okan 119: errx(1, "-s string too long");
1.1 deraadt 120: break;
1.36 ! tb 121: case 'w':
! 122: if (strlcpy(format, optarg, sizeof(format)) >=
! 123: sizeof(format))
! 124: errx(1, "-w word too long");
1.1 deraadt 125: break;
126: default:
1.7 aaron 127: usage();
1.1 deraadt 128: }
1.36 ! tb 129: }
1.8 pjanzen 130: argc -= optind;
131: argv += optind;
1.1 deraadt 132:
1.8 pjanzen 133: switch (argc) { /* examine args right to left, falling thru cases */
1.1 deraadt 134: case 4:
1.8 pjanzen 135: if (!is_default(argv[3])) {
1.32 tb 136: if (!sscanf(argv[3], "%lf", &step))
1.8 pjanzen 137: errx(1, "Bad s value: %s", argv[3]);
1.32 tb 138: mask |= STEP;
1.16 otto 139: if (randomize)
140: warnx("random seeding not supported");
1.1 deraadt 141: }
142: case 3:
1.8 pjanzen 143: if (!is_default(argv[2])) {
144: if (!sscanf(argv[2], "%lf", &ender))
145: ender = argv[2][strlen(argv[2])-1];
1.32 tb 146: mask |= ENDER;
1.15 otto 147: if (prec == -1)
1.8 pjanzen 148: n = getprec(argv[2]);
1.1 deraadt 149: }
150: case 2:
1.8 pjanzen 151: if (!is_default(argv[1])) {
152: if (!sscanf(argv[1], "%lf", &begin))
153: begin = argv[1][strlen(argv[1])-1];
1.32 tb 154: mask |= BEGIN;
1.15 otto 155: if (prec == -1)
1.8 pjanzen 156: prec = getprec(argv[1]);
1.1 deraadt 157: if (n > prec) /* maximum precision */
158: prec = n;
159: }
160: case 1:
1.8 pjanzen 161: if (!is_default(argv[0])) {
162: if (!sscanf(argv[0], "%ld", &reps))
163: errx(1, "Bad reps value: %s", argv[0]);
1.32 tb 164: mask |= REPS;
1.35 tb 165: if (reps == 0)
166: infinity = true;
1.15 otto 167: if (prec == -1)
168: prec = 0;
1.1 deraadt 169: }
170: break;
171: case 0:
1.8 pjanzen 172: usage();
173: break;
1.1 deraadt 174: default:
1.15 otto 175: errx(1, "Too many arguments. What do you mean by %s?",
176: argv[4]);
1.1 deraadt 177: }
1.35 tb 178:
1.1 deraadt 179: getformat();
1.35 tb 180:
1.32 tb 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: */
194: switch (mask) { /* Four cases involve both begin and ender. */
195: case REPS | BEGIN | ENDER | STEP:
1.35 tb 196: if (infinity)
1.32 tb 197: errx(1,
198: "Can't specify end of infinite sequence");
199: if (step != 0.0) {
200: long t = (ender - begin + step) / step;
201: if (t <= 0)
202: errx(1, "Impossible stepsize");
203: if (t < reps)
204: reps = t;
205: }
206: break;
207: case REPS | BEGIN | ENDER:
1.35 tb 208: if (infinity)
1.32 tb 209: errx(1,
210: "Can't specify end of infinite sequence");
211: if (reps == 1)
212: step = 0.0;
213: else
214: step = (ender - begin) / (reps - 1);
215: break;
216: case BEGIN | ENDER:
217: step = ender > begin ? 1 : -1; /* FreeBSD's behavior. */
1.31 tb 218: /* FALLTHROUGH */
1.32 tb 219: case BEGIN | ENDER | STEP:
220: if (step == 0.0) {
1.1 deraadt 221: reps = 0;
1.35 tb 222: infinity = true;
1.1 deraadt 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.35 tb 233: if (infinity)
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.35 tb 247:
248: for (i = 1, x = begin; i <= reps || infinity; i++, x += step)
249: if (putdata(x, reps == i && !infinity))
250: errx(1, "range error in conversion: %f", x);
251: } else { /* Random output: use defaults for omitted values. */
1.27 tb 252: bool use_unif;
253: uint32_t pow10 = 1;
254: uint32_t uintx = 0; /* Initialized to make gcc happy. */
255:
256: if (prec > 9) /* pow(10, prec) > UINT32_MAX */
257: errx(1, "requested precision too large");
258:
259: if (ender < begin) {
260: x = begin;
261: begin = ender;
262: ender = x;
263: }
264: x = ender - begin;
265:
1.28 tb 266: if (prec == 0 && (fmod(ender, 1) != 0 || fmod(begin, 1) != 0))
267: use_unif = 0;
268: else {
269: while (prec-- > 0)
270: pow10 *= 10;
271: /*
272: * If pow10 * (ender - begin) is an integer, use
273: * arc4random_uniform().
274: */
275: use_unif = fmod(pow10 * (ender - begin), 1) == 0;
276: if (use_unif) {
277: uintx = pow10 * (ender - begin);
278: if (uintx >= UINT32_MAX)
279: errx(1, "requested range too large");
280: uintx++;
281: }
1.27 tb 282: }
283:
1.15 otto 284: for (i = 1; i <= reps || infinity; i++) {
1.17 otto 285: double v;
1.27 tb 286:
287: if (use_unif) {
288: y = arc4random_uniform(uintx) / (double)pow10;
289: v = y + begin;
290: } else {
291: y = arc4random() / ((double)0xffffffff + 1);
292: v = y * x + begin;
293: }
1.17 otto 294: if (putdata(v, reps == i && !infinity))
295: errx(1, "range error in conversion: %f", v);
1.8 pjanzen 296: }
1.32 tb 297: }
1.35 tb 298:
1.15 otto 299: if (finalnl)
1.8 pjanzen 300: putchar('\n');
1.35 tb 301:
1.36 ! tb 302: return 0;
1.1 deraadt 303: }
304:
1.17 otto 305: static int
1.15 otto 306: putdata(double x, bool last)
1.1 deraadt 307: {
1.17 otto 308: if (boring)
1.1 deraadt 309: printf("%s", format);
1.17 otto 310: else if (longdata && nosign) {
311: if (x <= (double)ULONG_MAX && x >= 0.0)
312: printf(format, (unsigned long)x);
313: else
1.36 ! tb 314: return 1;
1.17 otto 315: } else if (longdata) {
316: if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
317: printf(format, (long)x);
318: else
1.36 ! tb 319: return 1;
1.17 otto 320: } else if (chardata || (intdata && !nosign)) {
321: if (x <= (double)INT_MAX && x >= (double)INT_MIN)
322: printf(format, (int)x);
323: else
1.36 ! tb 324: return 1;
1.17 otto 325: } else if (intdata) {
326: if (x <= (double)UINT_MAX && x >= 0.0)
327: printf(format, (unsigned int)x);
328: else
1.36 ! tb 329: return 1;
1.17 otto 330: } else
1.1 deraadt 331: printf(format, x);
1.15 otto 332: if (!last)
1.1 deraadt 333: fputs(sepstring, stdout);
1.17 otto 334:
1.36 ! tb 335: return 0;
1.1 deraadt 336: }
337:
1.33 tb 338: static void __dead
1.7 aaron 339: usage(void)
1.1 deraadt 340: {
1.14 jmc 341: (void)fprintf(stderr, "usage: jot [-cnr] [-b word] [-p precision] "
342: "[-s string] [-w word]\n"
343: " [reps [begin [end [s]]]]\n");
1.1 deraadt 344: exit(1);
345: }
346:
1.15 otto 347: static int
1.13 deraadt 348: getprec(char *s)
1.1 deraadt 349: {
1.34 tb 350: if ((s = strchr(s, '.')) == NULL)
1.36 ! tb 351: return 0;
! 352: return strspn(s + 1, "0123456789");
1.1 deraadt 353: }
354:
1.15 otto 355: static void
1.13 deraadt 356: getformat(void)
1.1 deraadt 357: {
1.17 otto 358: char *p, *p2;
359: int dot, hash, space, sign, numbers = 0;
1.8 pjanzen 360: size_t sz;
1.1 deraadt 361:
362: if (boring) /* no need to bother */
363: return;
1.15 otto 364: for (p = format; *p != '\0'; p++) /* look for '%' */
1.30 tb 365: if (*p == '%') {
366: if (*(p+1) != '%')
367: break;
368: p++; /* leave %% alone */
369: }
1.8 pjanzen 370: sz = sizeof(format) - strlen(format) - 1;
1.15 otto 371: if (*p == '\0' && !chardata) {
1.18 deraadt 372: int n;
373:
374: n = snprintf(p, sz, "%%.%df", prec);
375: if (n == -1 || n >= (int)sz)
1.8 pjanzen 376: errx(1, "-w word too long");
1.15 otto 377: } else if (*p == '\0' && chardata) {
1.8 pjanzen 378: if (strlcpy(p, "%c", sz) >= sz)
379: errx(1, "-w word too long");
1.17 otto 380: intdata = true;
1.15 otto 381: } else if (*(p+1) == '\0') {
1.8 pjanzen 382: if (sz <= 0)
383: errx(1, "-w word too long");
1.15 otto 384: /* cannot end in single '%' */
385: strlcat(format, "%", sizeof format);
1.8 pjanzen 386: } else {
1.17 otto 387: /*
388: * Allow conversion format specifiers of the form
389: * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
390: * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u}
391: */
392: p2 = p++;
393: dot = hash = space = sign = numbers = 0;
1.23 deraadt 394: while (!isalpha((unsigned char)*p)) {
395: if (isdigit((unsigned char)*p)) {
1.17 otto 396: numbers++;
397: p++;
398: } else if ((*p == '#' && !(numbers|dot|sign|space|
399: hash++)) ||
400: (*p == ' ' && !(numbers|dot|space++)) ||
401: ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
402: || (*p == '.' && !(dot++)))
403: p++;
404: else
405: goto fmt_broken;
406: }
407: if (*p == 'l') {
408: longdata = true;
409: if (*++p == 'l') {
410: if (p[1] != '\0')
411: p++;
412: goto fmt_broken;
413: }
414: }
1.1 deraadt 415: switch (*p) {
1.17 otto 416: case 'o': case 'u': case 'x': case 'X':
417: intdata = nosign = true;
1.1 deraadt 418: break;
1.17 otto 419: case 'd': case 'i':
420: intdata = true;
1.1 deraadt 421: break;
1.17 otto 422: case 'D':
423: if (!longdata) {
424: intdata = true;
425: break;
426: }
427: case 'O': case 'U':
428: if (!longdata) {
429: intdata = nosign = true;
430: break;
431: }
432: case 'c':
433: if (!(intdata | longdata)) {
434: chardata = true;
435: break;
436: }
437: case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
438: case '$': case '*':
439: goto fmt_broken;
440: case 'f': case 'e': case 'g': case 'E': case 'G':
441: if (!longdata)
442: break;
443: /* FALLTHROUGH */
1.8 pjanzen 444: default:
1.17 otto 445: fmt_broken:
446: *++p = '\0';
447: errx(1, "illegal or unsupported format '%s'", p2);
1.1 deraadt 448: }
1.17 otto 449: while (*++p != '\0')
450: if (*p == '%' && *(p+1) != '\0' && *(p+1) != '%')
451: errx(1, "too many conversions");
452: else if (*p == '%' && *(p+1) == '%')
453: p++;
454: else if (*p == '%' && *(p+1) == '\0') {
455: strlcat(format, "%", sizeof format);
456: break;
1.8 pjanzen 457: }
1.1 deraadt 458: }
459: }