1 /* $NetBSD: jot.c,v 1.24 2008/07/21 14:19:23 lukem Exp $ */
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1993\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93";
42 __RCSID("$NetBSD: jot.c,v 1.24 2008/07/21 14:19:23 lukem Exp $");
46 * jot - print sequential or random data
48 * Author: John Kunze, Office of Comp. Affairs, UCB
66 #define is_default(s) (strcmp((s), "-") == 0)
68 static double begin
= BEGIN_DEF
;
69 static double ender
= ENDER_DEF
;
70 static double step
= STEP_DEF
;
71 static long reps
= REPS_DEF
;
78 static const char *sepstring
= "\n";
79 static char format
[BUFSIZ
];
81 static void getargs(int, char *[]);
82 static void getformat(void);
83 static int getprec(char *);
84 static void putdata(double, long);
85 static void usage(void) __dead
;
88 main(int argc
, char *argv
[])
102 * We are printing floating point, generate random
103 * number that include both supplied limits.
104 * Due to FP routing for display the low and high
105 * values are likely to occur half as often as all
108 x
/= (1u << 31) - 1.0;
111 * We are printing integers increase the range by
112 * one but ensure we never generate it.
113 * This makes all the integer values equally likely.
118 srandom((unsigned long) step
);
119 for (i
= 1; i
<= reps
|| reps
== 0; i
++)
120 putdata(random() * x
+ begin
, reps
- i
);
123 * If we are going to display as integer, add 0.5 here
124 * and use floor(x) later to get sane rounding.
129 for (i
= 1; i
<= reps
|| reps
== 0; i
++, x
+= step
)
130 putdata(x
, reps
- i
);
138 getargs(int argc
, char *argv
[])
140 unsigned int have
= 0;
142 #define STEP 2 /* seed if -r */
150 switch (getopt(argc
, argv
, "b:cnp:rs:w:")) {
162 prec
= strtol(optarg
, &ep
, 0);
163 if (*ep
!= 0 || prec
< 0)
164 errx(EXIT_FAILURE
, "Bad precision value");
176 strlcpy(format
, optarg
, sizeof(format
));
184 switch (argc
) { /* examine args right to left, falling thru cases */
186 if (!is_default(argv
[3])) {
187 step
= strtod(argv
[3], &ep
);
189 errx(EXIT_FAILURE
, "Bad step value: %s",
194 if (!is_default(argv
[2])) {
195 if (!sscanf(argv
[2], "%lf", &ender
))
196 ender
= argv
[2][strlen(argv
[2])-1];
199 n
= getprec(argv
[2]);
202 if (!is_default(argv
[1])) {
203 if (!sscanf(argv
[1], "%lf", &begin
))
204 begin
= argv
[1][strlen(argv
[1])-1];
207 prec
= getprec(argv
[1]);
208 if (n
> prec
) /* maximum precision */
212 if (!is_default(argv
[0])) {
213 reps
= strtoul(argv
[0], &ep
, 0);
214 if (*ep
!= 0 || reps
< 0)
215 errx(EXIT_FAILURE
, "Bad reps value: %s",
225 "Too many arguments. What do you mean by %s?", argv
[4]);
233 /* 'step' is the seed here, use pseudo-random default */
235 step
= time(NULL
) * getpid();
236 /* Take the default values for everything else */
241 * The loop we run uses begin/step/reps, so if we have been
242 * given an end value (ender) we must use it to replace the
243 * default values of the others.
244 * We will assume a begin of 0 and step of 1 if necessary.
250 case ENDER
| STEP
| BEGIN
:
253 reps
= 0; /* ie infinite */
255 reps
= (ender
- begin
+ step
) / step
;
257 errx(EXIT_FAILURE
, "Impossible stepsize");
262 case REPS
| ENDER
| STEP
:
263 /* Calculate begin */
266 "Must specify begin if reps == 0");
267 begin
= ender
- reps
* step
+ step
;
270 case REPS
| BEGIN
| ENDER
:
274 "Infinite sequences cannot be bounded");
278 step
= (ender
- begin
) / (reps
- 1);
281 case REPS
| BEGIN
| ENDER
| STEP
:
282 /* reps given and implied - take smaller */
285 t
= (ender
- begin
+ step
) / step
;
288 "Impossible stepsize");
294 /* No values can be calculated, use defaults */
300 putdata(double x
, long notlast
)
303 if (boring
) /* repeated word */
304 printf("%s", format
);
305 else if (dox
) /* scalar */
306 printf(format
, (long)floor(x
));
310 fputs(sepstring
, stdout
);
316 (void)fprintf(stderr
, "usage: %s [-cnr] [-b word] [-p precision] "
317 "[-s string] [-w word] [reps [begin [end [step | seed]]]]\n",
323 getprec(char *num_str
)
326 num_str
= strchr(num_str
, '.');
329 return strspn(num_str
+ 1, "0123456789");
338 if (boring
) /* no need to bother */
340 for (p
= format
; *p
; p
++) { /* look for '%' */
344 p
++; /* leave %% alone */
347 sz
= sizeof(format
) - strlen(format
) - 1;
349 if (chardata
|| prec
== 0) {
350 if ((size_t)snprintf(p
, sz
, "%%%s", chardata
? "c" : "ld") >= sz
)
351 errx(EXIT_FAILURE
, "-w word too long");
354 if (snprintf(p
, sz
, "%%.%df", prec
) >= (int)sz
)
355 errx(EXIT_FAILURE
, "-w word too long");
357 } else if (!*(p
+1)) {
359 errx(EXIT_FAILURE
, "-w word too long");
360 strcat(format
, "%"); /* cannot end in single '%' */
362 p
++; /* skip leading % */
363 for(; *p
&& !isalpha((unsigned char)*p
); p
++) {
364 /* allow all valid printf(3) flags, but deny '*' */
365 if (!strchr("0123456789#-+. ", *p
))
368 /* Allow 'l' prefix, but no other. */
372 case 'f': case 'e': case 'g': case '%':
377 "cannot convert numeric data to strings");
379 case 'd': case 'o': case 'x': case 'u':
380 case 'D': case 'O': case 'X': case 'U':
385 errx(EXIT_FAILURE
, "unknown or invalid format `%s'",
388 /* Need to check for trailing stuff to print */
389 for (; *p
; p
++) /* look for '%' */
393 p
++; /* leave %% alone */
396 errx(EXIT_FAILURE
, "unknown or invalid format `%s'",