commit 8787e852ca96ee9c18d4ed1a45016996e464940a
parent d206d176dbb5704fda2d5cc33010f54b8f36ff38
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date: Wed, 11 May 2022 14:57:18 +0200
use safe formatting parameters and option parsing
Diffstat:
M | max.1 | | | 29 | ++++++++++++++++------------- |
M | max.c | | | 45 | ++++++++++++++++++++++++++------------------- |
M | mean.1 | | | 29 | ++++++++++++++++------------- |
M | mean.c | | | 45 | ++++++++++++++++++++++++++------------------- |
M | min.1 | | | 29 | ++++++++++++++++------------- |
M | min.c | | | 45 | ++++++++++++++++++++++++++------------------- |
M | randcounts.1 | | | 38 | ++++++++++++++++++++++++++++---------- |
M | randcounts.c | | | 98 | +++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- |
M | randnum.c | | | 8 | ++++---- |
M | range.1 | | | 61 | +++++++++++++++++++++++++++++++------------------------------ |
M | range.c | | | 107 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
M | rangetest.c | | | 40 | +++++++++++++++++++--------------------- |
M | stddev.1 | | | 27 | +++++++++++++++------------ |
M | stddev.c | | | 52 | ++++++++++++++++++++++++++++++---------------------- |
M | stdvar.1 | | | 29 | ++++++++++++++++------------- |
M | stdvar.c | | | 52 | ++++++++++++++++++++++++++++++---------------------- |
M | sum.1 | | | 29 | ++++++++++++++++------------- |
M | sum.c | | | 45 | ++++++++++++++++++++++++++------------------- |
M | transpose.1 | | | 6 | +++--- |
M | util.c | | | 9 | ++++----- |
M | util.h | | | 2 | +- |
21 files changed, 469 insertions(+), 356 deletions(-)
diff --git a/max.1 b/max.1
@@ -6,8 +6,9 @@
.Nd returns the maximum value for each column
.Sh SYNOPSIS
.Nm
-.Op Fl f Ar fmtstr
-.Op Fl h
+.Op Fl d Ar delimstr
+.Op Fl n
+.Op Fl p Ar prec
.Sh DESCRIPTION
.Nm
returns the maximum numerical value for each column in standard
@@ -17,20 +18,22 @@ the same number of fields.
.Pp
The options are as follows:
.Bl -tag -width Ds
-.It Fl f Ar fmtstr
-Formatting string to use as documented in
-.Xr printf 3 .
-When including a format specifier (%..), only use forms that are
-compatible with
-.Vt double
-types.
-The default format string is '%.17g'.
-.It Fl h
-Show usage information and exit.
+.It Fl d Ar delimstr
+Separate output values by
+.Ar delimstr .
+The default delimiter is tab characters.
+.It Fl n
+Do not print a newline after the final value.
+.It Fl p prec
+Print the output values with
+.Ar prec
+digits of precision.
+By default, the output is printed with 17 digits of precision, which is
+full double precision on 64-bit systems.
.El
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | max
-.Dl 4 5 6
+.Dl 4 5 6
.Sh SEE ALSO
.Xr mean 1 ,
.Xr min 1 ,
diff --git a/max.c b/max.c
@@ -4,40 +4,45 @@
#include <unistd.h>
#include <limits.h>
-#include "arg.h"
#include "util.h"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-f fmtstr] [-h] ", argv0);
+ errx(1, "usage: max [-d delimstr] [-n] [-p prec]");
}
int
main(int argc, char *argv[])
{
- int ret;
+ int ch, prec = 17, finalnl = 1;
size_t i = 0, nf = 0, nr = 0, linesize = 0;
- char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g";
+ char *line = NULL, *data = NULL, *delimstr = "\t";
+ const char *errstr;
double val, *vals = NULL;
if (pledge("stdio", NULL) == -1)
err(2, "pledge");
- ARGBEGIN {
- case 'f':
- ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage()));
- if (ret < 0 || (size_t)ret >= sizeof(fmtstr))
- errx(1, "%s: could not write fmtstr", __func__);
- break;
- case 'h':
- usage();
- break;
- default:
- usage();
- } ARGEND;
+ while ((ch = getopt(argc, argv, "d:np:")) != -1) {
+ switch (ch) {
+ case 'd':
+ delimstr = optarg;
+ break;
+ case 'n':
+ finalnl = 0;
+ break;
+ case 'p':
+ prec = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad precision value, %s: %s", errstr, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ /*argv += optind;*/
if (argc > 0)
usage();
@@ -54,7 +59,9 @@ main(int argc, char *argv[])
}
nr++;
}
- printfarr(fmtstr, vals, nf);
+ printfarr(delimstr, prec, vals, nf);
+ if (finalnl)
+ putchar('\n');
free(line);
free(vals);
diff --git a/mean.1 b/mean.1
@@ -6,8 +6,9 @@
.Nd returns the average value for each column
.Sh SYNOPSIS
.Nm
-.Op Fl f Ar fmtstr
-.Op Fl h
+.Op Fl d Ar delimstr
+.Op Fl n
+.Op Fl p Ar prec
.Sh DESCRIPTION
.Nm
returns the mean numerical value for each column in standard input.
@@ -16,20 +17,22 @@ number of fields.
.Pp
The options are as follows:
.Bl -tag -width Ds
-.It Fl f Ar fmtstr
-Formatting string to use as documented in
-.Xr printf 3 .
-When including a format specifier (%..), only use forms that are
-compatible with
-.Vt double
-types.
-The default format string is '%.17g'.
-.It Fl h
-Show usage information and exit.
+.It Fl d Ar delimstr
+Separate output values by
+.Ar delimstr .
+The default delimiter is tab characters.
+.It Fl n
+Do not print a newline after the final value.
+.It Fl p prec
+Print the output values with
+.Ar prec
+digits of precision.
+By default, the output is printed with 17 digits of precision, which is
+full double precision on 64-bit systems.
.El
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | mean
-.Dl 2.5 3.5 4.5
+.Dl 2.5 3.5 4.5
.Sh SEE ALSO
.Xr max 1 ,
.Xr min 1 ,
diff --git a/mean.c b/mean.c
@@ -4,40 +4,45 @@
#include <unistd.h>
#include <limits.h>
-#include "arg.h"
#include "util.h"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-f fmtstr] [-h] ", argv0);
+ errx(1, "usage: mean [-d delimstr] [-n] [-p prec]");
}
int
main(int argc, char *argv[])
{
- int ret;
+ int ch, prec = 17, finalnl = 1;
size_t i = 0, nf = 0, nr = 0, linesize = 0;
- char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g";
+ char *line = NULL, *data = NULL, *delimstr = "\t";
+ const char *errstr;
double val, *vals = NULL;
if (pledge("stdio", NULL) == -1)
err(2, "pledge");
- ARGBEGIN {
- case 'f':
- ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage()));
- if (ret < 0 || (size_t)ret >= sizeof(fmtstr))
- errx(1, "%s: could not write fmtstr", __func__);
- break;
- case 'h':
- usage();
- break;
- default:
- usage();
- } ARGEND;
+ while ((ch = getopt(argc, argv, "d:np:")) != -1) {
+ switch (ch) {
+ case 'd':
+ delimstr = optarg;
+ break;
+ case 'n':
+ finalnl = 0;
+ break;
+ case 'p':
+ prec = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad precision value, %s: %s", errstr, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ /*argv += optind;*/
if (argc > 0)
usage();
@@ -57,7 +62,9 @@ main(int argc, char *argv[])
}
for (i = 0; i < nf; i++)
vals[i] /= (double)nr;
- printfarr(fmtstr, vals, nf);
+ printfarr(delimstr, prec, vals, nf);
+ if (finalnl)
+ putchar('\n');
free(line);
free(vals);
diff --git a/min.1 b/min.1
@@ -6,8 +6,9 @@
.Nd returns the minimum value for each column
.Sh SYNOPSIS
.Nm
-.Op Fl f Ar fmtstr
-.Op Fl h
+.Op Fl d Ar delimstr
+.Op Fl n
+.Op Fl p Ar prec
.Sh DESCRIPTION
.Nm
returns the minimum numerical value for each column in standard
@@ -17,20 +18,22 @@ number of fields.
.Pp
The options are as follows:
.Bl -tag -width Ds
-.It Fl f Ar fmtstr
-Formatting string to use as documented in
-.Xr printf 3 .
-When including a format specifier (%..), only use forms that are
-compatible with
-.Vt double
-types.
-The default format string is '%.17g'.
-.It Fl h
-Show usage information and exit.
+.It Fl d Ar delimstr
+Separate output values by
+.Ar delimstr .
+The default delimiter is tab characters.
+.It Fl n
+Do not print a newline after the final value.
+.It Fl p prec
+Print the output values with
+.Ar prec
+digits of precision.
+By default, the output is printed with 17 digits of precision, which is
+full double precision on 64-bit systems.
.El
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | min
-.Dl 1 2 3
+.Dl 1 2 3
.Sh SEE ALSO
.Xr max 1 ,
.Xr mean 1 ,
diff --git a/min.c b/min.c
@@ -4,40 +4,45 @@
#include <unistd.h>
#include <limits.h>
-#include "arg.h"
#include "util.h"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-f fmtstr] [-h] ", argv0);
+ errx(1, "usage: max [-d delimstr] [-n] [-p prec]");
}
int
main(int argc, char *argv[])
{
- int ret;
+ int ch, prec = 17, finalnl = 1;
size_t i = 0, nf = 0, nr = 0, linesize = 0;
- char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g";
+ char *line = NULL, *data = NULL, *delimstr = "\t";
+ const char *errstr;
double val, *vals = NULL;
if (pledge("stdio", NULL) == -1)
err(2, "pledge");
- ARGBEGIN {
- case 'f':
- ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage()));
- if (ret < 0 || (size_t)ret >= sizeof(fmtstr))
- errx(1, "%s: could not write fmtstr", __func__);
- break;
- case 'h':
- usage();
- break;
- default:
- usage();
- } ARGEND;
+ while ((ch = getopt(argc, argv, "d:np:")) != -1) {
+ switch (ch) {
+ case 'd':
+ delimstr = optarg;
+ break;
+ case 'n':
+ finalnl = 0;
+ break;
+ case 'p':
+ prec = strtonum(optarg, -10, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad precision value, %s: %s", errstr, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ /*argv += optind;*/
if (argc > 0)
usage();
@@ -54,7 +59,9 @@ main(int argc, char *argv[])
}
nr++;
}
- printfarr(fmtstr, vals, nf);
+ printfarr(delimstr, prec, vals, nf);
+ if (finalnl)
+ putchar('\n');
free(line);
free(vals);
diff --git a/randcounts.1 b/randcounts.1
@@ -6,8 +6,10 @@
.Nd produces random counts in weighted bins
.Sh SYNOPSIS
.Nm
-.Op Fl h
-.Op Fl n Ar num
+.Op Fl d Ar delimstr
+.Op Fl n
+.Op Fl N Ar num
+.Op Fl p Ar prec
.Op Fl r Ar repeats
.Op Fl R
.Op Fl s Ar seed
@@ -31,15 +33,28 @@ Output consists of the number of points per bin, in tab-separated format.
.Pp
The options are as follows:
.Bl -tag -width Ds
-.It Fl h
-Show usage information.
-.It Fl n Ar num
+.It Fl d Ar delimstr
+Separate output values by
+.Ar delimstr .
+The default delimiter is tab characters.
+.It Fl n
+Do not print a newline after the final value.
+.It Fl N Ar num
Number of points to place in the bins.
The default is 1.
.It Fl r Ar repeats
Repeat the binning several times, with one realization per line of output.
.It Fl R
Show the output as ratios (in the range [0;1]) instead of counts.
+.It Fl p prec
+Print the output values with
+.Ar prec
+digits of precision.
+This option only applies if called with the
+.Fl R
+option.
+By default, the output is printed with 17 digits of precision, which is
+full double precision on 64-bit systems.
.It Fl s Ar seed
Seed the pseudo-random number generator with this value, which is used
to generate reproducable binning.
@@ -48,15 +63,18 @@ to generate reproducable binning.
Put one point in four bins with equal probability (25%).
Due to the randomness, your output may differ:
.Dl $ randcounts 0.25 0.25 0.25 0.25
-.Dl 0 1 0 0
+.Dl 0 1 0 0
.Pp
-Put 100 points in two bins with 75% and 25% probability, respectively:
-.Dl $ randcounts -n 100 0.75 0.25
+Put 100 points in two bins with 75% and 25% probability, respectively,
+and print the count ratios for each bin:
+.Dl $ randcounts -N 100 -R 0.75 0.25
+.Dl 0.72999999999999998 0.27000000000000002
.Pp
-Put 100 points in three equal bins 1000 times, and calculate the average bin sizes with
+Put 100 points in three equal bins 1000 times, and calculate the average
+bin sizes with
.Xr mean 1 :
.Dl $ randcounts -n 100 -r 1000 0.333 0.333 0.334 | mean
-.Dl 33.067 32.82 34.113
+.Dl 33.067 32.82 34.113
.Sh SEE ALSO
.Xr mean 1 ,
.Xr range 1 ,
diff --git a/randcounts.c b/randcounts.c
@@ -5,68 +5,85 @@
#include <string.h>
#include <math.h>
#include <sys/time.h>
+#include <unistd.h>
-#include "arg.h"
#include "util.h"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-h] [-n num] [-r repeats] [-R] [-s seed] "
- "weight1 [weight2 ...]\n", argv0);
+ errx(1, "usage: randcounts [-d delimstr] [-n] [-N num] [-p prec]"
+ "[-r repeats] [-R] [-s seed] weight1 [weight2 ...]");
}
int
main(int argc, char *argv[])
{
- int i, s = 0, N;
+ int i, ch, nbins, prec = 17, finalnl = 1, s = 0;
long j, seed, *counts = NULL, n = 1, r, repeats = 1, ratio = 0;
double val = 0.0, weightsum = 0.0, *weights = NULL;
+ char *delimstr = "\t";
+ const char *errstr;
struct timeval t1;
if (pledge("stdio", NULL) == -1)
err(2, "pledge");
- ARGBEGIN {
- case 'h':
- usage();
- break;
- case 'n':
- n = atol(EARGF(usage()));
- break;
- case 'r':
- repeats = atol(EARGF(usage()));
- break;
- case 'R':
- ratio = 1;
- break;
- case 's':
- s = 1;
- seed = atol(EARGF(usage()));
- break;
- default:
- usage();
- } ARGEND;
-
+ while ((ch = getopt(argc, argv, "d:nN:r:Rp:s:")) != -1) {
+ switch (ch) {
+ case 'd':
+ delimstr = optarg;
+ break;
+ case 'n':
+ finalnl = 0;
+ break;
+ case 'N':
+ n = strtonum(optarg, 0, LONG_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad num value, %s: %s", errstr, optarg);
+ break;
+ case 'r':
+ repeats = strtonum(optarg, 0, LONG_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad repeats value, %s: %s", errstr, optarg);
+ break;
+ case 'R':
+ ratio = 1;
+ break;
+ case 'p':
+ prec = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad precision value, %s: %s", errstr, optarg);
+ break;
+ case 's':
+ seed = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad seed value, %s: %s", errstr, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
if (argc < 1)
usage();
- N = argc;
- if (!(weights = calloc(N, sizeof(double))) ||
- !(counts = calloc(N, sizeof(long))))
+ nbins = argc;
+ if (!(weights = calloc(nbins, sizeof(double))) ||
+ !(counts = calloc(nbins, sizeof(long))))
err(1, "calloc");
- for (i = 0; i < N; i++) {
- weights[i] = atof(argv[i]);
+ for (i = 0; i < nbins; i++) {
+ if (!sscanf(argv[i], "%lf", &weights[i]))
+ errx(1, "bad weight value: %s", argv[i]);
if (weights[i] <= 0.0)
errx(1, "weight %d is not positive (%g)", i, weights[i]);
if (weights[i] > 1.0)
errx(1, "weight %d is greater than 1 (%g)", i, weights[i]);
}
- for (i = 0; i < N; i++)
+ for (i = 0; i < nbins; i++)
weightsum += weights[i];
if (fabs(weightsum - 1.0) > 1e-3)
errx(1, "weights do not sum to 1 (%g)", weightsum);
@@ -83,12 +100,12 @@ main(int argc, char *argv[])
#endif
for (r = 0; r < repeats; r++) {
- for (i = 0; i < N; i++)
+ for (i = 0; i < nbins; i++)
counts[i] = 0;
for (j = 0; j < n; j++) {
val = drand48();
weightsum = 0.0;
- for (i = 0; i < N; i++) {
+ for (i = 0; i < nbins; i++) {
weightsum += weights[i];
if (val <= weightsum) {
counts[i]++;
@@ -96,15 +113,16 @@ main(int argc, char *argv[])
}
}
}
- for (i = 0; i < N; i++) {
+ for (i = 0; i < nbins; i++) {
if (ratio)
- printf("%.17g", (double)counts[i] / n);
+ printf("%.*g", prec, (double)counts[i] / n);
else
printf("%ld", counts[i]);
- if (i < N - 1)
- putchar('\t');
+ if (i < nbins - 1)
+ fputs(delimstr, stdout);
else
- putchar('\n');
+ if (finalnl)
+ putchar('\n');
}
}
diff --git a/randnum.c b/randnum.c
@@ -20,9 +20,9 @@ usage(void)
int
main(int argc, char *argv[])
{
- int i, ret, ch, s = 0, prec = 17, finalnl = 1;
- long j, seed, n = 1;
- double val, minv = 0.0, maxv = 1.0;
+ int i, ch, s = 0, prec = 17, finalnl = 1;
+ long seed, n = 1;
+ double minv = 0.0, maxv = 1.0;
char *delimstr = "\n";
const char *errstr;
struct timeval t1;
@@ -44,7 +44,7 @@ main(int argc, char *argv[])
errx(1, "bad num value, %s: %s", errstr, optarg);
break;
case 'p':
- prec = strtonum(optarg, -10, INT_MAX, &errstr);
+ prec = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL)
errx(1, "bad precision value, %s: %s", errstr, optarg);
break;
diff --git a/range.1 b/range.1
@@ -7,11 +7,12 @@
.Sh SYNOPSIS
.Nm
.Op Fl b
+.Op Fl d Ar delimstr
.Op Fl e
-.Op Fl f Ar fmtstr
-.Op Fl h
.Op Fl l
-.Op Fl n Ar num
+.Op Fl n
+.Op Fl N Ar num
+.Op Fl p Ar prec
.Op Fl s
.Oo
.Op Ar min_val
@@ -45,6 +46,10 @@ as the first value, making it a half-open interval
.Ar max_val ],
or an entirely open interval when combined with
.Op Ar e .
+.It Fl d Ar delimstr
+Separate output values by
+.Ar delimstr .
+The default delimiter is newlines.
.It Fl e
Do not include
.Ar max_val
@@ -53,54 +58,50 @@ as the last value, making it a half-open interval
.Ar max_val [,
or an entirely open interval when combined with
.Op Ar b .
-.It Fl f Ar fmtstr
-Formatting string to use as documented in
-.Xr printf 3 .
-When including a format specifier (%..), only use forms that are
-compatible with
-.Vt double
-types.
-The default format string is '%.17g'.
-.It Fl h
-Show usage information.
.It Fl l
Produce output with even intervals in logarithmic space between 10^min_val
and 10^max_val.
-.It Fl n Ar num
+.It Fl n
+Do not print a newline after the final value.
+.It Fl N Ar num
Number of values to produce within the specified range.
The default is 10.
+.It Fl p prec
+Print the output values with
+.Ar prec
+digits of precision.
+By default, the output is printed with 17 digits of precision, which is
+full double precision on 64-bit systems.
.It Fl s
-Print the spacing between numbers and exit.
+Print the numerical spacing between numbers and exit.
.El
.Sh EXAMPLES
Generate four equally-spaced numbers in the closed default range [0;1]:
-.Dl $ range -n 4 -f '%.17g\en' 0 1
+.Dl $ range -N 4
.Dl 0
.Dl 0.33333333333333331
.Dl 0.66666666666666663
.Dl 1
.Pp
Generate four numbers in the range ]0;1[:
-.Dl $ range -b -e -n 4 0 1
-.Dl 0.2
-.Dl 0.4
-.Dl 0.6
-.Dl 0.8
+.Dl $ range -be -N 4
+.Dl 0.20000000000000001
+.Dl 0.40000000000000002
+.Dl 0.60000000000000009
+.Dl 0.80000000000000004
.Pp
-Repeat and modify a string three times:
-.Dl $ range -n 3 -f 'The best number is %.0g' 1 3
-.Dl The best number is 1
-.Dl The best number is 2
-.Dl The best number is 3
+Generate three space-separated numbers:
+.Dl $ range -d' ' -N 3 1 3
+.Dl 1 2 3
.Pp
Generate three numbers evenly distributed in logspace from 10^0 to 10^2:
-.Dl $ range -l -n 3 0 2
+.Dl $ range -l -N 3 0 2
.Dl 1
.Dl 10
.Dl 100
.Pp
Generate three numbers in the range [-2;-1]:
-.Dl $ range -n 3 -- -2 -1
+.Dl $ range -N 3 -- -2 -1
.Dl -2
.Dl -1.5
.Dl -1
@@ -108,7 +109,7 @@ Generate three numbers in the range [-2;-1]:
.Xr max 1 ,
.Xr mean 1 ,
.Xr min 1 ,
-.Xr rangetest 1 ,
-.Xr sum 1
+.Xr randnum 1 ,
+.Xr rangetest 1
.Sh AUTHORS
.An Anders Damsgaard Aq Mt anders@adamsgaard.dk
diff --git a/range.c b/range.c
@@ -4,78 +4,95 @@
#include <limits.h>
#include <string.h>
#include <math.h>
+#include <unistd.h>
-#include "arg.h"
#include "util.h"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-b] [-e] [-f fmtstr] [-h] [-l] [-n num] [-s] "
- "[[min_val] max_val]\n", argv0);
+ errx(1, "usage: range [-b] [-d delimstr] [-e] [-l] [-n] [-N num] "
+ "[-p prec] [-s] [[min_val] max_val]");
}
int
main(int argc, char *argv[])
{
- int i, ret, n = 10, logrange = 0, openstart = 0, openend = 0,
- reportdx = 0;
- double minv = 0.0, maxv = 1.0, dx;
- char fmtstr[PATH_MAX] = "%.17g";
+ int i, j, ch, n = 10, logrange = 0, openstart = 0, openend = 0,
+ prec = 17, finalnl = 1, reportdx = 0;
+ double minv = 0.0, maxv = 1.0, dx, val;
+ const char *errstr;
+ char *delimstr = "\n";
if (pledge("stdio", NULL) == -1)
err(2, "pledge");
- ARGBEGIN {
- case 'b':
- openstart = 1;
- break;
- case 'e':
- openend = 1;
- break;
- case 'f':
- ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage()));
- if (ret < 0 || (size_t)ret >= sizeof(fmtstr))
- errx(1, "%s: could not write fmtstr", __func__);
- break;
- case 'h':
- usage();
- break;
- case 'l':
- logrange = 1;
- break;
- case 'n':
- n = atoi(EARGF(usage()));
- break;
- case 's':
- reportdx = 1;
- break;
- default:
- usage();
- } ARGEND;
-
+ while ((ch = getopt(argc, argv, "bd:elnN:p:s")) != -1) {
+ switch (ch) {
+ case 'b':
+ openstart = 1;
+ break;
+ case 'd':
+ delimstr = optarg;
+ break;
+ case 'e':
+ openend = 1;
+ break;
+ case 'l':
+ logrange = 1;
+ break;
+ case 'n':
+ finalnl = 0;
+ break;
+ case 'N':
+ n = strtonum(optarg, 0, LONG_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad num value, %s: %s", errstr, optarg);
+ break;
+ case 'p':
+ prec = strtonum(optarg, -10, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad precision value, %s: %s", errstr, optarg);
+ break;
+ case 's':
+ reportdx = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
if (argc > 2)
usage();
else if (argc == 2) {
- minv = atof(argv[0]);
- maxv = atof(argv[1]);
+ if (!sscanf(argv[0], "%lf", &minv))
+ errx(1, "bad minv value: %s", argv[0]);
+ if (!sscanf(argv[1], "%lf", &maxv))
+ errx(1, "bad maxv value: %s", argv[1]);
} else if (argc == 1)
- maxv = atof(argv[0]);
+ if (!sscanf(argv[0], "%lf", &maxv))
+ errx(1, "bad maxv value: %s", argv[0]);
dx = (maxv - minv) / (n - 1 + openend + openstart);
if (reportdx) {
- printf(fmtstr, dx);
+ printf("%.*g", prec, dx);
+ if (finalnl)
+ putchar('\n');
return 0;
}
- for (i = 0 + openstart; i < n + openstart; i++) {
+ for (i = 0; i < n; i++) {
+ j = i + openstart;
if (logrange)
- printf(fmtstr, pow(10, minv + i * dx));
+ val = pow(10, minv + j * dx);
else
- printf(fmtstr, minv + i * dx);
- putchar('\n');
+ val = minv + j * dx;
+ printf("%.*g", prec, val);
+ if (i < n - 1)
+ fputs(delimstr, stdout);
}
+ if (finalnl)
+ putchar('\n');
return 0;
}
diff --git a/rangetest.c b/rangetest.c
@@ -3,19 +3,17 @@
#include <err.h>
#include <limits.h>
#include <string.h>
+#include <unistd.h>
-#include "arg.h"
#include "util.h"
#define VALUESTR "@VAL@"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-h] [-n maxiter] cmd min_val max_val\n"
- "where cmd must contain the string '" VALUESTR "'", argv0);
+ errx(1, "usage: rangetest [-n maxiter] cmd min_val max_val\n"
+ "where cmd must contain the string '" VALUESTR "'");
}
static int
@@ -41,8 +39,7 @@ launch(char *cmd, char *cmd0, double val)
static void
binary_search(char *cmd, char *cmd0, double minv, double maxv, int maxiter)
{
- int minfail, maxfail;
- int iter = 0;
+ int minfail, maxfail, iter = 0;
double val;
minfail = launch(cmd, cmd0, minv);
@@ -76,23 +73,24 @@ binary_search(char *cmd, char *cmd0, double minv, double maxv, int maxiter)
int
main(int argc, char *argv[])
{
- int maxiter = 10;
+ int ch, maxiter = 10;
double minv, maxv;
char cmd0[PATH_MAX] = "", cmd[PATH_MAX] = "";
+ const char *errstr;
- ARGBEGIN {
- case 'h':
- usage();
- break;
- case 'n':
- maxiter = atoi(EARGF(usage()));
- if (maxiter < 1)
- errx(1, "maxiter (-n) must be positive");
- break;
- default:
- usage();
- } ARGEND;
-
+ while ((ch = getopt(argc, argv, "N:")) != -1) {
+ switch (ch) {
+ case 'N':
+ maxiter = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad maxiter value, %s: %s", errstr, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
if (argc == 3) {
if (strlcpy(cmd0, argv[0], sizeof(cmd0)) >= sizeof(cmd0))
err(1, "cmd too long");
diff --git a/stddev.1 b/stddev.1
@@ -6,8 +6,9 @@
.Nd returns the standard deviation for each input column
.Sh SYNOPSIS
.Nm
-.Op Fl f Ar fmtstr
-.Op Fl h
+.Op Fl d Ar delimstr
+.Op Fl n
+.Op Fl p Ar prec
.Op Fl u
.Sh DESCRIPTION
.Nm
@@ -19,16 +20,18 @@ The output is always in full double precision.
.Pp
The options are as follows:
.Bl -tag -width Ds
-.It Fl f Ar fmtstr
-Formatting string to use as documented in
-.Xr printf 3 .
-When including a format specifier (%..), only use forms that are
-compatible with
-.Vt double
-types.
-The default format string is '%.17g'.
-.It Fl h
-Show usage information and exit.
+.It Fl d Ar delimstr
+Separate output values by
+.Ar delimstr .
+The default delimiter is tab characters.
+.It Fl n
+Do not print a newline after the final value.
+.It Fl p prec
+Print the output values with
+.Ar prec
+digits of precision.
+By default, the output is printed with 17 digits of precision, which is
+full double precision on 64-bit systems.
.It Fl u
Return the uncorrected sample standard deviation instead.
.El
diff --git a/stddev.c b/stddev.c
@@ -4,44 +4,50 @@
#include <unistd.h>
#include <math.h>
#include <limits.h>
+#include <unistd.h>
-#include "arg.h"
#include "util.h"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-f fmtstr] [-h] [-u]\n", argv0);
+ errx(1, "usage: stddev [-d delimstr] [-n] [-p prec] [-u]");
}
int
main(int argc, char *argv[])
{
- int ret;
+ int ch, prec = 17, finalnl = 1;
size_t i, j, nf = 0, nr = 0, correction = 1;
double *means = NULL, *stdvals = NULL, **vals = NULL;
- char fmtstr[PATH_MAX] = "%.17g";
+ const char *errstr;
+ char *delimstr = "\t";
if (pledge("stdio", NULL) == -1)
err(2, "pledge");
- ARGBEGIN {
- case 'f':
- ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage()));
- if (ret < 0 || (size_t)ret >= sizeof(fmtstr))
- errx(1, "%s: could not write fmtstr", __func__);
- break;
- case 'h':
- usage();
- break;
- case 'u':
- correction = 0;
- break;
- default:
- usage();
- } ARGEND;
+ while ((ch = getopt(argc, argv, "d:np:u")) != -1) {
+ switch (ch) {
+ case 'd':
+ delimstr = optarg;
+ break;
+ case 'n':
+ finalnl = 0;
+ break;
+ case 'p':
+ prec = strtonum(optarg, -10, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad precision value, %s: %s", errstr, optarg);
+ break;
+ case 'u':
+ correction = 0;
+ break;
+ default:
+ usage();
+ }
+ }
+ /*argc -= optind;*/
+ /*argv += optind;*/
nr = fscanmatrix(stdin, &vals, &nf);
@@ -63,7 +69,9 @@ main(int argc, char *argv[])
stdvals[i] = sqrt(stdvals[i] / ((double)(nr - correction)));
}
- printfarr(fmtstr, stdvals, nf);
+ printfarr(delimstr, prec, stdvals, nf);
+ if (finalnl)
+ putchar('\n');
free(means);
free(stdvals);
diff --git a/stdvar.1 b/stdvar.1
@@ -6,8 +6,9 @@
.Nd returns the standard variance for each input column
.Sh SYNOPSIS
.Nm
-.Op Fl f Ar fmtstr
-.Op Fl h
+.Op Fl d Ar delimstr
+.Op Fl n
+.Op Fl p Ar prec
.Op Fl u
.Sh DESCRIPTION
.Nm
@@ -19,18 +20,20 @@ The output is always in full double precision.
.Pp
The options are as follows:
.Bl -tag -width Ds
-.It Fl f Ar fmtstr
-Formatting string to use as documented in
-.Xr printf 3 .
-When including a format specifier (%..), only use forms that are
-compatible with
-.Vt double
-types.
-The default format string is '%.17g'.
-.It Fl h
-Show usage information and exit.
+.It Fl d Ar delimstr
+Separate output values by
+.Ar delimstr .
+The default delimiter is tab characters.
+.It Fl n
+Do not print a newline after the final value.
+.It Fl p prec
+Print the output values with
+.Ar prec
+digits of precision.
+By default, the output is printed with 17 digits of precision, which is
+full double precision on 64-bit systems.
.It Fl u
-Return the uncorrected sample standard variance instead.
+Return the uncorrected sample standard deviation instead.
.El
.Sh EXAMPLES
Compute the corrected standard variance for some input numbers:
diff --git a/stdvar.c b/stdvar.c
@@ -4,44 +4,50 @@
#include <unistd.h>
#include <math.h>
#include <limits.h>
+#include <unistd.h>
-#include "arg.h"
#include "util.h"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-f fmtstr] [-h] [-u]\n", argv0);
+ errx(1, "usage: stdvar [-d delimstr] [-n] [-p prec] [-u]");
}
int
main(int argc, char *argv[])
{
- int ret;
+ int ch, prec = 17, finalnl = 1;
size_t i, j, nf = 0, nr = 0, correction = 1;
double *means = NULL, *stdvars = NULL, **vals = NULL;
- char fmtstr[PATH_MAX] = "%.17g";
+ const char *errstr;
+ char *delimstr = "\t";
if (pledge("stdio", NULL) == -1)
err(2, "pledge");
- ARGBEGIN {
- case 'f':
- ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage()));
- if (ret < 0 || (size_t)ret >= sizeof(fmtstr))
- errx(1, "%s: could not write fmtstr", __func__);
- break;
- case 'h':
- usage();
- break;
- case 'u':
- correction = 0;
- break;
- default:
- usage();
- } ARGEND;
+ while ((ch = getopt(argc, argv, "d:np:u")) != -1) {
+ switch (ch) {
+ case 'd':
+ delimstr = optarg;
+ break;
+ case 'n':
+ finalnl = 0;
+ break;
+ case 'p':
+ prec = strtonum(optarg, -10, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad precision value, %s: %s", errstr, optarg);
+ break;
+ case 'u':
+ correction = 0;
+ break;
+ default:
+ usage();
+ }
+ }
+ /*argc -= optind;*/
+ /*argv += optind;*/
nr = fscanmatrix(stdin, &vals, &nf);
@@ -63,7 +69,9 @@ main(int argc, char *argv[])
stdvars[i] /= (double)(nr - correction);
}
- printfarr(fmtstr, stdvars, nf);
+ printfarr(delimstr, prec, stdvars, nf);
+ if (finalnl)
+ putchar('\n');
free(means);
free(stdvars);
diff --git a/sum.1 b/sum.1
@@ -6,8 +6,9 @@
.Nd returns the sum for each column
.Sh SYNOPSIS
.Nm
-.Op Fl f Ar fmtstr
-.Op Fl h
+.Op Fl d Ar delimstr
+.Op Fl n
+.Op Fl p Ar prec
.Sh DESCRIPTION
.Nm
returns the numerical sum for each column in standard input.
@@ -16,20 +17,22 @@ same number of fields.
.Pp
The options are as follows:
.Bl -tag -width Ds
-.It Fl f Ar fmtstr
-Formatting string to use as documented in
-.Xr printf 3 .
-When including a format specifier (%..), only use forms that are
-compatible with
-.Vt double
-types.
-The default format string is '%.17g'.
-.It Fl h
-Show usage information and exit.
+.It Fl d Ar delimstr
+Separate output values by
+.Ar delimstr .
+The default delimiter is tab characters.
+.It Fl n
+Do not print a newline after the final value.
+.It Fl p prec
+Print the output values with
+.Ar prec
+digits of precision.
+By default, the output is printed with 17 digits of precision, which is
+full double precision on 64-bit systems.
.El
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | sum
-.Dl 5 7 9
+.Dl 5 7 9
.Sh SEE ALSO
.Xr max 1 ,
.Xr mean 1 ,
diff --git a/sum.c b/sum.c
@@ -4,40 +4,45 @@
#include <unistd.h>
#include <limits.h>
-#include "arg.h"
#include "util.h"
-char *argv0;
-
static void
usage(void)
{
- errx(1, "usage: %s [-f fmtstr] [-h] ", argv0);
+ errx(1, "usage: sum [-d delimstr] [-n] [-p prec]");
}
int
main(int argc, char *argv[])
{
- int ret;
+ int ch, prec = 17, finalnl = 1;
size_t i = 0, nf = 0, nr = 0, linesize = 0;
- char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g";
+ char *line = NULL, *data = NULL, *delimstr = "\t";
+ const char *errstr;
double val, *vals = NULL;
if (pledge("stdio", NULL) == -1)
err(2, "pledge");
- ARGBEGIN {
- case 'f':
- ret = snprintf(fmtstr, sizeof(fmtstr), "%s", EARGF(usage()));
- if (ret < 0 || (size_t)ret >= sizeof(fmtstr))
- errx(1, "%s: could not write fmtstr", __func__);
- break;
- case 'h':
- usage();
- break;
- default:
- usage();
- } ARGEND;
+ while ((ch = getopt(argc, argv, "d:np:")) != -1) {
+ switch (ch) {
+ case 'd':
+ delimstr = optarg;
+ break;
+ case 'n':
+ finalnl = 0;
+ break;
+ case 'p':
+ prec = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "bad precision value, %s: %s", errstr, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ /*argv += optind;*/
if (argc > 0)
usage();
@@ -55,7 +60,9 @@ main(int argc, char *argv[])
}
nr++;
}
- printfarr(fmtstr, vals, nf);
+ printfarr(delimstr, prec, vals, nf);
+ if (finalnl)
+ putchar('\n');
free(line);
free(vals);
diff --git a/transpose.1 b/transpose.1
@@ -16,9 +16,9 @@ Input fields must be tab-separated and each line must contain the
same number of fields.
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | transpose
-.Dl 1 4
-.Dl 2 5
-.Dl 3 6
+.Dl 1 4
+.Dl 2 5
+.Dl 3 6
.Sh SEE ALSO
.Xr max 1 ,
.Xr mean 1 ,
diff --git a/util.c b/util.c
@@ -45,16 +45,15 @@ printarr(double *arr, size_t len)
}
void
-printfarr(char *fmtstr, double *arr, size_t len)
+printfarr(char *delimstr, int prec, double *arr, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
- printf(fmtstr, arr[i]);
- if (i < len)
- printf(DELIMSTR);
+ printf("%.*g", prec, arr[i]);
+ if (i < len - 1)
+ fputs(delimstr, stdout);
}
- putchar('\n');
}
size_t
diff --git a/util.h b/util.h
@@ -26,7 +26,7 @@ void * xreallocarray(void *m, size_t n, size_t s);
size_t allocarr(double **arr, const char *str, size_t maxlen);
int scannextval(char **str, double *val);
void printarr(double *arr, size_t len);
-void printfarr(char *fmtstr, double *arr, size_t len);
+void printfarr(char *delimstr, int prec, double *arr, size_t len);
size_t fscanmatrix(FILE *stream, double ***arr, size_t *nf);
#endif