1 /* $OpenBSD: jot.c,v 1.23 2013/11/26 13:21:18 deraadt 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 /* 34 * jot - print sequential or random data 35 * 36 * Author: John Kunze, Office of Comp. Affairs, UCB 37 */ 38 39 #include <err.h> 40 #include <stdbool.h> 41 #include <ctype.h> 42 #include <limits.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #define REPS_DEF 100 49 #define BEGIN_DEF 1 50 #define ENDER_DEF 100 51 #define STEP_DEF 1 52 53 #define is_default(s) (strcmp((s), "-") == 0) 54 55 static double begin; 56 static double ender; 57 static double s; 58 static long reps; 59 static bool randomize; 60 static bool infinity; 61 static bool boring; 62 static int prec = -1; 63 static bool intdata; 64 static bool longdata; 65 static bool chardata; 66 static bool nosign; 67 static bool finalnl = true; 68 static char sepstring[BUFSIZ] = "\n"; 69 static char format[BUFSIZ]; 70 71 static void getformat(void); 72 static int getprec(char *); 73 static int putdata(double, bool); 74 static void usage(void); 75 76 int 77 main(int argc, char *argv[]) 78 { 79 double x; 80 double y; 81 long i; 82 unsigned int mask = 0; 83 int n = 0; 84 int ch; 85 const char *errstr; 86 87 while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) 88 switch (ch) { 89 case 'r': 90 randomize = true; 91 break; 92 case 'c': 93 chardata = true; 94 break; 95 case 'n': 96 finalnl = false; 97 break; 98 case 'b': 99 boring = true; 100 if (strlcpy(format, optarg, sizeof(format)) >= 101 sizeof(format)) 102 errx(1, "-b word too long"); 103 break; 104 case 'w': 105 if (strlcpy(format, optarg, sizeof(format)) >= 106 sizeof(format)) 107 errx(1, "-w word too long"); 108 break; 109 case 's': 110 if (strlcpy(sepstring, optarg, sizeof(sepstring)) >= 111 sizeof(sepstring)) 112 errx(1, "-s string too long"); 113 break; 114 case 'p': 115 prec = strtonum(optarg, 0, INT_MAX, &errstr); 116 if (errstr != NULL) 117 errx(1, "bad precision value, %s: %s", errstr, 118 optarg); 119 break; 120 default: 121 usage(); 122 } 123 argc -= optind; 124 argv += optind; 125 126 switch (argc) { /* examine args right to left, falling thru cases */ 127 case 4: 128 if (!is_default(argv[3])) { 129 if (!sscanf(argv[3], "%lf", &s)) 130 errx(1, "Bad s value: %s", argv[3]); 131 mask |= 01; 132 if (randomize) 133 warnx("random seeding not supported"); 134 } 135 case 3: 136 if (!is_default(argv[2])) { 137 if (!sscanf(argv[2], "%lf", &ender)) 138 ender = argv[2][strlen(argv[2])-1]; 139 mask |= 02; 140 if (prec == -1) 141 n = getprec(argv[2]); 142 } 143 case 2: 144 if (!is_default(argv[1])) { 145 if (!sscanf(argv[1], "%lf", &begin)) 146 begin = argv[1][strlen(argv[1])-1]; 147 mask |= 04; 148 if (prec == -1) 149 prec = getprec(argv[1]); 150 if (n > prec) /* maximum precision */ 151 prec = n; 152 } 153 case 1: 154 if (!is_default(argv[0])) { 155 if (!sscanf(argv[0], "%ld", &reps)) 156 errx(1, "Bad reps value: %s", argv[0]); 157 mask |= 010; 158 if (prec == -1) 159 prec = 0; 160 } 161 break; 162 case 0: 163 usage(); 164 break; 165 default: 166 errx(1, "Too many arguments. What do you mean by %s?", 167 argv[4]); 168 } 169 getformat(); 170 while (mask) /* 4 bit mask has 1's where last 4 args were given */ 171 switch (mask) { /* fill in the 0's by default or computation */ 172 case 001: 173 reps = REPS_DEF; 174 mask = 011; 175 break; 176 case 002: 177 reps = REPS_DEF; 178 mask = 012; 179 break; 180 case 003: 181 reps = REPS_DEF; 182 mask = 013; 183 break; 184 case 004: 185 reps = REPS_DEF; 186 mask = 014; 187 break; 188 case 005: 189 reps = REPS_DEF; 190 mask = 015; 191 break; 192 case 006: 193 reps = REPS_DEF; 194 mask = 016; 195 break; 196 case 007: 197 if (randomize) { 198 reps = REPS_DEF; 199 mask = 0; 200 break; 201 } 202 if (s == 0.0) { 203 reps = 0; 204 mask = 0; 205 break; 206 } 207 reps = (ender - begin + s) / s; 208 if (reps <= 0) 209 errx(1, "Impossible stepsize"); 210 mask = 0; 211 break; 212 case 010: 213 begin = BEGIN_DEF; 214 mask = 014; 215 break; 216 case 011: 217 begin = BEGIN_DEF; 218 mask = 015; 219 break; 220 case 012: 221 s = STEP_DEF; 222 mask = 013; 223 break; 224 case 013: 225 if (randomize) 226 begin = BEGIN_DEF; 227 else if (reps == 0) 228 errx(1, "Must specify begin if reps == 0"); 229 begin = ender - reps * s + s; 230 mask = 0; 231 break; 232 case 014: 233 s = STEP_DEF; 234 mask = 015; 235 break; 236 case 015: 237 if (randomize) 238 ender = ENDER_DEF; 239 else 240 ender = begin + reps * s - s; 241 mask = 0; 242 break; 243 case 016: 244 if (reps == 0) 245 errx(1, "Infinite sequences cannot be bounded"); 246 else if (reps == 1) 247 s = 0.0; 248 else 249 s = (ender - begin) / (reps - 1); 250 mask = 0; 251 break; 252 case 017: /* if reps given and implied, */ 253 if (!randomize && s != 0.0) { 254 long t = (ender - begin + s) / s; 255 if (t <= 0) 256 errx(1, "Impossible stepsize"); 257 if (t < reps) /* take lesser */ 258 reps = t; 259 } 260 mask = 0; 261 break; 262 default: 263 errx(1, "bad mask"); 264 } 265 if (reps == 0) 266 infinity = true; 267 if (randomize) { 268 x = (ender - begin) * (ender > begin ? 1 : -1); 269 for (i = 1; i <= reps || infinity; i++) { 270 double v; 271 y = arc4random() / ((double)0xffffffff + 1); 272 v = y * x + begin; 273 if (putdata(v, reps == i && !infinity)) 274 errx(1, "range error in conversion: %f", v); 275 } 276 } 277 else 278 for (i = 1, x = begin; i <= reps || infinity; i++, x += s) 279 if (putdata(x, reps == i && !infinity)) 280 errx(1, "range error in conversion: %f", x); 281 if (finalnl) 282 putchar('\n'); 283 exit(0); 284 } 285 286 static int 287 putdata(double x, bool last) 288 { 289 if (boring) 290 printf("%s", format); 291 else if (longdata && nosign) { 292 if (x <= (double)ULONG_MAX && x >= 0.0) 293 printf(format, (unsigned long)x); 294 else 295 return (1); 296 } else if (longdata) { 297 if (x <= (double)LONG_MAX && x >= (double)LONG_MIN) 298 printf(format, (long)x); 299 else 300 return (1); 301 } else if (chardata || (intdata && !nosign)) { 302 if (x <= (double)INT_MAX && x >= (double)INT_MIN) 303 printf(format, (int)x); 304 else 305 return (1); 306 } else if (intdata) { 307 if (x <= (double)UINT_MAX && x >= 0.0) 308 printf(format, (unsigned int)x); 309 else 310 return (1); 311 } else 312 printf(format, x); 313 if (!last) 314 fputs(sepstring, stdout); 315 316 return (0); 317 } 318 319 static void 320 usage(void) 321 { 322 (void)fprintf(stderr, "usage: jot [-cnr] [-b word] [-p precision] " 323 "[-s string] [-w word]\n" 324 " [reps [begin [end [s]]]]\n"); 325 exit(1); 326 } 327 328 static int 329 getprec(char *s) 330 { 331 char *p; 332 char *q; 333 334 for (p = s; *p != '\0'; p++) 335 if (*p == '.') 336 break; 337 if (*p == '\0') 338 return (0); 339 for (q = ++p; *p != '\0'; p++) 340 if (!isdigit((unsigned char)*p)) 341 break; 342 return (p - q); 343 } 344 345 static void 346 getformat(void) 347 { 348 char *p, *p2; 349 int dot, hash, space, sign, numbers = 0; 350 size_t sz; 351 352 if (boring) /* no need to bother */ 353 return; 354 for (p = format; *p != '\0'; p++) /* look for '%' */ 355 if (*p == '%' && *(p+1) != '%') /* leave %% alone */ 356 break; 357 sz = sizeof(format) - strlen(format) - 1; 358 if (*p == '\0' && !chardata) { 359 int n; 360 361 n = snprintf(p, sz, "%%.%df", prec); 362 if (n == -1 || n >= (int)sz) 363 errx(1, "-w word too long"); 364 } else if (*p == '\0' && chardata) { 365 if (strlcpy(p, "%c", sz) >= sz) 366 errx(1, "-w word too long"); 367 intdata = true; 368 } else if (*(p+1) == '\0') { 369 if (sz <= 0) 370 errx(1, "-w word too long"); 371 /* cannot end in single '%' */ 372 strlcat(format, "%", sizeof format); 373 } else { 374 /* 375 * Allow conversion format specifiers of the form 376 * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 377 * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 378 */ 379 p2 = p++; 380 dot = hash = space = sign = numbers = 0; 381 while (!isalpha((unsigned char)*p)) { 382 if (isdigit((unsigned char)*p)) { 383 numbers++; 384 p++; 385 } else if ((*p == '#' && !(numbers|dot|sign|space| 386 hash++)) || 387 (*p == ' ' && !(numbers|dot|space++)) || 388 ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 389 || (*p == '.' && !(dot++))) 390 p++; 391 else 392 goto fmt_broken; 393 } 394 if (*p == 'l') { 395 longdata = true; 396 if (*++p == 'l') { 397 if (p[1] != '\0') 398 p++; 399 goto fmt_broken; 400 } 401 } 402 switch (*p) { 403 case 'o': case 'u': case 'x': case 'X': 404 intdata = nosign = true; 405 break; 406 case 'd': case 'i': 407 intdata = true; 408 break; 409 case 'D': 410 if (!longdata) { 411 intdata = true; 412 break; 413 } 414 case 'O': case 'U': 415 if (!longdata) { 416 intdata = nosign = true; 417 break; 418 } 419 case 'c': 420 if (!(intdata | longdata)) { 421 chardata = true; 422 break; 423 } 424 case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 425 case '$': case '*': 426 goto fmt_broken; 427 case 'f': case 'e': case 'g': case 'E': case 'G': 428 if (!longdata) 429 break; 430 /* FALLTHROUGH */ 431 default: 432 fmt_broken: 433 *++p = '\0'; 434 errx(1, "illegal or unsupported format '%s'", p2); 435 /* NOTREACHED */ 436 } 437 while (*++p != '\0') 438 if (*p == '%' && *(p+1) != '\0' && *(p+1) != '%') 439 errx(1, "too many conversions"); 440 else if (*p == '%' && *(p+1) == '%') 441 p++; 442 else if (*p == '%' && *(p+1) == '\0') { 443 strlcat(format, "%", sizeof format); 444 break; 445 } 446 } 447 } 448