jot.c revision 48995
1244158Sdteske/*- 2222417Sjulian * Copyright (c) 1993 3222417Sjulian * The Regents of the University of California. All rights reserved. 4222417Sjulian * 5222417Sjulian * Redistribution and use in source and binary forms, with or without 6222417Sjulian * modification, are permitted provided that the following conditions 7222417Sjulian * are met: 8222417Sjulian * 1. Redistributions of source code must retain the above copyright 9222417Sjulian * notice, this list of conditions and the following disclaimer. 10222417Sjulian * 2. Redistributions in binary form must reproduce the above copyright 11222417Sjulian * notice, this list of conditions and the following disclaimer in the 12222417Sjulian * documentation and/or other materials provided with the distribution. 13222417Sjulian * 3. All advertising materials mentioning features or use of this software 14222417Sjulian * must display the following acknowledgement: 15222417Sjulian * This product includes software developed by the University of 16222417Sjulian * California, Berkeley and its contributors. 17222417Sjulian * 4. Neither the name of the University nor the names of its contributors 18222417Sjulian * may be used to endorse or promote products derived from this software 19222417Sjulian * without specific prior written permission. 20222417Sjulian * 21222417Sjulian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22222417Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23222417Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24222417Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25222417Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26222417Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27222417Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28222417Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29222417Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30222417Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31222417Sjulian * SUCH DAMAGE. 32222417Sjulian */ 33222417Sjulian 34222417Sjulian#ifndef lint 35222417Sjulianstatic const char copyright[] = 36222417Sjulian"@(#) Copyright (c) 1993\n\ 37222417Sjulian The Regents of the University of California. All rights reserved.\n"; 38222417Sjulian#endif /* not lint */ 39222417Sjulian 40222417Sjulian#ifndef lint 41222417Sjulian#if 0 42222417Sjulianstatic char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; 43222417Sjulian#endif 44222417Sjulianstatic const char rcsid[] = 45222417Sjulian "$Id: jot.c,v 1.9 1999/05/13 12:18:24 kris Exp $"; 46222417Sjulian#endif /* not lint */ 47222417Sjulian 48222417Sjulian/* 49222417Sjulian * jot - print sequential or random data 50222417Sjulian * 51222417Sjulian * Author: John Kunze, Office of Comp. Affairs, UCB 52222417Sjulian */ 53222417Sjulian 54222417Sjulian#include <ctype.h> 55222417Sjulian#include <err.h> 56222417Sjulian#include <limits.h> 57222417Sjulian#include <stdio.h> 58222417Sjulian#include <stdlib.h> 59222417Sjulian#include <string.h> 60222417Sjulian#include <time.h> 61222417Sjulian#include <unistd.h> 62222417Sjulian 63222417Sjulian#define REPS_DEF 100 64222417Sjulian#define BEGIN_DEF 1 65222417Sjulian#define ENDER_DEF 100 66222417Sjulian#define STEP_DEF 1 67222417Sjulian 68222417Sjulian#define isdefault(s) (strcmp((s), "-") == 0) 69222417Sjulian 70222417Sjuliandouble begin; 71222417Sjuliandouble ender; 72222417Sjuliandouble s; 73222417Sjulianlong reps; 74222417Sjulianint randomize; 75222417Sjulianint infinity; 76222417Sjulianint boring; 77244158Sdteskeint prec; 78222417Sjulianint intdata; 79222417Sjulianint chardata; 80222417Sjulianint nosign; 81222417Sjulianint nofinalnl; 82222417Sjulianchar *sepstring = "\n"; 83222417Sjulianchar format[BUFSIZ]; 84222417Sjulian 85222417Sjulianvoid getargs __P((int, char *[])); 86222417Sjulianvoid getformat __P((void)); 87222417Sjulianint getprec __P((char *)); 88222417Sjulianvoid putdata __P((double, long)); 89222417Sjulianstatic void usage __P((void)); 90222417Sjulian 91222417Sjulianint 92222417Sjulianmain(argc, argv) 93222417Sjulian int argc; 94222417Sjulian char *argv[]; 95222417Sjulian{ 96222417Sjulian double xd, yd; 97222417Sjulian long id; 98222417Sjulian register double *x = &xd; 99222417Sjulian register double *y = &yd; 100222417Sjulian register long *i = &id; 101222417Sjulian 102222417Sjulian getargs(argc, argv); 103222417Sjulian if (randomize) { 104222417Sjulian *x = (ender - begin) * (ender > begin ? 1 : -1); 105222417Sjulian for (*i = 1; *i <= reps || infinity; (*i)++) { 106222417Sjulian *y = (double) arc4random() / ULONG_MAX; 107222417Sjulian putdata(*y * *x + begin, reps - *i); 108222417Sjulian } 109222417Sjulian } else 110222417Sjulian for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) 111222417Sjulian putdata(*x, reps - *i); 112222417Sjulian if (!nofinalnl) 113222417Sjulian putchar('\n'); 114222417Sjulian exit(0); 115222417Sjulian} 116222417Sjulian 117222417Sjulianvoid 118222417Sjuliangetargs(ac, av) 119222417Sjulian int ac; 120222417Sjulian char *av[]; 121222417Sjulian{ 122222417Sjulian register unsigned int mask = 0; 123222417Sjulian register int n = 0; 124222417Sjulian 125222417Sjulian while (--ac && **++av == '-' && !isdefault(*av)) 126222417Sjulian switch ((*av)[1]) { 127222417Sjulian case 'r': 128222417Sjulian randomize = 1; 129222417Sjulian break; 130222417Sjulian case 'c': 131222417Sjulian chardata = 1; 132222417Sjulian break; 133222417Sjulian case 'n': 134222417Sjulian nofinalnl = 1; 135222417Sjulian break; 136222417Sjulian case 'b': 137244158Sdteske boring = 1; 138244158Sdteske case 'w': 139244158Sdteske if ((*av)[2]) 140244158Sdteske strcpy(format, *av + 2); 141244158Sdteske else if (!--ac) 142244158Sdteske errx(1, "need context word after -w or -b"); 143244158Sdteske else 144244158Sdteske strcpy(format, *++av); 145244158Sdteske break; 146244158Sdteske case 's': 147244158Sdteske if ((*av)[2]) 148244158Sdteske sepstring = *av + 2; 149222417Sjulian else if (!--ac) 150222417Sjulian errx(1, "need string after -s"); 151244158Sdteske else 152244158Sdteske sepstring = *++av; 153222417Sjulian break; 154244158Sdteske case 'p': 155244158Sdteske if ((*av)[2]) 156222417Sjulian prec = atoi(*av + 2); 157244158Sdteske else if (!--ac) 158244158Sdteske errx(1, "need number after -p"); 159244158Sdteske else 160244158Sdteske prec = atoi(*++av); 161244158Sdteske if (prec <= 0) 162244158Sdteske errx(1, "bad precision value"); 163244158Sdteske break; 164244158Sdteske default: 165222417Sjulian usage(); 166222417Sjulian } 167222417Sjulian 168244158Sdteske switch (ac) { /* examine args right to left, falling thru cases */ 169244158Sdteske case 4: 170222417Sjulian if (!isdefault(av[3])) { 171 if (!sscanf(av[3], "%lf", &s)) 172 errx(1, "bad s value: %s", av[3]); 173 mask |= 01; 174 } 175 case 3: 176 if (!isdefault(av[2])) { 177 if (!sscanf(av[2], "%lf", &ender)) 178 ender = av[2][strlen(av[2])-1]; 179 mask |= 02; 180 if (!prec) 181 n = getprec(av[2]); 182 } 183 case 2: 184 if (!isdefault(av[1])) { 185 if (!sscanf(av[1], "%lf", &begin)) 186 begin = av[1][strlen(av[1])-1]; 187 mask |= 04; 188 if (!prec) 189 prec = getprec(av[1]); 190 if (n > prec) /* maximum precision */ 191 prec = n; 192 } 193 case 1: 194 if (!isdefault(av[0])) { 195 if (!sscanf(av[0], "%ld", &reps)) 196 errx(1, "bad reps value: %s", av[0]); 197 mask |= 010; 198 } 199 break; 200 case 0: 201 usage(); 202 default: 203 errx(1, "too many arguments. What do you mean by %s?", av[4]); 204 } 205 getformat(); 206 while (mask) /* 4 bit mask has 1's where last 4 args were given */ 207 switch (mask) { /* fill in the 0's by default or computation */ 208 case 001: 209 reps = REPS_DEF; 210 mask = 011; 211 break; 212 case 002: 213 reps = REPS_DEF; 214 mask = 012; 215 break; 216 case 003: 217 reps = REPS_DEF; 218 mask = 013; 219 break; 220 case 004: 221 reps = REPS_DEF; 222 mask = 014; 223 break; 224 case 005: 225 reps = REPS_DEF; 226 mask = 015; 227 break; 228 case 006: 229 reps = REPS_DEF; 230 mask = 016; 231 break; 232 case 007: 233 if (randomize) { 234 reps = REPS_DEF; 235 mask = 0; 236 break; 237 } 238 if (s == 0.0) { 239 reps = 0; 240 mask = 0; 241 break; 242 } 243 reps = (ender - begin + s) / s; 244 if (reps <= 0) 245 errx(1, "impossible stepsize"); 246 mask = 0; 247 break; 248 case 010: 249 begin = BEGIN_DEF; 250 mask = 014; 251 break; 252 case 011: 253 begin = BEGIN_DEF; 254 mask = 015; 255 break; 256 case 012: 257 s = (randomize ? -1.0 : STEP_DEF); 258 mask = 013; 259 break; 260 case 013: 261 if (randomize) 262 begin = BEGIN_DEF; 263 else if (reps == 0) 264 errx(1, "must specify begin if reps == 0"); 265 else 266 begin = ender - reps * s + s; 267 mask = 0; 268 break; 269 case 014: 270 s = (randomize ? -1.0 : STEP_DEF); 271 mask = 015; 272 break; 273 case 015: 274 if (randomize) 275 ender = ENDER_DEF; 276 else 277 ender = begin + reps * s - s; 278 mask = 0; 279 break; 280 case 016: 281 if (randomize) 282 s = -1.0; 283 else if (reps == 0) 284 errx(1, "infinite sequences cannot be bounded"); 285 else if (reps == 1) 286 s = 0.0; 287 else 288 s = (ender - begin) / (reps - 1); 289 mask = 0; 290 break; 291 case 017: /* if reps given and implied, */ 292 if (!randomize && s != 0.0) { 293 long t = (ender - begin + s) / s; 294 if (t <= 0) 295 errx(1, "impossible stepsize"); 296 if (t < reps) /* take lesser */ 297 reps = t; 298 } 299 mask = 0; 300 break; 301 default: 302 errx(1, "bad mask"); 303 } 304 if (reps == 0) 305 infinity = 1; 306} 307 308void 309putdata(x, notlast) 310 double x; 311 long notlast; 312{ 313 314 if (boring) /* repeated word */ 315 printf(format); 316 else if (chardata) /* character representation */ 317 printf(format, (int)x); 318 else if (intdata && nosign) /* scalar */ 319 printf(format, (unsigned long)x); 320 else if (intdata) 321 printf(format, (long)x); 322 else /* real */ 323 printf(format, x); 324 if (notlast != 0) 325 fputs(sepstring, stdout); 326} 327 328static void 329usage() 330{ 331 fprintf(stderr, "%s\n%s\n", 332 "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 333 " [reps [begin [end [s]]]]"); 334 exit(1); 335} 336 337int 338getprec(s) 339 char *s; 340{ 341 register char *p; 342 register char *q; 343 344 for (p = s; *p; p++) 345 if (*p == '.') 346 break; 347 if (!*p) 348 return (0); 349 for (q = ++p; *p; p++) 350 if (!isdigit(*p)) 351 break; 352 return (p - q); 353} 354 355void 356getformat() 357{ 358 register char *p; 359 int dot, hash, space, sign, numbers, islong = 0; 360 char *s; 361 362 if (boring) /* no need to bother */ 363 return; 364 for (p = format; *p; p++) /* look for '%' */ 365 if (*p == '%' && *(p+1) != '%') /* leave %% alone */ 366 break; 367 if (!*p && !chardata) 368 sprintf(p, "%%.%df", prec); 369 else if (!*p && chardata) { 370 strcpy(p, "%c"); 371 intdata = 1; 372 } else if (!*(p+1)) 373 strcat(format, "%"); /* cannot end in single '%' */ 374 else { 375 /* 376 * Allow conversion format specifiers of the form 377 * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 378 * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 379 */ 380 s = p++; 381 dot = hash = space = sign = numbers = 0; 382 while (!isalpha(*p)) { 383 if (isdigit(*p)) { 384 numbers++; 385 p++; 386 } else if ((*p == '#' && !(numbers|dot|sign|space| 387 hash++)) || 388 (*p == ' ' && !(numbers|dot|space++)) || 389 ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) 390 || (*p == '.' && !(dot++))) 391 p++; 392 else if (*p == '$' || *p == '*') 393 errx(1, "unsupported format character %c", *p); 394 else if (*p == '\0') 395 errx(1, "missing format character"); 396 else 397 errx(1, "illegal format character %c", *p); 398 } 399 switch (*p) { 400 case 'l': 401 islong = 1; 402 p++; 403 /* FALLTHROUGH */ 404 case 'o': case 'u': case 'x': case 'X': 405 intdata = nosign = 1; 406 break; 407 case 'd': case 'i': 408 intdata = 1; 409 break; 410 case 'D': 411 if (!islong) { 412 intdata = 1; 413 break; 414 } 415 case 'O': case 'U': 416 if (!islong) { 417 intdata = nosign = 1; 418 break; 419 } 420 case 'c': 421 if (!(intdata | islong)) { 422 chardata = 1; 423 break; 424 } 425 case 's': 426 errx(1, "cannot convert numeric data to strings"); 427 break; 428 case 'h': case 'n': case 'p': case 'q': case 'L': 429 case '$': case '*': 430 errx(1, "unsupported format character %c", *p); 431 /* NOTREACHED */ 432 case 'f': case 'e': case 'g': case 'E': case 'G': 433 if (!islong) 434 break; 435 /* FALLTHROUGH */ 436 default: 437 *++p = '\0'; 438 errx(1, "illegal or unsupported format '%s'", s); 439 /* NOTREACHED */ 440 } 441 while (*++p) 442 if (*p == '%' && *(p+1) && *(p+1) != '%') 443 errx(1, "too many conversions"); 444 else if (*p == '%' && *(p+1) == '%') 445 p++; 446 else if (*p == '%' && !*(p+1)) { 447 strcat(format, "%"); 448 break; 449 } 450 } 451} 452