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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3127423Scharnierstatic const char copyright[] = 321590Srgrimes"@(#) Copyright (c) 1993\n\ 331590Srgrimes The Regents of the University of California. All rights reserved.\n"; 341590Srgrimes#endif /* not lint */ 351590Srgrimes 361590Srgrimes#ifndef lint 3727423Scharnier#if 0 381590Srgrimesstatic char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; 3927423Scharnier#endif 4098254Sjmallett#endif 4198254Sjmallett#include <sys/cdefs.h> 4298254Sjmallett__FBSDID("$FreeBSD: stable/11/usr.bin/jot/jot.c 351873 2019-09-05 16:53:34Z bdrewery $"); 4398254Sjmallett 441590Srgrimes/* 451590Srgrimes * jot - print sequential or random data 461590Srgrimes * 471590Srgrimes * Author: John Kunze, Office of Comp. Affairs, UCB 481590Srgrimes */ 491590Srgrimes 501590Srgrimes#include <ctype.h> 5127423Scharnier#include <err.h> 521590Srgrimes#include <limits.h> 531590Srgrimes#include <stdio.h> 5499457Smike#include <stdint.h> 551590Srgrimes#include <stdlib.h> 56164026Sdds#include <stdbool.h> 571590Srgrimes#include <string.h> 58200462Sdelphij#include <time.h> 5923511Sache#include <unistd.h> 601590Srgrimes 61164046Sdds/* Defaults */ 621590Srgrimes#define REPS_DEF 100 631590Srgrimes#define BEGIN_DEF 1 641590Srgrimes#define ENDER_DEF 100 651590Srgrimes#define STEP_DEF 1 661590Srgrimes 67164046Sdds/* Flags of options that have been set */ 68164021Sdds#define HAVE_STEP 1 69164021Sdds#define HAVE_ENDER 2 70164021Sdds#define HAVE_BEGIN 4 71164021Sdds#define HAVE_REPS 8 72164021Sdds 73164028Sdds#define is_default(s) (*(s) == 0 || strcmp((s), "-") == 0) 741590Srgrimes 75164046Sddsstatic bool boring; 76208728Sbrianstatic int prec = -1; 77164046Sddsstatic bool longdata; 78164046Sddsstatic bool intdata; 79164046Sddsstatic bool chardata; 80164046Sddsstatic bool nosign; 81164046Sddsstatic const char *sepstring = "\n"; 82164046Sddsstatic char format[BUFSIZ]; 831590Srgrimes 84164046Sddsstatic void getformat(void); 85164046Sddsstatic int getprec(const char *); 86164046Sddsstatic int putdata(double, bool); 8792920Simpstatic void usage(void); 881590Srgrimes 891590Srgrimesint 9098254Sjmallettmain(int argc, char **argv) 911590Srgrimes{ 92164046Sdds bool have_format = false; 93164046Sdds bool infinity = false; 94164046Sdds bool nofinalnl = false; 95164046Sdds bool randomize = false; 96164046Sdds bool use_random = false; 97164046Sdds int ch; 98164046Sdds int mask = 0; 99164046Sdds int n = 0; 100195443Sbrian double begin = BEGIN_DEF; 101164046Sdds double divisor; 102195443Sbrian double ender = ENDER_DEF; 103195443Sbrian double s = STEP_DEF; 104164025Sdds double x, y; 105164025Sdds long i; 106195443Sbrian long reps = REPS_DEF; 1071590Srgrimes 108164046Sdds while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1) 10998254Sjmallett switch (ch) { 1101590Srgrimes case 'b': 111164046Sdds boring = true; 11277276Sdd /* FALLTHROUGH */ 1131590Srgrimes case 'w': 11477276Sdd if (strlcpy(format, optarg, sizeof(format)) >= 11577276Sdd sizeof(format)) 11677276Sdd errx(1, "-%c word too long", ch); 117164035Sdds have_format = true; 1181590Srgrimes break; 119164046Sdds case 'c': 120164046Sdds chardata = true; 1211590Srgrimes break; 122164046Sdds case 'n': 123164046Sdds nofinalnl = true; 124164046Sdds break; 1251590Srgrimes case 'p': 12677276Sdd prec = atoi(optarg); 127208728Sbrian if (prec < 0) 12827423Scharnier errx(1, "bad precision value"); 129164035Sdds have_format = true; 1301590Srgrimes break; 131164046Sdds case 'r': 132164046Sdds randomize = true; 133164046Sdds break; 134164046Sdds case 's': 135164046Sdds sepstring = optarg; 136164046Sdds break; 1371590Srgrimes default: 13827423Scharnier usage(); 1391590Srgrimes } 14077276Sdd argc -= optind; 14177276Sdd argv += optind; 1421590Srgrimes 14377276Sdd switch (argc) { /* examine args right to left, falling thru cases */ 1441590Srgrimes case 4: 14577276Sdd if (!is_default(argv[3])) { 14677276Sdd if (!sscanf(argv[3], "%lf", &s)) 14777276Sdd errx(1, "bad s value: %s", argv[3]); 148164021Sdds mask |= HAVE_STEP; 149164026Sdds if (randomize) 150164035Sdds use_random = true; 1511590Srgrimes } 152164021Sdds /* FALLTHROUGH */ 1531590Srgrimes case 3: 15477276Sdd if (!is_default(argv[2])) { 15577276Sdd if (!sscanf(argv[2], "%lf", &ender)) 15677276Sdd ender = argv[2][strlen(argv[2])-1]; 157164021Sdds mask |= HAVE_ENDER; 158208728Sbrian if (prec < 0) 15977276Sdd n = getprec(argv[2]); 1601590Srgrimes } 161164021Sdds /* FALLTHROUGH */ 1621590Srgrimes case 2: 16377276Sdd if (!is_default(argv[1])) { 16477276Sdd if (!sscanf(argv[1], "%lf", &begin)) 16577276Sdd begin = argv[1][strlen(argv[1])-1]; 166164021Sdds mask |= HAVE_BEGIN; 167208728Sbrian if (prec < 0) 16877276Sdd prec = getprec(argv[1]); 1691590Srgrimes if (n > prec) /* maximum precision */ 1701590Srgrimes prec = n; 1711590Srgrimes } 172164021Sdds /* FALLTHROUGH */ 1731590Srgrimes case 1: 17477276Sdd if (!is_default(argv[0])) { 17577276Sdd if (!sscanf(argv[0], "%ld", &reps)) 17677276Sdd errx(1, "bad reps value: %s", argv[0]); 177164021Sdds mask |= HAVE_REPS; 1781590Srgrimes } 1791590Srgrimes break; 1801590Srgrimes case 0: 18127423Scharnier usage(); 1821590Srgrimes default: 18377276Sdd errx(1, "too many arguments. What do you mean by %s?", 18477276Sdd argv[4]); 1851590Srgrimes } 1861590Srgrimes getformat(); 187208728Sbrian 188208728Sbrian if (prec == -1) 189208728Sbrian prec = 0; 190208728Sbrian 1911590Srgrimes while (mask) /* 4 bit mask has 1's where last 4 args were given */ 1921590Srgrimes switch (mask) { /* fill in the 0's by default or computation */ 193164021Sdds case HAVE_STEP: 194164021Sdds case HAVE_ENDER: 195164021Sdds case HAVE_ENDER | HAVE_STEP: 196164021Sdds case HAVE_BEGIN: 197164021Sdds case HAVE_BEGIN | HAVE_STEP: 1981590Srgrimes reps = REPS_DEF; 199164023Sdds mask |= HAVE_REPS; 2001590Srgrimes break; 201164043Sdds case HAVE_BEGIN | HAVE_ENDER: 202164043Sdds s = ender > begin ? 1 : -1; 203164043Sdds mask |= HAVE_STEP; 204164043Sdds break; 205164021Sdds case HAVE_BEGIN | HAVE_ENDER | HAVE_STEP: 206164023Sdds if (randomize) 2071590Srgrimes reps = REPS_DEF; 208164023Sdds else if (s == 0.0) 2091590Srgrimes reps = 0; 210164023Sdds else 211164023Sdds reps = (ender - begin + s) / s; 2121590Srgrimes if (reps <= 0) 21327423Scharnier errx(1, "impossible stepsize"); 2141590Srgrimes mask = 0; 2151590Srgrimes break; 216164021Sdds case HAVE_REPS: 217164021Sdds case HAVE_REPS | HAVE_STEP: 2181590Srgrimes begin = BEGIN_DEF; 219164023Sdds mask |= HAVE_BEGIN; 2201590Srgrimes break; 221164021Sdds case HAVE_REPS | HAVE_ENDER: 222164026Sdds s = STEP_DEF; 223164021Sdds mask = HAVE_REPS | HAVE_ENDER | HAVE_STEP; 2241590Srgrimes break; 225164021Sdds case HAVE_REPS | HAVE_ENDER | HAVE_STEP: 2261590Srgrimes if (randomize) 2271590Srgrimes begin = BEGIN_DEF; 2281590Srgrimes else if (reps == 0) 22927423Scharnier errx(1, "must specify begin if reps == 0"); 23077276Sdd begin = ender - reps * s + s; 2311590Srgrimes mask = 0; 2321590Srgrimes break; 233164021Sdds case HAVE_REPS | HAVE_BEGIN: 234164026Sdds s = STEP_DEF; 235164021Sdds mask = HAVE_REPS | HAVE_BEGIN | HAVE_STEP; 2361590Srgrimes break; 237164021Sdds case HAVE_REPS | HAVE_BEGIN | HAVE_STEP: 2381590Srgrimes if (randomize) 2391590Srgrimes ender = ENDER_DEF; 2401590Srgrimes else 2411590Srgrimes ender = begin + reps * s - s; 2421590Srgrimes mask = 0; 2431590Srgrimes break; 244164021Sdds case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER: 245351873Sbdrewery if (!randomize) { 246351873Sbdrewery if (reps == 0) 247351873Sbdrewery errx(1, "infinite sequences cannot " 248351873Sbdrewery "be bounded"); 249351873Sbdrewery else if (reps == 1) 250351873Sbdrewery s = 0.0; 251351873Sbdrewery else 252351873Sbdrewery s = (ender - begin) / (reps - 1); 253351873Sbdrewery } 2541590Srgrimes mask = 0; 2551590Srgrimes break; 256164021Sdds case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER | HAVE_STEP: 257164021Sdds /* if reps given and implied, */ 2581590Srgrimes if (!randomize && s != 0.0) { 2591590Srgrimes long t = (ender - begin + s) / s; 2601590Srgrimes if (t <= 0) 26127423Scharnier errx(1, "impossible stepsize"); 2621590Srgrimes if (t < reps) /* take lesser */ 2631590Srgrimes reps = t; 2641590Srgrimes } 2651590Srgrimes mask = 0; 2661590Srgrimes break; 2671590Srgrimes default: 26827423Scharnier errx(1, "bad mask"); 2691590Srgrimes } 2701590Srgrimes if (reps == 0) 271164046Sdds infinity = true; 27277276Sdd if (randomize) { 273164035Sdds if (use_random) { 274164035Sdds srandom((unsigned long)s); 275164035Sdds divisor = (double)INT32_MAX + 1; 276164035Sdds } else 277164035Sdds divisor = (double)UINT32_MAX + 1; 278164035Sdds 279164035Sdds /* 280164035Sdds * Attempt to DWIM when the user has specified an 281164035Sdds * integer range within that of the random number 282164035Sdds * generator: distribute the numbers equally in 283164035Sdds * the range [begin .. ender]. Jot's default %.0f 284164035Sdds * format would make the appearance of the first and 285164035Sdds * last specified value half as likely as the rest. 286164035Sdds */ 287164035Sdds if (!have_format && prec == 0 && 288164035Sdds begin >= 0 && begin < divisor && 289164035Sdds ender >= 0 && ender < divisor) { 290208728Sbrian if (begin <= ender) 291208728Sbrian ender += 1; 292208728Sbrian else 293208728Sbrian begin += 1; 294164046Sdds nosign = true; 295164046Sdds intdata = true; 296164035Sdds (void)strlcpy(format, 297164035Sdds chardata ? "%c" : "%u", sizeof(format)); 298164035Sdds } 299208728Sbrian x = ender - begin; 300164025Sdds for (i = 1; i <= reps || infinity; i++) { 301164035Sdds if (use_random) 302164035Sdds y = random() / divisor; 303164026Sdds else 304164035Sdds y = arc4random() / divisor; 305164046Sdds if (putdata(y * x + begin, !(reps - i))) 30677276Sdd errx(1, "range error in conversion"); 30777276Sdd } 30877276Sdd } else 309164025Sdds for (i = 1, x = begin; i <= reps || infinity; i++, x += s) 310164046Sdds if (putdata(x, !(reps - i))) 31177276Sdd errx(1, "range error in conversion"); 31277276Sdd if (!nofinalnl) 31377276Sdd putchar('\n'); 31477276Sdd exit(0); 3151590Srgrimes} 3161590Srgrimes 317164046Sdds/* 318164046Sdds * Send x to stdout using the specified format. 319164046Sdds * Last is true if this is the set's last value. 320164046Sdds * Return 0 if OK, or a positive number if the number passed was 321164046Sdds * outside the range specified by the various flags. 322164046Sdds */ 323164046Sddsstatic int 324164046Sddsputdata(double x, bool last) 3251590Srgrimes{ 3261590Srgrimes 32755515Ssheldonh if (boring) 32862871Skris printf("%s", format); 32955515Ssheldonh else if (longdata && nosign) { 33055515Ssheldonh if (x <= (double)ULONG_MAX && x >= (double)0) 33155515Ssheldonh printf(format, (unsigned long)x); 33255515Ssheldonh else 33355515Ssheldonh return (1); 33455515Ssheldonh } else if (longdata) { 33555515Ssheldonh if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) 33655515Ssheldonh printf(format, (long)x); 33755515Ssheldonh else 33855515Ssheldonh return (1); 33955515Ssheldonh } else if (chardata || (intdata && !nosign)) { 34055515Ssheldonh if (x <= (double)INT_MAX && x >= (double)INT_MIN) 34155515Ssheldonh printf(format, (int)x); 34255515Ssheldonh else 34355515Ssheldonh return (1); 34455515Ssheldonh } else if (intdata) { 34555515Ssheldonh if (x <= (double)UINT_MAX && x >= (double)0) 34655515Ssheldonh printf(format, (unsigned int)x); 34755515Ssheldonh else 34855515Ssheldonh return (1); 34955515Ssheldonh 35055515Ssheldonh } else 3511590Srgrimes printf(format, x); 352164046Sdds if (!last) 3531590Srgrimes fputs(sepstring, stdout); 35455515Ssheldonh 35555515Ssheldonh return (0); 3561590Srgrimes} 3571590Srgrimes 35827423Scharnierstatic void 35998254Sjmallettusage(void) 3601590Srgrimes{ 36127423Scharnier fprintf(stderr, "%s\n%s\n", 36230908Scharnier "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 36330908Scharnier " [reps [begin [end [s]]]]"); 3641590Srgrimes exit(1); 3651590Srgrimes} 3661590Srgrimes 367164046Sdds/* 368164046Sdds * Return the number of digits following the number's decimal point. 369164046Sdds * Return 0 if no decimal point is found. 370164046Sdds */ 371164046Sddsstatic int 372164046Sddsgetprec(const char *str) 3731590Srgrimes{ 374164046Sdds const char *p; 375164046Sdds const char *q; 3761590Srgrimes 37777287Sdd for (p = str; *p; p++) 3781590Srgrimes if (*p == '.') 3791590Srgrimes break; 3801590Srgrimes if (!*p) 3811590Srgrimes return (0); 3821590Srgrimes for (q = ++p; *p; p++) 383132240Stjr if (!isdigit((unsigned char)*p)) 3841590Srgrimes break; 3851590Srgrimes return (p - q); 3861590Srgrimes} 3871590Srgrimes 388164046Sdds/* 389164046Sdds * Set format, intdata, chardata, longdata, and nosign 390164046Sdds * based on the command line arguments. 391164046Sdds */ 392164046Sddsstatic void 39398254Sjmallettgetformat(void) 3941590Srgrimes{ 39577287Sdd char *p, *p2; 39655515Ssheldonh int dot, hash, space, sign, numbers = 0; 39777276Sdd size_t sz; 3981590Srgrimes 3991590Srgrimes if (boring) /* no need to bother */ 4001590Srgrimes return; 4011590Srgrimes for (p = format; *p; p++) /* look for '%' */ 402165029Sdelphij if (*p == '%') { 403164851Sdds if (p[1] == '%') 404164851Sdds p++; /* leave %% alone */ 405164851Sdds else 406164851Sdds break; 407165029Sdelphij } 40877276Sdd sz = sizeof(format) - strlen(format) - 1; 40977276Sdd if (!*p && !chardata) { 41077276Sdd if (snprintf(p, sz, "%%.%df", prec) >= (int)sz) 41177276Sdd errx(1, "-w word too long"); 41277276Sdd } else if (!*p && chardata) { 41377276Sdd if (strlcpy(p, "%c", sz) >= sz) 41477276Sdd errx(1, "-w word too long"); 415164046Sdds intdata = true; 41677276Sdd } else if (!*(p+1)) { 41777276Sdd if (sz <= 0) 41877276Sdd errx(1, "-w word too long"); 4191590Srgrimes strcat(format, "%"); /* cannot end in single '%' */ 42077276Sdd } else { 42148995Ssheldonh /* 42248995Ssheldonh * Allow conversion format specifiers of the form 42348995Ssheldonh * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 42448995Ssheldonh * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 42548995Ssheldonh */ 42677287Sdd p2 = p++; 42748995Ssheldonh dot = hash = space = sign = numbers = 0; 428132240Stjr while (!isalpha((unsigned char)*p)) { 429132240Stjr if (isdigit((unsigned char)*p)) { 43048995Ssheldonh numbers++; 43148995Ssheldonh p++; 43248995Ssheldonh } else if ((*p == '#' && !(numbers|dot|sign|space| 43348995Ssheldonh hash++)) || 43448995Ssheldonh (*p == ' ' && !(numbers|dot|space++)) || 43548995Ssheldonh ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 43648995Ssheldonh || (*p == '.' && !(dot++))) 43748995Ssheldonh p++; 43848995Ssheldonh else 43955515Ssheldonh goto fmt_broken; 44048995Ssheldonh } 44155515Ssheldonh if (*p == 'l') { 442164046Sdds longdata = true; 44355515Ssheldonh if (*++p == 'l') { 44455515Ssheldonh if (p[1] != '\0') 44555515Ssheldonh p++; 44655515Ssheldonh goto fmt_broken; 44755515Ssheldonh } 44855515Ssheldonh } 44948995Ssheldonh switch (*p) { 45048995Ssheldonh case 'o': case 'u': case 'x': case 'X': 451164046Sdds intdata = nosign = true; 4521590Srgrimes break; 45348995Ssheldonh case 'd': case 'i': 454164046Sdds intdata = true; 45548995Ssheldonh break; 45648995Ssheldonh case 'D': 45755515Ssheldonh if (!longdata) { 458164046Sdds intdata = true; 45948995Ssheldonh break; 46048995Ssheldonh } 46148995Ssheldonh case 'O': case 'U': 46255515Ssheldonh if (!longdata) { 463164046Sdds intdata = nosign = true; 46448995Ssheldonh break; 46548995Ssheldonh } 46648995Ssheldonh case 'c': 46755515Ssheldonh if (!(intdata | longdata)) { 468164046Sdds chardata = true; 46948995Ssheldonh break; 47048995Ssheldonh } 47155515Ssheldonh case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 47248995Ssheldonh case '$': case '*': 47355515Ssheldonh goto fmt_broken; 47448995Ssheldonh case 'f': case 'e': case 'g': case 'E': case 'G': 47555515Ssheldonh if (!longdata) 47648995Ssheldonh break; 47748995Ssheldonh /* FALLTHROUGH */ 4781590Srgrimes default: 47955515Ssheldonhfmt_broken: 48048995Ssheldonh *++p = '\0'; 48177287Sdd errx(1, "illegal or unsupported format '%s'", p2); 48248995Ssheldonh /* NOTREACHED */ 4831590Srgrimes } 48448995Ssheldonh while (*++p) 48548995Ssheldonh if (*p == '%' && *(p+1) && *(p+1) != '%') 48648995Ssheldonh errx(1, "too many conversions"); 48748995Ssheldonh else if (*p == '%' && *(p+1) == '%') 48848995Ssheldonh p++; 48948995Ssheldonh else if (*p == '%' && !*(p+1)) { 490164852Sdds if (strlcat(format, "%", sizeof(format)) >= 491164852Sdds sizeof(format)) 492164852Sdds errx(1, "-w word too long"); 49348995Ssheldonh break; 49448995Ssheldonh } 4951590Srgrimes } 4961590Srgrimes} 497