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