jot.c revision 1.18 1 /* $NetBSD: jot.c,v 1.18 2008/02/23 23:59:59 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.18 2008/02/23 23:59:59 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 char sepstring[BUFSIZ] = "\n";
80 char format[BUFSIZ];
81
82 void getargs(int, char *[]);
83 void getformat(void);
84 int getprec(char *);
85 int main(int, char **);
86 void putdata(double, long);
87 static void usage(void);
88
89 int
90 main(int argc, char *argv[])
91 {
92 double x, y;
93 long i;
94
95 getargs(argc, argv);
96 if (randomize) {
97 x = (ender + dox - begin) * (ender > begin ? 1 : -1);
98 srandom((unsigned long) step);
99 for (i = 1; i <= reps || infinity; i++) {
100 y = (double) random() / INT_MAX;
101 putdata(y * x + begin, reps - i);
102 }
103 } else
104 for (i = 1, x = begin; i <= reps || infinity; i++, x += step)
105 putdata(x, reps - i);
106 if (!nofinalnl)
107 putchar('\n');
108 exit(0);
109 }
110
111 void
112 getargs(int argc, char *argv[])
113 {
114 unsigned int mask = 0;
115 int n = 0;
116
117 while (--argc && **++argv == '-' && !is_default(*argv)) {
118 switch ((*argv)[1]) {
119 case 'r':
120 randomize = 1;
121 break;
122 case 'c':
123 chardata = 1;
124 break;
125 case 'n':
126 nofinalnl = 1;
127 break;
128 case 'b':
129 boring = 1;
130 case 'w':
131 if ((*argv)[2])
132 strlcpy(format, *argv + 2, sizeof(format));
133 else if (!--argc)
134 errx(1, "Need context word after -w or -b");
135 else
136 strlcpy(format, *++argv, sizeof(format));
137 break;
138 case 's':
139 if ((*argv)[2])
140 strlcpy(sepstring, *argv + 2, sizeof(sepstring));
141 else if (!--argc)
142 errx(1, "Need string after -s");
143 else
144 strlcpy(sepstring, *++argv, sizeof(sepstring));
145 break;
146 case 'p':
147 if ((*argv)[2])
148 prec = atoi(*argv + 2);
149 else if (!--argc)
150 errx(1, "Need number after -p");
151 else
152 prec = atoi(*++argv);
153 if (prec < 0)
154 errx(1, "Bad precision value");
155 break;
156 default:
157 warnx("unknown option `%s'", *argv);
158 usage();
159 }
160 }
161
162 switch (argc) { /* examine args right to left, falling thru cases */
163 case 4:
164 if (!is_default(argv[3])) {
165 if (!sscanf(argv[3], "%lf", &step))
166 errx(1, "Bad step value: %s", argv[3]);
167 mask |= 01;
168 }
169 case 3:
170 if (!is_default(argv[2])) {
171 if (!sscanf(argv[2], "%lf", &ender))
172 ender = argv[2][strlen(argv[2])-1];
173 mask |= 02;
174 if (prec < 0)
175 n = getprec(argv[2]);
176 }
177 case 2:
178 if (!is_default(argv[1])) {
179 if (!sscanf(argv[1], "%lf", &begin))
180 begin = argv[1][strlen(argv[1])-1];
181 mask |= 04;
182 if (prec < 0)
183 prec = getprec(argv[1]);
184 if (n > prec) /* maximum precision */
185 prec = n;
186 }
187 case 1:
188 if (!is_default(argv[0])) {
189 if (!sscanf(argv[0], "%ld", &reps))
190 errx(1, "Bad reps value: %s", argv[0]);
191 mask |= 010;
192 }
193 break;
194 case 0:
195 usage();
196 break;
197 default:
198 errx(1, "Too many arguments. What do you mean by %s?", argv[4]);
199 }
200 getformat();
201 while (mask) { /* 4 bit mask has 1's where last 4 args were given */
202 switch (mask) { /* fill in the 0's by default or computation */
203 case 001:
204 reps = REPS_DEF;
205 mask = 011;
206 break;
207 case 002:
208 reps = REPS_DEF;
209 mask = 012;
210 break;
211 case 003:
212 reps = REPS_DEF;
213 mask = 013;
214 break;
215 case 004:
216 reps = REPS_DEF;
217 mask = 014;
218 break;
219 case 005:
220 reps = REPS_DEF;
221 mask = 015;
222 break;
223 case 006:
224 reps = REPS_DEF;
225 mask = 016;
226 break;
227 case 007:
228 if (randomize) {
229 reps = REPS_DEF;
230 mask = 0;
231 break;
232 }
233 if (step == 0.0) {
234 reps = 0;
235 mask = 0;
236 break;
237 }
238 reps = (ender - begin + step) / step;
239 if (reps <= 0)
240 errx(1, "Impossible stepsize");
241 mask = 0;
242 break;
243 case 010:
244 begin = BEGIN_DEF;
245 mask = 014;
246 break;
247 case 011:
248 begin = BEGIN_DEF;
249 mask = 015;
250 break;
251 case 012:
252 step = (randomize ? time(NULL) * getpid() : STEP_DEF);
253 mask = 013;
254 break;
255 case 013:
256 if (randomize)
257 begin = BEGIN_DEF;
258 else if (reps == 0)
259 errx(1, "Must specify begin if reps == 0");
260 begin = ender - reps * step + step;
261 mask = 0;
262 break;
263 case 014:
264 step = (randomize ? time(NULL) * getpid() : STEP_DEF);
265 mask = 015;
266 break;
267 case 015:
268 if (randomize)
269 ender = ENDER_DEF;
270 else
271 ender = begin + reps * step - step;
272 mask = 0;
273 break;
274 case 016:
275 if (randomize)
276 step = time(NULL) * getpid();
277 else if (reps == 0)
278 errx(1, "Infinite sequences cannot be bounded");
279 else if (reps == 1)
280 step = 0.0;
281 else
282 step = (ender - begin) / (reps - 1);
283 mask = 0;
284 break;
285 case 017: /* if reps given and implied, */
286 if (!randomize && step != 0.0) {
287 long t = (ender - begin + step) / step;
288 if (t <= 0)
289 errx(1, "Impossible stepsize");
290 if (t < reps) /* take lesser */
291 reps = t;
292 }
293 mask = 0;
294 break;
295 default:
296 errx(1, "bad mask");
297 }
298 }
299 if (reps == 0)
300 infinity = 1;
301
302 if (prec == -1)
303 prec = 0;
304 }
305
306 void
307 putdata(double x, long notlast)
308 {
309 long d = x;
310
311 if (boring) /* repeated word */
312 printf("%s", format);
313 else if (dox) /* scalar */
314 printf(format, d);
315 else /* real */
316 printf(format, x);
317 if (notlast != 0)
318 fputs(sepstring, stdout);
319 }
320
321 static void
322 usage(void)
323 {
324 (void)fprintf(stderr, "usage: %s [-cnr] [-b word] [-p precision] "
325 "[-s string] [-w word] [reps [begin [end [step]]]]\n", getprogname());
326 exit(1);
327 }
328
329 int
330 getprec(char *s)
331 {
332 char *p;
333 char *q;
334
335 for (p = s; *p; p++)
336 if (*p == '.')
337 break;
338 if (!*p)
339 return (0);
340 for (q = ++p; *p; p++)
341 if (!isdigit((unsigned char)*p))
342 break;
343 return (p - q);
344 }
345
346 void
347 getformat(void)
348 {
349 char *p;
350 size_t sz;
351
352 if (boring) /* no need to bother */
353 return;
354 for (p = format; *p; p++) /* look for '%' */
355 if (*p == '%') {
356 if (*(p+1) != '%')
357 break;
358 p++; /* leave %% alone */
359 }
360 sz = sizeof(format) - strlen(format) - 1;
361 if (!*p) {
362 if (chardata || prec == 0) {
363 if (snprintf(p, sz, "%%%s", chardata ? "c" : "ld") >= sz)
364 errx(1, "-w word too long");
365 dox = 1;
366 } else {
367 if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
368 errx(1, "-w word too long");
369 }
370 } else if (!*(p+1)) {
371 if (sz <= 0)
372 errx(1, "-w word too long");
373 strcat(format, "%"); /* cannot end in single '%' */
374 } else {
375 p++; /* skip leading % */
376 for(; *p && !isalpha((unsigned char)*p); p++) {
377 /* allow all valid printf(3) flags, but deny '*' */
378 if (!strchr("0123456789#-+. ", *p))
379 break;
380 }
381 /* Allow 'l' prefix, but no other. */
382 if (*p == 'l')
383 p++;
384 switch (*p) {
385 case 'f': case 'e': case 'g': case '%':
386 case 'E': case 'G':
387 break;
388 case 's':
389 errx(1, "cannot convert numeric data to strings");
390 break;
391 case 'd': case 'o': case 'x': case 'u':
392 case 'D': case 'O': case 'X': case 'U':
393 case 'c': case 'i':
394 dox = 1;
395 break;
396 default:
397 errx(1, "unknown or invalid format `%s'", format);
398 }
399 /* Need to check for trailing stuff to print */
400 for (; *p; p++) /* look for '%' */
401 if (*p == '%') {
402 if (*(p+1) != '%')
403 break;
404 p++; /* leave %% alone */
405 }
406 if (*p)
407 errx(1, "unknown or invalid format `%s'", format);
408 }
409 }
410