jot.c revision 48995
1244158Sdteske/*-
2222417Sjulian * Copyright (c) 1993
3222417Sjulian *	The Regents of the University of California.  All rights reserved.
4222417Sjulian *
5222417Sjulian * Redistribution and use in source and binary forms, with or without
6222417Sjulian * modification, are permitted provided that the following conditions
7222417Sjulian * are met:
8222417Sjulian * 1. Redistributions of source code must retain the above copyright
9222417Sjulian *    notice, this list of conditions and the following disclaimer.
10222417Sjulian * 2. Redistributions in binary form must reproduce the above copyright
11222417Sjulian *    notice, this list of conditions and the following disclaimer in the
12222417Sjulian *    documentation and/or other materials provided with the distribution.
13222417Sjulian * 3. All advertising materials mentioning features or use of this software
14222417Sjulian *    must display the following acknowledgement:
15222417Sjulian *	This product includes software developed by the University of
16222417Sjulian *	California, Berkeley and its contributors.
17222417Sjulian * 4. Neither the name of the University nor the names of its contributors
18222417Sjulian *    may be used to endorse or promote products derived from this software
19222417Sjulian *    without specific prior written permission.
20222417Sjulian *
21222417Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22222417Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23222417Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24222417Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25222417Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26222417Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27222417Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28222417Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29222417Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30222417Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31222417Sjulian * SUCH DAMAGE.
32222417Sjulian */
33222417Sjulian
34222417Sjulian#ifndef lint
35222417Sjulianstatic const char copyright[] =
36222417Sjulian"@(#) Copyright (c) 1993\n\
37222417Sjulian	The Regents of the University of California.  All rights reserved.\n";
38222417Sjulian#endif /* not lint */
39222417Sjulian
40222417Sjulian#ifndef lint
41222417Sjulian#if 0
42222417Sjulianstatic char sccsid[] = "@(#)jot.c	8.1 (Berkeley) 6/6/93";
43222417Sjulian#endif
44222417Sjulianstatic const char rcsid[] =
45222417Sjulian	"$Id: jot.c,v 1.9 1999/05/13 12:18:24 kris Exp $";
46222417Sjulian#endif /* not lint */
47222417Sjulian
48222417Sjulian/*
49222417Sjulian * jot - print sequential or random data
50222417Sjulian *
51222417Sjulian * Author:  John Kunze, Office of Comp. Affairs, UCB
52222417Sjulian */
53222417Sjulian
54222417Sjulian#include <ctype.h>
55222417Sjulian#include <err.h>
56222417Sjulian#include <limits.h>
57222417Sjulian#include <stdio.h>
58222417Sjulian#include <stdlib.h>
59222417Sjulian#include <string.h>
60222417Sjulian#include <time.h>
61222417Sjulian#include <unistd.h>
62222417Sjulian
63222417Sjulian#define	REPS_DEF	100
64222417Sjulian#define	BEGIN_DEF	1
65222417Sjulian#define	ENDER_DEF	100
66222417Sjulian#define	STEP_DEF	1
67222417Sjulian
68222417Sjulian#define	isdefault(s)	(strcmp((s), "-") == 0)
69222417Sjulian
70222417Sjuliandouble	begin;
71222417Sjuliandouble	ender;
72222417Sjuliandouble	s;
73222417Sjulianlong	reps;
74222417Sjulianint	randomize;
75222417Sjulianint	infinity;
76222417Sjulianint	boring;
77244158Sdteskeint	prec;
78222417Sjulianint	intdata;
79222417Sjulianint	chardata;
80222417Sjulianint	nosign;
81222417Sjulianint	nofinalnl;
82222417Sjulianchar	*sepstring = "\n";
83222417Sjulianchar	format[BUFSIZ];
84222417Sjulian
85222417Sjulianvoid	getargs __P((int, char *[]));
86222417Sjulianvoid	getformat __P((void));
87222417Sjulianint		getprec __P((char *));
88222417Sjulianvoid	putdata __P((double, long));
89222417Sjulianstatic void usage __P((void));
90222417Sjulian
91222417Sjulianint
92222417Sjulianmain(argc, argv)
93222417Sjulian	int argc;
94222417Sjulian	char *argv[];
95222417Sjulian{
96222417Sjulian	double	xd, yd;
97222417Sjulian	long	id;
98222417Sjulian	register double	*x = &xd;
99222417Sjulian	register double	*y = &yd;
100222417Sjulian	register long	*i = &id;
101222417Sjulian
102222417Sjulian	getargs(argc, argv);
103222417Sjulian	if (randomize) {
104222417Sjulian		*x = (ender - begin) * (ender > begin ? 1 : -1);
105222417Sjulian		for (*i = 1; *i <= reps || infinity; (*i)++) {
106222417Sjulian			*y = (double) arc4random() / ULONG_MAX;
107222417Sjulian			putdata(*y * *x + begin, reps - *i);
108222417Sjulian		}
109222417Sjulian	} else
110222417Sjulian		for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s)
111222417Sjulian			putdata(*x, reps - *i);
112222417Sjulian	if (!nofinalnl)
113222417Sjulian		putchar('\n');
114222417Sjulian	exit(0);
115222417Sjulian}
116222417Sjulian
117222417Sjulianvoid
118222417Sjuliangetargs(ac, av)
119222417Sjulian	int ac;
120222417Sjulian	char *av[];
121222417Sjulian{
122222417Sjulian	register unsigned int	mask = 0;
123222417Sjulian	register int		n = 0;
124222417Sjulian
125222417Sjulian	while (--ac && **++av == '-' && !isdefault(*av))
126222417Sjulian		switch ((*av)[1]) {
127222417Sjulian		case 'r':
128222417Sjulian			randomize = 1;
129222417Sjulian			break;
130222417Sjulian		case 'c':
131222417Sjulian			chardata = 1;
132222417Sjulian			break;
133222417Sjulian		case 'n':
134222417Sjulian			nofinalnl = 1;
135222417Sjulian			break;
136222417Sjulian		case 'b':
137244158Sdteske			boring = 1;
138244158Sdteske		case 'w':
139244158Sdteske			if ((*av)[2])
140244158Sdteske				strcpy(format, *av + 2);
141244158Sdteske			else if (!--ac)
142244158Sdteske				errx(1, "need context word after -w or -b");
143244158Sdteske			else
144244158Sdteske				strcpy(format, *++av);
145244158Sdteske			break;
146244158Sdteske		case 's':
147244158Sdteske			if ((*av)[2])
148244158Sdteske				sepstring = *av + 2;
149222417Sjulian			else if (!--ac)
150222417Sjulian				errx(1, "need string after -s");
151244158Sdteske			else
152244158Sdteske				sepstring = *++av;
153222417Sjulian			break;
154244158Sdteske		case 'p':
155244158Sdteske			if ((*av)[2])
156222417Sjulian				prec = atoi(*av + 2);
157244158Sdteske			else if (!--ac)
158244158Sdteske				errx(1, "need number after -p");
159244158Sdteske			else
160244158Sdteske				prec = atoi(*++av);
161244158Sdteske			if (prec <= 0)
162244158Sdteske				errx(1, "bad precision value");
163244158Sdteske			break;
164244158Sdteske		default:
165222417Sjulian			usage();
166222417Sjulian		}
167222417Sjulian
168244158Sdteske	switch (ac) {	/* examine args right to left, falling thru cases */
169244158Sdteske	case 4:
170222417Sjulian		if (!isdefault(av[3])) {
171			if (!sscanf(av[3], "%lf", &s))
172				errx(1, "bad s value: %s", av[3]);
173			mask |= 01;
174		}
175	case 3:
176		if (!isdefault(av[2])) {
177			if (!sscanf(av[2], "%lf", &ender))
178				ender = av[2][strlen(av[2])-1];
179			mask |= 02;
180			if (!prec)
181				n = getprec(av[2]);
182		}
183	case 2:
184		if (!isdefault(av[1])) {
185			if (!sscanf(av[1], "%lf", &begin))
186				begin = av[1][strlen(av[1])-1];
187			mask |= 04;
188			if (!prec)
189				prec = getprec(av[1]);
190			if (n > prec)		/* maximum precision */
191				prec = n;
192		}
193	case 1:
194		if (!isdefault(av[0])) {
195			if (!sscanf(av[0], "%ld", &reps))
196				errx(1, "bad reps value: %s", av[0]);
197			mask |= 010;
198		}
199		break;
200	case 0:
201		usage();
202	default:
203		errx(1, "too many arguments. What do you mean by %s?", av[4]);
204	}
205	getformat();
206	while (mask)	/* 4 bit mask has 1's where last 4 args were given */
207		switch (mask) {	/* fill in the 0's by default or computation */
208		case 001:
209			reps = REPS_DEF;
210			mask = 011;
211			break;
212		case 002:
213			reps = REPS_DEF;
214			mask = 012;
215			break;
216		case 003:
217			reps = REPS_DEF;
218			mask = 013;
219			break;
220		case 004:
221			reps = REPS_DEF;
222			mask = 014;
223			break;
224		case 005:
225			reps = REPS_DEF;
226			mask = 015;
227			break;
228		case 006:
229			reps = REPS_DEF;
230			mask = 016;
231			break;
232		case 007:
233			if (randomize) {
234				reps = REPS_DEF;
235				mask = 0;
236				break;
237			}
238			if (s == 0.0) {
239				reps = 0;
240				mask = 0;
241				break;
242			}
243			reps = (ender - begin + s) / s;
244			if (reps <= 0)
245				errx(1, "impossible stepsize");
246			mask = 0;
247			break;
248		case 010:
249			begin = BEGIN_DEF;
250			mask = 014;
251			break;
252		case 011:
253			begin = BEGIN_DEF;
254			mask = 015;
255			break;
256		case 012:
257			s = (randomize ? -1.0 : STEP_DEF);
258			mask = 013;
259			break;
260		case 013:
261			if (randomize)
262				begin = BEGIN_DEF;
263			else if (reps == 0)
264				errx(1, "must specify begin if reps == 0");
265			else
266				begin = ender - reps * s + s;
267			mask = 0;
268			break;
269		case 014:
270			s = (randomize ? -1.0 : 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 = -1.0;
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
308void
309putdata(x, notlast)
310	double x;
311	long notlast;
312{
313
314	if (boring)				/* repeated word */
315		printf(format);
316	else if (chardata)			/* character representation */
317		printf(format, (int)x);
318	else if (intdata && nosign)		/* scalar */
319		printf(format, (unsigned long)x);
320	else if (intdata)
321		printf(format, (long)x);
322	else					/* real */
323		printf(format, x);
324	if (notlast != 0)
325		fputs(sepstring, stdout);
326}
327
328static void
329usage()
330{
331	fprintf(stderr, "%s\n%s\n",
332	"usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]",
333	"           [reps [begin [end [s]]]]");
334	exit(1);
335}
336
337int
338getprec(s)
339	char *s;
340{
341	register char	*p;
342	register char	*q;
343
344	for (p = s; *p; p++)
345		if (*p == '.')
346			break;
347	if (!*p)
348		return (0);
349	for (q = ++p; *p; p++)
350		if (!isdigit(*p))
351			break;
352	return (p - q);
353}
354
355void
356getformat()
357{
358	register char	*p;
359	int dot, hash, space, sign, numbers, islong = 0;
360	char *s;
361
362	if (boring)				/* no need to bother */
363		return;
364	for (p = format; *p; p++)		/* look for '%' */
365		if (*p == '%' && *(p+1) != '%')	/* leave %% alone */
366			break;
367	if (!*p && !chardata)
368		sprintf(p, "%%.%df", prec);
369	else if (!*p && chardata) {
370		strcpy(p, "%c");
371		intdata = 1;
372	} else if (!*(p+1))
373		strcat(format, "%");		/* cannot end in single '%' */
374	else {
375		/*
376		 * Allow conversion format specifiers of the form
377		 * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
378		 * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u}
379		 */
380		s = p++;
381		dot = hash = space = sign = numbers = 0;
382		while (!isalpha(*p)) {
383			if (isdigit(*p)) {
384				numbers++;
385				p++;
386			} else if ((*p == '#' && !(numbers|dot|sign|space|
387			    hash++)) ||
388			    (*p == ' ' && !(numbers|dot|space++)) ||
389			    ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
390			    || (*p == '.' && !(dot++)))
391				p++;
392			else if (*p == '$' || *p == '*')
393				errx(1, "unsupported format character %c", *p);
394			else if (*p == '\0')
395				errx(1, "missing format character");
396			else
397				errx(1, "illegal format character %c", *p);
398		}
399		switch (*p) {
400		case 'l':
401			islong = 1;
402			p++;
403			/* FALLTHROUGH */
404		case 'o': case 'u': case 'x': case 'X':
405			intdata = nosign = 1;
406			break;
407		case 'd': case 'i':
408			intdata = 1;
409			break;
410		case 'D':
411			if (!islong) {
412				intdata = 1;
413				break;
414			}
415		case 'O': case 'U':
416			if (!islong) {
417				intdata = nosign = 1;
418				break;
419			}
420		case 'c':
421			if (!(intdata | islong)) {
422				chardata = 1;
423				break;
424			}
425		case 's':
426			errx(1, "cannot convert numeric data to strings");
427			break;
428		case 'h': case 'n': case 'p': case 'q': case 'L':
429		case '$': case '*':
430			errx(1, "unsupported format character %c", *p);
431			/* NOTREACHED */
432		case 'f': case 'e': case 'g': case 'E': case 'G':
433			if (!islong)
434				break;
435			/* FALLTHROUGH */
436		default:
437			*++p = '\0';
438			errx(1, "illegal or unsupported format '%s'", s);
439			/* NOTREACHED */
440		}
441		while (*++p)
442			if (*p == '%' && *(p+1) && *(p+1) != '%')
443				errx(1, "too many conversions");
444			else if (*p == '%' && *(p+1) == '%')
445				p++;
446			else if (*p == '%' && !*(p+1)) {
447				strcat(format, "%");
448				break;
449			}
450	}
451}
452