Annotation of src/usr.bin/jot/jot.c, Revision 1.17
1.17 ! otto 1: /* $OpenBSD: jot.c,v 1.16 2003/12/30 19:41:48 otto 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.17 ! otto 43: static const char rcsid[] = "$OpenBSD: jot.c,v 1.16 2003/12/30 19:41:48 otto 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.1 deraadt 97:
1.8 pjanzen 98: while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1)
1.15 otto 99: switch (ch) {
1.1 deraadt 100: case 'r':
1.15 otto 101: randomize = true;
1.1 deraadt 102: break;
103: case 'c':
1.15 otto 104: chardata = true;
1.1 deraadt 105: break;
106: case 'n':
1.15 otto 107: finalnl = false;
1.1 deraadt 108: break;
109: case 'b':
1.15 otto 110: boring = true;
1.8 pjanzen 111: if (strlcpy(format, optarg, sizeof(format)) >=
112: sizeof(format))
113: errx(1, "-b word too long");
114: break;
1.1 deraadt 115: case 'w':
1.8 pjanzen 116: if (strlcpy(format, optarg, sizeof(format)) >=
117: sizeof(format))
118: errx(1, "-w word too long");
1.1 deraadt 119: break;
120: case 's':
1.8 pjanzen 121: if (strlcpy(sepstring, optarg, sizeof(sepstring)) >=
122: sizeof(sepstring))
123: errx(1, "-s word too long");
1.1 deraadt 124: break;
125: case 'p':
1.8 pjanzen 126: prec = atoi(optarg);
1.15 otto 127: if (prec < 0)
1.8 pjanzen 128: errx(1, "bad precision value");
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])) {
139: if (!sscanf(argv[3], "%lf", &s))
140: errx(1, "Bad s value: %s", argv[3]);
1.1 deraadt 141: mask |= 01;
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.1 deraadt 149: mask |= 02;
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.1 deraadt 157: mask |= 04;
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.1 deraadt 167: mask |= 010;
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();
180: while (mask) /* 4 bit mask has 1's where last 4 args were given */
181: switch (mask) { /* fill in the 0's by default or computation */
182: case 001:
183: reps = REPS_DEF;
184: mask = 011;
185: break;
186: case 002:
187: reps = REPS_DEF;
188: mask = 012;
189: break;
190: case 003:
191: reps = REPS_DEF;
192: mask = 013;
193: break;
194: case 004:
195: reps = REPS_DEF;
196: mask = 014;
197: break;
198: case 005:
199: reps = REPS_DEF;
200: mask = 015;
201: break;
202: case 006:
203: reps = REPS_DEF;
204: mask = 016;
205: break;
206: case 007:
207: if (randomize) {
208: reps = REPS_DEF;
209: mask = 0;
210: break;
211: }
212: if (s == 0.0) {
213: reps = 0;
214: mask = 0;
215: break;
216: }
217: reps = (ender - begin + s) / s;
218: if (reps <= 0)
1.7 aaron 219: errx(1, "Impossible stepsize");
1.1 deraadt 220: mask = 0;
221: break;
222: case 010:
223: begin = BEGIN_DEF;
224: mask = 014;
225: break;
226: case 011:
227: begin = BEGIN_DEF;
228: mask = 015;
229: break;
230: case 012:
1.16 otto 231: s = STEP_DEF;
1.1 deraadt 232: mask = 013;
233: break;
234: case 013:
235: if (randomize)
236: begin = BEGIN_DEF;
237: else if (reps == 0)
1.7 aaron 238: errx(1, "Must specify begin if reps == 0");
1.1 deraadt 239: begin = ender - reps * s + s;
240: mask = 0;
241: break;
242: case 014:
1.16 otto 243: s = STEP_DEF;
1.1 deraadt 244: mask = 015;
245: break;
246: case 015:
247: if (randomize)
248: ender = ENDER_DEF;
249: else
250: ender = begin + reps * s - s;
251: mask = 0;
252: break;
253: case 016:
1.16 otto 254: if (reps == 0)
1.7 aaron 255: errx(1, "Infinite sequences cannot be bounded");
1.1 deraadt 256: else if (reps == 1)
257: s = 0.0;
258: else
259: s = (ender - begin) / (reps - 1);
260: mask = 0;
261: break;
262: case 017: /* if reps given and implied, */
263: if (!randomize && s != 0.0) {
264: long t = (ender - begin + s) / s;
265: if (t <= 0)
1.7 aaron 266: errx(1, "Impossible stepsize");
1.1 deraadt 267: if (t < reps) /* take lesser */
268: reps = t;
269: }
270: mask = 0;
271: break;
272: default:
1.8 pjanzen 273: errx(1, "bad mask");
1.1 deraadt 274: }
275: if (reps == 0)
1.15 otto 276: infinity = true;
1.8 pjanzen 277: if (randomize) {
1.15 otto 278: x = (ender - begin) * (ender > begin ? 1 : -1);
279: for (i = 1; i <= reps || infinity; i++) {
1.17 ! otto 280: double v;
1.16 otto 281: y = arc4random() / ((double)0xffffffff + 1);
1.17 ! otto 282: v = y * x + begin;
! 283: if (putdata(v, reps == i && !infinity))
! 284: errx(1, "range error in conversion: %f", v);
1.8 pjanzen 285: }
286: }
287: else
1.15 otto 288: for (i = 1, x = begin; i <= reps || infinity; i++, x += s)
1.17 ! otto 289: if (putdata(x, reps == i && !infinity))
! 290: errx(1, "range error in conversion: %f", x);
1.15 otto 291: if (finalnl)
1.8 pjanzen 292: putchar('\n');
293: exit(0);
1.1 deraadt 294: }
295:
1.17 ! otto 296: static int
1.15 otto 297: putdata(double x, bool last)
1.1 deraadt 298: {
1.17 ! otto 299: if (boring)
1.1 deraadt 300: printf("%s", format);
1.17 ! otto 301: else if (longdata && nosign) {
! 302: if (x <= (double)ULONG_MAX && x >= 0.0)
! 303: printf(format, (unsigned long)x);
! 304: else
! 305: return (1);
! 306: } else if (longdata) {
! 307: if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
! 308: printf(format, (long)x);
! 309: else
! 310: return (1);
! 311: } else if (chardata || (intdata && !nosign)) {
! 312: if (x <= (double)INT_MAX && x >= (double)INT_MIN)
! 313: printf(format, (int)x);
! 314: else
! 315: return (1);
! 316: } else if (intdata) {
! 317: if (x <= (double)UINT_MAX && x >= 0.0)
! 318: printf(format, (unsigned int)x);
! 319: else
! 320: return (1);
! 321: } else
1.1 deraadt 322: printf(format, x);
1.15 otto 323: if (!last)
1.1 deraadt 324: fputs(sepstring, stdout);
1.17 ! otto 325:
! 326: return (0);
1.1 deraadt 327: }
328:
1.7 aaron 329: static void
330: usage(void)
1.1 deraadt 331: {
1.14 jmc 332: (void)fprintf(stderr, "usage: jot [-cnr] [-b word] [-p precision] "
333: "[-s string] [-w word]\n"
334: " [reps [begin [end [s]]]]\n");
1.1 deraadt 335: exit(1);
336: }
337:
1.15 otto 338: static int
1.13 deraadt 339: getprec(char *s)
1.1 deraadt 340: {
1.8 pjanzen 341: char *p;
342: char *q;
1.1 deraadt 343:
1.15 otto 344: for (p = s; *p != '\0'; p++)
1.1 deraadt 345: if (*p == '.')
346: break;
1.15 otto 347: if (*p == '\0')
1.1 deraadt 348: return (0);
1.15 otto 349: for (q = ++p; *p != '\0'; p++)
1.1 deraadt 350: if (!isdigit(*p))
351: break;
352: return (p - q);
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.17 ! otto 365: if (*p == '%' && *(p+1) != '%') /* leave %% alone */
! 366: break;
1.8 pjanzen 367: sz = sizeof(format) - strlen(format) - 1;
1.15 otto 368: if (*p == '\0' && !chardata) {
1.8 pjanzen 369: if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
370: errx(1, "-w word too long");
1.15 otto 371: } else if (*p == '\0' && chardata) {
1.8 pjanzen 372: if (strlcpy(p, "%c", sz) >= sz)
373: errx(1, "-w word too long");
1.17 ! otto 374: intdata = true;
1.15 otto 375: } else if (*(p+1) == '\0') {
1.8 pjanzen 376: if (sz <= 0)
377: errx(1, "-w word too long");
1.15 otto 378: /* cannot end in single '%' */
379: strlcat(format, "%", sizeof format);
1.8 pjanzen 380: } else {
1.17 ! otto 381: /*
! 382: * Allow conversion format specifiers of the form
! 383: * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
! 384: * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u}
! 385: */
! 386: p2 = p++;
! 387: dot = hash = space = sign = numbers = 0;
! 388: while (!isalpha(*p)) {
! 389: if (isdigit(*p)) {
! 390: numbers++;
! 391: p++;
! 392: } else if ((*p == '#' && !(numbers|dot|sign|space|
! 393: hash++)) ||
! 394: (*p == ' ' && !(numbers|dot|space++)) ||
! 395: ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
! 396: || (*p == '.' && !(dot++)))
! 397: p++;
! 398: else
! 399: goto fmt_broken;
! 400: }
! 401: if (*p == 'l') {
! 402: longdata = true;
! 403: if (*++p == 'l') {
! 404: if (p[1] != '\0')
! 405: p++;
! 406: goto fmt_broken;
! 407: }
! 408: }
1.1 deraadt 409: switch (*p) {
1.17 ! otto 410: case 'o': case 'u': case 'x': case 'X':
! 411: intdata = nosign = true;
1.1 deraadt 412: break;
1.17 ! otto 413: case 'd': case 'i':
! 414: intdata = true;
1.1 deraadt 415: break;
1.17 ! otto 416: case 'D':
! 417: if (!longdata) {
! 418: intdata = true;
! 419: break;
! 420: }
! 421: case 'O': case 'U':
! 422: if (!longdata) {
! 423: intdata = nosign = true;
! 424: break;
! 425: }
! 426: case 'c':
! 427: if (!(intdata | longdata)) {
! 428: chardata = true;
! 429: break;
! 430: }
! 431: case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
! 432: case '$': case '*':
! 433: goto fmt_broken;
! 434: case 'f': case 'e': case 'g': case 'E': case 'G':
! 435: if (!longdata)
! 436: break;
! 437: /* FALLTHROUGH */
1.8 pjanzen 438: default:
1.17 ! otto 439: fmt_broken:
! 440: *++p = '\0';
! 441: errx(1, "illegal or unsupported format '%s'", p2);
! 442: /* NOTREACHED */
1.1 deraadt 443: }
1.17 ! otto 444: while (*++p != '\0')
! 445: if (*p == '%' && *(p+1) != '\0' && *(p+1) != '%')
! 446: errx(1, "too many conversions");
! 447: else if (*p == '%' && *(p+1) == '%')
! 448: p++;
! 449: else if (*p == '%' && *(p+1) == '\0') {
! 450: strlcat(format, "%", sizeof format);
! 451: break;
1.8 pjanzen 452: }
1.1 deraadt 453: }
454: }