jot.c revision 62871
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3527423Scharnierstatic const char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
4127423Scharnier#if 0
421590Srgrimesstatic char sccsid[] = "@(#)jot.c	8.1 (Berkeley) 6/6/93";
4327423Scharnier#endif
4427423Scharnierstatic const char rcsid[] =
4550477Speter  "$FreeBSD: head/usr.bin/jot/jot.c 62871 2000-07-10 06:02:13Z kris $";
461590Srgrimes#endif /* not lint */
471590Srgrimes
481590Srgrimes/*
491590Srgrimes * jot - print sequential or random data
501590Srgrimes *
511590Srgrimes * Author:  John Kunze, Office of Comp. Affairs, UCB
521590Srgrimes */
531590Srgrimes
541590Srgrimes#include <ctype.h>
5527423Scharnier#include <err.h>
561590Srgrimes#include <limits.h>
571590Srgrimes#include <stdio.h>
581590Srgrimes#include <stdlib.h>
591590Srgrimes#include <string.h>
601590Srgrimes#include <time.h>
6123511Sache#include <unistd.h>
621590Srgrimes
631590Srgrimes#define	REPS_DEF	100
641590Srgrimes#define	BEGIN_DEF	1
651590Srgrimes#define	ENDER_DEF	100
661590Srgrimes#define	STEP_DEF	1
671590Srgrimes
681590Srgrimes#define	isdefault(s)	(strcmp((s), "-") == 0)
691590Srgrimes
701590Srgrimesdouble	begin;
711590Srgrimesdouble	ender;
721590Srgrimesdouble	s;
731590Srgrimeslong	reps;
741590Srgrimesint	randomize;
751590Srgrimesint	infinity;
761590Srgrimesint	boring;
771590Srgrimesint	prec;
7855515Ssheldonhint	longdata;
7948995Ssheldonhint	intdata;
801590Srgrimesint	chardata;
8148995Ssheldonhint	nosign;
821590Srgrimesint	nofinalnl;
831590Srgrimeschar	*sepstring = "\n";
841590Srgrimeschar	format[BUFSIZ];
851590Srgrimes
861590Srgrimesvoid	getargs __P((int, char *[]));
871590Srgrimesvoid	getformat __P((void));
8827423Scharnierint		getprec __P((char *));
8955515Ssheldonhint	putdata __P((double, long));
9027423Scharnierstatic void usage __P((void));
911590Srgrimes
921590Srgrimesint
931590Srgrimesmain(argc, argv)
941590Srgrimes	int argc;
951590Srgrimes	char *argv[];
961590Srgrimes{
971590Srgrimes	double	xd, yd;
981590Srgrimes	long	id;
991590Srgrimes	register double	*x = &xd;
1001590Srgrimes	register double	*y = &yd;
1011590Srgrimes	register long	*i = &id;
1021590Srgrimes
1031590Srgrimes	getargs(argc, argv);
1041590Srgrimes	if (randomize) {
1051590Srgrimes		*x = (ender - begin) * (ender > begin ? 1 : -1);
1061590Srgrimes		for (*i = 1; *i <= reps || infinity; (*i)++) {
10747107Skris			*y = (double) arc4random() / ULONG_MAX;
10855515Ssheldonh			if (putdata(*y * *x + begin, reps - *i))
10955515Ssheldonh				errx(1, "range error in conversion");
1101590Srgrimes		}
11148995Ssheldonh	} else
1121590Srgrimes		for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s)
11355515Ssheldonh			if (putdata(*x, reps - *i))
11455515Ssheldonh				errx(1, "range error in conversion");
1151590Srgrimes	if (!nofinalnl)
1161590Srgrimes		putchar('\n');
1171590Srgrimes	exit(0);
1181590Srgrimes}
1191590Srgrimes
1201590Srgrimesvoid
1211590Srgrimesgetargs(ac, av)
1221590Srgrimes	int ac;
1231590Srgrimes	char *av[];
1241590Srgrimes{
1251590Srgrimes	register unsigned int	mask = 0;
1261590Srgrimes	register int		n = 0;
1271590Srgrimes
1281590Srgrimes	while (--ac && **++av == '-' && !isdefault(*av))
1291590Srgrimes		switch ((*av)[1]) {
1301590Srgrimes		case 'r':
1311590Srgrimes			randomize = 1;
1321590Srgrimes			break;
1331590Srgrimes		case 'c':
1341590Srgrimes			chardata = 1;
1351590Srgrimes			break;
1361590Srgrimes		case 'n':
1371590Srgrimes			nofinalnl = 1;
1381590Srgrimes			break;
1391590Srgrimes		case 'b':
1401590Srgrimes			boring = 1;
1411590Srgrimes		case 'w':
1421590Srgrimes			if ((*av)[2])
1431590Srgrimes				strcpy(format, *av + 2);
1441590Srgrimes			else if (!--ac)
14527423Scharnier				errx(1, "need context word after -w or -b");
1461590Srgrimes			else
1471590Srgrimes				strcpy(format, *++av);
1481590Srgrimes			break;
1491590Srgrimes		case 's':
1501590Srgrimes			if ((*av)[2])
15113101Sjoerg				sepstring = *av + 2;
1521590Srgrimes			else if (!--ac)
15327423Scharnier				errx(1, "need string after -s");
1541590Srgrimes			else
15513101Sjoerg				sepstring = *++av;
1561590Srgrimes			break;
1571590Srgrimes		case 'p':
1581590Srgrimes			if ((*av)[2])
1591590Srgrimes				prec = atoi(*av + 2);
1601590Srgrimes			else if (!--ac)
16127423Scharnier				errx(1, "need number after -p");
1621590Srgrimes			else
1631590Srgrimes				prec = atoi(*++av);
1641590Srgrimes			if (prec <= 0)
16527423Scharnier				errx(1, "bad precision value");
1661590Srgrimes			break;
1671590Srgrimes		default:
16827423Scharnier			usage();
1691590Srgrimes		}
1701590Srgrimes
1711590Srgrimes	switch (ac) {	/* examine args right to left, falling thru cases */
1721590Srgrimes	case 4:
1731590Srgrimes		if (!isdefault(av[3])) {
1741590Srgrimes			if (!sscanf(av[3], "%lf", &s))
17527423Scharnier				errx(1, "bad s value: %s", av[3]);
1761590Srgrimes			mask |= 01;
1771590Srgrimes		}
1781590Srgrimes	case 3:
1791590Srgrimes		if (!isdefault(av[2])) {
1801590Srgrimes			if (!sscanf(av[2], "%lf", &ender))
1811590Srgrimes				ender = av[2][strlen(av[2])-1];
1821590Srgrimes			mask |= 02;
1831590Srgrimes			if (!prec)
1841590Srgrimes				n = getprec(av[2]);
1851590Srgrimes		}
1861590Srgrimes	case 2:
1871590Srgrimes		if (!isdefault(av[1])) {
1881590Srgrimes			if (!sscanf(av[1], "%lf", &begin))
1891590Srgrimes				begin = av[1][strlen(av[1])-1];
1901590Srgrimes			mask |= 04;
1911590Srgrimes			if (!prec)
1921590Srgrimes				prec = getprec(av[1]);
1931590Srgrimes			if (n > prec)		/* maximum precision */
1941590Srgrimes				prec = n;
1951590Srgrimes		}
1961590Srgrimes	case 1:
1971590Srgrimes		if (!isdefault(av[0])) {
1981590Srgrimes			if (!sscanf(av[0], "%ld", &reps))
19927423Scharnier				errx(1, "bad reps value: %s", av[0]);
2001590Srgrimes			mask |= 010;
2011590Srgrimes		}
2021590Srgrimes		break;
2031590Srgrimes	case 0:
20427423Scharnier		usage();
2051590Srgrimes	default:
20627423Scharnier		errx(1, "too many arguments. What do you mean by %s?", av[4]);
2071590Srgrimes	}
2081590Srgrimes	getformat();
2091590Srgrimes	while (mask)	/* 4 bit mask has 1's where last 4 args were given */
2101590Srgrimes		switch (mask) {	/* fill in the 0's by default or computation */
2111590Srgrimes		case 001:
2121590Srgrimes			reps = REPS_DEF;
2131590Srgrimes			mask = 011;
2141590Srgrimes			break;
2151590Srgrimes		case 002:
2161590Srgrimes			reps = REPS_DEF;
2171590Srgrimes			mask = 012;
2181590Srgrimes			break;
2191590Srgrimes		case 003:
2201590Srgrimes			reps = REPS_DEF;
2211590Srgrimes			mask = 013;
2221590Srgrimes			break;
2231590Srgrimes		case 004:
2241590Srgrimes			reps = REPS_DEF;
2251590Srgrimes			mask = 014;
2261590Srgrimes			break;
2271590Srgrimes		case 005:
2281590Srgrimes			reps = REPS_DEF;
2291590Srgrimes			mask = 015;
2301590Srgrimes			break;
2311590Srgrimes		case 006:
2321590Srgrimes			reps = REPS_DEF;
2331590Srgrimes			mask = 016;
2341590Srgrimes			break;
2351590Srgrimes		case 007:
2361590Srgrimes			if (randomize) {
2371590Srgrimes				reps = REPS_DEF;
2381590Srgrimes				mask = 0;
2391590Srgrimes				break;
2401590Srgrimes			}
2411590Srgrimes			if (s == 0.0) {
2421590Srgrimes				reps = 0;
2431590Srgrimes				mask = 0;
2441590Srgrimes				break;
2451590Srgrimes			}
2461590Srgrimes			reps = (ender - begin + s) / s;
2471590Srgrimes			if (reps <= 0)
24827423Scharnier				errx(1, "impossible stepsize");
2491590Srgrimes			mask = 0;
2501590Srgrimes			break;
2511590Srgrimes		case 010:
2521590Srgrimes			begin = BEGIN_DEF;
2531590Srgrimes			mask = 014;
2541590Srgrimes			break;
2551590Srgrimes		case 011:
2561590Srgrimes			begin = BEGIN_DEF;
2571590Srgrimes			mask = 015;
2581590Srgrimes			break;
2591590Srgrimes		case 012:
26024419Sache			s = (randomize ? -1.0 : STEP_DEF);
2611590Srgrimes			mask = 013;
2621590Srgrimes			break;
2631590Srgrimes		case 013:
2641590Srgrimes			if (randomize)
2651590Srgrimes				begin = BEGIN_DEF;
2661590Srgrimes			else if (reps == 0)
26727423Scharnier				errx(1, "must specify begin if reps == 0");
26824419Sache			else
26924419Sache				begin = ender - reps * s + s;
2701590Srgrimes			mask = 0;
2711590Srgrimes			break;
2721590Srgrimes		case 014:
27324419Sache			s = (randomize ? -1.0 : STEP_DEF);
2741590Srgrimes			mask = 015;
2751590Srgrimes			break;
2761590Srgrimes		case 015:
2771590Srgrimes			if (randomize)
2781590Srgrimes				ender = ENDER_DEF;
2791590Srgrimes			else
2801590Srgrimes				ender = begin + reps * s - s;
2811590Srgrimes			mask = 0;
2821590Srgrimes			break;
2831590Srgrimes		case 016:
2841590Srgrimes			if (randomize)
28524419Sache				s = -1.0;
2861590Srgrimes			else if (reps == 0)
28727423Scharnier				errx(1, "infinite sequences cannot be bounded");
2881590Srgrimes			else if (reps == 1)
2891590Srgrimes				s = 0.0;
2901590Srgrimes			else
2911590Srgrimes				s = (ender - begin) / (reps - 1);
2921590Srgrimes			mask = 0;
2931590Srgrimes			break;
2941590Srgrimes		case 017:		/* if reps given and implied, */
2951590Srgrimes			if (!randomize && s != 0.0) {
2961590Srgrimes				long t = (ender - begin + s) / s;
2971590Srgrimes				if (t <= 0)
29827423Scharnier					errx(1, "impossible stepsize");
2991590Srgrimes				if (t < reps)		/* take lesser */
3001590Srgrimes					reps = t;
3011590Srgrimes			}
3021590Srgrimes			mask = 0;
3031590Srgrimes			break;
3041590Srgrimes		default:
30527423Scharnier			errx(1, "bad mask");
3061590Srgrimes		}
3071590Srgrimes	if (reps == 0)
3081590Srgrimes		infinity = 1;
3091590Srgrimes}
3101590Srgrimes
31155515Ssheldonhint
3121590Srgrimesputdata(x, notlast)
3131590Srgrimes	double x;
3141590Srgrimes	long notlast;
3151590Srgrimes{
3161590Srgrimes
31755515Ssheldonh	if (boring)
31862871Skris		printf("%s", format);
31955515Ssheldonh	else if (longdata && nosign) {
32055515Ssheldonh		if (x <= (double)ULONG_MAX && x >= (double)0)
32155515Ssheldonh			printf(format, (unsigned long)x);
32255515Ssheldonh		else
32355515Ssheldonh			return (1);
32455515Ssheldonh	} else if (longdata) {
32555515Ssheldonh		if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
32655515Ssheldonh			printf(format, (long)x);
32755515Ssheldonh		else
32855515Ssheldonh			return (1);
32955515Ssheldonh	} else if (chardata || (intdata && !nosign)) {
33055515Ssheldonh		if (x <= (double)INT_MAX && x >= (double)INT_MIN)
33155515Ssheldonh			printf(format, (int)x);
33255515Ssheldonh		else
33355515Ssheldonh			return (1);
33455515Ssheldonh	} else if (intdata) {
33555515Ssheldonh		if (x <= (double)UINT_MAX && x >= (double)0)
33655515Ssheldonh			printf(format, (unsigned int)x);
33755515Ssheldonh		else
33855515Ssheldonh			return (1);
33955515Ssheldonh
34055515Ssheldonh	} else
3411590Srgrimes		printf(format, x);
3421590Srgrimes	if (notlast != 0)
3431590Srgrimes		fputs(sepstring, stdout);
34455515Ssheldonh
34555515Ssheldonh	return (0);
3461590Srgrimes}
3471590Srgrimes
34827423Scharnierstatic void
34927423Scharnierusage()
3501590Srgrimes{
35127423Scharnier	fprintf(stderr, "%s\n%s\n",
35230908Scharnier	"usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]",
35330908Scharnier	"           [reps [begin [end [s]]]]");
3541590Srgrimes	exit(1);
3551590Srgrimes}
3561590Srgrimes
3571590Srgrimesint
3581590Srgrimesgetprec(s)
3591590Srgrimes	char *s;
3601590Srgrimes{
3611590Srgrimes	register char	*p;
3621590Srgrimes	register char	*q;
3631590Srgrimes
3641590Srgrimes	for (p = s; *p; p++)
3651590Srgrimes		if (*p == '.')
3661590Srgrimes			break;
3671590Srgrimes	if (!*p)
3681590Srgrimes		return (0);
3691590Srgrimes	for (q = ++p; *p; p++)
3701590Srgrimes		if (!isdigit(*p))
3711590Srgrimes			break;
3721590Srgrimes	return (p - q);
3731590Srgrimes}
3741590Srgrimes
3751590Srgrimesvoid
3761590Srgrimesgetformat()
3771590Srgrimes{
3781590Srgrimes	register char	*p;
37955515Ssheldonh	int dot, hash, space, sign, numbers = 0;
38048995Ssheldonh	char *s;
3811590Srgrimes
3821590Srgrimes	if (boring)				/* no need to bother */
3831590Srgrimes		return;
3841590Srgrimes	for (p = format; *p; p++)		/* look for '%' */
3851590Srgrimes		if (*p == '%' && *(p+1) != '%')	/* leave %% alone */
3861590Srgrimes			break;
3871590Srgrimes	if (!*p && !chardata)
3881590Srgrimes		sprintf(p, "%%.%df", prec);
3891590Srgrimes	else if (!*p && chardata) {
3901590Srgrimes		strcpy(p, "%c");
39148995Ssheldonh		intdata = 1;
39248995Ssheldonh	} else if (!*(p+1))
3931590Srgrimes		strcat(format, "%");		/* cannot end in single '%' */
3941590Srgrimes	else {
39548995Ssheldonh		/*
39648995Ssheldonh		 * Allow conversion format specifiers of the form
39748995Ssheldonh		 * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
39848995Ssheldonh		 * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u}
39948995Ssheldonh		 */
40048995Ssheldonh		s = p++;
40148995Ssheldonh		dot = hash = space = sign = numbers = 0;
40248995Ssheldonh		while (!isalpha(*p)) {
40348995Ssheldonh			if (isdigit(*p)) {
40448995Ssheldonh				numbers++;
40548995Ssheldonh				p++;
40648995Ssheldonh			} else if ((*p == '#' && !(numbers|dot|sign|space|
40748995Ssheldonh			    hash++)) ||
40848995Ssheldonh			    (*p == ' ' && !(numbers|dot|space++)) ||
40948995Ssheldonh			    ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
41048995Ssheldonh			    || (*p == '.' && !(dot++)))
41148995Ssheldonh				p++;
41248995Ssheldonh			else
41355515Ssheldonh				goto fmt_broken;
41448995Ssheldonh		}
41555515Ssheldonh		if (*p == 'l') {
41655515Ssheldonh			longdata = 1;
41755515Ssheldonh			if (*++p == 'l') {
41855515Ssheldonh				if (p[1] != '\0')
41955515Ssheldonh					p++;
42055515Ssheldonh				goto fmt_broken;
42155515Ssheldonh			}
42255515Ssheldonh		}
42348995Ssheldonh		switch (*p) {
42448995Ssheldonh		case 'o': case 'u': case 'x': case 'X':
42548995Ssheldonh			intdata = nosign = 1;
4261590Srgrimes			break;
42748995Ssheldonh		case 'd': case 'i':
42848995Ssheldonh			intdata = 1;
42948995Ssheldonh			break;
43048995Ssheldonh		case 'D':
43155515Ssheldonh			if (!longdata) {
43248995Ssheldonh				intdata = 1;
43348995Ssheldonh				break;
43448995Ssheldonh			}
43548995Ssheldonh		case 'O': case 'U':
43655515Ssheldonh			if (!longdata) {
43748995Ssheldonh				intdata = nosign = 1;
43848995Ssheldonh				break;
43948995Ssheldonh			}
44048995Ssheldonh		case 'c':
44155515Ssheldonh			if (!(intdata | longdata)) {
44248995Ssheldonh				chardata = 1;
44348995Ssheldonh				break;
44448995Ssheldonh			}
44555515Ssheldonh		case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
44648995Ssheldonh		case '$': case '*':
44755515Ssheldonh			goto fmt_broken;
44848995Ssheldonh		case 'f': case 'e': case 'g': case 'E': case 'G':
44955515Ssheldonh			if (!longdata)
45048995Ssheldonh				break;
45148995Ssheldonh			/* FALLTHROUGH */
4521590Srgrimes		default:
45355515Ssheldonhfmt_broken:
45448995Ssheldonh			*++p = '\0';
45548995Ssheldonh			errx(1, "illegal or unsupported format '%s'", s);
45648995Ssheldonh			/* NOTREACHED */
4571590Srgrimes		}
45848995Ssheldonh		while (*++p)
45948995Ssheldonh			if (*p == '%' && *(p+1) && *(p+1) != '%')
46048995Ssheldonh				errx(1, "too many conversions");
46148995Ssheldonh			else if (*p == '%' && *(p+1) == '%')
46248995Ssheldonh				p++;
46348995Ssheldonh			else if (*p == '%' && !*(p+1)) {
46448995Ssheldonh				strcat(format, "%");
46548995Ssheldonh				break;
46648995Ssheldonh			}
4671590Srgrimes	}
4681590Srgrimes}
469