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