newsyslog(8): Further reduce differences with FreeBSD.
[dragonfly.git] / usr.bin / jot / jot.c
bloba075f27d13d940b7b02f89342da954b8b852c702
1 /*-
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 * @(#) Copyright (c) 1993 The Regents of the University of California. All rights reserved.
30 * @(#)jot.c 8.1 (Berkeley) 6/6/93
31 * $FreeBSD: src/usr.bin/jot/jot.c,v 1.13.2.3 2001/12/17 13:49:50 gallatin Exp $
35 * jot - print sequential or random data
37 * Author: John Kunze, Office of Comp. Affairs, UCB
40 #include <ctype.h>
41 #include <err.h>
42 #include <limits.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdint.h>
46 #include <string.h>
47 #include <time.h>
48 #include <unistd.h>
50 #define REPS_DEF 100
51 #define BEGIN_DEF 1
52 #define ENDER_DEF 100
53 #define STEP_DEF 1
55 #define is_default(s) (strcmp((s), "-") == 0)
57 double begin;
58 double ender;
59 double s;
60 long reps;
61 int randomize;
62 int infinity;
63 int boring;
64 int prec;
65 int longdata;
66 int intdata;
67 int chardata;
68 int nosign;
69 int nofinalnl;
70 const char *sepstring = "\n";
71 char format[BUFSIZ];
73 void getformat(void);
74 int getprec(char *);
75 int putdata(double, long);
76 static void usage(void) __dead2;
78 int
79 main(int argc, char **argv)
81 double xd, yd;
82 long id;
83 double *x = &xd;
84 double *y = &yd;
85 long *i = &id;
86 unsigned int mask = 0;
87 int n = 0;
88 int ch;
90 while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1)
91 switch ((char)ch) {
92 case 'r':
93 randomize = 1;
94 break;
95 case 'c':
96 chardata = 1;
97 break;
98 case 'n':
99 nofinalnl = 1;
100 break;
101 case 'b':
102 boring = 1;
103 /* FALLTHROUGH */
104 case 'w':
105 if (strlcpy(format, optarg, sizeof(format)) >=
106 sizeof(format))
107 errx(1, "-%c word too long", ch);
108 break;
109 case 's':
110 sepstring = optarg;
111 break;
112 case 'p':
113 prec = atoi(optarg);
114 if (prec <= 0)
115 errx(1, "bad precision value");
116 break;
117 default:
118 usage();
120 argc -= optind;
121 argv += optind;
123 switch (argc) { /* examine args right to left, falling thru cases */
124 case 4:
125 if (!is_default(argv[3])) {
126 if (!sscanf(argv[3], "%lf", &s))
127 errx(1, "bad s value: %s", argv[3]);
128 mask |= 01;
130 case 3:
131 if (!is_default(argv[2])) {
132 if (!sscanf(argv[2], "%lf", &ender))
133 ender = argv[2][strlen(argv[2])-1];
134 mask |= 02;
135 if (!prec)
136 n = getprec(argv[2]);
138 case 2:
139 if (!is_default(argv[1])) {
140 if (!sscanf(argv[1], "%lf", &begin))
141 begin = argv[1][strlen(argv[1])-1];
142 mask |= 04;
143 if (!prec)
144 prec = getprec(argv[1]);
145 if (n > prec) /* maximum precision */
146 prec = n;
148 case 1:
149 if (!is_default(argv[0])) {
150 if (!sscanf(argv[0], "%ld", &reps))
151 errx(1, "bad reps value: %s", argv[0]);
152 mask |= 010;
154 break;
155 case 0:
156 usage();
157 default:
158 errx(1, "too many arguments. What do you mean by %s?",
159 argv[4]);
161 getformat();
162 while (mask) /* 4 bit mask has 1's where last 4 args were given */
163 switch (mask) { /* fill in the 0's by default or computation */
164 case 001:
165 reps = REPS_DEF;
166 mask = 011;
167 break;
168 case 002:
169 reps = REPS_DEF;
170 mask = 012;
171 break;
172 case 003:
173 reps = REPS_DEF;
174 mask = 013;
175 break;
176 case 004:
177 reps = REPS_DEF;
178 mask = 014;
179 break;
180 case 005:
181 reps = REPS_DEF;
182 mask = 015;
183 break;
184 case 006:
185 reps = REPS_DEF;
186 mask = 016;
187 break;
188 case 007:
189 if (randomize) {
190 reps = REPS_DEF;
191 mask = 0;
192 break;
194 if (s == 0.0) {
195 reps = 0;
196 mask = 0;
197 break;
199 reps = (ender - begin + s) / s;
200 if (reps <= 0)
201 errx(1, "impossible stepsize");
202 mask = 0;
203 break;
204 case 010:
205 begin = BEGIN_DEF;
206 mask = 014;
207 break;
208 case 011:
209 begin = BEGIN_DEF;
210 mask = 015;
211 break;
212 case 012:
213 s = (randomize ? time(NULL) : STEP_DEF);
214 mask = 013;
215 break;
216 case 013:
217 if (randomize)
218 begin = BEGIN_DEF;
219 else if (reps == 0)
220 errx(1, "must specify begin if reps == 0");
221 begin = ender - reps * s + s;
222 mask = 0;
223 break;
224 case 014:
225 s = (randomize ? -1.0 : STEP_DEF);
226 mask = 015;
227 break;
228 case 015:
229 if (randomize)
230 ender = ENDER_DEF;
231 else
232 ender = begin + reps * s - s;
233 mask = 0;
234 break;
235 case 016:
236 if (randomize)
237 s = -1.0;
238 else if (reps == 0)
239 errx(1, "infinite sequences cannot be bounded");
240 else if (reps == 1)
241 s = 0.0;
242 else
243 s = (ender - begin) / (reps - 1);
244 mask = 0;
245 break;
246 case 017: /* if reps given and implied, */
247 if (!randomize && s != 0.0) {
248 long t = (ender - begin + s) / s;
249 if (t <= 0)
250 errx(1, "impossible stepsize");
251 if (t < reps) /* take lesser */
252 reps = t;
254 mask = 0;
255 break;
256 default:
257 errx(1, "bad mask");
259 if (reps == 0)
260 infinity = 1;
261 if (randomize) {
262 *x = (ender - begin) * (ender > begin ? 1 : -1);
263 for (*i = 1; *i <= reps || infinity; (*i)++) {
264 *y = arc4random() / (double)0xffffffffU;
265 if (putdata(*y * *x + begin, reps - *i))
266 errx(1, "range error in conversion");
268 } else
269 for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s)
270 if (putdata(*x, reps - *i))
271 errx(1, "range error in conversion");
272 if (!nofinalnl)
273 putchar('\n');
274 exit(0);
278 putdata(double x, long notlast)
281 if (boring)
282 printf("%s", format);
283 else if (longdata && nosign) {
284 if (x <= (double)ULONG_MAX && x >= (double)0)
285 printf(format, (unsigned long)x);
286 else
287 return (1);
288 } else if (longdata) {
289 if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
290 printf(format, (long)x);
291 else
292 return (1);
293 } else if (chardata || (intdata && !nosign)) {
294 if (x <= (double)INT_MAX && x >= (double)INT_MIN)
295 printf(format, (int)x);
296 else
297 return (1);
298 } else if (intdata) {
299 if (x <= (double)UINT_MAX && x >= (double)0)
300 printf(format, (unsigned int)x);
301 else
302 return (1);
304 } else
305 printf(format, x);
306 if (notlast != 0)
307 fputs(sepstring, stdout);
309 return (0);
312 static void
313 usage(void)
315 fprintf(stderr, "%s\n%s\n",
316 "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]",
317 " [reps [begin [end [s]]]]");
318 exit(1);
322 getprec(char *str)
324 char *p;
325 char *q;
327 for (p = str; *p; p++)
328 if (*p == '.')
329 break;
330 if (!*p)
331 return (0);
332 for (q = ++p; *p; p++)
333 if (!isdigit(*p))
334 break;
335 return (p - q);
338 void
339 getformat(void)
341 char *p, *p2;
342 int dot, hash, space, sign, numbers = 0;
343 size_t sz;
345 if (boring) /* no need to bother */
346 return;
347 for (p = format; *p; p++) /* look for '%' */
348 if (*p == '%' && *(p+1) != '%') /* leave %% alone */
349 break;
350 sz = sizeof(format) - strlen(format) - 1;
351 if (!*p && !chardata) {
352 if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
353 errx(1, "-w word too long");
354 } else if (!*p && chardata) {
355 if (strlcpy(p, "%c", sz) >= sz)
356 errx(1, "-w word too long");
357 intdata = 1;
358 } else if (!*(p+1)) {
359 if (sz <= 0)
360 errx(1, "-w word too long");
361 strcat(format, "%"); /* cannot end in single '%' */
362 } else {
364 * Allow conversion format specifiers of the form
365 * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
366 * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u}
368 p2 = p++;
369 dot = hash = space = sign = numbers = 0;
370 while (!isalpha(*p)) {
371 if (isdigit(*p)) {
372 numbers++;
373 p++;
374 } else if ((*p == '#' && !(numbers|dot|sign|space|
375 hash++)) ||
376 (*p == ' ' && !(numbers|dot|space++)) ||
377 ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
378 || (*p == '.' && !(dot++)))
379 p++;
380 else
381 goto fmt_broken;
383 if (*p == 'l') {
384 longdata = 1;
385 if (*++p == 'l') {
386 if (p[1] != '\0')
387 p++;
388 goto fmt_broken;
391 switch (*p) {
392 case 'o': case 'u': case 'x': case 'X':
393 intdata = nosign = 1;
394 break;
395 case 'd': case 'i':
396 intdata = 1;
397 break;
398 case 'D':
399 if (!longdata) {
400 intdata = 1;
401 break;
403 case 'O': case 'U':
404 if (!longdata) {
405 intdata = nosign = 1;
406 break;
408 case 'c':
409 if (!(intdata | longdata)) {
410 chardata = 1;
411 break;
413 case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
414 case '$': case '*':
415 goto fmt_broken;
416 case 'f': case 'e': case 'g': case 'E': case 'G':
417 if (!longdata)
418 break;
419 /* FALLTHROUGH */
420 default:
421 fmt_broken:
422 *++p = '\0';
423 errx(1, "illegal or unsupported format '%s'", p2);
424 /* NOTREACHED */
426 while (*++p)
427 if (*p == '%' && *(p+1) && *(p+1) != '%')
428 errx(1, "too many conversions");
429 else if (*p == '%' && *(p+1) == '%')
430 p++;
431 else if (*p == '%' && !*(p+1)) {
432 strcat(format, "%");
433 break;