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