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