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