jot.c revision 98254
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 4498254Sjmallett#endif 451590Srgrimes 4698254Sjmallett#include <sys/cdefs.h> 4798254Sjmallett__FBSDID("$FreeBSD: head/usr.bin/jot/jot.c 98254 2002-06-15 11:26:25Z jmallett $"); 4898254Sjmallett 491590Srgrimes/* 501590Srgrimes * jot - print sequential or random data 511590Srgrimes * 521590Srgrimes * Author: John Kunze, Office of Comp. Affairs, UCB 531590Srgrimes */ 541590Srgrimes 551590Srgrimes#include <ctype.h> 5627423Scharnier#include <err.h> 571590Srgrimes#include <limits.h> 581590Srgrimes#include <stdio.h> 591590Srgrimes#include <stdlib.h> 601590Srgrimes#include <string.h> 611590Srgrimes#include <time.h> 6223511Sache#include <unistd.h> 631590Srgrimes 641590Srgrimes#define REPS_DEF 100 651590Srgrimes#define BEGIN_DEF 1 661590Srgrimes#define ENDER_DEF 100 671590Srgrimes#define STEP_DEF 1 681590Srgrimes 6977276Sdd#define is_default(s) (strcmp((s), "-") == 0) 701590Srgrimes 711590Srgrimesdouble begin; 721590Srgrimesdouble ender; 731590Srgrimesdouble s; 741590Srgrimeslong reps; 751590Srgrimesint randomize; 761590Srgrimesint infinity; 771590Srgrimesint boring; 781590Srgrimesint prec; 7955515Ssheldonhint longdata; 8048995Ssheldonhint intdata; 811590Srgrimesint chardata; 8248995Ssheldonhint nosign; 831590Srgrimesint nofinalnl; 8477287Sddconst char *sepstring = "\n"; 851590Srgrimeschar format[BUFSIZ]; 861590Srgrimes 8792920Simpint main(int, char *[]); 8892920Simpvoid getformat(void); 8992920Simpint getprec(char *); 9092920Simpint putdata(double, long); 9192920Simpstatic void usage(void); 921590Srgrimes 931590Srgrimesint 9498254Sjmallettmain(int argc, char **argv) 951590Srgrimes{ 961590Srgrimes double xd, yd; 971590Srgrimes long id; 9877276Sdd double *x = &xd; 9977276Sdd double *y = &yd; 10077276Sdd long *i = &id; 10177276Sdd unsigned int mask = 0; 10277276Sdd int n = 0; 10377276Sdd int ch; 1041590Srgrimes 10577276Sdd while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) 10698254Sjmallett switch (ch) { 1071590Srgrimes case 'r': 1081590Srgrimes randomize = 1; 1091590Srgrimes break; 1101590Srgrimes case 'c': 1111590Srgrimes chardata = 1; 1121590Srgrimes break; 1131590Srgrimes case 'n': 1141590Srgrimes nofinalnl = 1; 1151590Srgrimes break; 1161590Srgrimes case 'b': 1171590Srgrimes boring = 1; 11877276Sdd /* FALLTHROUGH */ 1191590Srgrimes case 'w': 12077276Sdd if (strlcpy(format, optarg, sizeof(format)) >= 12177276Sdd sizeof(format)) 12277276Sdd errx(1, "-%c word too long", ch); 1231590Srgrimes break; 1241590Srgrimes case 's': 12577276Sdd sepstring = optarg; 1261590Srgrimes break; 1271590Srgrimes case 'p': 12877276Sdd prec = atoi(optarg); 1291590Srgrimes if (prec <= 0) 13027423Scharnier errx(1, "bad precision value"); 1311590Srgrimes break; 1321590Srgrimes default: 13327423Scharnier usage(); 1341590Srgrimes } 13577276Sdd argc -= optind; 13677276Sdd argv += optind; 1371590Srgrimes 13877276Sdd switch (argc) { /* examine args right to left, falling thru cases */ 1391590Srgrimes case 4: 14077276Sdd if (!is_default(argv[3])) { 14177276Sdd if (!sscanf(argv[3], "%lf", &s)) 14277276Sdd errx(1, "bad s value: %s", argv[3]); 1431590Srgrimes mask |= 01; 1441590Srgrimes } 1451590Srgrimes case 3: 14677276Sdd if (!is_default(argv[2])) { 14777276Sdd if (!sscanf(argv[2], "%lf", &ender)) 14877276Sdd ender = argv[2][strlen(argv[2])-1]; 1491590Srgrimes mask |= 02; 1501590Srgrimes if (!prec) 15177276Sdd n = getprec(argv[2]); 1521590Srgrimes } 1531590Srgrimes case 2: 15477276Sdd if (!is_default(argv[1])) { 15577276Sdd if (!sscanf(argv[1], "%lf", &begin)) 15677276Sdd begin = argv[1][strlen(argv[1])-1]; 1571590Srgrimes mask |= 04; 1581590Srgrimes if (!prec) 15977276Sdd prec = getprec(argv[1]); 1601590Srgrimes if (n > prec) /* maximum precision */ 1611590Srgrimes prec = n; 1621590Srgrimes } 1631590Srgrimes case 1: 16477276Sdd if (!is_default(argv[0])) { 16577276Sdd if (!sscanf(argv[0], "%ld", &reps)) 16677276Sdd errx(1, "bad reps value: %s", argv[0]); 1671590Srgrimes mask |= 010; 1681590Srgrimes } 1691590Srgrimes break; 1701590Srgrimes case 0: 17127423Scharnier usage(); 1721590Srgrimes default: 17377276Sdd errx(1, "too many arguments. What do you mean by %s?", 17477276Sdd argv[4]); 1751590Srgrimes } 1761590Srgrimes getformat(); 1771590Srgrimes while (mask) /* 4 bit mask has 1's where last 4 args were given */ 1781590Srgrimes switch (mask) { /* fill in the 0's by default or computation */ 1791590Srgrimes case 001: 1801590Srgrimes reps = REPS_DEF; 1811590Srgrimes mask = 011; 1821590Srgrimes break; 1831590Srgrimes case 002: 1841590Srgrimes reps = REPS_DEF; 1851590Srgrimes mask = 012; 1861590Srgrimes break; 1871590Srgrimes case 003: 1881590Srgrimes reps = REPS_DEF; 1891590Srgrimes mask = 013; 1901590Srgrimes break; 1911590Srgrimes case 004: 1921590Srgrimes reps = REPS_DEF; 1931590Srgrimes mask = 014; 1941590Srgrimes break; 1951590Srgrimes case 005: 1961590Srgrimes reps = REPS_DEF; 1971590Srgrimes mask = 015; 1981590Srgrimes break; 1991590Srgrimes case 006: 2001590Srgrimes reps = REPS_DEF; 2011590Srgrimes mask = 016; 2021590Srgrimes break; 2031590Srgrimes case 007: 2041590Srgrimes if (randomize) { 2051590Srgrimes reps = REPS_DEF; 2061590Srgrimes mask = 0; 2071590Srgrimes break; 2081590Srgrimes } 2091590Srgrimes if (s == 0.0) { 2101590Srgrimes reps = 0; 2111590Srgrimes mask = 0; 2121590Srgrimes break; 2131590Srgrimes } 2141590Srgrimes reps = (ender - begin + s) / s; 2151590Srgrimes if (reps <= 0) 21627423Scharnier errx(1, "impossible stepsize"); 2171590Srgrimes mask = 0; 2181590Srgrimes break; 2191590Srgrimes case 010: 2201590Srgrimes begin = BEGIN_DEF; 2211590Srgrimes mask = 014; 2221590Srgrimes break; 2231590Srgrimes case 011: 2241590Srgrimes begin = BEGIN_DEF; 2251590Srgrimes mask = 015; 2261590Srgrimes break; 2271590Srgrimes case 012: 22877276Sdd s = (randomize ? time(NULL) : STEP_DEF); 2291590Srgrimes mask = 013; 2301590Srgrimes break; 2311590Srgrimes case 013: 2321590Srgrimes if (randomize) 2331590Srgrimes begin = BEGIN_DEF; 2341590Srgrimes else if (reps == 0) 23527423Scharnier errx(1, "must specify begin if reps == 0"); 23677276Sdd begin = ender - reps * s + s; 2371590Srgrimes mask = 0; 2381590Srgrimes break; 2391590Srgrimes case 014: 24024419Sache s = (randomize ? -1.0 : STEP_DEF); 2411590Srgrimes mask = 015; 2421590Srgrimes break; 2431590Srgrimes case 015: 2441590Srgrimes if (randomize) 2451590Srgrimes ender = ENDER_DEF; 2461590Srgrimes else 2471590Srgrimes ender = begin + reps * s - s; 2481590Srgrimes mask = 0; 2491590Srgrimes break; 2501590Srgrimes case 016: 2511590Srgrimes if (randomize) 25224419Sache s = -1.0; 2531590Srgrimes else if (reps == 0) 25427423Scharnier errx(1, "infinite sequences cannot be bounded"); 2551590Srgrimes else if (reps == 1) 2561590Srgrimes s = 0.0; 2571590Srgrimes else 2581590Srgrimes s = (ender - begin) / (reps - 1); 2591590Srgrimes mask = 0; 2601590Srgrimes break; 2611590Srgrimes case 017: /* if reps given and implied, */ 2621590Srgrimes if (!randomize && s != 0.0) { 2631590Srgrimes long t = (ender - begin + s) / s; 2641590Srgrimes if (t <= 0) 26527423Scharnier errx(1, "impossible stepsize"); 2661590Srgrimes if (t < reps) /* take lesser */ 2671590Srgrimes reps = t; 2681590Srgrimes } 2691590Srgrimes mask = 0; 2701590Srgrimes break; 2711590Srgrimes default: 27227423Scharnier errx(1, "bad mask"); 2731590Srgrimes } 2741590Srgrimes if (reps == 0) 2751590Srgrimes infinity = 1; 27677276Sdd if (randomize) { 27777276Sdd *x = (ender - begin) * (ender > begin ? 1 : -1); 27877276Sdd for (*i = 1; *i <= reps || infinity; (*i)++) { 27986197Swollman *y = arc4random() / (double)UINT32_MAX; 28077276Sdd if (putdata(*y * *x + begin, reps - *i)) 28177276Sdd errx(1, "range error in conversion"); 28277276Sdd } 28377276Sdd } else 28477276Sdd for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) 28577276Sdd if (putdata(*x, reps - *i)) 28677276Sdd errx(1, "range error in conversion"); 28777276Sdd if (!nofinalnl) 28877276Sdd putchar('\n'); 28977276Sdd exit(0); 2901590Srgrimes} 2911590Srgrimes 29255515Ssheldonhint 29398254Sjmallettputdata(double x, long int notlast) 2941590Srgrimes{ 2951590Srgrimes 29655515Ssheldonh if (boring) 29762871Skris printf("%s", format); 29855515Ssheldonh else if (longdata && nosign) { 29955515Ssheldonh if (x <= (double)ULONG_MAX && x >= (double)0) 30055515Ssheldonh printf(format, (unsigned long)x); 30155515Ssheldonh else 30255515Ssheldonh return (1); 30355515Ssheldonh } else if (longdata) { 30455515Ssheldonh if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) 30555515Ssheldonh printf(format, (long)x); 30655515Ssheldonh else 30755515Ssheldonh return (1); 30855515Ssheldonh } else if (chardata || (intdata && !nosign)) { 30955515Ssheldonh if (x <= (double)INT_MAX && x >= (double)INT_MIN) 31055515Ssheldonh printf(format, (int)x); 31155515Ssheldonh else 31255515Ssheldonh return (1); 31355515Ssheldonh } else if (intdata) { 31455515Ssheldonh if (x <= (double)UINT_MAX && x >= (double)0) 31555515Ssheldonh printf(format, (unsigned int)x); 31655515Ssheldonh else 31755515Ssheldonh return (1); 31855515Ssheldonh 31955515Ssheldonh } else 3201590Srgrimes printf(format, x); 3211590Srgrimes if (notlast != 0) 3221590Srgrimes fputs(sepstring, stdout); 32355515Ssheldonh 32455515Ssheldonh return (0); 3251590Srgrimes} 3261590Srgrimes 32727423Scharnierstatic void 32898254Sjmallettusage(void) 3291590Srgrimes{ 33027423Scharnier fprintf(stderr, "%s\n%s\n", 33130908Scharnier "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 33230908Scharnier " [reps [begin [end [s]]]]"); 3331590Srgrimes exit(1); 3341590Srgrimes} 3351590Srgrimes 3361590Srgrimesint 33798254Sjmallettgetprec(char *str) 3381590Srgrimes{ 33977276Sdd char *p; 34077276Sdd char *q; 3411590Srgrimes 34277287Sdd for (p = str; *p; p++) 3431590Srgrimes if (*p == '.') 3441590Srgrimes break; 3451590Srgrimes if (!*p) 3461590Srgrimes return (0); 3471590Srgrimes for (q = ++p; *p; p++) 3481590Srgrimes if (!isdigit(*p)) 3491590Srgrimes break; 3501590Srgrimes return (p - q); 3511590Srgrimes} 3521590Srgrimes 3531590Srgrimesvoid 35498254Sjmallettgetformat(void) 3551590Srgrimes{ 35677287Sdd char *p, *p2; 35755515Ssheldonh int dot, hash, space, sign, numbers = 0; 35877276Sdd size_t sz; 3591590Srgrimes 3601590Srgrimes if (boring) /* no need to bother */ 3611590Srgrimes return; 3621590Srgrimes for (p = format; *p; p++) /* look for '%' */ 3631590Srgrimes if (*p == '%' && *(p+1) != '%') /* leave %% alone */ 3641590Srgrimes break; 36577276Sdd sz = sizeof(format) - strlen(format) - 1; 36677276Sdd if (!*p && !chardata) { 36777276Sdd if (snprintf(p, sz, "%%.%df", prec) >= (int)sz) 36877276Sdd errx(1, "-w word too long"); 36977276Sdd } else if (!*p && chardata) { 37077276Sdd if (strlcpy(p, "%c", sz) >= sz) 37177276Sdd errx(1, "-w word too long"); 37248995Ssheldonh intdata = 1; 37377276Sdd } else if (!*(p+1)) { 37477276Sdd if (sz <= 0) 37577276Sdd errx(1, "-w word too long"); 3761590Srgrimes strcat(format, "%"); /* cannot end in single '%' */ 37777276Sdd } else { 37848995Ssheldonh /* 37948995Ssheldonh * Allow conversion format specifiers of the form 38048995Ssheldonh * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 38148995Ssheldonh * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 38248995Ssheldonh */ 38377287Sdd p2 = p++; 38448995Ssheldonh dot = hash = space = sign = numbers = 0; 38548995Ssheldonh while (!isalpha(*p)) { 38648995Ssheldonh if (isdigit(*p)) { 38748995Ssheldonh numbers++; 38848995Ssheldonh p++; 38948995Ssheldonh } else if ((*p == '#' && !(numbers|dot|sign|space| 39048995Ssheldonh hash++)) || 39148995Ssheldonh (*p == ' ' && !(numbers|dot|space++)) || 39248995Ssheldonh ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 39348995Ssheldonh || (*p == '.' && !(dot++))) 39448995Ssheldonh p++; 39548995Ssheldonh else 39655515Ssheldonh goto fmt_broken; 39748995Ssheldonh } 39855515Ssheldonh if (*p == 'l') { 39955515Ssheldonh longdata = 1; 40055515Ssheldonh if (*++p == 'l') { 40155515Ssheldonh if (p[1] != '\0') 40255515Ssheldonh p++; 40355515Ssheldonh goto fmt_broken; 40455515Ssheldonh } 40555515Ssheldonh } 40648995Ssheldonh switch (*p) { 40748995Ssheldonh case 'o': case 'u': case 'x': case 'X': 40848995Ssheldonh intdata = nosign = 1; 4091590Srgrimes break; 41048995Ssheldonh case 'd': case 'i': 41148995Ssheldonh intdata = 1; 41248995Ssheldonh break; 41348995Ssheldonh case 'D': 41455515Ssheldonh if (!longdata) { 41548995Ssheldonh intdata = 1; 41648995Ssheldonh break; 41748995Ssheldonh } 41848995Ssheldonh case 'O': case 'U': 41955515Ssheldonh if (!longdata) { 42048995Ssheldonh intdata = nosign = 1; 42148995Ssheldonh break; 42248995Ssheldonh } 42348995Ssheldonh case 'c': 42455515Ssheldonh if (!(intdata | longdata)) { 42548995Ssheldonh chardata = 1; 42648995Ssheldonh break; 42748995Ssheldonh } 42855515Ssheldonh case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 42948995Ssheldonh case '$': case '*': 43055515Ssheldonh goto fmt_broken; 43148995Ssheldonh case 'f': case 'e': case 'g': case 'E': case 'G': 43255515Ssheldonh if (!longdata) 43348995Ssheldonh break; 43448995Ssheldonh /* FALLTHROUGH */ 4351590Srgrimes default: 43655515Ssheldonhfmt_broken: 43748995Ssheldonh *++p = '\0'; 43877287Sdd errx(1, "illegal or unsupported format '%s'", p2); 43948995Ssheldonh /* NOTREACHED */ 4401590Srgrimes } 44148995Ssheldonh while (*++p) 44248995Ssheldonh if (*p == '%' && *(p+1) && *(p+1) != '%') 44348995Ssheldonh errx(1, "too many conversions"); 44448995Ssheldonh else if (*p == '%' && *(p+1) == '%') 44548995Ssheldonh p++; 44648995Ssheldonh else if (*p == '%' && !*(p+1)) { 44748995Ssheldonh strcat(format, "%"); 44848995Ssheldonh break; 44948995Ssheldonh } 4501590Srgrimes } 4511590Srgrimes} 452