jot.c revision 1.20 1 /* $NetBSD: jot.c,v 1.20 2008/02/27 22:47:32 dsl Exp $ */
2
3 /*-
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1993\n\
35 The Regents of the University of California. All rights reserved.\n");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93";
41 #endif
42 __RCSID("$NetBSD: jot.c,v 1.20 2008/02/27 22:47:32 dsl Exp $");
43 #endif /* not lint */
44
45 /*
46 * jot - print sequential or random data
47 *
48 * Author: John Kunze, Office of Comp. Affairs, UCB
49 */
50
51 #include <ctype.h>
52 #include <err.h>
53 #include <limits.h>
54 #include <math.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <time.h>
59 #include <unistd.h>
60
61 #define REPS_DEF 100
62 #define BEGIN_DEF 1
63 #define ENDER_DEF 100
64 #define STEP_DEF 1
65
66 #define is_default(s) (strcmp((s), "-") == 0)
67
68 double begin;
69 double ender;
70 double step;
71 long reps;
72 int randomize;
73 int infinity;
74 int boring;
75 int prec = -1;
76 int dox;
77 int chardata;
78 int nofinalnl;
79 const char *sepstring = "\n";
80 char format[BUFSIZ];
81
82 static void getargs(int, char *[]);
83 static void getformat(void);
84 static int getprec(char *);
85 static void putdata(double, long);
86 static void usage(void) __dead;
87
88 int
89 main(int argc, char *argv[])
90 {
91 double x, y;
92 long i;
93
94 getargs(argc, argv);
95 if (randomize) {
96 x = (ender + dox - begin) * (ender > begin ? 1 : -1);
97 srandom((unsigned long) step);
98 for (i = 1; i <= reps || infinity; i++) {
99 y = (double) random() / INT_MAX;
100 putdata(y * x + begin, reps - i);
101 }
102 } else {
103 for (i = 1, x = begin; i <= reps || infinity; i++, x += step)
104 putdata(x, reps - i);
105 }
106 if (!nofinalnl)
107 putchar('\n');
108 exit(0);
109 }
110
111 static void
112 getargs(int argc, char *argv[])
113 {
114 unsigned int mask = 0;
115 int n = 0;
116 char *ep;
117
118 for (;;) {
119 switch (getopt(argc, argv, "b:cnp:rs:w:")) {
120 default:
121 usage();
122 case -1:
123 break;
124 case 'c':
125 chardata = 1;
126 continue;
127 case 'n':
128 nofinalnl = 1;
129 continue;
130 case 'p':
131 prec = strtol(optarg, &ep, 0);
132 if (*ep != 0 || prec < 0)
133 errx(EXIT_FAILURE, "Bad precision value");
134 continue;
135 case 'r':
136 randomize = 1;
137 continue;
138 case 's':
139 sepstring = optarg;
140 continue;
141 case 'b':
142 boring = 1;
143 /* FALLTHROUGH */
144 case 'w':
145 strlcpy(format, optarg, sizeof(format));
146 continue;
147 }
148 break;
149 }
150 argc -= optind;
151 argv += optind;
152
153 switch (argc) { /* examine args right to left, falling thru cases */
154 case 4:
155 if (!is_default(argv[3])) {
156 if (!sscanf(argv[3], "%lf", &step))
157 errx(EXIT_FAILURE, "Bad step value: %s",
158 argv[3]);
159 mask |= 01;
160 }
161 case 3:
162 if (!is_default(argv[2])) {
163 if (!sscanf(argv[2], "%lf", &ender))
164 ender = argv[2][strlen(argv[2])-1];
165 mask |= 02;
166 if (prec < 0)
167 n = getprec(argv[2]);
168 }
169 case 2:
170 if (!is_default(argv[1])) {
171 if (!sscanf(argv[1], "%lf", &begin))
172 begin = argv[1][strlen(argv[1])-1];
173 mask |= 04;
174 if (prec < 0)
175 prec = getprec(argv[1]);
176 if (n > prec) /* maximum precision */
177 prec = n;
178 }
179 case 1:
180 if (!is_default(argv[0])) {
181 if (!sscanf(argv[0], "%ld", &reps))
182 errx(EXIT_FAILURE, "Bad reps value: %s",
183 argv[0]);
184 mask |= 010;
185 }
186 break;
187 case 0:
188 usage();
189 break;
190 default:
191 errx(EXIT_FAILURE,
192 "Too many arguments. What do you mean by %s?", argv[4]);
193 }
194 getformat();
195 while (mask) { /* 4 bit mask has 1's where last 4 args were given */
196 switch (mask) { /* fill in the 0's by default or computation */
197 case 001:
198 reps = REPS_DEF;
199 mask = 011;
200 break;
201 case 002:
202 reps = REPS_DEF;
203 mask = 012;
204 break;
205 case 003:
206 reps = REPS_DEF;
207 mask = 013;
208 break;
209 case 004:
210 reps = REPS_DEF;
211 mask = 014;
212 break;
213 case 005:
214 reps = REPS_DEF;
215 mask = 015;
216 break;
217 case 006:
218 reps = REPS_DEF;
219 mask = 016;
220 break;
221 case 007:
222 if (randomize) {
223 reps = REPS_DEF;
224 mask = 0;
225 break;
226 }
227 if (step == 0.0) {
228 reps = 0;
229 mask = 0;
230 break;
231 }
232 reps = (ender - begin + step) / step;
233 if (reps <= 0)
234 errx(EXIT_FAILURE, "Impossible stepsize");
235 mask = 0;
236 break;
237 case 010:
238 begin = BEGIN_DEF;
239 mask = 014;
240 break;
241 case 011:
242 begin = BEGIN_DEF;
243 mask = 015;
244 break;
245 case 012:
246 step = (randomize ? time(NULL) * getpid() : STEP_DEF);
247 mask = 013;
248 break;
249 case 013:
250 if (randomize)
251 begin = BEGIN_DEF;
252 else if (reps == 0)
253 errx(EXIT_FAILURE,
254 "Must specify begin if reps == 0");
255 begin = ender - reps * step + step;
256 mask = 0;
257 break;
258 case 014:
259 step = (randomize ? time(NULL) * getpid() : STEP_DEF);
260 mask = 015;
261 break;
262 case 015:
263 if (randomize)
264 ender = ENDER_DEF;
265 else
266 ender = begin + reps * step - step;
267 mask = 0;
268 break;
269 case 016:
270 if (randomize)
271 step = time(NULL) * getpid();
272 else if (reps == 0)
273 errx(EXIT_FAILURE,
274 "Infinite sequences cannot be bounded");
275 else if (reps == 1)
276 step = 0.0;
277 else
278 step = (ender - begin) / (reps - 1);
279 mask = 0;
280 break;
281 case 017: /* if reps given and implied, */
282 if (!randomize && step != 0.0) {
283 long t = (ender - begin + step) / step;
284 if (t <= 0)
285 errx(EXIT_FAILURE,
286 "Impossible stepsize");
287 if (t < reps) /* take lesser */
288 reps = t;
289 }
290 mask = 0;
291 break;
292 default:
293 errx(EXIT_FAILURE, "bad mask");
294 }
295 }
296 if (reps == 0)
297 infinity = 1;
298
299 if (prec == -1)
300 prec = 0;
301 }
302
303 static void
304 putdata(double x, long notlast)
305 {
306 long d = floor(x);
307
308 if (boring) /* repeated word */
309 printf("%s", format);
310 else if (dox) /* scalar */
311 printf(format, d);
312 else /* real */
313 printf(format, x);
314 if (notlast != 0)
315 fputs(sepstring, stdout);
316 }
317
318 __dead static void
319 usage(void)
320 {
321 (void)fprintf(stderr, "usage: %s [-cnr] [-b word] [-p precision] "
322 "[-s string] [-w word] [reps [begin [end [step | seed]]]]\n",
323 getprogname());
324 exit(1);
325 }
326
327 static int
328 getprec(char *num_str)
329 {
330
331 num_str = strchr(num_str, '.');
332 if (num_str == NULL)
333 return 0;
334 return strspn(num_str + 1, "0123456789");
335 }
336
337 static void
338 getformat(void)
339 {
340 char *p;
341 size_t sz;
342
343 if (boring) /* no need to bother */
344 return;
345 for (p = format; *p; p++) { /* look for '%' */
346 if (*p == '%') {
347 if (*(p+1) != '%')
348 break;
349 p++; /* leave %% alone */
350 }
351 }
352 sz = sizeof(format) - strlen(format) - 1;
353 if (!*p) {
354 if (chardata || prec == 0) {
355 if (snprintf(p, sz, "%%%s", chardata ? "c" : "ld") >= sz)
356 errx(EXIT_FAILURE, "-w word too long");
357 dox = 1;
358 } else {
359 if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
360 errx(EXIT_FAILURE, "-w word too long");
361 }
362 } else if (!*(p+1)) {
363 if (sz <= 0)
364 errx(EXIT_FAILURE, "-w word too long");
365 strcat(format, "%"); /* cannot end in single '%' */
366 } else {
367 p++; /* skip leading % */
368 for(; *p && !isalpha((unsigned char)*p); p++) {
369 /* allow all valid printf(3) flags, but deny '*' */
370 if (!strchr("0123456789#-+. ", *p))
371 break;
372 }
373 /* Allow 'l' prefix, but no other. */
374 if (*p == 'l')
375 p++;
376 switch (*p) {
377 case 'f': case 'e': case 'g': case '%':
378 case 'E': case 'G':
379 break;
380 case 's':
381 errx(EXIT_FAILURE,
382 "cannot convert numeric data to strings");
383 break;
384 case 'd': case 'o': case 'x': case 'u':
385 case 'D': case 'O': case 'X': case 'U':
386 case 'c': case 'i':
387 dox = 1;
388 break;
389 default:
390 errx(EXIT_FAILURE, "unknown or invalid format `%s'",
391 format);
392 }
393 /* Need to check for trailing stuff to print */
394 for (; *p; p++) /* look for '%' */
395 if (*p == '%') {
396 if (*(p+1) != '%')
397 break;
398 p++; /* leave %% alone */
399 }
400 if (*p)
401 errx(EXIT_FAILURE, "unknown or invalid format `%s'",
402 format);
403 }
404 }
405