19b50d902SRodney W. Grimes /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 49b50d902SRodney W. Grimes * Copyright (c) 1993 59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 69b50d902SRodney W. Grimes * 79b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 89b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 99b50d902SRodney W. Grimes * are met: 109b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 129b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 139b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 149b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 169b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 179b50d902SRodney W. Grimes * without specific prior written permission. 189b50d902SRodney W. Grimes * 199b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 209b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 219b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 229b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 239b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 249b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 259b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 269b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 279b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 289b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 299b50d902SRodney W. Grimes * SUCH DAMAGE. 309b50d902SRodney W. Grimes */ 319b50d902SRodney W. Grimes 329b50d902SRodney W. Grimes #ifndef lint 337bd7ad50SPhilippe Charnier static const char copyright[] = 349b50d902SRodney W. Grimes "@(#) Copyright (c) 1993\n\ 359b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 369b50d902SRodney W. Grimes #endif /* not lint */ 379b50d902SRodney W. Grimes 389b50d902SRodney W. Grimes #ifndef lint 397bd7ad50SPhilippe Charnier #if 0 409b50d902SRodney W. Grimes static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; 417bd7ad50SPhilippe Charnier #endif 42cf0def93SJuli Mallett #endif 43cf0def93SJuli Mallett #include <sys/cdefs.h> 44cf0def93SJuli Mallett __FBSDID("$FreeBSD$"); 459b50d902SRodney W. Grimes 469b50d902SRodney W. Grimes /* 479b50d902SRodney W. Grimes * jot - print sequential or random data 489b50d902SRodney W. Grimes * 499b50d902SRodney W. Grimes * Author: John Kunze, Office of Comp. Affairs, UCB 509b50d902SRodney W. Grimes */ 519b50d902SRodney W. Grimes 521532e656SConrad Meyer #include <sys/capsicum.h> 531532e656SConrad Meyer #include <capsicum_helpers.h> 549b50d902SRodney W. Grimes #include <ctype.h> 557bd7ad50SPhilippe Charnier #include <err.h> 561532e656SConrad Meyer #include <errno.h> 579b50d902SRodney W. Grimes #include <limits.h> 589b50d902SRodney W. Grimes #include <stdio.h> 590ad736e6SMike Barcroft #include <stdint.h> 609b50d902SRodney W. Grimes #include <stdlib.h> 61a26a6612SDiomidis Spinellis #include <stdbool.h> 629b50d902SRodney W. Grimes #include <string.h> 63821df508SXin LI #include <time.h> 649d288406SAndrey A. Chernov #include <unistd.h> 659b50d902SRodney W. Grimes 663241f274SDiomidis Spinellis /* Defaults */ 679b50d902SRodney W. Grimes #define REPS_DEF 100 689b50d902SRodney W. Grimes #define BEGIN_DEF 1 699b50d902SRodney W. Grimes #define ENDER_DEF 100 709b50d902SRodney W. Grimes #define STEP_DEF 1 719b50d902SRodney W. Grimes 723241f274SDiomidis Spinellis /* Flags of options that have been set */ 73afe53a49SDiomidis Spinellis #define HAVE_STEP 1 74afe53a49SDiomidis Spinellis #define HAVE_ENDER 2 75afe53a49SDiomidis Spinellis #define HAVE_BEGIN 4 76afe53a49SDiomidis Spinellis #define HAVE_REPS 8 77afe53a49SDiomidis Spinellis 78fee14f30SDiomidis Spinellis #define is_default(s) (*(s) == 0 || strcmp((s), "-") == 0) 799b50d902SRodney W. Grimes 803241f274SDiomidis Spinellis static bool boring; 819c24af3dSBrian Somers static int prec = -1; 823241f274SDiomidis Spinellis static bool longdata; 833241f274SDiomidis Spinellis static bool intdata; 843241f274SDiomidis Spinellis static bool chardata; 853241f274SDiomidis Spinellis static bool nosign; 863241f274SDiomidis Spinellis static const char *sepstring = "\n"; 873241f274SDiomidis Spinellis static char format[BUFSIZ]; 889b50d902SRodney W. Grimes 893241f274SDiomidis Spinellis static void getformat(void); 903241f274SDiomidis Spinellis static int getprec(const char *); 913241f274SDiomidis Spinellis static int putdata(double, bool); 92f1bb2cd2SWarner Losh static void usage(void); 939b50d902SRodney W. Grimes 949b50d902SRodney W. Grimes int 95cf0def93SJuli Mallett main(int argc, char **argv) 969b50d902SRodney W. Grimes { 971532e656SConrad Meyer cap_rights_t rights; 983241f274SDiomidis Spinellis bool have_format = false; 993241f274SDiomidis Spinellis bool infinity = false; 1003241f274SDiomidis Spinellis bool nofinalnl = false; 1013241f274SDiomidis Spinellis bool randomize = false; 1023241f274SDiomidis Spinellis bool use_random = false; 1033241f274SDiomidis Spinellis int ch; 1043241f274SDiomidis Spinellis int mask = 0; 1053241f274SDiomidis Spinellis int n = 0; 10658a654f6SBrian Somers double begin = BEGIN_DEF; 1073241f274SDiomidis Spinellis double divisor; 10858a654f6SBrian Somers double ender = ENDER_DEF; 10958a654f6SBrian Somers double s = STEP_DEF; 11055f965aeSDiomidis Spinellis double x, y; 11155f965aeSDiomidis Spinellis long i; 11258a654f6SBrian Somers long reps = REPS_DEF; 1139b50d902SRodney W. Grimes 1141532e656SConrad Meyer if (caph_limit_stdio() < 0) 1151532e656SConrad Meyer err(1, "unable to limit rights for stdio"); 1161532e656SConrad Meyer cap_rights_init(&rights); 1171532e656SConrad Meyer if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) 1181532e656SConrad Meyer err(1, "unable to limit rights for stdin"); 1191532e656SConrad Meyer 1201532e656SConrad Meyer /* 1211532e656SConrad Meyer * Cache NLS data, for strerror, for err(3), before entering capability 1221532e656SConrad Meyer * mode. 1231532e656SConrad Meyer */ 1241532e656SConrad Meyer caph_cache_catpages(); 1251532e656SConrad Meyer 126*7672a014SMariusz Zaborski if (caph_enter() < 0) 1271532e656SConrad Meyer err(1, "unable to enter capability mode"); 1281532e656SConrad Meyer 1293241f274SDiomidis Spinellis while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1) 130cf0def93SJuli Mallett switch (ch) { 1319b50d902SRodney W. Grimes case 'b': 1323241f274SDiomidis Spinellis boring = true; 13315ba0427SDima Dorfman /* FALLTHROUGH */ 1349b50d902SRodney W. Grimes case 'w': 13515ba0427SDima Dorfman if (strlcpy(format, optarg, sizeof(format)) >= 13615ba0427SDima Dorfman sizeof(format)) 13715ba0427SDima Dorfman errx(1, "-%c word too long", ch); 138d129c68aSDiomidis Spinellis have_format = true; 1399b50d902SRodney W. Grimes break; 1403241f274SDiomidis Spinellis case 'c': 1413241f274SDiomidis Spinellis chardata = true; 1423241f274SDiomidis Spinellis break; 1433241f274SDiomidis Spinellis case 'n': 1443241f274SDiomidis Spinellis nofinalnl = true; 1459b50d902SRodney W. Grimes break; 1469b50d902SRodney W. Grimes case 'p': 14715ba0427SDima Dorfman prec = atoi(optarg); 1489c24af3dSBrian Somers if (prec < 0) 1497bd7ad50SPhilippe Charnier errx(1, "bad precision value"); 150d129c68aSDiomidis Spinellis have_format = true; 1519b50d902SRodney W. Grimes break; 1523241f274SDiomidis Spinellis case 'r': 1533241f274SDiomidis Spinellis randomize = true; 1543241f274SDiomidis Spinellis break; 1553241f274SDiomidis Spinellis case 's': 1563241f274SDiomidis Spinellis sepstring = optarg; 1573241f274SDiomidis Spinellis break; 1589b50d902SRodney W. Grimes default: 1597bd7ad50SPhilippe Charnier usage(); 1609b50d902SRodney W. Grimes } 16115ba0427SDima Dorfman argc -= optind; 16215ba0427SDima Dorfman argv += optind; 1639b50d902SRodney W. Grimes 16415ba0427SDima Dorfman switch (argc) { /* examine args right to left, falling thru cases */ 1659b50d902SRodney W. Grimes case 4: 16615ba0427SDima Dorfman if (!is_default(argv[3])) { 16715ba0427SDima Dorfman if (!sscanf(argv[3], "%lf", &s)) 16815ba0427SDima Dorfman errx(1, "bad s value: %s", argv[3]); 169afe53a49SDiomidis Spinellis mask |= HAVE_STEP; 170a26a6612SDiomidis Spinellis if (randomize) 171d129c68aSDiomidis Spinellis use_random = true; 1729b50d902SRodney W. Grimes } 173afe53a49SDiomidis Spinellis /* FALLTHROUGH */ 1749b50d902SRodney W. Grimes case 3: 17515ba0427SDima Dorfman if (!is_default(argv[2])) { 17615ba0427SDima Dorfman if (!sscanf(argv[2], "%lf", &ender)) 17715ba0427SDima Dorfman ender = argv[2][strlen(argv[2])-1]; 178afe53a49SDiomidis Spinellis mask |= HAVE_ENDER; 1799c24af3dSBrian Somers if (prec < 0) 18015ba0427SDima Dorfman n = getprec(argv[2]); 1819b50d902SRodney W. Grimes } 182afe53a49SDiomidis Spinellis /* FALLTHROUGH */ 1839b50d902SRodney W. Grimes case 2: 18415ba0427SDima Dorfman if (!is_default(argv[1])) { 18515ba0427SDima Dorfman if (!sscanf(argv[1], "%lf", &begin)) 18615ba0427SDima Dorfman begin = argv[1][strlen(argv[1])-1]; 187afe53a49SDiomidis Spinellis mask |= HAVE_BEGIN; 1889c24af3dSBrian Somers if (prec < 0) 18915ba0427SDima Dorfman prec = getprec(argv[1]); 1909b50d902SRodney W. Grimes if (n > prec) /* maximum precision */ 1919b50d902SRodney W. Grimes prec = n; 1929b50d902SRodney W. Grimes } 193afe53a49SDiomidis Spinellis /* FALLTHROUGH */ 1949b50d902SRodney W. Grimes case 1: 19515ba0427SDima Dorfman if (!is_default(argv[0])) { 19615ba0427SDima Dorfman if (!sscanf(argv[0], "%ld", &reps)) 19715ba0427SDima Dorfman errx(1, "bad reps value: %s", argv[0]); 198afe53a49SDiomidis Spinellis mask |= HAVE_REPS; 1999b50d902SRodney W. Grimes } 2009b50d902SRodney W. Grimes break; 2019b50d902SRodney W. Grimes case 0: 2027bd7ad50SPhilippe Charnier usage(); 2039b50d902SRodney W. Grimes default: 20415ba0427SDima Dorfman errx(1, "too many arguments. What do you mean by %s?", 20515ba0427SDima Dorfman argv[4]); 2069b50d902SRodney W. Grimes } 2079b50d902SRodney W. Grimes getformat(); 2089c24af3dSBrian Somers 2099c24af3dSBrian Somers if (prec == -1) 2109c24af3dSBrian Somers prec = 0; 2119c24af3dSBrian Somers 2129b50d902SRodney W. Grimes while (mask) /* 4 bit mask has 1's where last 4 args were given */ 2139b50d902SRodney W. Grimes switch (mask) { /* fill in the 0's by default or computation */ 214afe53a49SDiomidis Spinellis case HAVE_STEP: 215afe53a49SDiomidis Spinellis case HAVE_ENDER: 216afe53a49SDiomidis Spinellis case HAVE_ENDER | HAVE_STEP: 217afe53a49SDiomidis Spinellis case HAVE_BEGIN: 218afe53a49SDiomidis Spinellis case HAVE_BEGIN | HAVE_STEP: 2199b50d902SRodney W. Grimes reps = REPS_DEF; 220d737ec1aSDiomidis Spinellis mask |= HAVE_REPS; 2219b50d902SRodney W. Grimes break; 2227d71f06cSDiomidis Spinellis case HAVE_BEGIN | HAVE_ENDER: 2237d71f06cSDiomidis Spinellis s = ender > begin ? 1 : -1; 2247d71f06cSDiomidis Spinellis mask |= HAVE_STEP; 2257d71f06cSDiomidis Spinellis break; 226afe53a49SDiomidis Spinellis case HAVE_BEGIN | HAVE_ENDER | HAVE_STEP: 227d737ec1aSDiomidis Spinellis if (randomize) 2289b50d902SRodney W. Grimes reps = REPS_DEF; 229d737ec1aSDiomidis Spinellis else if (s == 0.0) 2309b50d902SRodney W. Grimes reps = 0; 231d737ec1aSDiomidis Spinellis else 2329b50d902SRodney W. Grimes reps = (ender - begin + s) / s; 2339b50d902SRodney W. Grimes if (reps <= 0) 2347bd7ad50SPhilippe Charnier errx(1, "impossible stepsize"); 2359b50d902SRodney W. Grimes mask = 0; 2369b50d902SRodney W. Grimes break; 237afe53a49SDiomidis Spinellis case HAVE_REPS: 238afe53a49SDiomidis Spinellis case HAVE_REPS | HAVE_STEP: 2399b50d902SRodney W. Grimes begin = BEGIN_DEF; 240d737ec1aSDiomidis Spinellis mask |= HAVE_BEGIN; 2419b50d902SRodney W. Grimes break; 242afe53a49SDiomidis Spinellis case HAVE_REPS | HAVE_ENDER: 243a26a6612SDiomidis Spinellis s = STEP_DEF; 244afe53a49SDiomidis Spinellis mask = HAVE_REPS | HAVE_ENDER | HAVE_STEP; 2459b50d902SRodney W. Grimes break; 246afe53a49SDiomidis Spinellis case HAVE_REPS | HAVE_ENDER | HAVE_STEP: 2479b50d902SRodney W. Grimes if (randomize) 2489b50d902SRodney W. Grimes begin = BEGIN_DEF; 2499b50d902SRodney W. Grimes else if (reps == 0) 2507bd7ad50SPhilippe Charnier errx(1, "must specify begin if reps == 0"); 2519b50d902SRodney W. Grimes begin = ender - reps * s + s; 2529b50d902SRodney W. Grimes mask = 0; 2539b50d902SRodney W. Grimes break; 254afe53a49SDiomidis Spinellis case HAVE_REPS | HAVE_BEGIN: 255a26a6612SDiomidis Spinellis s = STEP_DEF; 256afe53a49SDiomidis Spinellis mask = HAVE_REPS | HAVE_BEGIN | HAVE_STEP; 2579b50d902SRodney W. Grimes break; 258afe53a49SDiomidis Spinellis case HAVE_REPS | HAVE_BEGIN | HAVE_STEP: 2599b50d902SRodney W. Grimes if (randomize) 2609b50d902SRodney W. Grimes ender = ENDER_DEF; 2619b50d902SRodney W. Grimes else 2629b50d902SRodney W. Grimes ender = begin + reps * s - s; 2639b50d902SRodney W. Grimes mask = 0; 2649b50d902SRodney W. Grimes break; 265afe53a49SDiomidis Spinellis case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER: 266a26a6612SDiomidis Spinellis if (reps == 0) 2677bd7ad50SPhilippe Charnier errx(1, "infinite sequences cannot be bounded"); 2689b50d902SRodney W. Grimes else if (reps == 1) 2699b50d902SRodney W. Grimes s = 0.0; 2709b50d902SRodney W. Grimes else 2719b50d902SRodney W. Grimes s = (ender - begin) / (reps - 1); 2729b50d902SRodney W. Grimes mask = 0; 2739b50d902SRodney W. Grimes break; 274afe53a49SDiomidis Spinellis case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER | HAVE_STEP: 275afe53a49SDiomidis Spinellis /* if reps given and implied, */ 2769b50d902SRodney W. Grimes if (!randomize && s != 0.0) { 2779b50d902SRodney W. Grimes long t = (ender - begin + s) / s; 2789b50d902SRodney W. Grimes if (t <= 0) 2797bd7ad50SPhilippe Charnier errx(1, "impossible stepsize"); 2809b50d902SRodney W. Grimes if (t < reps) /* take lesser */ 2819b50d902SRodney W. Grimes reps = t; 2829b50d902SRodney W. Grimes } 2839b50d902SRodney W. Grimes mask = 0; 2849b50d902SRodney W. Grimes break; 2859b50d902SRodney W. Grimes default: 2867bd7ad50SPhilippe Charnier errx(1, "bad mask"); 2879b50d902SRodney W. Grimes } 2889b50d902SRodney W. Grimes if (reps == 0) 2893241f274SDiomidis Spinellis infinity = true; 29015ba0427SDima Dorfman if (randomize) { 291d129c68aSDiomidis Spinellis if (use_random) { 292a26a6612SDiomidis Spinellis srandom((unsigned long)s); 293d129c68aSDiomidis Spinellis divisor = (double)INT32_MAX + 1; 294d129c68aSDiomidis Spinellis } else 295d129c68aSDiomidis Spinellis divisor = (double)UINT32_MAX + 1; 296d129c68aSDiomidis Spinellis 297d129c68aSDiomidis Spinellis /* 298d129c68aSDiomidis Spinellis * Attempt to DWIM when the user has specified an 299d129c68aSDiomidis Spinellis * integer range within that of the random number 300d129c68aSDiomidis Spinellis * generator: distribute the numbers equally in 301d129c68aSDiomidis Spinellis * the range [begin .. ender]. Jot's default %.0f 302d129c68aSDiomidis Spinellis * format would make the appearance of the first and 303d129c68aSDiomidis Spinellis * last specified value half as likely as the rest. 304d129c68aSDiomidis Spinellis */ 305d129c68aSDiomidis Spinellis if (!have_format && prec == 0 && 306d129c68aSDiomidis Spinellis begin >= 0 && begin < divisor && 307d129c68aSDiomidis Spinellis ender >= 0 && ender < divisor) { 3089c24af3dSBrian Somers if (begin <= ender) 309d129c68aSDiomidis Spinellis ender += 1; 3109c24af3dSBrian Somers else 3119c24af3dSBrian Somers begin += 1; 3123241f274SDiomidis Spinellis nosign = true; 3133241f274SDiomidis Spinellis intdata = true; 314d129c68aSDiomidis Spinellis (void)strlcpy(format, 315d129c68aSDiomidis Spinellis chardata ? "%c" : "%u", sizeof(format)); 316d129c68aSDiomidis Spinellis } 3179c24af3dSBrian Somers x = ender - begin; 31855f965aeSDiomidis Spinellis for (i = 1; i <= reps || infinity; i++) { 319d129c68aSDiomidis Spinellis if (use_random) 320d129c68aSDiomidis Spinellis y = random() / divisor; 321a26a6612SDiomidis Spinellis else 322d129c68aSDiomidis Spinellis y = arc4random() / divisor; 3233241f274SDiomidis Spinellis if (putdata(y * x + begin, !(reps - i))) 32415ba0427SDima Dorfman errx(1, "range error in conversion"); 32515ba0427SDima Dorfman } 32615ba0427SDima Dorfman } else 32755f965aeSDiomidis Spinellis for (i = 1, x = begin; i <= reps || infinity; i++, x += s) 3283241f274SDiomidis Spinellis if (putdata(x, !(reps - i))) 32915ba0427SDima Dorfman errx(1, "range error in conversion"); 33015ba0427SDima Dorfman if (!nofinalnl) 33115ba0427SDima Dorfman putchar('\n'); 33215ba0427SDima Dorfman exit(0); 3339b50d902SRodney W. Grimes } 3349b50d902SRodney W. Grimes 3353241f274SDiomidis Spinellis /* 3363241f274SDiomidis Spinellis * Send x to stdout using the specified format. 3373241f274SDiomidis Spinellis * Last is true if this is the set's last value. 3383241f274SDiomidis Spinellis * Return 0 if OK, or a positive number if the number passed was 3393241f274SDiomidis Spinellis * outside the range specified by the various flags. 3403241f274SDiomidis Spinellis */ 3413241f274SDiomidis Spinellis static int 3423241f274SDiomidis Spinellis putdata(double x, bool last) 3439b50d902SRodney W. Grimes { 3449b50d902SRodney W. Grimes 3455249bd84SSheldon Hearn if (boring) 346612740bdSKris Kennaway printf("%s", format); 3475249bd84SSheldon Hearn else if (longdata && nosign) { 3485249bd84SSheldon Hearn if (x <= (double)ULONG_MAX && x >= (double)0) 3498db8a33bSSheldon Hearn printf(format, (unsigned long)x); 3505249bd84SSheldon Hearn else 3515249bd84SSheldon Hearn return (1); 3525249bd84SSheldon Hearn } else if (longdata) { 3535249bd84SSheldon Hearn if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) 3548db8a33bSSheldon Hearn printf(format, (long)x); 3555249bd84SSheldon Hearn else 3565249bd84SSheldon Hearn return (1); 3575249bd84SSheldon Hearn } else if (chardata || (intdata && !nosign)) { 3585249bd84SSheldon Hearn if (x <= (double)INT_MAX && x >= (double)INT_MIN) 3595249bd84SSheldon Hearn printf(format, (int)x); 3605249bd84SSheldon Hearn else 3615249bd84SSheldon Hearn return (1); 3625249bd84SSheldon Hearn } else if (intdata) { 3635249bd84SSheldon Hearn if (x <= (double)UINT_MAX && x >= (double)0) 3645249bd84SSheldon Hearn printf(format, (unsigned int)x); 3655249bd84SSheldon Hearn else 3665249bd84SSheldon Hearn return (1); 3675249bd84SSheldon Hearn 3685249bd84SSheldon Hearn } else 3699b50d902SRodney W. Grimes printf(format, x); 3703241f274SDiomidis Spinellis if (!last) 3719b50d902SRodney W. Grimes fputs(sepstring, stdout); 3725249bd84SSheldon Hearn 3735249bd84SSheldon Hearn return (0); 3749b50d902SRodney W. Grimes } 3759b50d902SRodney W. Grimes 3767bd7ad50SPhilippe Charnier static void 377cf0def93SJuli Mallett usage(void) 3789b50d902SRodney W. Grimes { 3797bd7ad50SPhilippe Charnier fprintf(stderr, "%s\n%s\n", 3807bd7ad50SPhilippe Charnier "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 3817bd7ad50SPhilippe Charnier " [reps [begin [end [s]]]]"); 3829b50d902SRodney W. Grimes exit(1); 3839b50d902SRodney W. Grimes } 3849b50d902SRodney W. Grimes 3853241f274SDiomidis Spinellis /* 3863241f274SDiomidis Spinellis * Return the number of digits following the number's decimal point. 3873241f274SDiomidis Spinellis * Return 0 if no decimal point is found. 3883241f274SDiomidis Spinellis */ 3893241f274SDiomidis Spinellis static int 3903241f274SDiomidis Spinellis getprec(const char *str) 3919b50d902SRodney W. Grimes { 3923241f274SDiomidis Spinellis const char *p; 3933241f274SDiomidis Spinellis const char *q; 3949b50d902SRodney W. Grimes 395edd7b267SDima Dorfman for (p = str; *p; p++) 3969b50d902SRodney W. Grimes if (*p == '.') 3979b50d902SRodney W. Grimes break; 3989b50d902SRodney W. Grimes if (!*p) 3999b50d902SRodney W. Grimes return (0); 4009b50d902SRodney W. Grimes for (q = ++p; *p; p++) 401911a3ff9STim J. Robbins if (!isdigit((unsigned char)*p)) 4029b50d902SRodney W. Grimes break; 4039b50d902SRodney W. Grimes return (p - q); 4049b50d902SRodney W. Grimes } 4059b50d902SRodney W. Grimes 4063241f274SDiomidis Spinellis /* 4073241f274SDiomidis Spinellis * Set format, intdata, chardata, longdata, and nosign 4083241f274SDiomidis Spinellis * based on the command line arguments. 4093241f274SDiomidis Spinellis */ 4103241f274SDiomidis Spinellis static void 411cf0def93SJuli Mallett getformat(void) 4129b50d902SRodney W. Grimes { 413edd7b267SDima Dorfman char *p, *p2; 4145249bd84SSheldon Hearn int dot, hash, space, sign, numbers = 0; 41515ba0427SDima Dorfman size_t sz; 4169b50d902SRodney W. Grimes 4179b50d902SRodney W. Grimes if (boring) /* no need to bother */ 4189b50d902SRodney W. Grimes return; 4199b50d902SRodney W. Grimes for (p = format; *p; p++) /* look for '%' */ 42082417e9fSXin LI if (*p == '%') { 42134785a9fSDiomidis Spinellis if (p[1] == '%') 42234785a9fSDiomidis Spinellis p++; /* leave %% alone */ 42334785a9fSDiomidis Spinellis else 4249b50d902SRodney W. Grimes break; 42582417e9fSXin LI } 42615ba0427SDima Dorfman sz = sizeof(format) - strlen(format) - 1; 42715ba0427SDima Dorfman if (!*p && !chardata) { 42815ba0427SDima Dorfman if (snprintf(p, sz, "%%.%df", prec) >= (int)sz) 42915ba0427SDima Dorfman errx(1, "-w word too long"); 43015ba0427SDima Dorfman } else if (!*p && chardata) { 43115ba0427SDima Dorfman if (strlcpy(p, "%c", sz) >= sz) 43215ba0427SDima Dorfman errx(1, "-w word too long"); 4333241f274SDiomidis Spinellis intdata = true; 43415ba0427SDima Dorfman } else if (!*(p+1)) { 43515ba0427SDima Dorfman if (sz <= 0) 43615ba0427SDima Dorfman errx(1, "-w word too long"); 4379b50d902SRodney W. Grimes strcat(format, "%"); /* cannot end in single '%' */ 43815ba0427SDima Dorfman } else { 4398db8a33bSSheldon Hearn /* 4408db8a33bSSheldon Hearn * Allow conversion format specifiers of the form 4418db8a33bSSheldon Hearn * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 4428db8a33bSSheldon Hearn * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 4438db8a33bSSheldon Hearn */ 444edd7b267SDima Dorfman p2 = p++; 4458db8a33bSSheldon Hearn dot = hash = space = sign = numbers = 0; 446911a3ff9STim J. Robbins while (!isalpha((unsigned char)*p)) { 447911a3ff9STim J. Robbins if (isdigit((unsigned char)*p)) { 4488db8a33bSSheldon Hearn numbers++; 4499b50d902SRodney W. Grimes p++; 4508db8a33bSSheldon Hearn } else if ((*p == '#' && !(numbers|dot|sign|space| 4518db8a33bSSheldon Hearn hash++)) || 4528db8a33bSSheldon Hearn (*p == ' ' && !(numbers|dot|space++)) || 4538db8a33bSSheldon Hearn ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 4548db8a33bSSheldon Hearn || (*p == '.' && !(dot++))) 4558db8a33bSSheldon Hearn p++; 4568db8a33bSSheldon Hearn else 4575249bd84SSheldon Hearn goto fmt_broken; 4585249bd84SSheldon Hearn } 4595249bd84SSheldon Hearn if (*p == 'l') { 4603241f274SDiomidis Spinellis longdata = true; 4615249bd84SSheldon Hearn if (*++p == 'l') { 4625249bd84SSheldon Hearn if (p[1] != '\0') 4635249bd84SSheldon Hearn p++; 4645249bd84SSheldon Hearn goto fmt_broken; 4655249bd84SSheldon Hearn } 4668db8a33bSSheldon Hearn } 4679b50d902SRodney W. Grimes switch (*p) { 4688db8a33bSSheldon Hearn case 'o': case 'u': case 'x': case 'X': 4693241f274SDiomidis Spinellis intdata = nosign = true; 4709b50d902SRodney W. Grimes break; 4718db8a33bSSheldon Hearn case 'd': case 'i': 4723241f274SDiomidis Spinellis intdata = true; 4738db8a33bSSheldon Hearn break; 4748db8a33bSSheldon Hearn case 'D': 4755249bd84SSheldon Hearn if (!longdata) { 4763241f274SDiomidis Spinellis intdata = true; 4778db8a33bSSheldon Hearn break; 4788db8a33bSSheldon Hearn } 4798db8a33bSSheldon Hearn case 'O': case 'U': 4805249bd84SSheldon Hearn if (!longdata) { 4813241f274SDiomidis Spinellis intdata = nosign = true; 4828db8a33bSSheldon Hearn break; 4838db8a33bSSheldon Hearn } 4848db8a33bSSheldon Hearn case 'c': 4855249bd84SSheldon Hearn if (!(intdata | longdata)) { 4863241f274SDiomidis Spinellis chardata = true; 4878db8a33bSSheldon Hearn break; 4888db8a33bSSheldon Hearn } 4895249bd84SSheldon Hearn case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 4908db8a33bSSheldon Hearn case '$': case '*': 4915249bd84SSheldon Hearn goto fmt_broken; 4928db8a33bSSheldon Hearn case 'f': case 'e': case 'g': case 'E': case 'G': 4935249bd84SSheldon Hearn if (!longdata) 4948db8a33bSSheldon Hearn break; 4958db8a33bSSheldon Hearn /* FALLTHROUGH */ 4969b50d902SRodney W. Grimes default: 4975249bd84SSheldon Hearn fmt_broken: 4988db8a33bSSheldon Hearn *++p = '\0'; 499edd7b267SDima Dorfman errx(1, "illegal or unsupported format '%s'", p2); 5008db8a33bSSheldon Hearn /* NOTREACHED */ 5018db8a33bSSheldon Hearn } 5028db8a33bSSheldon Hearn while (*++p) 5038db8a33bSSheldon Hearn if (*p == '%' && *(p+1) && *(p+1) != '%') 5048db8a33bSSheldon Hearn errx(1, "too many conversions"); 5058db8a33bSSheldon Hearn else if (*p == '%' && *(p+1) == '%') 5068db8a33bSSheldon Hearn p++; 5078db8a33bSSheldon Hearn else if (*p == '%' && !*(p+1)) { 508f88b45d7SDiomidis Spinellis if (strlcat(format, "%", sizeof(format)) >= 509f88b45d7SDiomidis Spinellis sizeof(format)) 510f88b45d7SDiomidis Spinellis errx(1, "-w word too long"); 5119b50d902SRodney W. Grimes break; 5129b50d902SRodney W. Grimes } 5139b50d902SRodney W. Grimes } 5149b50d902SRodney W. Grimes } 515