xref: /netbsd-src/usr.bin/jot/jot.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: jot.c,v 1.11 2004/01/05 23:23:34 jmmv 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.11 2004/01/05 23:23:34 jmmv 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