]>
git.saurik.com Git - apple/shell_cmds.git/blob - jot/jot.c
   3  *      The Regents of the University of California.  All rights reserved. 
   5  * Redistribution and use in source and binary forms, with or without 
   6  * modification, are permitted provided that the following conditions 
   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. 
  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 
  35 static const char copyright
[] = 
  36 "@(#) Copyright (c) 1993\n\ 
  37         The Regents of the University of California.  All rights reserved.\n"; 
  42 static char sccsid
[] = "@(#)jot.c       8.1 (Berkeley) 6/6/93"; 
  45 #include <sys/cdefs.h> 
  46 __FBSDID("$FreeBSD: src/usr.bin/jot/jot.c,v 1.40 2009/12/13 03:14:06 delphij Exp $"); 
  49  * jot - print sequential or random data 
  51  * Author:  John Kunze, Office of Comp. Affairs, UCB 
  71 /* Flags of options that have been set */ 
  77 #define is_default(s)   (*(s) == 0 || strcmp((s), "-") == 0) 
  85 static const    char *sepstring 
= "\n"; 
  86 static char     format
[BUFSIZ
]; 
  88 static void     getformat(void); 
  89 static int      getprec(const char *); 
  90 static int      putdata(double, bool); 
  91 static void     usage(void); 
  94 main(int argc
, char **argv
) 
  96         bool    have_format 
= false; 
  97         bool    infinity 
= false; 
  98         bool    nofinalnl 
= false; 
  99         bool    randomize 
= false; 
 100         bool    use_random 
= false; 
 104         double  begin 
= BEGIN_DEF
; 
 106         double  ender 
= ENDER_DEF
; 
 110         long    reps 
= REPS_DEF
; 
 112         while ((ch 
= getopt(argc
, argv
, "b:cnp:rs:w:")) != -1) 
 118                         if (strlcpy(format
, optarg
, sizeof(format
)) >= 
 120                                 errx(1, "-%c word too long", ch
); 
 132                                 errx(1, "bad precision value"); 
 147         switch (argc
) { /* examine args right to left, falling thru cases */ 
 149                 if (!is_default(argv
[3])) { 
 150                         if (!sscanf(argv
[3], "%lf", &s
)) 
 151                                 errx(1, "bad s value: %s", argv
[3]); 
 158                 if (!is_default(argv
[2])) { 
 159                         if (!sscanf(argv
[2], "%lf", &ender
)) 
 160                                 ender 
= argv
[2][strlen(argv
[2])-1]; 
 163                                 n 
= getprec(argv
[2]); 
 167                 if (!is_default(argv
[1])) { 
 168                         if (!sscanf(argv
[1], "%lf", &begin
)) 
 169                                 begin 
= argv
[1][strlen(argv
[1])-1]; 
 172                                 prec 
= getprec(argv
[1]); 
 173                         if (n 
> prec
)           /* maximum precision */ 
 178                 if (!is_default(argv
[0])) { 
 179                         if (!sscanf(argv
[0], "%ld", &reps
)) 
 180                                 errx(1, "bad reps value: %s", argv
[0]); 
 187                 errx(1, "too many arguments.  What do you mean by %s?", 
 191         while (mask
)    /* 4 bit mask has 1's where last 4 args were given */ 
 192                 switch (mask
) { /* fill in the 0's by default or computation */ 
 195                 case HAVE_ENDER 
| HAVE_STEP
: 
 197                 case HAVE_BEGIN 
| HAVE_STEP
: 
 201                 case HAVE_BEGIN 
| HAVE_ENDER
: 
 202                         s 
= ender 
> begin 
? 1 : -1; 
 205                 case HAVE_BEGIN 
| HAVE_ENDER 
| HAVE_STEP
: 
 211                                 reps 
= (ender 
- begin 
+ s
) / s
; 
 213                                 errx(1, "impossible stepsize"); 
 217                 case HAVE_REPS 
| HAVE_STEP
: 
 221                 case HAVE_REPS 
| HAVE_ENDER
: 
 223                         mask 
= HAVE_REPS 
| HAVE_ENDER 
| HAVE_STEP
; 
 225                 case HAVE_REPS 
| HAVE_ENDER 
| HAVE_STEP
: 
 229                                 errx(1, "must specify begin if reps == 0"); 
 230                         begin 
= ender 
- reps 
* s 
+ s
; 
 233                 case HAVE_REPS 
| HAVE_BEGIN
: 
 235                         mask 
= HAVE_REPS 
| HAVE_BEGIN 
| HAVE_STEP
; 
 237                 case HAVE_REPS 
| HAVE_BEGIN 
| HAVE_STEP
: 
 241                                 ender 
= begin 
+ reps 
* s 
- s
; 
 244                 case HAVE_REPS 
| HAVE_BEGIN 
| HAVE_ENDER
: 
 246                                 errx(1, "infinite sequences cannot be bounded"); 
 250                                 s 
= (ender 
- begin
) / (reps 
- 1); 
 253                 case HAVE_REPS 
| HAVE_BEGIN 
| HAVE_ENDER 
| HAVE_STEP
: 
 254                         /* if reps given and implied, */ 
 255                         if (!randomize 
&& s 
!= 0.0) { 
 256                                 long t 
= (ender 
- begin 
+ s
) / s
; 
 258                                         errx(1, "impossible stepsize"); 
 259                                 if (t 
< reps
)           /* take lesser */ 
 271                         srandom((unsigned long)s
); 
 272                         divisor 
= (double)INT32_MAX 
+ 1; 
 274                         divisor 
= (double)UINT32_MAX 
+ 1; 
 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. 
 284                 if (!have_format 
&& prec 
== 0 && 
 285                     begin 
>= 0 && begin 
< divisor 
&& 
 286                     ender 
>= 0 && ender 
< divisor
) { 
 290                         (void)strlcpy(format
, 
 291                             chardata 
? "%c" : "%u", sizeof(format
)); 
 293                 x 
= (ender 
- begin
) * (ender 
> begin 
? 1 : -1); 
 294                 for (i 
= 1; i 
<= reps 
|| infinity
; i
++) { 
 296                                 y 
= random() / divisor
; 
 298                                 y 
= arc4random() / divisor
; 
 299                         if (putdata(y 
* x 
+ begin
, !(reps 
- i
))) 
 300                                 errx(1, "range error in conversion"); 
 303                 for (i 
= 1, x 
= begin
; i 
<= reps 
|| infinity
; i
++, x 
+= s
) 
 304                         if (putdata(x
, !(reps 
- i
))) 
 305                                 errx(1, "range error in conversion"); 
 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. 
 318 putdata(double x
, bool last
) 
 322                 printf("%s", format
); 
 323         else if (longdata 
&& nosign
) { 
 324                 if (x 
<= (double)ULONG_MAX 
&& x 
>= (double)0) 
 325                         printf(format
, (unsigned long)x
); 
 328         } else if (longdata
) { 
 329                 if (x 
<= (double)LONG_MAX 
&& x 
>= (double)LONG_MIN
) 
 330                         printf(format
, (long)x
); 
 333         } else if (chardata 
|| (intdata 
&& !nosign
)) { 
 334                 if (x 
<= (double)INT_MAX 
&& x 
>= (double)INT_MIN
) 
 335                         printf(format
, (int)x
); 
 338         } else if (intdata
) { 
 339                 if (x 
<= (double)UINT_MAX 
&& x 
>= (double)0) 
 340                         printf(format
, (unsigned int)x
); 
 347                 fputs(sepstring
, stdout
); 
 355         fprintf(stderr
, "%s\n%s\n", 
 356         "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]", 
 357         "           [reps [begin [end [s]]]]"); 
 362  * Return the number of digits following the number's decimal point. 
 363  * Return 0 if no decimal point is found. 
 366 getprec(const char *str
) 
 371         for (p 
= str
; *p
; p
++) 
 376         for (q 
= ++p
; *p
; p
++) 
 377                 if (!isdigit((unsigned char)*p
)) 
 383  * Set format, intdata, chardata, longdata, and nosign 
 384  * based on the command line arguments. 
 390         int dot
, hash
, space
, sign
, numbers 
= 0; 
 393         if (boring
)                             /* no need to bother */ 
 395         for (p 
= format
; *p
; p
++)               /* look for '%' */ 
 398                                 p
++;            /* leave %% alone */ 
 402         sz 
= sizeof(format
) - strlen(format
) - 1; 
 403         if (!*p 
&& !chardata
) { 
 404                 if (snprintf(p
, sz
, "%%.%df", prec
) >= (int)sz
) 
 405                         errx(1, "-w word too long"); 
 406         } else if (!*p 
&& chardata
) { 
 407                 if (strlcpy(p
, "%c", sz
) >= sz
) 
 408                         errx(1, "-w word too long"); 
 410         } else if (!*(p
+1)) { 
 412                         errx(1, "-w word too long"); 
 413                 strcat(format
, "%");            /* cannot end in single '%' */ 
 416                  * Allow conversion format specifiers of the form 
 417                  * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of 
 418                  * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} 
 421                 dot 
= hash 
= space 
= sign 
= numbers 
= 0; 
 422                 while (!isalpha((unsigned char)*p
)) { 
 423                         if (isdigit((unsigned char)*p
)) { 
 426                         } else if ((*p 
== '#' && !(numbers
|dot
|sign
|space
| 
 428                             (*p 
== ' ' && !(numbers
|dot
|space
++)) || 
 429                             ((*p 
== '+' || *p 
== '-') && !(numbers
|dot
|sign
++)) 
 430                             || (*p 
== '.' && !(dot
++))) 
 444                 case 'o': case 'u': case 'x': case 'X': 
 445                         intdata 
= nosign 
= true; 
 457                                 intdata 
= nosign 
= true; 
 461                         if (!(intdata 
| longdata
)) { 
 465                 case 'h': case 'n': case 'p': case 'q': case 's': case 'L': 
 468                 case 'f': case 'e': case 'g': case 'E': case 'G': 
 475                         errx(1, "illegal or unsupported format '%s'", p2
); 
 479                         if (*p 
== '%' && *(p
+1) && *(p
+1) != '%') 
 480                                 errx(1, "too many conversions"); 
 481                         else if (*p 
== '%' && *(p
+1) == '%') 
 483                         else if (*p 
== '%' && !*(p
+1)) { 
 484                                 if (strlcat(format
, "%", sizeof(format
)) >= 
 486                                         errx(1, "-w word too long");