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 static const char rcsid[] = 45 "$FreeBSD$"; 46 #endif /* not lint */ 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 <signal.h> 58 #include <stdio.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 isdefault(s) (strcmp((s), "-") == 0) 70 71 double begin; 72 double ender; 73 double s; 74 long reps; 75 int randomize; 76 int infinity; 77 int boring; 78 int prec; 79 int intdata; 80 int chardata; 81 int nosign; 82 int nofinalnl; 83 int oflowlen; 84 char *oflowstr; 85 char *sepstring = "\n"; 86 char format[BUFSIZ]; 87 struct sigaction act, oact; 88 89 void arith_oflow __P((int)); 90 void getargs __P((int, char *[])); 91 void getformat __P((void)); 92 int getprec __P((char *)); 93 void putdata __P((double, long)); 94 static void usage __P((void)); 95 96 int 97 main(argc, argv) 98 int argc; 99 char *argv[]; 100 { 101 double xd, yd; 102 long id; 103 register double *x = &xd; 104 register double *y = &yd; 105 register long *i = &id; 106 107 act.sa_handler = arith_oflow; 108 act.sa_flags = 0; 109 sigfillset(&act.sa_mask); 110 oflowstr = "caught SIGFPE: arithmetic overflow\n"; 111 oflowlen = strlen(oflowstr); 112 if (sigaction(SIGFPE, &act, &oact)) 113 err(1, "loading SIGFPE handler"); 114 getargs(argc, argv); 115 if (randomize) { 116 *x = (ender - begin) * (ender > begin ? 1 : -1); 117 for (*i = 1; *i <= reps || infinity; (*i)++) { 118 *y = (double) arc4random() / ULONG_MAX; 119 putdata(*y * *x + begin, reps - *i); 120 } 121 } else 122 for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) 123 putdata(*x, reps - *i); 124 if (!nofinalnl) 125 putchar('\n'); 126 exit(0); 127 } 128 129 void 130 getargs(ac, av) 131 int ac; 132 char *av[]; 133 { 134 register unsigned int mask = 0; 135 register int n = 0; 136 137 while (--ac && **++av == '-' && !isdefault(*av)) 138 switch ((*av)[1]) { 139 case 'r': 140 randomize = 1; 141 break; 142 case 'c': 143 chardata = 1; 144 break; 145 case 'n': 146 nofinalnl = 1; 147 break; 148 case 'b': 149 boring = 1; 150 case 'w': 151 if ((*av)[2]) 152 strcpy(format, *av + 2); 153 else if (!--ac) 154 errx(1, "need context word after -w or -b"); 155 else 156 strcpy(format, *++av); 157 break; 158 case 's': 159 if ((*av)[2]) 160 sepstring = *av + 2; 161 else if (!--ac) 162 errx(1, "need string after -s"); 163 else 164 sepstring = *++av; 165 break; 166 case 'p': 167 if ((*av)[2]) 168 prec = atoi(*av + 2); 169 else if (!--ac) 170 errx(1, "need number after -p"); 171 else 172 prec = atoi(*++av); 173 if (prec <= 0) 174 errx(1, "bad precision value"); 175 break; 176 default: 177 usage(); 178 } 179 180 switch (ac) { /* examine args right to left, falling thru cases */ 181 case 4: 182 if (!isdefault(av[3])) { 183 if (!sscanf(av[3], "%lf", &s)) 184 errx(1, "bad s value: %s", av[3]); 185 mask |= 01; 186 } 187 case 3: 188 if (!isdefault(av[2])) { 189 if (!sscanf(av[2], "%lf", &ender)) 190 ender = av[2][strlen(av[2])-1]; 191 mask |= 02; 192 if (!prec) 193 n = getprec(av[2]); 194 } 195 case 2: 196 if (!isdefault(av[1])) { 197 if (!sscanf(av[1], "%lf", &begin)) 198 begin = av[1][strlen(av[1])-1]; 199 mask |= 04; 200 if (!prec) 201 prec = getprec(av[1]); 202 if (n > prec) /* maximum precision */ 203 prec = n; 204 } 205 case 1: 206 if (!isdefault(av[0])) { 207 if (!sscanf(av[0], "%ld", &reps)) 208 errx(1, "bad reps value: %s", av[0]); 209 mask |= 010; 210 } 211 break; 212 case 0: 213 usage(); 214 default: 215 errx(1, "too many arguments. What do you mean by %s?", av[4]); 216 } 217 getformat(); 218 while (mask) /* 4 bit mask has 1's where last 4 args were given */ 219 switch (mask) { /* fill in the 0's by default or computation */ 220 case 001: 221 reps = REPS_DEF; 222 mask = 011; 223 break; 224 case 002: 225 reps = REPS_DEF; 226 mask = 012; 227 break; 228 case 003: 229 reps = REPS_DEF; 230 mask = 013; 231 break; 232 case 004: 233 reps = REPS_DEF; 234 mask = 014; 235 break; 236 case 005: 237 reps = REPS_DEF; 238 mask = 015; 239 break; 240 case 006: 241 reps = REPS_DEF; 242 mask = 016; 243 break; 244 case 007: 245 if (randomize) { 246 reps = REPS_DEF; 247 mask = 0; 248 break; 249 } 250 if (s == 0.0) { 251 reps = 0; 252 mask = 0; 253 break; 254 } 255 reps = (ender - begin + s) / s; 256 if (reps <= 0) 257 errx(1, "impossible stepsize"); 258 mask = 0; 259 break; 260 case 010: 261 begin = BEGIN_DEF; 262 mask = 014; 263 break; 264 case 011: 265 begin = BEGIN_DEF; 266 mask = 015; 267 break; 268 case 012: 269 s = (randomize ? -1.0 : STEP_DEF); 270 mask = 013; 271 break; 272 case 013: 273 if (randomize) 274 begin = BEGIN_DEF; 275 else if (reps == 0) 276 errx(1, "must specify begin if reps == 0"); 277 else 278 begin = ender - reps * s + s; 279 mask = 0; 280 break; 281 case 014: 282 s = (randomize ? -1.0 : STEP_DEF); 283 mask = 015; 284 break; 285 case 015: 286 if (randomize) 287 ender = ENDER_DEF; 288 else 289 ender = begin + reps * s - s; 290 mask = 0; 291 break; 292 case 016: 293 if (randomize) 294 s = -1.0; 295 else if (reps == 0) 296 errx(1, "infinite sequences cannot be bounded"); 297 else if (reps == 1) 298 s = 0.0; 299 else 300 s = (ender - begin) / (reps - 1); 301 mask = 0; 302 break; 303 case 017: /* if reps given and implied, */ 304 if (!randomize && s != 0.0) { 305 long t = (ender - begin + s) / s; 306 if (t <= 0) 307 errx(1, "impossible stepsize"); 308 if (t < reps) /* take lesser */ 309 reps = t; 310 } 311 mask = 0; 312 break; 313 default: 314 errx(1, "bad mask"); 315 } 316 if (reps == 0) 317 infinity = 1; 318 } 319 320 void 321 putdata(x, notlast) 322 double x; 323 long notlast; 324 { 325 326 if (boring) /* repeated word */ 327 printf(format); 328 else if (chardata) /* character representation */ 329 printf(format, (int)x); 330 else if (intdata && nosign) /* scalar */ 331 printf(format, (unsigned long)x); 332 else if (intdata) 333 printf(format, (long)x); 334 else /* real */ 335 printf(format, x); 336 if (notlast != 0) 337 fputs(sepstring, stdout); 338 } 339 340 static void 341 usage() 342 { 343 fprintf(stderr, "%s\n%s\n", 344 "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 345 " [reps [begin [end [s]]]]"); 346 exit(1); 347 } 348 349 int 350 getprec(s) 351 char *s; 352 { 353 register char *p; 354 register char *q; 355 356 for (p = s; *p; p++) 357 if (*p == '.') 358 break; 359 if (!*p) 360 return (0); 361 for (q = ++p; *p; p++) 362 if (!isdigit(*p)) 363 break; 364 return (p - q); 365 } 366 367 void 368 getformat() 369 { 370 register char *p; 371 int dot, hash, space, sign, numbers, islong = 0; 372 char *s; 373 374 if (boring) /* no need to bother */ 375 return; 376 for (p = format; *p; p++) /* look for '%' */ 377 if (*p == '%' && *(p+1) != '%') /* leave %% alone */ 378 break; 379 if (!*p && !chardata) 380 sprintf(p, "%%.%df", prec); 381 else if (!*p && chardata) { 382 strcpy(p, "%c"); 383 intdata = 1; 384 } else if (!*(p+1)) 385 strcat(format, "%"); /* cannot end in single '%' */ 386 else { 387 /* 388 * Allow conversion format specifiers of the form 389 * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 390 * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 391 */ 392 s = p++; 393 dot = hash = space = sign = numbers = 0; 394 while (!isalpha(*p)) { 395 if (isdigit(*p)) { 396 numbers++; 397 p++; 398 } else if ((*p == '#' && !(numbers|dot|sign|space| 399 hash++)) || 400 (*p == ' ' && !(numbers|dot|space++)) || 401 ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 402 || (*p == '.' && !(dot++))) 403 p++; 404 else if (*p == '$' || *p == '*') 405 errx(1, "unsupported format character %c", *p); 406 else if (*p == '\0') 407 errx(1, "missing format character"); 408 else 409 errx(1, "illegal format character %c", *p); 410 } 411 switch (*p) { 412 case 'l': 413 islong = 1; 414 p++; 415 /* FALLTHROUGH */ 416 case 'o': case 'u': case 'x': case 'X': 417 intdata = nosign = 1; 418 break; 419 case 'd': case 'i': 420 intdata = 1; 421 break; 422 case 'D': 423 if (!islong) { 424 intdata = 1; 425 break; 426 } 427 case 'O': case 'U': 428 if (!islong) { 429 intdata = nosign = 1; 430 break; 431 } 432 case 'c': 433 if (!(intdata | islong)) { 434 chardata = 1; 435 break; 436 } 437 case 's': 438 errx(1, "cannot convert numeric data to strings"); 439 break; 440 case 'h': case 'n': case 'p': case 'q': case 'L': 441 case '$': case '*': 442 errx(1, "unsupported format character %c", *p); 443 /* NOTREACHED */ 444 case 'f': case 'e': case 'g': case 'E': case 'G': 445 if (!islong) 446 break; 447 /* FALLTHROUGH */ 448 default: 449 *++p = '\0'; 450 errx(1, "illegal or unsupported format '%s'", s); 451 /* NOTREACHED */ 452 } 453 while (*++p) 454 if (*p == '%' && *(p+1) && *(p+1) != '%') 455 errx(1, "too many conversions"); 456 else if (*p == '%' && *(p+1) == '%') 457 p++; 458 else if (*p == '%' && !*(p+1)) { 459 strcat(format, "%"); 460 break; 461 } 462 } 463 } 464 465 void 466 arith_oflow(int sig) 467 { 468 469 write(STDERR_FILENO, oflowstr, oflowlen); 470 _exit(sig); 471 } 472