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