diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 5e197e485..01096ec79 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -363,6 +363,7 @@ ./usr/bin/isoinfo minix-sys ./usr/bin/isoread minix-sys ./usr/bin/join minix-sys +./usr/bin/jot minix-sys ./usr/bin/kill minix-sys obsolete ./usr/bin/kyua minix-sys kyua ./usr/bin/lam minix-sys @@ -1941,6 +1942,7 @@ ./usr/man/man1/isoread.1 minix-sys ./usr/man/man1/jobs.1 minix-sys ./usr/man/man1/join.1 minix-sys +./usr/man/man1/jot.1 minix-sys ./usr/man/man1/kill.1 minix-sys ./usr/man/man1/ksh.1 minix-sys ./usr/man/man1/kyua.1 minix-sys kyua diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index b2099498b..abbb18bc1 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -176,6 +176,7 @@ 2012/10/17 12:00:00,usr.bin/indent 2012/10/17 12:00:00,usr.bin/infocmp 2012/10/17 12:00:00,usr.bin/join +2012/10/17 12:00:00,usr.bin/jot 2012/10/17 12:00:00,usr.bin/lam 2011/01/17 18:11:10,usr.bin/ldd 2013/10/18 12:00:00,usr.bin/leave diff --git a/usr.bin/Makefile b/usr.bin/Makefile index e468a1797..41355ddce 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -12,7 +12,7 @@ SUBDIR= asa \ env expand \ finger fold from \ fsplit ftp genassym getopt \ - head hexdump indent infocmp join \ + head hexdump indent infocmp join jot \ lam ldd leave \ lock login logname lorder m4 \ machine make man menuc mesg \ diff --git a/usr.bin/jot/Makefile b/usr.bin/jot/Makefile new file mode 100644 index 000000000..2c574975a --- /dev/null +++ b/usr.bin/jot/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.6 2011/08/16 10:37:21 christos Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= jot +DPADD= ${LIBMATH} +LDADD= -lm + +COPTS.jot.c += -Wno-format-nonliteral + +.include diff --git a/usr.bin/jot/jot.1 b/usr.bin/jot/jot.1 new file mode 100644 index 000000000..523ec6502 --- /dev/null +++ b/usr.bin/jot/jot.1 @@ -0,0 +1,203 @@ +.\" $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 diff --git a/usr.bin/jot/jot.c b/usr.bin/jot/jot.c new file mode 100644 index 000000000..120031c27 --- /dev/null +++ b/usr.bin/jot/jot.c @@ -0,0 +1,399 @@ +/* $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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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); + } +}