1*5dc82c03Skamil /* $NetBSD: jot.c,v 1.28 2020/06/14 01:26:46 kamil Exp $ */
26e0c4dedSjtc
39636069cSjtc /*-
49636069cSjtc * Copyright (c) 1993
59636069cSjtc * The Regents of the University of California. All rights reserved.
69636069cSjtc *
79636069cSjtc * Redistribution and use in source and binary forms, with or without
89636069cSjtc * modification, are permitted provided that the following conditions
99636069cSjtc * are met:
109636069cSjtc * 1. Redistributions of source code must retain the above copyright
119636069cSjtc * notice, this list of conditions and the following disclaimer.
129636069cSjtc * 2. Redistributions in binary form must reproduce the above copyright
139636069cSjtc * notice, this list of conditions and the following disclaimer in the
149636069cSjtc * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
169636069cSjtc * may be used to endorse or promote products derived from this software
179636069cSjtc * without specific prior written permission.
189636069cSjtc *
199636069cSjtc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209636069cSjtc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219636069cSjtc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229636069cSjtc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239636069cSjtc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249636069cSjtc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259636069cSjtc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269636069cSjtc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279636069cSjtc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289636069cSjtc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299636069cSjtc * SUCH DAMAGE.
309636069cSjtc */
319636069cSjtc
32ac4e9aa7Slukem #include <sys/cdefs.h>
339636069cSjtc #ifndef lint
3498e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1993\
3598e5374cSlukem The Regents of the University of California. All rights reserved.");
369636069cSjtc #endif /* not lint */
379636069cSjtc
389636069cSjtc #ifndef lint
396e0c4dedSjtc #if 0
409636069cSjtc static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93";
416e0c4dedSjtc #endif
42*5dc82c03Skamil __RCSID("$NetBSD: jot.c,v 1.28 2020/06/14 01:26:46 kamil Exp $");
439636069cSjtc #endif /* not lint */
449636069cSjtc
459636069cSjtc /*
469636069cSjtc * jot - print sequential or random data
479636069cSjtc *
489636069cSjtc * Author: John Kunze, Office of Comp. Affairs, UCB
499636069cSjtc */
509636069cSjtc
519636069cSjtc #include <ctype.h>
52ac4e9aa7Slukem #include <err.h>
539636069cSjtc #include <limits.h>
54d8817d5aSgarbled #include <math.h>
559636069cSjtc #include <stdio.h>
569636069cSjtc #include <stdlib.h>
579636069cSjtc #include <string.h>
589636069cSjtc #include <time.h>
593db0e47bSatatat #include <unistd.h>
609636069cSjtc
619636069cSjtc #define REPS_DEF 100
629636069cSjtc #define BEGIN_DEF 1
639636069cSjtc #define ENDER_DEF 100
649636069cSjtc #define STEP_DEF 1
659636069cSjtc
66507cbfd5Sjdolecek #define is_default(s) (strcmp((s), "-") == 0)
679636069cSjtc
6893190b89Sdsl static double begin = BEGIN_DEF;
6993190b89Sdsl static double ender = ENDER_DEF;
7093190b89Sdsl static double step = STEP_DEF;
7193190b89Sdsl static long reps = REPS_DEF;
7293190b89Sdsl static int randomize;
7393190b89Sdsl static int boring;
7493190b89Sdsl static int prec = -1;
7593190b89Sdsl static int dox;
7693190b89Sdsl static int chardata;
7793190b89Sdsl static int nofinalnl;
7893190b89Sdsl static const char *sepstring = "\n";
7993190b89Sdsl static char format[BUFSIZ];
809636069cSjtc
81f127a329Sdsl static void getargs(int, char *[]);
82f127a329Sdsl static void getformat(void);
83f127a329Sdsl static int getprec(char *);
84f127a329Sdsl static void putdata(double, long);
85f127a329Sdsl static void usage(void) __dead;
869636069cSjtc
879636069cSjtc int
main(int argc,char * argv[])8810e955c2Sperry main(int argc, char *argv[])
899636069cSjtc {
901b00238dSdsl double x;
91c4d8b28dSdsl long i;
929636069cSjtc
939636069cSjtc getargs(argc, argv);
949636069cSjtc if (randomize) {
951b00238dSdsl x = ender - begin;
969890613cSdsl if (x < 0) {
979890613cSdsl x = -x;
989890613cSdsl begin = ender;
999890613cSdsl }
1001b00238dSdsl if (dox == 0)
1011b00238dSdsl /*
1021b00238dSdsl * We are printing floating point, generate random
1031b00238dSdsl * number that include both supplied limits.
1041b00238dSdsl * Due to FP routing for display the low and high
1051b00238dSdsl * values are likely to occur half as often as all
1061b00238dSdsl * the others.
1071b00238dSdsl */
1081b00238dSdsl x /= (1u << 31) - 1.0;
1091b00238dSdsl else {
1101b00238dSdsl /*
1111b00238dSdsl * We are printing integers increase the range by
1121b00238dSdsl * one but ensure we never generate it.
1131b00238dSdsl * This makes all the integer values equally likely.
1141b00238dSdsl */
1151b00238dSdsl x += 1.0;
1161b00238dSdsl x /= (1u << 31);
1179636069cSjtc }
1181b00238dSdsl srandom((unsigned long) step);
1191b00238dSdsl for (i = 1; i <= reps || reps == 0; i++)
1201b00238dSdsl putdata(random() * x + begin, reps - i);
121f127a329Sdsl } else {
1221b00238dSdsl /*
1231b00238dSdsl * If we are going to display as integer, add 0.5 here
1241b00238dSdsl * and use floor(x) later to get sane rounding.
1251b00238dSdsl */
1261b00238dSdsl x = begin;
1271b00238dSdsl if (dox)
1281b00238dSdsl x += 0.5;
1291b00238dSdsl for (i = 1; i <= reps || reps == 0; i++, x += step)
130c4d8b28dSdsl putdata(x, reps - i);
131f127a329Sdsl }
1329636069cSjtc if (!nofinalnl)
1339636069cSjtc putchar('\n');
1349636069cSjtc exit(0);
1359636069cSjtc }
1369636069cSjtc
137f127a329Sdsl static void
getargs(int argc,char * argv[])13810e955c2Sperry getargs(int argc, char *argv[])
1399636069cSjtc {
14093190b89Sdsl unsigned int have = 0;
14193190b89Sdsl #define BEGIN 1
14293190b89Sdsl #define STEP 2 /* seed if -r */
14393190b89Sdsl #define REPS 4
14493190b89Sdsl #define ENDER 8
145ac4e9aa7Slukem int n = 0;
14693190b89Sdsl long t;
147f127a329Sdsl char *ep;
1489636069cSjtc
149f127a329Sdsl for (;;) {
150f127a329Sdsl switch (getopt(argc, argv, "b:cnp:rs:w:")) {
151f127a329Sdsl default:
152f127a329Sdsl usage();
153f127a329Sdsl case -1:
1549636069cSjtc break;
1559636069cSjtc case 'c':
1569636069cSjtc chardata = 1;
157f127a329Sdsl continue;
1589636069cSjtc case 'n':
1599636069cSjtc nofinalnl = 1;
160f127a329Sdsl continue;
161f127a329Sdsl case 'p':
162f127a329Sdsl prec = strtol(optarg, &ep, 0);
163f127a329Sdsl if (*ep != 0 || prec < 0)
164f127a329Sdsl errx(EXIT_FAILURE, "Bad precision value");
165f127a329Sdsl continue;
166f127a329Sdsl case 'r':
167f127a329Sdsl randomize = 1;
168f127a329Sdsl continue;
169f127a329Sdsl case 's':
170f127a329Sdsl sepstring = optarg;
171f127a329Sdsl continue;
1729636069cSjtc case 'b':
1739636069cSjtc boring = 1;
174f127a329Sdsl /* FALLTHROUGH */
1759636069cSjtc case 'w':
176f127a329Sdsl strlcpy(format, optarg, sizeof(format));
177f127a329Sdsl continue;
1789636069cSjtc }
179f127a329Sdsl break;
180c4d8b28dSdsl }
181f127a329Sdsl argc -= optind;
182f127a329Sdsl argv += optind;
1839636069cSjtc
184507cbfd5Sjdolecek switch (argc) { /* examine args right to left, falling thru cases */
1859636069cSjtc case 4:
186507cbfd5Sjdolecek if (!is_default(argv[3])) {
18793190b89Sdsl step = strtod(argv[3], &ep);
18893190b89Sdsl if (*ep != 0)
189f127a329Sdsl errx(EXIT_FAILURE, "Bad step value: %s",
190f127a329Sdsl argv[3]);
19193190b89Sdsl have |= STEP;
1929636069cSjtc }
193fbffadb9Smrg /* FALLTHROUGH */
1949636069cSjtc case 3:
195507cbfd5Sjdolecek if (!is_default(argv[2])) {
196507cbfd5Sjdolecek if (!sscanf(argv[2], "%lf", &ender))
197507cbfd5Sjdolecek ender = argv[2][strlen(argv[2])-1];
19893190b89Sdsl have |= ENDER;
1999d6613d4Sdsl if (prec < 0)
200507cbfd5Sjdolecek n = getprec(argv[2]);
2019636069cSjtc }
202fbffadb9Smrg /* FALLTHROUGH */
2039636069cSjtc case 2:
204507cbfd5Sjdolecek if (!is_default(argv[1])) {
205507cbfd5Sjdolecek if (!sscanf(argv[1], "%lf", &begin))
206507cbfd5Sjdolecek begin = argv[1][strlen(argv[1])-1];
20793190b89Sdsl have |= BEGIN;
2089d6613d4Sdsl if (prec < 0)
209507cbfd5Sjdolecek prec = getprec(argv[1]);
2109636069cSjtc if (n > prec) /* maximum precision */
2119636069cSjtc prec = n;
2129636069cSjtc }
213fbffadb9Smrg /* FALLTHROUGH */
2149636069cSjtc case 1:
215507cbfd5Sjdolecek if (!is_default(argv[0])) {
21693190b89Sdsl reps = strtoul(argv[0], &ep, 0);
21793190b89Sdsl if (*ep != 0 || reps < 0)
218f127a329Sdsl errx(EXIT_FAILURE, "Bad reps value: %s",
219f127a329Sdsl argv[0]);
22093190b89Sdsl have |= REPS;
2219636069cSjtc }
222fbffadb9Smrg /* FALLTHROUGH */
2239636069cSjtc case 0:
224507cbfd5Sjdolecek break;
2259636069cSjtc default:
226f127a329Sdsl errx(EXIT_FAILURE,
227f127a329Sdsl "Too many arguments. What do you mean by %s?", argv[4]);
2289636069cSjtc }
2299d6613d4Sdsl
2309d6613d4Sdsl if (prec == -1)
2319d6613d4Sdsl prec = 0;
23293190b89Sdsl
233*5dc82c03Skamil getformat();
234*5dc82c03Skamil
23593190b89Sdsl if (randomize) {
23693190b89Sdsl /* 'step' is the seed here, use pseudo-random default */
23793190b89Sdsl if (!(have & STEP))
23893190b89Sdsl step = time(NULL) * getpid();
23993190b89Sdsl /* Take the default values for everything else */
24093190b89Sdsl return;
24193190b89Sdsl }
24293190b89Sdsl
24393190b89Sdsl /*
24493190b89Sdsl * The loop we run uses begin/step/reps, so if we have been
24593190b89Sdsl * given an end value (ender) we must use it to replace the
24693190b89Sdsl * default values of the others.
24793190b89Sdsl * We will assume a begin of 0 and step of 1 if necessary.
24893190b89Sdsl */
24993190b89Sdsl
25093190b89Sdsl switch (have) {
25193190b89Sdsl
25293190b89Sdsl case ENDER | STEP:
25393190b89Sdsl case ENDER | STEP | BEGIN:
25493190b89Sdsl /* Calculate reps */
25593190b89Sdsl if (step == 0.0)
25693190b89Sdsl reps = 0; /* ie infinite */
25793190b89Sdsl else {
25893190b89Sdsl reps = (ender - begin + step) / step;
25993190b89Sdsl if (reps <= 0)
26093190b89Sdsl errx(EXIT_FAILURE, "Impossible stepsize");
26193190b89Sdsl }
26293190b89Sdsl break;
26393190b89Sdsl
26493190b89Sdsl case REPS | ENDER:
26593190b89Sdsl case REPS | ENDER | STEP:
26693190b89Sdsl /* Calculate begin */
26793190b89Sdsl if (reps == 0)
26893190b89Sdsl errx(EXIT_FAILURE,
26993190b89Sdsl "Must specify begin if reps == 0");
27093190b89Sdsl begin = ender - reps * step + step;
27193190b89Sdsl break;
27293190b89Sdsl
27393190b89Sdsl case REPS | BEGIN | ENDER:
27493190b89Sdsl /* Calculate step */
27593190b89Sdsl if (reps == 0)
27693190b89Sdsl errx(EXIT_FAILURE,
27793190b89Sdsl "Infinite sequences cannot be bounded");
27893190b89Sdsl if (reps == 1)
27993190b89Sdsl step = 0.0;
28093190b89Sdsl else
28193190b89Sdsl step = (ender - begin) / (reps - 1);
28293190b89Sdsl break;
28393190b89Sdsl
28493190b89Sdsl case REPS | BEGIN | ENDER | STEP:
28593190b89Sdsl /* reps given and implied - take smaller */
28693190b89Sdsl if (step == 0.0)
28793190b89Sdsl break;
28893190b89Sdsl t = (ender - begin + step) / step;
28993190b89Sdsl if (t <= 0)
29093190b89Sdsl errx(EXIT_FAILURE,
29193190b89Sdsl "Impossible stepsize");
29293190b89Sdsl if (t < reps)
29393190b89Sdsl reps = t;
29493190b89Sdsl break;
29593190b89Sdsl
29693190b89Sdsl default:
29793190b89Sdsl /* No values can be calculated, use defaults */
29893190b89Sdsl break;
29993190b89Sdsl }
3009636069cSjtc }
3019636069cSjtc
302f127a329Sdsl static void
putdata(double x,long notlast)30310e955c2Sperry putdata(double x, long notlast)
3049636069cSjtc {
3059636069cSjtc
3069636069cSjtc if (boring) /* repeated word */
30722e62219Spk printf("%s", format);
3089636069cSjtc else if (dox) /* scalar */
3091b00238dSdsl printf(format, (long)floor(x));
3109636069cSjtc else /* real */
3119636069cSjtc printf(format, x);
3129636069cSjtc if (notlast != 0)
3139636069cSjtc fputs(sepstring, stdout);
3149636069cSjtc }
3159636069cSjtc
316f127a329Sdsl __dead static void
usage(void)317507cbfd5Sjdolecek usage(void)
3189636069cSjtc {
3192c12af6aSpeter (void)fprintf(stderr, "usage: %s [-cnr] [-b word] [-p precision] "
320f127a329Sdsl "[-s string] [-w word] [reps [begin [end [step | seed]]]]\n",
321f127a329Sdsl getprogname());
3229636069cSjtc exit(1);
3239636069cSjtc }
3249636069cSjtc
325f127a329Sdsl static int
getprec(char * num_str)326f127a329Sdsl getprec(char *num_str)
3279636069cSjtc {
3289636069cSjtc
329f127a329Sdsl num_str = strchr(num_str, '.');
330f127a329Sdsl if (num_str == NULL)
331f127a329Sdsl return 0;
332f127a329Sdsl return strspn(num_str + 1, "0123456789");
3339636069cSjtc }
3349636069cSjtc
335f127a329Sdsl static void
getformat(void)33610e955c2Sperry getformat(void)
3379636069cSjtc {
338ac4e9aa7Slukem char *p;
339507cbfd5Sjdolecek size_t sz;
3409636069cSjtc
3419636069cSjtc if (boring) /* no need to bother */
3429636069cSjtc return;
343f127a329Sdsl for (p = format; *p; p++) { /* look for '%' */
344507cbfd5Sjdolecek if (*p == '%') {
345507cbfd5Sjdolecek if (*(p+1) != '%')
3469636069cSjtc break;
347507cbfd5Sjdolecek p++; /* leave %% alone */
348507cbfd5Sjdolecek }
349f127a329Sdsl }
350507cbfd5Sjdolecek sz = sizeof(format) - strlen(format) - 1;
351507cbfd5Sjdolecek if (!*p) {
352a357ac49Sdsl if (chardata || prec == 0) {
35339a84db3Slukem if ((size_t)snprintf(p, sz, "%%%s", chardata ? "c" : "ld") >= sz)
354f127a329Sdsl errx(EXIT_FAILURE, "-w word too long");
3559636069cSjtc dox = 1;
356618d6288Ssimonb } else {
357618d6288Ssimonb if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
358f127a329Sdsl errx(EXIT_FAILURE, "-w word too long");
3599636069cSjtc }
360507cbfd5Sjdolecek } else if (!*(p+1)) {
361507cbfd5Sjdolecek if (sz <= 0)
362f127a329Sdsl errx(EXIT_FAILURE, "-w word too long");
3639636069cSjtc strcat(format, "%"); /* cannot end in single '%' */
364507cbfd5Sjdolecek } else {
365507cbfd5Sjdolecek p++; /* skip leading % */
366507cbfd5Sjdolecek for(; *p && !isalpha((unsigned char)*p); p++) {
367507cbfd5Sjdolecek /* allow all valid printf(3) flags, but deny '*' */
368507cbfd5Sjdolecek if (!strchr("0123456789#-+. ", *p))
369507cbfd5Sjdolecek break;
370507cbfd5Sjdolecek }
371507cbfd5Sjdolecek /* Allow 'l' prefix, but no other. */
372507cbfd5Sjdolecek if (*p == 'l')
373507cbfd5Sjdolecek p++;
3749636069cSjtc switch (*p) {
3759636069cSjtc case 'f': case 'e': case 'g': case '%':
376507cbfd5Sjdolecek case 'E': case 'G':
3779636069cSjtc break;
3789636069cSjtc case 's':
379f127a329Sdsl errx(EXIT_FAILURE,
380f127a329Sdsl "cannot convert numeric data to strings");
3819636069cSjtc break;
382507cbfd5Sjdolecek case 'd': case 'o': case 'x': case 'u':
383507cbfd5Sjdolecek case 'D': case 'O': case 'X': case 'U':
384507cbfd5Sjdolecek case 'c': case 'i':
3859636069cSjtc dox = 1;
3869636069cSjtc break;
387507cbfd5Sjdolecek default:
388f127a329Sdsl errx(EXIT_FAILURE, "unknown or invalid format `%s'",
389f127a329Sdsl format);
3909636069cSjtc }
391507cbfd5Sjdolecek /* Need to check for trailing stuff to print */
392507cbfd5Sjdolecek for (; *p; p++) /* look for '%' */
393507cbfd5Sjdolecek if (*p == '%') {
394507cbfd5Sjdolecek if (*(p+1) != '%')
395507cbfd5Sjdolecek break;
396507cbfd5Sjdolecek p++; /* leave %% alone */
397507cbfd5Sjdolecek }
398507cbfd5Sjdolecek if (*p)
399f127a329Sdsl errx(EXIT_FAILURE, "unknown or invalid format `%s'",
400f127a329Sdsl format);
4019636069cSjtc }
4029636069cSjtc }
403