1 /* $OpenBSD: jot.c,v 1.8 2001/03/08 01:39:17 pjanzen Exp $ */ 2 /* $NetBSD: jot.c,v 1.3 1994/12/02 20:29:43 pk Exp $ */ 3 4 /*- 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; 46 #endif 47 static char rcsid[] = "$OpenBSD: jot.c,v 1.8 2001/03/08 01:39:17 pjanzen Exp $"; 48 #endif /* not lint */ 49 50 /* 51 * jot - print sequential or random data 52 * 53 * Author: John Kunze, Office of Comp. Affairs, UCB 54 */ 55 56 #include <err.h> 57 #include <ctype.h> 58 #include <limits.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <time.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 is_default(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 dox; 80 int chardata; 81 int nofinalnl; 82 char sepstring[BUFSIZ] = "\n"; 83 char format[BUFSIZ]; 84 85 void getargs __P((int, char *[])); 86 void getformat __P((void)); 87 int getprec __P((char *)); 88 void putdata __P((double, long)); 89 static void usage __P((void)); 90 91 int 92 main(argc, argv) 93 int argc; 94 char *argv[]; 95 { 96 double xd, yd; 97 long id; 98 double *x = &xd; 99 double *y = &yd; 100 long *i = &id; 101 unsigned int mask = 0; 102 int n = 0; 103 int ch; 104 105 while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1) 106 switch((char)ch) { 107 case 'r': 108 randomize = 1; 109 break; 110 case 'c': 111 chardata = 1; 112 break; 113 case 'n': 114 nofinalnl = 1; 115 break; 116 case 'b': 117 boring = 1; 118 if (strlcpy(format, optarg, sizeof(format)) >= 119 sizeof(format)) 120 errx(1, "-b word too long"); 121 break; 122 case 'w': 123 if (strlcpy(format, optarg, sizeof(format)) >= 124 sizeof(format)) 125 errx(1, "-w word too long"); 126 break; 127 case 's': 128 if (strlcpy(sepstring, optarg, sizeof(sepstring)) >= 129 sizeof(sepstring)) 130 errx(1, "-s word too long"); 131 break; 132 case 'p': 133 prec = atoi(optarg); 134 if (prec <= 0) 135 errx(1, "bad precision value"); 136 break; 137 default: 138 usage(); 139 } 140 argc -= optind; 141 argv += optind; 142 143 switch (argc) { /* examine args right to left, falling thru cases */ 144 case 4: 145 if (!is_default(argv[3])) { 146 if (!sscanf(argv[3], "%lf", &s)) 147 errx(1, "Bad s value: %s", argv[3]); 148 mask |= 01; 149 } 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 |= 02; 155 if (!prec) 156 n = getprec(argv[2]); 157 } 158 case 2: 159 if (!is_default(argv[1])) { 160 if (!sscanf(argv[1], "%lf", &begin)) 161 begin = argv[1][strlen(argv[1])-1]; 162 mask |= 04; 163 if (!prec) 164 prec = getprec(argv[1]); 165 if (n > prec) /* maximum precision */ 166 prec = n; 167 } 168 case 1: 169 if (!is_default(argv[0])) { 170 if (!sscanf(argv[0], "%ld", &reps)) 171 errx(1, "Bad reps value: %s", argv[0]); 172 mask |= 010; 173 } 174 break; 175 case 0: 176 usage(); 177 break; 178 default: 179 errx(1, "Too many arguments. What do you mean by %s?", argv[4]); 180 } 181 getformat(); 182 while (mask) /* 4 bit mask has 1's where last 4 args were given */ 183 switch (mask) { /* fill in the 0's by default or computation */ 184 case 001: 185 reps = REPS_DEF; 186 mask = 011; 187 break; 188 case 002: 189 reps = REPS_DEF; 190 mask = 012; 191 break; 192 case 003: 193 reps = REPS_DEF; 194 mask = 013; 195 break; 196 case 004: 197 reps = REPS_DEF; 198 mask = 014; 199 break; 200 case 005: 201 reps = REPS_DEF; 202 mask = 015; 203 break; 204 case 006: 205 reps = REPS_DEF; 206 mask = 016; 207 break; 208 case 007: 209 if (randomize) { 210 reps = REPS_DEF; 211 mask = 0; 212 break; 213 } 214 if (s == 0.0) { 215 reps = 0; 216 mask = 0; 217 break; 218 } 219 reps = (ender - begin + s) / s; 220 if (reps <= 0) 221 errx(1, "Impossible stepsize"); 222 mask = 0; 223 break; 224 case 010: 225 begin = BEGIN_DEF; 226 mask = 014; 227 break; 228 case 011: 229 begin = BEGIN_DEF; 230 mask = 015; 231 break; 232 case 012: 233 s = (randomize ? time(NULL) : STEP_DEF); 234 mask = 013; 235 break; 236 case 013: 237 if (randomize) 238 begin = BEGIN_DEF; 239 else if (reps == 0) 240 errx(1, "Must specify begin if reps == 0"); 241 begin = ender - reps * s + s; 242 mask = 0; 243 break; 244 case 014: 245 s = (randomize ? time(NULL) : STEP_DEF); 246 mask = 015; 247 break; 248 case 015: 249 if (randomize) 250 ender = ENDER_DEF; 251 else 252 ender = begin + reps * s - s; 253 mask = 0; 254 break; 255 case 016: 256 if (randomize) 257 s = time(NULL); 258 else if (reps == 0) 259 errx(1, "Infinite sequences cannot be bounded"); 260 else if (reps == 1) 261 s = 0.0; 262 else 263 s = (ender - begin) / (reps - 1); 264 mask = 0; 265 break; 266 case 017: /* if reps given and implied, */ 267 if (!randomize && s != 0.0) { 268 long t = (ender - begin + s) / s; 269 if (t <= 0) 270 errx(1, "Impossible stepsize"); 271 if (t < reps) /* take lesser */ 272 reps = t; 273 } 274 mask = 0; 275 break; 276 default: 277 errx(1, "bad mask"); 278 } 279 if (reps == 0) 280 infinity = 1; 281 if (randomize) { 282 *x = (ender - begin) * (ender > begin ? 1 : -1); 283 for (*i = 1; *i <= reps || infinity; (*i)++) { 284 *y = (double) arc4random() / ULONG_MAX; 285 putdata(*y * *x + begin, reps - *i); 286 } 287 } 288 else 289 for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) 290 putdata(*x, reps - *i); 291 if (!nofinalnl) 292 putchar('\n'); 293 exit(0); 294 } 295 296 void 297 putdata(x, notlast) 298 double x; 299 long notlast; 300 { 301 long d = x; 302 long *dp = &d; 303 304 if (boring) /* repeated word */ 305 printf("%s", format); 306 else if (dox) /* scalar */ 307 printf(format, *dp); 308 else /* real */ 309 printf(format, x); 310 if (notlast != 0) 311 fputs(sepstring, stdout); 312 } 313 314 static void 315 usage(void) 316 { 317 (void)fprintf(stderr, "usage: jot [-cnr] [-b word] [-w word] " 318 "[-s string] [-p precision] [reps [begin [end [s]]]]\n"); 319 exit(1); 320 } 321 322 int 323 getprec(s) 324 char *s; 325 { 326 char *p; 327 char *q; 328 329 for (p = s; *p; p++) 330 if (*p == '.') 331 break; 332 if (!*p) 333 return (0); 334 for (q = ++p; *p; p++) 335 if (!isdigit(*p)) 336 break; 337 return (p - q); 338 } 339 340 void 341 getformat() 342 { 343 char *p; 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 == '%') { 350 if (*(p+1) != '%') 351 break; 352 p++; /* leave %% alone */ 353 } 354 sz = sizeof(format) - strlen(format) - 1; 355 if (!*p && !chardata) { 356 if (snprintf(p, sz, "%%.%df", prec) >= (int)sz) 357 errx(1, "-w word too long"); 358 } else if (!*p && chardata) { 359 if (strlcpy(p, "%c", sz) >= sz) 360 errx(1, "-w word too long"); 361 dox = 1; 362 } else if (!*(p+1)) { 363 if (sz <= 0) 364 errx(1, "-w word too long"); 365 strcat(format, "%"); /* cannot end in single '%' */ 366 } else { 367 for (; *p && !isalpha(*p); p++) 368 /* Certain nonalphanumerics we can't allow */ 369 if (*p == '$' || *p == '*') 370 break; 371 /* Allow 'l' prefix, but no other. */ 372 if (*p == 'l') 373 p++; 374 switch (*p) { 375 case 'f': case 'e': case 'g': case '%': 376 case 'E': case 'G': 377 break; 378 case 's': 379 errx(1, "cannot convert numeric data to strings"); 380 break; 381 case 'd': case 'o': case 'x': case 'u': 382 case 'D': case 'O': case 'X': case 'U': 383 case 'c': case 'i': 384 dox = 1; 385 break; 386 default: 387 errx(1, "unknown or invalid format `%s'", format); 388 } 389 /* Need to check for trailing stuff to print */ 390 for (; *p; p++) /* look for '%' */ 391 if (*p == '%') { 392 if (*(p+1) != '%') 393 break; 394 p++; /* leave %% alone */ 395 } 396 if (*p) 397 errx(1, "unknown or invalid format `%s'", format); 398 } 399 } 400