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