jot.c revision 164023
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 4598254Sjmallett#include <sys/cdefs.h> 4698254Sjmallett__FBSDID("$FreeBSD: head/usr.bin/jot/jot.c 164023 2006-11-06 08:47:41Z dds $"); 4798254Sjmallett 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> 5899457Smike#include <stdint.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 69164021Sdds#define HAVE_STEP 1 70164021Sdds#define HAVE_ENDER 2 71164021Sdds#define HAVE_BEGIN 4 72164021Sdds#define HAVE_REPS 8 73164021Sdds 7477276Sdd#define is_default(s) (strcmp((s), "-") == 0) 751590Srgrimes 761590Srgrimesdouble begin; 771590Srgrimesdouble ender; 781590Srgrimesdouble s; 791590Srgrimeslong reps; 801590Srgrimesint randomize; 811590Srgrimesint infinity; 821590Srgrimesint boring; 831590Srgrimesint prec; 8455515Ssheldonhint longdata; 8548995Ssheldonhint intdata; 861590Srgrimesint chardata; 8748995Ssheldonhint nosign; 881590Srgrimesint nofinalnl; 8977287Sddconst char *sepstring = "\n"; 901590Srgrimeschar format[BUFSIZ]; 911590Srgrimes 9292920Simpvoid getformat(void); 9392920Simpint getprec(char *); 9492920Simpint putdata(double, long); 9592920Simpstatic void usage(void); 961590Srgrimes 971590Srgrimesint 9898254Sjmallettmain(int argc, char **argv) 991590Srgrimes{ 1001590Srgrimes double xd, yd; 1011590Srgrimes long id; 10277276Sdd double *x = &xd; 10377276Sdd double *y = &yd; 10477276Sdd long *i = &id; 10577276Sdd unsigned int mask = 0; 10677276Sdd int n = 0; 10777276Sdd int ch; 1081590Srgrimes 10977276Sdd while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) 11098254Sjmallett switch (ch) { 1111590Srgrimes case 'r': 1121590Srgrimes randomize = 1; 1131590Srgrimes break; 1141590Srgrimes case 'c': 1151590Srgrimes chardata = 1; 1161590Srgrimes break; 1171590Srgrimes case 'n': 1181590Srgrimes nofinalnl = 1; 1191590Srgrimes break; 1201590Srgrimes case 'b': 1211590Srgrimes boring = 1; 12277276Sdd /* FALLTHROUGH */ 1231590Srgrimes case 'w': 12477276Sdd if (strlcpy(format, optarg, sizeof(format)) >= 12577276Sdd sizeof(format)) 12677276Sdd errx(1, "-%c word too long", ch); 1271590Srgrimes break; 1281590Srgrimes case 's': 12977276Sdd sepstring = optarg; 1301590Srgrimes break; 1311590Srgrimes case 'p': 13277276Sdd prec = atoi(optarg); 1331590Srgrimes if (prec <= 0) 13427423Scharnier errx(1, "bad precision value"); 1351590Srgrimes break; 1361590Srgrimes default: 13727423Scharnier usage(); 1381590Srgrimes } 13977276Sdd argc -= optind; 14077276Sdd argv += optind; 1411590Srgrimes 14277276Sdd switch (argc) { /* examine args right to left, falling thru cases */ 1431590Srgrimes case 4: 14477276Sdd if (!is_default(argv[3])) { 14577276Sdd if (!sscanf(argv[3], "%lf", &s)) 14677276Sdd errx(1, "bad s value: %s", argv[3]); 147164021Sdds mask |= HAVE_STEP; 1481590Srgrimes } 149164021Sdds /* FALLTHROUGH */ 1501590Srgrimes case 3: 15177276Sdd if (!is_default(argv[2])) { 15277276Sdd if (!sscanf(argv[2], "%lf", &ender)) 15377276Sdd ender = argv[2][strlen(argv[2])-1]; 154164021Sdds mask |= HAVE_ENDER; 1551590Srgrimes if (!prec) 15677276Sdd n = getprec(argv[2]); 1571590Srgrimes } 158164021Sdds /* FALLTHROUGH */ 1591590Srgrimes case 2: 16077276Sdd if (!is_default(argv[1])) { 16177276Sdd if (!sscanf(argv[1], "%lf", &begin)) 16277276Sdd begin = argv[1][strlen(argv[1])-1]; 163164021Sdds mask |= HAVE_BEGIN; 1641590Srgrimes if (!prec) 16577276Sdd prec = getprec(argv[1]); 1661590Srgrimes if (n > prec) /* maximum precision */ 1671590Srgrimes prec = n; 1681590Srgrimes } 169164021Sdds /* FALLTHROUGH */ 1701590Srgrimes case 1: 17177276Sdd if (!is_default(argv[0])) { 17277276Sdd if (!sscanf(argv[0], "%ld", &reps)) 17377276Sdd errx(1, "bad reps value: %s", argv[0]); 174164021Sdds mask |= HAVE_REPS; 1751590Srgrimes } 1761590Srgrimes break; 1771590Srgrimes case 0: 17827423Scharnier usage(); 1791590Srgrimes default: 18077276Sdd errx(1, "too many arguments. What do you mean by %s?", 18177276Sdd argv[4]); 1821590Srgrimes } 1831590Srgrimes getformat(); 1841590Srgrimes while (mask) /* 4 bit mask has 1's where last 4 args were given */ 1851590Srgrimes switch (mask) { /* fill in the 0's by default or computation */ 186164021Sdds case HAVE_STEP: 187164021Sdds case HAVE_ENDER: 188164021Sdds case HAVE_ENDER | HAVE_STEP: 189164021Sdds case HAVE_BEGIN: 190164021Sdds case HAVE_BEGIN | HAVE_STEP: 191164021Sdds case HAVE_BEGIN | HAVE_ENDER: 1921590Srgrimes reps = REPS_DEF; 193164023Sdds mask |= HAVE_REPS; 1941590Srgrimes break; 195164021Sdds case HAVE_BEGIN | HAVE_ENDER | HAVE_STEP: 196164023Sdds if (randomize) 1971590Srgrimes reps = REPS_DEF; 198164023Sdds else if (s == 0.0) 1991590Srgrimes reps = 0; 200164023Sdds else 201164023Sdds reps = (ender - begin + s) / s; 2021590Srgrimes if (reps <= 0) 20327423Scharnier errx(1, "impossible stepsize"); 2041590Srgrimes mask = 0; 2051590Srgrimes break; 206164021Sdds case HAVE_REPS: 207164021Sdds case HAVE_REPS | HAVE_STEP: 2081590Srgrimes begin = BEGIN_DEF; 209164023Sdds mask |= HAVE_BEGIN; 2101590Srgrimes break; 211164021Sdds case HAVE_REPS | HAVE_ENDER: 21277276Sdd s = (randomize ? time(NULL) : STEP_DEF); 213164021Sdds mask = HAVE_REPS | HAVE_ENDER | HAVE_STEP; 2141590Srgrimes break; 215164021Sdds case HAVE_REPS | HAVE_ENDER | HAVE_STEP: 2161590Srgrimes if (randomize) 2171590Srgrimes begin = BEGIN_DEF; 2181590Srgrimes else if (reps == 0) 21927423Scharnier errx(1, "must specify begin if reps == 0"); 22077276Sdd begin = ender - reps * s + s; 2211590Srgrimes mask = 0; 2221590Srgrimes break; 223164021Sdds case HAVE_REPS | HAVE_BEGIN: 22424419Sache s = (randomize ? -1.0 : STEP_DEF); 225164021Sdds mask = HAVE_REPS | HAVE_BEGIN | HAVE_STEP; 2261590Srgrimes break; 227164021Sdds case HAVE_REPS | HAVE_BEGIN | HAVE_STEP: 2281590Srgrimes if (randomize) 2291590Srgrimes ender = ENDER_DEF; 2301590Srgrimes else 2311590Srgrimes ender = begin + reps * s - s; 2321590Srgrimes mask = 0; 2331590Srgrimes break; 234164021Sdds case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER: 2351590Srgrimes if (randomize) 23624419Sache s = -1.0; 2371590Srgrimes else if (reps == 0) 23827423Scharnier errx(1, "infinite sequences cannot be bounded"); 2391590Srgrimes else if (reps == 1) 2401590Srgrimes s = 0.0; 2411590Srgrimes else 2421590Srgrimes s = (ender - begin) / (reps - 1); 2431590Srgrimes mask = 0; 2441590Srgrimes break; 245164021Sdds case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER | HAVE_STEP: 246164021Sdds /* if reps given and implied, */ 2471590Srgrimes if (!randomize && s != 0.0) { 2481590Srgrimes long t = (ender - begin + s) / s; 2491590Srgrimes if (t <= 0) 25027423Scharnier errx(1, "impossible stepsize"); 2511590Srgrimes if (t < reps) /* take lesser */ 2521590Srgrimes reps = t; 2531590Srgrimes } 2541590Srgrimes mask = 0; 2551590Srgrimes break; 2561590Srgrimes default: 25727423Scharnier errx(1, "bad mask"); 2581590Srgrimes } 2591590Srgrimes if (reps == 0) 2601590Srgrimes infinity = 1; 26177276Sdd if (randomize) { 26277276Sdd *x = (ender - begin) * (ender > begin ? 1 : -1); 26377276Sdd for (*i = 1; *i <= reps || infinity; (*i)++) { 264118310Sdas *y = arc4random() / ((double)UINT32_MAX + 1); 26577276Sdd if (putdata(*y * *x + begin, reps - *i)) 26677276Sdd errx(1, "range error in conversion"); 26777276Sdd } 26877276Sdd } else 26977276Sdd for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) 27077276Sdd if (putdata(*x, reps - *i)) 27177276Sdd errx(1, "range error in conversion"); 27277276Sdd if (!nofinalnl) 27377276Sdd putchar('\n'); 27477276Sdd exit(0); 2751590Srgrimes} 2761590Srgrimes 27755515Ssheldonhint 27898254Sjmallettputdata(double x, long int notlast) 2791590Srgrimes{ 2801590Srgrimes 28155515Ssheldonh if (boring) 28262871Skris printf("%s", format); 28355515Ssheldonh else if (longdata && nosign) { 28455515Ssheldonh if (x <= (double)ULONG_MAX && x >= (double)0) 28555515Ssheldonh printf(format, (unsigned long)x); 28655515Ssheldonh else 28755515Ssheldonh return (1); 28855515Ssheldonh } else if (longdata) { 28955515Ssheldonh if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) 29055515Ssheldonh printf(format, (long)x); 29155515Ssheldonh else 29255515Ssheldonh return (1); 29355515Ssheldonh } else if (chardata || (intdata && !nosign)) { 29455515Ssheldonh if (x <= (double)INT_MAX && x >= (double)INT_MIN) 29555515Ssheldonh printf(format, (int)x); 29655515Ssheldonh else 29755515Ssheldonh return (1); 29855515Ssheldonh } else if (intdata) { 29955515Ssheldonh if (x <= (double)UINT_MAX && x >= (double)0) 30055515Ssheldonh printf(format, (unsigned int)x); 30155515Ssheldonh else 30255515Ssheldonh return (1); 30355515Ssheldonh 30455515Ssheldonh } else 3051590Srgrimes printf(format, x); 3061590Srgrimes if (notlast != 0) 3071590Srgrimes fputs(sepstring, stdout); 30855515Ssheldonh 30955515Ssheldonh return (0); 3101590Srgrimes} 3111590Srgrimes 31227423Scharnierstatic void 31398254Sjmallettusage(void) 3141590Srgrimes{ 31527423Scharnier fprintf(stderr, "%s\n%s\n", 31630908Scharnier "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 31730908Scharnier " [reps [begin [end [s]]]]"); 3181590Srgrimes exit(1); 3191590Srgrimes} 3201590Srgrimes 3211590Srgrimesint 32298254Sjmallettgetprec(char *str) 3231590Srgrimes{ 32477276Sdd char *p; 32577276Sdd char *q; 3261590Srgrimes 32777287Sdd for (p = str; *p; p++) 3281590Srgrimes if (*p == '.') 3291590Srgrimes break; 3301590Srgrimes if (!*p) 3311590Srgrimes return (0); 3321590Srgrimes for (q = ++p; *p; p++) 333132240Stjr if (!isdigit((unsigned char)*p)) 3341590Srgrimes break; 3351590Srgrimes return (p - q); 3361590Srgrimes} 3371590Srgrimes 3381590Srgrimesvoid 33998254Sjmallettgetformat(void) 3401590Srgrimes{ 34177287Sdd char *p, *p2; 34255515Ssheldonh int dot, hash, space, sign, numbers = 0; 34377276Sdd size_t sz; 3441590Srgrimes 3451590Srgrimes if (boring) /* no need to bother */ 3461590Srgrimes return; 3471590Srgrimes for (p = format; *p; p++) /* look for '%' */ 3481590Srgrimes if (*p == '%' && *(p+1) != '%') /* leave %% alone */ 3491590Srgrimes break; 35077276Sdd sz = sizeof(format) - strlen(format) - 1; 35177276Sdd if (!*p && !chardata) { 35277276Sdd if (snprintf(p, sz, "%%.%df", prec) >= (int)sz) 35377276Sdd errx(1, "-w word too long"); 35477276Sdd } else if (!*p && chardata) { 35577276Sdd if (strlcpy(p, "%c", sz) >= sz) 35677276Sdd errx(1, "-w word too long"); 35748995Ssheldonh intdata = 1; 35877276Sdd } else if (!*(p+1)) { 35977276Sdd if (sz <= 0) 36077276Sdd errx(1, "-w word too long"); 3611590Srgrimes strcat(format, "%"); /* cannot end in single '%' */ 36277276Sdd } else { 36348995Ssheldonh /* 36448995Ssheldonh * Allow conversion format specifiers of the form 36548995Ssheldonh * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 36648995Ssheldonh * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 36748995Ssheldonh */ 36877287Sdd p2 = p++; 36948995Ssheldonh dot = hash = space = sign = numbers = 0; 370132240Stjr while (!isalpha((unsigned char)*p)) { 371132240Stjr if (isdigit((unsigned char)*p)) { 37248995Ssheldonh numbers++; 37348995Ssheldonh p++; 37448995Ssheldonh } else if ((*p == '#' && !(numbers|dot|sign|space| 37548995Ssheldonh hash++)) || 37648995Ssheldonh (*p == ' ' && !(numbers|dot|space++)) || 37748995Ssheldonh ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 37848995Ssheldonh || (*p == '.' && !(dot++))) 37948995Ssheldonh p++; 38048995Ssheldonh else 38155515Ssheldonh goto fmt_broken; 38248995Ssheldonh } 38355515Ssheldonh if (*p == 'l') { 38455515Ssheldonh longdata = 1; 38555515Ssheldonh if (*++p == 'l') { 38655515Ssheldonh if (p[1] != '\0') 38755515Ssheldonh p++; 38855515Ssheldonh goto fmt_broken; 38955515Ssheldonh } 39055515Ssheldonh } 39148995Ssheldonh switch (*p) { 39248995Ssheldonh case 'o': case 'u': case 'x': case 'X': 39348995Ssheldonh intdata = nosign = 1; 3941590Srgrimes break; 39548995Ssheldonh case 'd': case 'i': 39648995Ssheldonh intdata = 1; 39748995Ssheldonh break; 39848995Ssheldonh case 'D': 39955515Ssheldonh if (!longdata) { 40048995Ssheldonh intdata = 1; 40148995Ssheldonh break; 40248995Ssheldonh } 40348995Ssheldonh case 'O': case 'U': 40455515Ssheldonh if (!longdata) { 40548995Ssheldonh intdata = nosign = 1; 40648995Ssheldonh break; 40748995Ssheldonh } 40848995Ssheldonh case 'c': 40955515Ssheldonh if (!(intdata | longdata)) { 41048995Ssheldonh chardata = 1; 41148995Ssheldonh break; 41248995Ssheldonh } 41355515Ssheldonh case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 41448995Ssheldonh case '$': case '*': 41555515Ssheldonh goto fmt_broken; 41648995Ssheldonh case 'f': case 'e': case 'g': case 'E': case 'G': 41755515Ssheldonh if (!longdata) 41848995Ssheldonh break; 41948995Ssheldonh /* FALLTHROUGH */ 4201590Srgrimes default: 42155515Ssheldonhfmt_broken: 42248995Ssheldonh *++p = '\0'; 42377287Sdd errx(1, "illegal or unsupported format '%s'", p2); 42448995Ssheldonh /* NOTREACHED */ 4251590Srgrimes } 42648995Ssheldonh while (*++p) 42748995Ssheldonh if (*p == '%' && *(p+1) && *(p+1) != '%') 42848995Ssheldonh errx(1, "too many conversions"); 42948995Ssheldonh else if (*p == '%' && *(p+1) == '%') 43048995Ssheldonh p++; 43148995Ssheldonh else if (*p == '%' && !*(p+1)) { 43248995Ssheldonh strcat(format, "%"); 43348995Ssheldonh break; 43448995Ssheldonh } 4351590Srgrimes } 4361590Srgrimes} 437