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