--- /dev/null
+.\" $NetBSD: jot.1,v 1.12 2012/04/08 22:00:39 wiz Exp $
+.\"
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)jot.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd January 5, 2010
+.Dt JOT 1
+.Os
+.Sh NAME
+.Nm jot
+.Nd print sequential or random data
+.Sh SYNOPSIS
+.Nm
+.Op Fl cnr
+.Op Fl b Ar word
+.Op Fl p Ar precision
+.Op Fl s Ar string
+.Op Fl w Ar word
+.Oo Ar reps
+.Oo Ar begin
+.Oo Ar end
+.Op Ar s
+.Oc
+.Oc
+.Oc
+.Sh DESCRIPTION
+The
+.Nm jot
+utility is used to print out increasing, decreasing, random,
+or redundant data (usually numbers) one per line.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl b Ar word
+Just print
+.Ar word
+repetitively.
+.It Fl c
+This is an abbreviation for
+.Fl w Ar %c .
+.It Fl n
+Do not print the final newline normally appended to the output.
+.It Fl p Ar precision
+Print only as many digits or characters of the data
+as indicated by the integer
+.Ar precision .
+In the absence of
+.Fl p ,
+the precision is the greater of the precisions of
+.Ar begin
+and
+.Ar end .
+The
+.Fl p
+option is overridden by whatever appears in a
+.Xr printf 3
+conversion following
+.Fl w .
+.It Fl r
+Generate random data instead of sequential data, the default.
+.It Fl s Ar string
+Print data separated by
+.Ar string .
+Normally, newlines separate data.
+.It Fl w Ar word
+Print
+.Ar word
+with the generated data appended to it.
+Octal, hexadecimal, exponential, ASCII, zero padded,
+and right-adjusted representations
+are possible by using the appropriate
+.Xr printf 3
+conversion specification inside
+.Ar word ,
+in which case the data are inserted rather than appended.
+.El
+.Pp
+The last four arguments indicate, respectively,
+the number of data, the lower bound, the upper bound,
+and the step size or, for random data, the seed.
+While at least one of them must appear,
+any of the other three may be omitted, and
+will be considered as such if given as
+.Dq - .
+Any three of these arguments determines the fourth.
+If four are specified and the given and computed values of
+.Ar reps
+conflict, the lower value is used.
+If fewer than three are specified, defaults are assigned
+left to right, except for
+.Ar s ,
+which assumes its default unless both
+.Ar begin
+and
+.Ar end
+are given.
+.Pp
+Defaults for the four arguments are, respectively,
+100, 1, 100, and 1, except that when random data are requested,
+.Ar s
+defaults to a seed depending upon the time of day.
+.Ar reps
+is expected to be an unsigned integer,
+and if given as zero is taken to be infinite.
+.Ar begin
+and
+.Ar end
+may be given as real numbers or as characters
+representing the corresponding value in ASCII.
+The last argument must be a real number.
+.Pp
+Random numbers are obtained through
+.Xr random 3 .
+The name
+.Nm jot
+derives in part from
+.Nm iota ,
+a function in APL.
+.Sh EXAMPLES
+The command:
+.Dl "jot - 42 87 1"
+prints the integers from 42 to 87, inclusive.
+.Pp
+The command:
+.Dl "jot 21 \-1 1.00"
+prints 21 evenly spaced numbers increasing from \-1 to 1.
+.Pp
+The command:
+.Dl "jot \-c 128 0"
+prints the ASCII character set.
+.Pp
+The command:
+.Dl "jot \-w xa%c 26 a"
+prints the strings
+.Dq xaa
+through
+.Dq xaz .
+.Pp
+The command:
+.Dl "jot \-r \-c 160 a z | rs \-g 0 8"
+prints 20 random 8-letter strings.
+.Pp
+The command:
+.Dl "jot \-b y 0"
+is equivalent to
+.Xr yes 1 .
+.Pp
+The command:
+.Dl "jot \-w %ds/old/new/ 30 2 \- 5"
+prints thirty
+.Xr ed 1
+substitution commands applying to lines 2, 7, 12, etc.
+.Pp
+The command:
+.Dl "jot 0 9 \- \-.5"
+prints the stuttering sequence 9, 8, 8, 7, etc.
+.Pp
+The command:
+.Dl "jot \-b x 512 \*[Gt] block"
+creates a file containing exactly 1024 bytes.
+.Pp
+The command:
+.Dl "expand \-\`jot \-s, \- 10 132 4\`"
+sets tabs four spaces apart starting
+from column 10 and ending in column 132.
+.Pp
+The command:
+.Dl "grep \`jot \-s """" \-b . 80\`"
+prints all lines 80 characters or longer.
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr expand 1 ,
+.Xr rs 1 ,
+.Xr seq 1 ,
+.Xr yes 1 ,
+.Xr printf 3 ,
+.Xr random 3
--- /dev/null
+/* $NetBSD: jot.c,v 1.25 2009/04/12 11:19:18 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1993\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: jot.c,v 1.25 2009/04/12 11:19:18 lukem Exp $");
+#endif /* not lint */
+
+/*
+ * jot - print sequential or random data
+ *
+ * Author: John Kunze, Office of Comp. Affairs, UCB
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define REPS_DEF 100
+#define BEGIN_DEF 1
+#define ENDER_DEF 100
+#define STEP_DEF 1
+
+#define is_default(s) (strcmp((s), "-") == 0)
+
+static double begin = BEGIN_DEF;
+static double ender = ENDER_DEF;
+static double step = STEP_DEF;
+static long reps = REPS_DEF;
+static int randomize;
+static int boring;
+static int prec = -1;
+static int dox;
+static int chardata;
+static int nofinalnl;
+static const char *sepstring = "\n";
+static char format[BUFSIZ];
+
+static void getargs(int, char *[]);
+static void getformat(void);
+static int getprec(char *);
+static void putdata(double, long);
+static void usage(void) __dead;
+
+int
+main(int argc, char *argv[])
+{
+ double x;
+ long i;
+
+ getargs(argc, argv);
+ if (randomize) {
+ x = ender - begin;
+ if (x < 0) {
+ x = -x;
+ begin = ender;
+ }
+ if (dox == 0)
+ /*
+ * We are printing floating point, generate random
+ * number that include both supplied limits.
+ * Due to FP routing for display the low and high
+ * values are likely to occur half as often as all
+ * the others.
+ */
+ x /= (1u << 31) - 1.0;
+ else {
+ /*
+ * We are printing integers increase the range by
+ * one but ensure we never generate it.
+ * This makes all the integer values equally likely.
+ */
+ x += 1.0;
+ x /= (1u << 31);
+ }
+ srandom((unsigned long) step);
+ for (i = 1; i <= reps || reps == 0; i++)
+ putdata(random() * x + begin, reps - i);
+ } else {
+ /*
+ * If we are going to display as integer, add 0.5 here
+ * and use floor(x) later to get sane rounding.
+ */
+ x = begin;
+ if (dox)
+ x += 0.5;
+ for (i = 1; i <= reps || reps == 0; i++, x += step)
+ putdata(x, reps - i);
+ }
+ if (!nofinalnl)
+ putchar('\n');
+ exit(0);
+}
+
+static void
+getargs(int argc, char *argv[])
+{
+ unsigned int have = 0;
+#define BEGIN 1
+#define STEP 2 /* seed if -r */
+#define REPS 4
+#define ENDER 8
+ int n = 0;
+ long t;
+ char *ep;
+
+ for (;;) {
+ switch (getopt(argc, argv, "b:cnp:rs:w:")) {
+ default:
+ usage();
+ case -1:
+ break;
+ case 'c':
+ chardata = 1;
+ continue;
+ case 'n':
+ nofinalnl = 1;
+ continue;
+ case 'p':
+ prec = strtol(optarg, &ep, 0);
+ if (*ep != 0 || prec < 0)
+ errx(EXIT_FAILURE, "Bad precision value");
+ continue;
+ case 'r':
+ randomize = 1;
+ continue;
+ case 's':
+ sepstring = optarg;
+ continue;
+ case 'b':
+ boring = 1;
+ /* FALLTHROUGH */
+ case 'w':
+ strlcpy(format, optarg, sizeof(format));
+ continue;
+ }
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) { /* examine args right to left, falling thru cases */
+ case 4:
+ if (!is_default(argv[3])) {
+ step = strtod(argv[3], &ep);
+ if (*ep != 0)
+ errx(EXIT_FAILURE, "Bad step value: %s",
+ argv[3]);
+ have |= STEP;
+ }
+ case 3:
+ if (!is_default(argv[2])) {
+ if (!sscanf(argv[2], "%lf", &ender))
+ ender = argv[2][strlen(argv[2])-1];
+ have |= ENDER;
+ if (prec < 0)
+ n = getprec(argv[2]);
+ }
+ case 2:
+ if (!is_default(argv[1])) {
+ if (!sscanf(argv[1], "%lf", &begin))
+ begin = argv[1][strlen(argv[1])-1];
+ have |= BEGIN;
+ if (prec < 0)
+ prec = getprec(argv[1]);
+ if (n > prec) /* maximum precision */
+ prec = n;
+ }
+ case 1:
+ if (!is_default(argv[0])) {
+ reps = strtoul(argv[0], &ep, 0);
+ if (*ep != 0 || reps < 0)
+ errx(EXIT_FAILURE, "Bad reps value: %s",
+ argv[0]);
+ have |= REPS;
+ }
+ break;
+ case 0:
+ usage();
+ break;
+ default:
+ errx(EXIT_FAILURE,
+ "Too many arguments. What do you mean by %s?", argv[4]);
+ }
+ getformat();
+
+ if (prec == -1)
+ prec = 0;
+
+ if (randomize) {
+ /* 'step' is the seed here, use pseudo-random default */
+ if (!(have & STEP))
+ step = time(NULL) * getpid();
+ /* Take the default values for everything else */
+ return;
+ }
+
+ /*
+ * The loop we run uses begin/step/reps, so if we have been
+ * given an end value (ender) we must use it to replace the
+ * default values of the others.
+ * We will assume a begin of 0 and step of 1 if necessary.
+ */
+
+ switch (have) {
+
+ case ENDER | STEP:
+ case ENDER | STEP | BEGIN:
+ /* Calculate reps */
+ if (step == 0.0)
+ reps = 0; /* ie infinite */
+ else {
+ reps = (ender - begin + step) / step;
+ if (reps <= 0)
+ errx(EXIT_FAILURE, "Impossible stepsize");
+ }
+ break;
+
+ case REPS | ENDER:
+ case REPS | ENDER | STEP:
+ /* Calculate begin */
+ if (reps == 0)
+ errx(EXIT_FAILURE,
+ "Must specify begin if reps == 0");
+ begin = ender - reps * step + step;
+ break;
+
+ case REPS | BEGIN | ENDER:
+ /* Calculate step */
+ if (reps == 0)
+ errx(EXIT_FAILURE,
+ "Infinite sequences cannot be bounded");
+ if (reps == 1)
+ step = 0.0;
+ else
+ step = (ender - begin) / (reps - 1);
+ break;
+
+ case REPS | BEGIN | ENDER | STEP:
+ /* reps given and implied - take smaller */
+ if (step == 0.0)
+ break;
+ t = (ender - begin + step) / step;
+ if (t <= 0)
+ errx(EXIT_FAILURE,
+ "Impossible stepsize");
+ if (t < reps)
+ reps = t;
+ break;
+
+ default:
+ /* No values can be calculated, use defaults */
+ break;
+ }
+}
+
+static void
+putdata(double x, long notlast)
+{
+
+ if (boring) /* repeated word */
+ printf("%s", format);
+ else if (dox) /* scalar */
+ printf(format, (long)floor(x));
+ else /* real */
+ printf(format, x);
+ if (notlast != 0)
+ fputs(sepstring, stdout);
+}
+
+__dead static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: %s [-cnr] [-b word] [-p precision] "
+ "[-s string] [-w word] [reps [begin [end [step | seed]]]]\n",
+ getprogname());
+ exit(1);
+}
+
+static int
+getprec(char *num_str)
+{
+
+ num_str = strchr(num_str, '.');
+ if (num_str == NULL)
+ return 0;
+ return strspn(num_str + 1, "0123456789");
+}
+
+static void
+getformat(void)
+{
+ char *p;
+ size_t sz;
+
+ if (boring) /* no need to bother */
+ return;
+ for (p = format; *p; p++) { /* look for '%' */
+ if (*p == '%') {
+ if (*(p+1) != '%')
+ break;
+ p++; /* leave %% alone */
+ }
+ }
+ sz = sizeof(format) - strlen(format) - 1;
+ if (!*p) {
+ if (chardata || prec == 0) {
+ if ((size_t)snprintf(p, sz, "%%%s", chardata ? "c" : "ld") >= sz)
+ errx(EXIT_FAILURE, "-w word too long");
+ dox = 1;
+ } else {
+ if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
+ errx(EXIT_FAILURE, "-w word too long");
+ }
+ } else if (!*(p+1)) {
+ if (sz <= 0)
+ errx(EXIT_FAILURE, "-w word too long");
+ strcat(format, "%"); /* cannot end in single '%' */
+ } else {
+ p++; /* skip leading % */
+ for(; *p && !isalpha((unsigned char)*p); p++) {
+ /* allow all valid printf(3) flags, but deny '*' */
+ if (!strchr("0123456789#-+. ", *p))
+ break;
+ }
+ /* Allow 'l' prefix, but no other. */
+ if (*p == 'l')
+ p++;
+ switch (*p) {
+ case 'f': case 'e': case 'g': case '%':
+ case 'E': case 'G':
+ break;
+ case 's':
+ errx(EXIT_FAILURE,
+ "cannot convert numeric data to strings");
+ break;
+ case 'd': case 'o': case 'x': case 'u':
+ case 'D': case 'O': case 'X': case 'U':
+ case 'c': case 'i':
+ dox = 1;
+ break;
+ default:
+ errx(EXIT_FAILURE, "unknown or invalid format `%s'",
+ format);
+ }
+ /* Need to check for trailing stuff to print */
+ for (; *p; p++) /* look for '%' */
+ if (*p == '%') {
+ if (*(p+1) != '%')
+ break;
+ p++; /* leave %% alone */
+ }
+ if (*p)
+ errx(EXIT_FAILURE, "unknown or invalid format `%s'",
+ format);
+ }
+}