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