jot.c (7d71f06cb47227f16ac20155c202725aa2b3d9b2) | jot.c (3241f274f1664e7bd5d6dbbf68cac86033134800) |
---|---|
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 --- 48 unchanged lines hidden (view full) --- 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 | 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 --- 48 unchanged lines hidden (view full) --- 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/* Defaults */ |
|
65#define REPS_DEF 100 66#define BEGIN_DEF 1 67#define ENDER_DEF 100 68#define STEP_DEF 1 69 | 66#define REPS_DEF 100 67#define BEGIN_DEF 1 68#define ENDER_DEF 100 69#define STEP_DEF 1 70 |
71/* Flags of options that have been set */ |
|
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 | 72#define HAVE_STEP 1 73#define HAVE_ENDER 2 74#define HAVE_BEGIN 4 75#define HAVE_REPS 8 76 77#define is_default(s) (*(s) == 0 || strcmp((s), "-") == 0) 78 |
77double begin; 78double ender; 79double s; 80long reps; 81int randomize; 82int infinity; 83int boring; 84int prec; 85int longdata; 86int intdata; 87int chardata; 88int nosign; 89int nofinalnl; 90const char *sepstring = "\n"; 91char format[BUFSIZ]; | 79static bool boring; 80static int prec; 81static bool longdata; 82static bool intdata; 83static bool chardata; 84static bool nosign; 85static const char *sepstring = "\n"; 86static char format[BUFSIZ]; |
92 | 87 |
93void getformat(void); 94int getprec(char *); 95int putdata(double, long); | 88static void getformat(void); 89static int getprec(const char *); 90static int putdata(double, bool); |
96static void usage(void); 97 98int 99main(int argc, char **argv) 100{ | 91static void usage(void); 92 93int 94main(int argc, char **argv) 95{ |
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; | 96 bool have_format = false; |
97 bool infinity = false; 98 bool nofinalnl = false; 99 bool randomize = false; 100 bool use_random = false; 101 int ch; 102 int mask = 0; 103 int n = 0; 104 double begin; |
|
108 double divisor; | 105 double divisor; |
106 double ender; 107 double s; 108 double x, y; 109 long i; 110 long reps; |
|
109 | 111 |
110 while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) | 112 while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1) |
111 switch (ch) { | 113 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': | 114 case 'b': |
122 boring = 1; | 115 boring = true; |
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; | 116 /* FALLTHROUGH */ 117 case 'w': 118 if (strlcpy(format, optarg, sizeof(format)) >= 119 sizeof(format)) 120 errx(1, "-%c word too long", ch); 121 have_format = true; 122 break; |
130 case 's': 131 sepstring = optarg; | 123 case 'c': 124 chardata = true; |
132 break; | 125 break; |
126 case 'n': 127 nofinalnl = true; 128 break; |
|
133 case 'p': 134 prec = atoi(optarg); 135 if (prec <= 0) 136 errx(1, "bad precision value"); 137 have_format = true; 138 break; | 129 case 'p': 130 prec = atoi(optarg); 131 if (prec <= 0) 132 errx(1, "bad precision value"); 133 have_format = true; 134 break; |
135 case 'r': 136 randomize = true; 137 break; 138 case 's': 139 sepstring = optarg; 140 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: --- 111 unchanged lines hidden (view full) --- 258 reps = t; 259 } 260 mask = 0; 261 break; 262 default: 263 errx(1, "bad mask"); 264 } 265 if (reps == 0) | 141 default: 142 usage(); 143 } 144 argc -= optind; 145 argv += optind; 146 147 switch (argc) { /* examine args right to left, falling thru cases */ 148 case 4: --- 111 unchanged lines hidden (view full) --- 260 reps = t; 261 } 262 mask = 0; 263 break; 264 default: 265 errx(1, "bad mask"); 266 } 267 if (reps == 0) |
266 infinity = 1; | 268 infinity = true; |
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; | 269 if (randomize) { 270 if (use_random) { 271 srandom((unsigned long)s); 272 divisor = (double)INT32_MAX + 1; 273 } else 274 divisor = (double)UINT32_MAX + 1; 275 276 /* 277 * Attempt to DWIM when the user has specified an 278 * integer range within that of the random number 279 * generator: distribute the numbers equally in 280 * the range [begin .. ender]. Jot's default %.0f 281 * format would make the appearance of the first and 282 * last specified value half as likely as the rest. 283 */ 284 if (!have_format && prec == 0 && 285 begin >= 0 && begin < divisor && 286 ender >= 0 && ender < divisor) { 287 ender += 1; |
286 nosign = 1; 287 intdata = 1; | 288 nosign = true; 289 intdata = true; |
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; | 290 (void)strlcpy(format, 291 chardata ? "%c" : "%u", sizeof(format)); 292 } 293 x = (ender - begin) * (ender > begin ? 1 : -1); 294 for (i = 1; i <= reps || infinity; i++) { 295 if (use_random) 296 y = random() / divisor; 297 else 298 y = arc4random() / divisor; |
297 if (putdata(y * x + begin, reps - i)) | 299 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) | 300 errx(1, "range error in conversion"); 301 } 302 } else 303 for (i = 1, x = begin; i <= reps || infinity; i++, x += s) |
302 if (putdata(x, reps - i)) | 304 if (putdata(x, !(reps - i))) |
303 errx(1, "range error in conversion"); 304 if (!nofinalnl) 305 putchar('\n'); 306 exit(0); 307} 308 | 305 errx(1, "range error in conversion"); 306 if (!nofinalnl) 307 putchar('\n'); 308 exit(0); 309} 310 |
309int 310putdata(double x, long int notlast) | 311/* 312 * Send x to stdout using the specified format. 313 * Last is true if this is the set's last value. 314 * Return 0 if OK, or a positive number if the number passed was 315 * outside the range specified by the various flags. 316 */ 317static int 318putdata(double x, bool last) |
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 --- 11 unchanged lines hidden (view full) --- 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); | 319{ 320 321 if (boring) 322 printf("%s", format); 323 else if (longdata && nosign) { 324 if (x <= (double)ULONG_MAX && x >= (double)0) 325 printf(format, (unsigned long)x); 326 else --- 11 unchanged lines hidden (view full) --- 338 } else if (intdata) { 339 if (x <= (double)UINT_MAX && x >= (double)0) 340 printf(format, (unsigned int)x); 341 else 342 return (1); 343 344 } else 345 printf(format, x); |
338 if (notlast != 0) | 346 if (!last) |
339 fputs(sepstring, stdout); 340 341 return (0); 342} 343 344static void 345usage(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 | 347 fputs(sepstring, stdout); 348 349 return (0); 350} 351 352static void 353usage(void) 354{ 355 fprintf(stderr, "%s\n%s\n", 356 "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 357 " [reps [begin [end [s]]]]"); 358 exit(1); 359} 360 |
353int 354getprec(char *str) | 361/* 362 * Return the number of digits following the number's decimal point. 363 * Return 0 if no decimal point is found. 364 */ 365static int 366getprec(const char *str) |
355{ | 367{ |
356 char *p; 357 char *q; | 368 const char *p; 369 const 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 371 for (p = str; *p; p++) 372 if (*p == '.') 373 break; 374 if (!*p) 375 return (0); 376 for (q = ++p; *p; p++) 377 if (!isdigit((unsigned char)*p)) 378 break; 379 return (p - q); 380} 381 |
370void | 382/* 383 * Set format, intdata, chardata, longdata, and nosign 384 * based on the command line arguments. 385 */ 386static void |
371getformat(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"); | 387getformat(void) 388{ 389 char *p, *p2; 390 int dot, hash, space, sign, numbers = 0; 391 size_t sz; 392 393 if (boring) /* no need to bother */ 394 return; 395 for (p = format; *p; p++) /* look for '%' */ 396 if (*p == '%' && *(p+1) != '%') /* leave %% alone */ 397 break; 398 sz = sizeof(format) - strlen(format) - 1; 399 if (!*p && !chardata) { 400 if (snprintf(p, sz, "%%.%df", prec) >= (int)sz) 401 errx(1, "-w word too long"); 402 } else if (!*p && chardata) { 403 if (strlcpy(p, "%c", sz) >= sz) 404 errx(1, "-w word too long"); |
389 intdata = 1; | 405 intdata = true; |
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 --- 10 unchanged lines hidden (view full) --- 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') { | 406 } else if (!*(p+1)) { 407 if (sz <= 0) 408 errx(1, "-w word too long"); 409 strcat(format, "%"); /* cannot end in single '%' */ 410 } else { 411 /* 412 * Allow conversion format specifiers of the form 413 * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of --- 10 unchanged lines hidden (view full) --- 424 (*p == ' ' && !(numbers|dot|space++)) || 425 ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 426 || (*p == '.' && !(dot++))) 427 p++; 428 else 429 goto fmt_broken; 430 } 431 if (*p == 'l') { |
416 longdata = 1; | 432 longdata = true; |
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': | 433 if (*++p == 'l') { 434 if (p[1] != '\0') 435 p++; 436 goto fmt_broken; 437 } 438 } 439 switch (*p) { 440 case 'o': case 'u': case 'x': case 'X': |
425 intdata = nosign = 1; | 441 intdata = nosign = true; |
426 break; 427 case 'd': case 'i': | 442 break; 443 case 'd': case 'i': |
428 intdata = 1; | 444 intdata = true; |
429 break; 430 case 'D': 431 if (!longdata) { | 445 break; 446 case 'D': 447 if (!longdata) { |
432 intdata = 1; | 448 intdata = true; |
433 break; 434 } 435 case 'O': case 'U': 436 if (!longdata) { | 449 break; 450 } 451 case 'O': case 'U': 452 if (!longdata) { |
437 intdata = nosign = 1; | 453 intdata = nosign = true; |
438 break; 439 } 440 case 'c': 441 if (!(intdata | longdata)) { | 454 break; 455 } 456 case 'c': 457 if (!(intdata | longdata)) { |
442 chardata = 1; | 458 chardata = true; |
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; --- 18 unchanged lines hidden --- | 459 break; 460 } 461 case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 462 case '$': case '*': 463 goto fmt_broken; 464 case 'f': case 'e': case 'g': case 'E': case 'G': 465 if (!longdata) 466 break; --- 18 unchanged lines hidden --- |