commit 8b5e9b0cf97126537c548e49329ead6bad47c105
parent 5c71d867b926ca74ab063744b0359086be572e88
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date: Mon, 9 May 2022 16:52:46 +0200
add option parsing and format string options to all programs
Diffstat:
M | max.1 | | | 17 | ++++++++++++++++- |
M | max.c | | | 32 | +++++++++++++++++++++++++++++--- |
M | mean.1 | | | 16 | ++++++++++++++++ |
M | mean.c | | | 32 | +++++++++++++++++++++++++++++--- |
M | min.1 | | | 16 | ++++++++++++++++ |
M | min.c | | | 32 | +++++++++++++++++++++++++++++--- |
M | stddev.1 | | | 9 | +++++++++ |
M | stddev.c | | | 24 | ++++++++++++++++-------- |
M | stdvar.1 | | | 9 | +++++++++ |
M | stdvar.c | | | 12 | ++++++++++-- |
M | sum.1 | | | 16 | ++++++++++++++++ |
M | sum.c | | | 32 | +++++++++++++++++++++++++++++--- |
M | util.c | | | 13 | +++++++++++++ |
M | util.h | | | 1 | + |
14 files changed, 238 insertions(+), 23 deletions(-)
diff --git a/max.1 b/max.1
@@ -6,13 +6,28 @@
.Nd returns the maximum value for each column
.Sh SYNOPSIS
.Nm
-.Op Ar file
+.Op Fl f Ar fmtstr
+.Op Fl h
.Sh DESCRIPTION
.Nm
returns the maximum numerical value for each column in standard
input.
Input fields must be tab-separated and each line must contain
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.
+.El
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | max
.Dl 4 5 6
diff --git a/max.c b/max.c
@@ -2,19 +2,45 @@
#include <stdio.h>
#include <stdlib.h>
#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);
+}
+
int
-main(void)
+main(int argc, char *argv[])
{
+ int ret;
size_t i = 0, nf = 0, nr = 0, linesize = 0;
- char *line = NULL, *data = NULL;
+ char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g";
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;
+ if (argc > 0)
+ usage();
+
while (getline(&line, &linesize, stdin) > 0) {
if (nr == 0)
if ((nf = allocarr(&vals, line, linesize)) == 0)
@@ -28,7 +54,7 @@ main(void)
}
nr++;
}
- printarr(vals, nf);
+ printfarr(fmtstr, vals, nf);
free(line);
free(vals);
diff --git a/mean.1 b/mean.1
@@ -6,11 +6,27 @@
.Nd returns the average value for each column
.Sh SYNOPSIS
.Nm
+.Op Fl f Ar fmtstr
+.Op Fl h
.Sh DESCRIPTION
.Nm
returns the mean numerical value for each column in standard input.
Input fields must be tab-separated and each line must contain 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.
+.El
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | mean
.Dl 2.5 3.5 4.5
diff --git a/mean.c b/mean.c
@@ -2,19 +2,45 @@
#include <stdio.h>
#include <stdlib.h>
#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);
+}
+
int
-main(void)
+main(int argc, char *argv[])
{
+ int ret;
size_t i = 0, nf = 0, nr = 0, linesize = 0;
- char *line = NULL, *data = NULL;
+ char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g";
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;
+ if (argc > 0)
+ usage();
+
while (getline(&line, &linesize, stdin) > 0) {
if (nr == 0)
if ((nf = allocarr(&vals, line, linesize)) == 0)
@@ -31,7 +57,7 @@ main(void)
}
for (i = 0; i < nf; i++)
vals[i] /= (double)nr;
- printarr(vals, nf);
+ printfarr(fmtstr, vals, nf);
free(line);
free(vals);
diff --git a/min.1 b/min.1
@@ -6,12 +6,28 @@
.Nd returns the minimum value for each column
.Sh SYNOPSIS
.Nm
+.Op Fl f Ar fmtstr
+.Op Fl h
.Sh DESCRIPTION
.Nm
returns the minimum numerical value for each column in standard
input.
Input fields must be tab-separated and each line must contain 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.
+.El
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | min
.Dl 1 2 3
diff --git a/min.c b/min.c
@@ -2,19 +2,45 @@
#include <stdio.h>
#include <stdlib.h>
#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);
+}
+
int
-main(void)
+main(int argc, char *argv[])
{
+ int ret;
size_t i = 0, nf = 0, nr = 0, linesize = 0;
- char *line = NULL, *data = NULL;
+ char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g";
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;
+ if (argc > 0)
+ usage();
+
while (getline(&line, &linesize, stdin) > 0) {
if (nr == 0)
if ((nf = allocarr(&vals, line, linesize)) == 0)
@@ -28,7 +54,7 @@ main(void)
}
nr++;
}
- printarr(vals, nf);
+ printfarr(fmtstr, vals, nf);
free(line);
free(vals);
diff --git a/stddev.1 b/stddev.1
@@ -6,6 +6,7 @@
.Nd returns the standard deviation for each column
.Sh SYNOPSIS
.Nm
+.Op Fl f Ar fmtstr
.Op Fl h
.Op Fl u
.Sh DESCRIPTION
@@ -18,6 +19,14 @@ 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 u
diff --git a/stddev.c b/stddev.c
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
+#include <limits.h>
#include "arg.h"
#include "util.h"
@@ -12,19 +13,26 @@ char *argv0;
static void
usage(void)
{
- errx(1, "usage: %s [-h] [-u]\n", argv0);
+ errx(1, "usage: %s [-f fmtstr] [-h] [-u]\n", argv0);
}
int
main(int argc, char *argv[])
{
+ int ret;
size_t i, j, nf = 0, nr = 0, correction = 1;
- double *means = NULL, *stdvars = NULL, **vals = NULL;
+ double *means = NULL, *stdvals = NULL, **vals = NULL;
+ char fmtstr[PATH_MAX] = "%.17g";
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;
@@ -38,7 +46,7 @@ main(int argc, char *argv[])
nr = fscanmatrix(stdin, &vals, &nf);
if (!(means = calloc(nf, sizeof(double))) ||
- !(stdvars = calloc(nf, sizeof(double))))
+ !(stdvals = calloc(nf, sizeof(double))))
err(1, "calloc");
for (i = 0; i < nf; i++) {
@@ -49,16 +57,16 @@ main(int argc, char *argv[])
}
for (i = 0; i < nf; i++) {
- stdvars[i] = 0.0;
+ stdvals[i] = 0.0;
for (j = 0; j < nr; j++)
- stdvars[i] += pow(vals[j][i] - means[i], 2.0);
- stdvars[i] = sqrt(stdvars[i] / ((double)(nr - correction)));
+ stdvals[i] += pow(vals[j][i] - means[i], 2.0);
+ stdvals[i] = sqrt(stdvals[i] / ((double)(nr - correction)));
}
- printarr(stdvars, nf);
+ printfarr(fmtstr, stdvals, nf);
free(means);
- free(stdvars);
+ free(stdvals);
for (i = 0; i < nr; i++)
free(vals[i]);
free(vals);
diff --git a/stdvar.1 b/stdvar.1
@@ -6,6 +6,7 @@
.Nd returns the standard variance for each column
.Sh SYNOPSIS
.Nm
+.Op Fl f Ar fmtstr
.Op Fl h
.Op Fl u
.Sh DESCRIPTION
@@ -18,6 +19,14 @@ 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 u
diff --git a/stdvar.c b/stdvar.c
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
+#include <limits.h>
#include "arg.h"
#include "util.h"
@@ -12,19 +13,26 @@ char *argv0;
static void
usage(void)
{
- errx(1, "usage: %s [-h] [-u]\n", argv0);
+ errx(1, "usage: %s [-f fmtstr] [-h] [-u]\n", argv0);
}
int
main(int argc, char *argv[])
{
+ int ret;
size_t i, j, nf = 0, nr = 0, correction = 1;
double *means = NULL, *stdvars = NULL, **vals = NULL;
+ char fmtstr[PATH_MAX] = "%.17g";
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;
@@ -55,7 +63,7 @@ main(int argc, char *argv[])
stdvars[i] /= (double)(nr - correction);
}
- printarr(stdvars, nf);
+ printfarr(fmtstr, stdvars, nf);
free(means);
free(stdvars);
diff --git a/sum.1 b/sum.1
@@ -6,11 +6,27 @@
.Nd returns the sum for each column
.Sh SYNOPSIS
.Nm
+.Op Fl f Ar fmtstr
+.Op Fl h
.Sh DESCRIPTION
.Nm
returns the numerical sum for each column in standard input.
Input fields must be tab-separated and each line must contain 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.
+.El
.Sh EXAMPLES
.Dl $ printf '1\et2\et3\en4\et5\et6\en' | sum
.Dl 5 7 9
diff --git a/sum.c b/sum.c
@@ -2,19 +2,45 @@
#include <stdio.h>
#include <stdlib.h>
#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);
+}
+
int
-main(void)
+main(int argc, char *argv[])
{
+ int ret;
size_t i = 0, nf = 0, nr = 0, linesize = 0;
- char *line = NULL, *data = NULL;
+ char *line = NULL, *data = NULL, fmtstr[PATH_MAX] = "%.17g";
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;
+ if (argc > 0)
+ usage();
+
while (getline(&line, &linesize, stdin) > 0) {
if (nr == 0)
if ((nf = allocarr(&vals, line, linesize)) == 0)
@@ -29,7 +55,7 @@ main(void)
}
nr++;
}
- printarr(vals, nf);
+ printfarr(fmtstr, vals, nf);
free(line);
free(vals);
diff --git a/util.c b/util.c
@@ -44,6 +44,19 @@ printarr(double *arr, size_t len)
puts("");
}
+void
+printfarr(char *fmtstr, double *arr, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ printf(fmtstr, arr[i]);
+ if (i < len)
+ printf(DELIMSTR);
+ }
+ puts("");
+}
+
size_t
fscanmatrix(FILE *stream, double ***arr, size_t *nf)
{
diff --git a/util.h b/util.h
@@ -22,6 +22,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);
size_t fscanmatrix(FILE *stream, double ***arr, size_t *nf);
#endif