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