1 /* $OpenBSD: jot.c,v 1.19 2007/05/01 01:26:30 jdixon Exp $ */ 2 /* $NetBSD: jot.c,v 1.3 1994/12/02 20:29:43 pk Exp $ */ 3 4 /*- 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 static const char copyright[] = 35 "@(#) Copyright (c) 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #ifndef lint 40 #if 0 41 static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; 42 #endif 43 static const char rcsid[] = "$OpenBSD: jot.c,v 1.19 2007/05/01 01:26:30 jdixon Exp $"; 44 #endif /* not lint */ 45 46 /* 47 * jot - print sequential or random data 48 * 49 * Author: John Kunze, Office of Comp. Affairs, UCB 50 */ 51 52 #include <err.h> 53 #include <stdbool.h> 54 #include <ctype.h> 55 #include <limits.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 60 #define REPS_DEF 100 61 #define BEGIN_DEF 1 62 #define ENDER_DEF 100 63 #define STEP_DEF 1 64 65 #define is_default(s) (strcmp((s), "-") == 0) 66 67 static double begin; 68 static double ender; 69 static double s; 70 static long reps; 71 static bool randomize; 72 static bool infinity; 73 static bool boring; 74 static int prec = -1; 75 static bool intdata; 76 static bool longdata; 77 static bool chardata; 78 static bool nosign; 79 static bool finalnl = true; 80 static char sepstring[BUFSIZ] = "\n"; 81 static char format[BUFSIZ]; 82 83 static void getformat(void); 84 static int getprec(char *); 85 static int putdata(double, bool); 86 static void usage(void); 87 88 int 89 main(int argc, char *argv[]) 90 { 91 double x; 92 double y; 93 long i; 94 unsigned int mask = 0; 95 int n = 0; 96 int ch; 97 const char *errstr; 98 99 while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) 100 switch (ch) { 101 case 'r': 102 randomize = true; 103 break; 104 case 'c': 105 chardata = true; 106 break; 107 case 'n': 108 finalnl = false; 109 break; 110 case 'b': 111 boring = true; 112 if (strlcpy(format, optarg, sizeof(format)) >= 113 sizeof(format)) 114 errx(1, "-b word too long"); 115 break; 116 case 'w': 117 if (strlcpy(format, optarg, sizeof(format)) >= 118 sizeof(format)) 119 errx(1, "-w word too long"); 120 break; 121 case 's': 122 if (strlcpy(sepstring, optarg, sizeof(sepstring)) >= 123 sizeof(sepstring)) 124 errx(1, "-s word too long"); 125 break; 126 case 'p': 127 prec = strtonum(optarg, 0, INT_MAX, &errstr); 128 if (errstr != NULL) 129 errx(1, "bad precision value, %s: %s", errstr, 130 optarg); 131 break; 132 default: 133 usage(); 134 } 135 argc -= optind; 136 argv += optind; 137 138 switch (argc) { /* examine args right to left, falling thru cases */ 139 case 4: 140 if (!is_default(argv[3])) { 141 if (!sscanf(argv[3], "%lf", &s)) 142 errx(1, "Bad s value: %s", argv[3]); 143 mask |= 01; 144 if (randomize) 145 warnx("random seeding not supported"); 146 } 147 case 3: 148 if (!is_default(argv[2])) { 149 if (!sscanf(argv[2], "%lf", &ender)) 150 ender = argv[2][strlen(argv[2])-1]; 151 mask |= 02; 152 if (prec == -1) 153 n = getprec(argv[2]); 154 } 155 case 2: 156 if (!is_default(argv[1])) { 157 if (!sscanf(argv[1], "%lf", &begin)) 158 begin = argv[1][strlen(argv[1])-1]; 159 mask |= 04; 160 if (prec == -1) 161 prec = getprec(argv[1]); 162 if (n > prec) /* maximum precision */ 163 prec = n; 164 } 165 case 1: 166 if (!is_default(argv[0])) { 167 if (!sscanf(argv[0], "%ld", &reps)) 168 errx(1, "Bad reps value: %s", argv[0]); 169 mask |= 010; 170 if (prec == -1) 171 prec = 0; 172 } 173 break; 174 case 0: 175 usage(); 176 break; 177 default: 178 errx(1, "Too many arguments. What do you mean by %s?", 179 argv[4]); 180 } 181 getformat(); 182 while (mask) /* 4 bit mask has 1's where last 4 args were given */ 183 switch (mask) { /* fill in the 0's by default or computation */ 184 case 001: 185 reps = REPS_DEF; 186 mask = 011; 187 break; 188 case 002: 189 reps = REPS_DEF; 190 mask = 012; 191 break; 192 case 003: 193 reps = REPS_DEF; 194 mask = 013; 195 break; 196 case 004: 197 reps = REPS_DEF; 198 mask = 014; 199 break; 200 case 005: 201 reps = REPS_DEF; 202 mask = 015; 203 break; 204 case 006: 205 reps = REPS_DEF; 206 mask = 016; 207 break; 208 case 007: 209 if (randomize) { 210 reps = REPS_DEF; 211 mask = 0; 212 break; 213 } 214 if (s == 0.0) { 215 reps = 0; 216 mask = 0; 217 break; 218 } 219 reps = (ender - begin + s) / s; 220 if (reps <= 0) 221 errx(1, "Impossible stepsize"); 222 mask = 0; 223 break; 224 case 010: 225 begin = BEGIN_DEF; 226 mask = 014; 227 break; 228 case 011: 229 begin = BEGIN_DEF; 230 mask = 015; 231 break; 232 case 012: 233 s = STEP_DEF; 234 mask = 013; 235 break; 236 case 013: 237 if (randomize) 238 begin = BEGIN_DEF; 239 else if (reps == 0) 240 errx(1, "Must specify begin if reps == 0"); 241 begin = ender - reps * s + s; 242 mask = 0; 243 break; 244 case 014: 245 s = STEP_DEF; 246 mask = 015; 247 break; 248 case 015: 249 if (randomize) 250 ender = ENDER_DEF; 251 else 252 ender = begin + reps * s - s; 253 mask = 0; 254 break; 255 case 016: 256 if (reps == 0) 257 errx(1, "Infinite sequences cannot be bounded"); 258 else if (reps == 1) 259 s = 0.0; 260 else 261 s = (ender - begin) / (reps - 1); 262 mask = 0; 263 break; 264 case 017: /* if reps given and implied, */ 265 if (!randomize && s != 0.0) { 266 long t = (ender - begin + s) / s; 267 if (t <= 0) 268 errx(1, "Impossible stepsize"); 269 if (t < reps) /* take lesser */ 270 reps = t; 271 } 272 mask = 0; 273 break; 274 default: 275 errx(1, "bad mask"); 276 } 277 if (reps == 0) 278 infinity = true; 279 if (randomize) { 280 x = (ender - begin) * (ender > begin ? 1 : -1); 281 for (i = 1; i <= reps || infinity; i++) { 282 double v; 283 y = arc4random() / ((double)0xffffffff + 1); 284 v = y * x + begin; 285 if (putdata(v, reps == i && !infinity)) 286 errx(1, "range error in conversion: %f", v); 287 } 288 } 289 else 290 for (i = 1, x = begin; i <= reps || infinity; i++, x += s) 291 if (putdata(x, reps == i && !infinity)) 292 errx(1, "range error in conversion: %f", x); 293 if (finalnl) 294 putchar('\n'); 295 exit(0); 296 } 297 298 static int 299 putdata(double x, bool last) 300 { 301 if (boring) 302 printf("%s", format); 303 else if (longdata && nosign) { 304 if (x <= (double)ULONG_MAX && x >= 0.0) 305 printf(format, (unsigned long)x); 306 else 307 return (1); 308 } else if (longdata) { 309 if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) 310 printf(format, (long)x); 311 else 312 return (1); 313 } else if (chardata || (intdata && !nosign)) { 314 if (x <= (double)INT_MAX && x >= (double)INT_MIN) 315 printf(format, (int)x); 316 else 317 return (1); 318 } else if (intdata) { 319 if (x <= (double)UINT_MAX && x >= 0.0) 320 printf(format, (unsigned int)x); 321 else 322 return (1); 323 } else 324 printf(format, x); 325 if (!last) 326 fputs(sepstring, stdout); 327 328 return (0); 329 } 330 331 static void 332 usage(void) 333 { 334 (void)fprintf(stderr, "usage: jot [-cnr] [-b word] [-p precision] " 335 "[-s string] [-w word]\n" 336 " [reps [begin [end [s]]]]\n"); 337 exit(1); 338 } 339 340 static int 341 getprec(char *s) 342 { 343 char *p; 344 char *q; 345 346 for (p = s; *p != '\0'; p++) 347 if (*p == '.') 348 break; 349 if (*p == '\0') 350 return (0); 351 for (q = ++p; *p != '\0'; p++) 352 if (!isdigit(*p)) 353 break; 354 return (p - q); 355 } 356 357 static void 358 getformat(void) 359 { 360 char *p, *p2; 361 int dot, hash, space, sign, numbers = 0; 362 size_t sz; 363 364 if (boring) /* no need to bother */ 365 return; 366 for (p = format; *p != '\0'; p++) /* look for '%' */ 367 if (*p == '%' && *(p+1) != '%') /* leave %% alone */ 368 break; 369 sz = sizeof(format) - strlen(format) - 1; 370 if (*p == '\0' && !chardata) { 371 int n; 372 373 n = snprintf(p, sz, "%%.%df", prec); 374 if (n == -1 || n >= (int)sz) 375 errx(1, "-w word too long"); 376 } else if (*p == '\0' && chardata) { 377 if (strlcpy(p, "%c", sz) >= sz) 378 errx(1, "-w word too long"); 379 intdata = true; 380 } else if (*(p+1) == '\0') { 381 if (sz <= 0) 382 errx(1, "-w word too long"); 383 /* cannot end in single '%' */ 384 strlcat(format, "%", sizeof format); 385 } else { 386 /* 387 * Allow conversion format specifiers of the form 388 * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 389 * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 390 */ 391 p2 = p++; 392 dot = hash = space = sign = numbers = 0; 393 while (!isalpha(*p)) { 394 if (isdigit(*p)) { 395 numbers++; 396 p++; 397 } else if ((*p == '#' && !(numbers|dot|sign|space| 398 hash++)) || 399 (*p == ' ' && !(numbers|dot|space++)) || 400 ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 401 || (*p == '.' && !(dot++))) 402 p++; 403 else 404 goto fmt_broken; 405 } 406 if (*p == 'l') { 407 longdata = true; 408 if (*++p == 'l') { 409 if (p[1] != '\0') 410 p++; 411 goto fmt_broken; 412 } 413 } 414 switch (*p) { 415 case 'o': case 'u': case 'x': case 'X': 416 intdata = nosign = true; 417 break; 418 case 'd': case 'i': 419 intdata = true; 420 break; 421 case 'D': 422 if (!longdata) { 423 intdata = true; 424 break; 425 } 426 case 'O': case 'U': 427 if (!longdata) { 428 intdata = nosign = true; 429 break; 430 } 431 case 'c': 432 if (!(intdata | longdata)) { 433 chardata = true; 434 break; 435 } 436 case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 437 case '$': case '*': 438 goto fmt_broken; 439 case 'f': case 'e': case 'g': case 'E': case 'G': 440 if (!longdata) 441 break; 442 /* FALLTHROUGH */ 443 default: 444 fmt_broken: 445 *++p = '\0'; 446 errx(1, "illegal or unsupported format '%s'", p2); 447 /* NOTREACHED */ 448 } 449 while (*++p != '\0') 450 if (*p == '%' && *(p+1) != '\0' && *(p+1) != '%') 451 errx(1, "too many conversions"); 452 else if (*p == '%' && *(p+1) == '%') 453 p++; 454 else if (*p == '%' && *(p+1) == '\0') { 455 strlcat(format, "%", sizeof format); 456 break; 457 } 458 } 459 } 460