jot.c revision 92920
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 92920 2002-03-22 01:22:50Z imp $"; 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 6877276Sdd#define is_default(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; 8377287Sddconst char *sepstring = "\n"; 841590Srgrimeschar format[BUFSIZ]; 851590Srgrimes 8692920Simpint main(int, char *[]); 8792920Simpvoid getformat(void); 8892920Simpint getprec(char *); 8992920Simpint putdata(double, long); 9092920Simpstatic void usage(void); 911590Srgrimes 921590Srgrimesint 931590Srgrimesmain(argc, argv) 941590Srgrimes int argc; 951590Srgrimes char *argv[]; 961590Srgrimes{ 971590Srgrimes double xd, yd; 981590Srgrimes long id; 9977276Sdd double *x = &xd; 10077276Sdd double *y = &yd; 10177276Sdd long *i = &id; 10277276Sdd unsigned int mask = 0; 10377276Sdd int n = 0; 10477276Sdd int ch; 1051590Srgrimes 10677276Sdd while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) 10777276Sdd switch ((char)ch) { 1081590Srgrimes case 'r': 1091590Srgrimes randomize = 1; 1101590Srgrimes break; 1111590Srgrimes case 'c': 1121590Srgrimes chardata = 1; 1131590Srgrimes break; 1141590Srgrimes case 'n': 1151590Srgrimes nofinalnl = 1; 1161590Srgrimes break; 1171590Srgrimes case 'b': 1181590Srgrimes boring = 1; 11977276Sdd /* FALLTHROUGH */ 1201590Srgrimes case 'w': 12177276Sdd if (strlcpy(format, optarg, sizeof(format)) >= 12277276Sdd sizeof(format)) 12377276Sdd errx(1, "-%c word too long", ch); 1241590Srgrimes break; 1251590Srgrimes case 's': 12677276Sdd sepstring = optarg; 1271590Srgrimes break; 1281590Srgrimes case 'p': 12977276Sdd prec = atoi(optarg); 1301590Srgrimes if (prec <= 0) 13127423Scharnier errx(1, "bad precision value"); 1321590Srgrimes break; 1331590Srgrimes default: 13427423Scharnier usage(); 1351590Srgrimes } 13677276Sdd argc -= optind; 13777276Sdd argv += optind; 1381590Srgrimes 13977276Sdd switch (argc) { /* examine args right to left, falling thru cases */ 1401590Srgrimes case 4: 14177276Sdd if (!is_default(argv[3])) { 14277276Sdd if (!sscanf(argv[3], "%lf", &s)) 14377276Sdd errx(1, "bad s value: %s", argv[3]); 1441590Srgrimes mask |= 01; 1451590Srgrimes } 1461590Srgrimes case 3: 14777276Sdd if (!is_default(argv[2])) { 14877276Sdd if (!sscanf(argv[2], "%lf", &ender)) 14977276Sdd ender = argv[2][strlen(argv[2])-1]; 1501590Srgrimes mask |= 02; 1511590Srgrimes if (!prec) 15277276Sdd n = getprec(argv[2]); 1531590Srgrimes } 1541590Srgrimes case 2: 15577276Sdd if (!is_default(argv[1])) { 15677276Sdd if (!sscanf(argv[1], "%lf", &begin)) 15777276Sdd begin = argv[1][strlen(argv[1])-1]; 1581590Srgrimes mask |= 04; 1591590Srgrimes if (!prec) 16077276Sdd prec = getprec(argv[1]); 1611590Srgrimes if (n > prec) /* maximum precision */ 1621590Srgrimes prec = n; 1631590Srgrimes } 1641590Srgrimes case 1: 16577276Sdd if (!is_default(argv[0])) { 16677276Sdd if (!sscanf(argv[0], "%ld", &reps)) 16777276Sdd errx(1, "bad reps value: %s", argv[0]); 1681590Srgrimes mask |= 010; 1691590Srgrimes } 1701590Srgrimes break; 1711590Srgrimes case 0: 17227423Scharnier usage(); 1731590Srgrimes default: 17477276Sdd errx(1, "too many arguments. What do you mean by %s?", 17577276Sdd argv[4]); 1761590Srgrimes } 1771590Srgrimes getformat(); 1781590Srgrimes while (mask) /* 4 bit mask has 1's where last 4 args were given */ 1791590Srgrimes switch (mask) { /* fill in the 0's by default or computation */ 1801590Srgrimes case 001: 1811590Srgrimes reps = REPS_DEF; 1821590Srgrimes mask = 011; 1831590Srgrimes break; 1841590Srgrimes case 002: 1851590Srgrimes reps = REPS_DEF; 1861590Srgrimes mask = 012; 1871590Srgrimes break; 1881590Srgrimes case 003: 1891590Srgrimes reps = REPS_DEF; 1901590Srgrimes mask = 013; 1911590Srgrimes break; 1921590Srgrimes case 004: 1931590Srgrimes reps = REPS_DEF; 1941590Srgrimes mask = 014; 1951590Srgrimes break; 1961590Srgrimes case 005: 1971590Srgrimes reps = REPS_DEF; 1981590Srgrimes mask = 015; 1991590Srgrimes break; 2001590Srgrimes case 006: 2011590Srgrimes reps = REPS_DEF; 2021590Srgrimes mask = 016; 2031590Srgrimes break; 2041590Srgrimes case 007: 2051590Srgrimes if (randomize) { 2061590Srgrimes reps = REPS_DEF; 2071590Srgrimes mask = 0; 2081590Srgrimes break; 2091590Srgrimes } 2101590Srgrimes if (s == 0.0) { 2111590Srgrimes reps = 0; 2121590Srgrimes mask = 0; 2131590Srgrimes break; 2141590Srgrimes } 2151590Srgrimes reps = (ender - begin + s) / s; 2161590Srgrimes if (reps <= 0) 21727423Scharnier errx(1, "impossible stepsize"); 2181590Srgrimes mask = 0; 2191590Srgrimes break; 2201590Srgrimes case 010: 2211590Srgrimes begin = BEGIN_DEF; 2221590Srgrimes mask = 014; 2231590Srgrimes break; 2241590Srgrimes case 011: 2251590Srgrimes begin = BEGIN_DEF; 2261590Srgrimes mask = 015; 2271590Srgrimes break; 2281590Srgrimes case 012: 22977276Sdd s = (randomize ? time(NULL) : STEP_DEF); 2301590Srgrimes mask = 013; 2311590Srgrimes break; 2321590Srgrimes case 013: 2331590Srgrimes if (randomize) 2341590Srgrimes begin = BEGIN_DEF; 2351590Srgrimes else if (reps == 0) 23627423Scharnier errx(1, "must specify begin if reps == 0"); 23777276Sdd begin = ender - reps * s + s; 2381590Srgrimes mask = 0; 2391590Srgrimes break; 2401590Srgrimes case 014: 24124419Sache s = (randomize ? -1.0 : STEP_DEF); 2421590Srgrimes mask = 015; 2431590Srgrimes break; 2441590Srgrimes case 015: 2451590Srgrimes if (randomize) 2461590Srgrimes ender = ENDER_DEF; 2471590Srgrimes else 2481590Srgrimes ender = begin + reps * s - s; 2491590Srgrimes mask = 0; 2501590Srgrimes break; 2511590Srgrimes case 016: 2521590Srgrimes if (randomize) 25324419Sache s = -1.0; 2541590Srgrimes else if (reps == 0) 25527423Scharnier errx(1, "infinite sequences cannot be bounded"); 2561590Srgrimes else if (reps == 1) 2571590Srgrimes s = 0.0; 2581590Srgrimes else 2591590Srgrimes s = (ender - begin) / (reps - 1); 2601590Srgrimes mask = 0; 2611590Srgrimes break; 2621590Srgrimes case 017: /* if reps given and implied, */ 2631590Srgrimes if (!randomize && s != 0.0) { 2641590Srgrimes long t = (ender - begin + s) / s; 2651590Srgrimes if (t <= 0) 26627423Scharnier errx(1, "impossible stepsize"); 2671590Srgrimes if (t < reps) /* take lesser */ 2681590Srgrimes reps = t; 2691590Srgrimes } 2701590Srgrimes mask = 0; 2711590Srgrimes break; 2721590Srgrimes default: 27327423Scharnier errx(1, "bad mask"); 2741590Srgrimes } 2751590Srgrimes if (reps == 0) 2761590Srgrimes infinity = 1; 27777276Sdd if (randomize) { 27877276Sdd *x = (ender - begin) * (ender > begin ? 1 : -1); 27977276Sdd for (*i = 1; *i <= reps || infinity; (*i)++) { 28086197Swollman *y = arc4random() / (double)UINT32_MAX; 28177276Sdd if (putdata(*y * *x + begin, reps - *i)) 28277276Sdd errx(1, "range error in conversion"); 28377276Sdd } 28477276Sdd } else 28577276Sdd for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) 28677276Sdd if (putdata(*x, reps - *i)) 28777276Sdd errx(1, "range error in conversion"); 28877276Sdd if (!nofinalnl) 28977276Sdd putchar('\n'); 29077276Sdd exit(0); 2911590Srgrimes} 2921590Srgrimes 29355515Ssheldonhint 2941590Srgrimesputdata(x, notlast) 2951590Srgrimes double x; 2961590Srgrimes long notlast; 2971590Srgrimes{ 2981590Srgrimes 29955515Ssheldonh if (boring) 30062871Skris printf("%s", format); 30155515Ssheldonh else if (longdata && nosign) { 30255515Ssheldonh if (x <= (double)ULONG_MAX && x >= (double)0) 30355515Ssheldonh printf(format, (unsigned long)x); 30455515Ssheldonh else 30555515Ssheldonh return (1); 30655515Ssheldonh } else if (longdata) { 30755515Ssheldonh if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) 30855515Ssheldonh printf(format, (long)x); 30955515Ssheldonh else 31055515Ssheldonh return (1); 31155515Ssheldonh } else if (chardata || (intdata && !nosign)) { 31255515Ssheldonh if (x <= (double)INT_MAX && x >= (double)INT_MIN) 31355515Ssheldonh printf(format, (int)x); 31455515Ssheldonh else 31555515Ssheldonh return (1); 31655515Ssheldonh } else if (intdata) { 31755515Ssheldonh if (x <= (double)UINT_MAX && x >= (double)0) 31855515Ssheldonh printf(format, (unsigned int)x); 31955515Ssheldonh else 32055515Ssheldonh return (1); 32155515Ssheldonh 32255515Ssheldonh } else 3231590Srgrimes printf(format, x); 3241590Srgrimes if (notlast != 0) 3251590Srgrimes fputs(sepstring, stdout); 32655515Ssheldonh 32755515Ssheldonh return (0); 3281590Srgrimes} 3291590Srgrimes 33027423Scharnierstatic void 33127423Scharnierusage() 3321590Srgrimes{ 33327423Scharnier fprintf(stderr, "%s\n%s\n", 33430908Scharnier "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 33530908Scharnier " [reps [begin [end [s]]]]"); 3361590Srgrimes exit(1); 3371590Srgrimes} 3381590Srgrimes 3391590Srgrimesint 34077287Sddgetprec(str) 34177287Sdd char *str; 3421590Srgrimes{ 34377276Sdd char *p; 34477276Sdd char *q; 3451590Srgrimes 34677287Sdd for (p = str; *p; p++) 3471590Srgrimes if (*p == '.') 3481590Srgrimes break; 3491590Srgrimes if (!*p) 3501590Srgrimes return (0); 3511590Srgrimes for (q = ++p; *p; p++) 3521590Srgrimes if (!isdigit(*p)) 3531590Srgrimes break; 3541590Srgrimes return (p - q); 3551590Srgrimes} 3561590Srgrimes 3571590Srgrimesvoid 3581590Srgrimesgetformat() 3591590Srgrimes{ 36077287Sdd char *p, *p2; 36155515Ssheldonh int dot, hash, space, sign, numbers = 0; 36277276Sdd size_t sz; 3631590Srgrimes 3641590Srgrimes if (boring) /* no need to bother */ 3651590Srgrimes return; 3661590Srgrimes for (p = format; *p; p++) /* look for '%' */ 3671590Srgrimes if (*p == '%' && *(p+1) != '%') /* leave %% alone */ 3681590Srgrimes break; 36977276Sdd sz = sizeof(format) - strlen(format) - 1; 37077276Sdd if (!*p && !chardata) { 37177276Sdd if (snprintf(p, sz, "%%.%df", prec) >= (int)sz) 37277276Sdd errx(1, "-w word too long"); 37377276Sdd } else if (!*p && chardata) { 37477276Sdd if (strlcpy(p, "%c", sz) >= sz) 37577276Sdd errx(1, "-w word too long"); 37648995Ssheldonh intdata = 1; 37777276Sdd } else if (!*(p+1)) { 37877276Sdd if (sz <= 0) 37977276Sdd errx(1, "-w word too long"); 3801590Srgrimes strcat(format, "%"); /* cannot end in single '%' */ 38177276Sdd } else { 38248995Ssheldonh /* 38348995Ssheldonh * Allow conversion format specifiers of the form 38448995Ssheldonh * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 38548995Ssheldonh * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 38648995Ssheldonh */ 38777287Sdd p2 = p++; 38848995Ssheldonh dot = hash = space = sign = numbers = 0; 38948995Ssheldonh while (!isalpha(*p)) { 39048995Ssheldonh if (isdigit(*p)) { 39148995Ssheldonh numbers++; 39248995Ssheldonh p++; 39348995Ssheldonh } else if ((*p == '#' && !(numbers|dot|sign|space| 39448995Ssheldonh hash++)) || 39548995Ssheldonh (*p == ' ' && !(numbers|dot|space++)) || 39648995Ssheldonh ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 39748995Ssheldonh || (*p == '.' && !(dot++))) 39848995Ssheldonh p++; 39948995Ssheldonh else 40055515Ssheldonh goto fmt_broken; 40148995Ssheldonh } 40255515Ssheldonh if (*p == 'l') { 40355515Ssheldonh longdata = 1; 40455515Ssheldonh if (*++p == 'l') { 40555515Ssheldonh if (p[1] != '\0') 40655515Ssheldonh p++; 40755515Ssheldonh goto fmt_broken; 40855515Ssheldonh } 40955515Ssheldonh } 41048995Ssheldonh switch (*p) { 41148995Ssheldonh case 'o': case 'u': case 'x': case 'X': 41248995Ssheldonh intdata = nosign = 1; 4131590Srgrimes break; 41448995Ssheldonh case 'd': case 'i': 41548995Ssheldonh intdata = 1; 41648995Ssheldonh break; 41748995Ssheldonh case 'D': 41855515Ssheldonh if (!longdata) { 41948995Ssheldonh intdata = 1; 42048995Ssheldonh break; 42148995Ssheldonh } 42248995Ssheldonh case 'O': case 'U': 42355515Ssheldonh if (!longdata) { 42448995Ssheldonh intdata = nosign = 1; 42548995Ssheldonh break; 42648995Ssheldonh } 42748995Ssheldonh case 'c': 42855515Ssheldonh if (!(intdata | longdata)) { 42948995Ssheldonh chardata = 1; 43048995Ssheldonh break; 43148995Ssheldonh } 43255515Ssheldonh case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 43348995Ssheldonh case '$': case '*': 43455515Ssheldonh goto fmt_broken; 43548995Ssheldonh case 'f': case 'e': case 'g': case 'E': case 'G': 43655515Ssheldonh if (!longdata) 43748995Ssheldonh break; 43848995Ssheldonh /* FALLTHROUGH */ 4391590Srgrimes default: 44055515Ssheldonhfmt_broken: 44148995Ssheldonh *++p = '\0'; 44277287Sdd errx(1, "illegal or unsupported format '%s'", p2); 44348995Ssheldonh /* NOTREACHED */ 4441590Srgrimes } 44548995Ssheldonh while (*++p) 44648995Ssheldonh if (*p == '%' && *(p+1) && *(p+1) != '%') 44748995Ssheldonh errx(1, "too many conversions"); 44848995Ssheldonh else if (*p == '%' && *(p+1) == '%') 44948995Ssheldonh p++; 45048995Ssheldonh else if (*p == '%' && !*(p+1)) { 45148995Ssheldonh strcat(format, "%"); 45248995Ssheldonh break; 45348995Ssheldonh } 4541590Srgrimes } 4551590Srgrimes} 456