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