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