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