tadd option parsing and format string options to all programs - numtools - perform numerical operations on vectors and matrices in unix pipes
 (HTM) git clone git://src.adamsgaard.dk/numtools
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 8b5e9b0cf97126537c548e49329ead6bad47c105
 (DIR) parent 5c71d867b926ca74ab063744b0359086be572e88
 (HTM) 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(-)
       ---
 (DIR) diff --git a/max.1 b/max.1
       t@@ -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
 (DIR) diff --git a/max.c b/max.c
       t@@ -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)
       t@@ -28,7 +54,7 @@ main(void)
                        }
                        nr++;
                }
       -        printarr(vals, nf);
       +        printfarr(fmtstr, vals, nf);
        
                free(line);
                free(vals);
 (DIR) diff --git a/mean.1 b/mean.1
       t@@ -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
 (DIR) diff --git a/mean.c b/mean.c
       t@@ -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)
       t@@ -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);
 (DIR) diff --git a/min.1 b/min.1
       t@@ -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
 (DIR) diff --git a/min.c b/min.c
       t@@ -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)
       t@@ -28,7 +54,7 @@ main(void)
                        }
                        nr++;
                }
       -        printarr(vals, nf);
       +        printfarr(fmtstr, vals, nf);
        
                free(line);
                free(vals);
 (DIR) diff --git a/stddev.1 b/stddev.1
       t@@ -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
       t@@ -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
 (DIR) diff --git a/stddev.c b/stddev.c
       t@@ -3,6 +3,7 @@
        #include <stdlib.h>
        #include <unistd.h>
        #include <math.h>
       +#include <limits.h>
        
        #include "arg.h"
        #include "util.h"
       t@@ -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;
       t@@ -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++) {
       t@@ -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);
 (DIR) diff --git a/stdvar.1 b/stdvar.1
       t@@ -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
       t@@ -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
 (DIR) diff --git a/stdvar.c b/stdvar.c
       t@@ -3,6 +3,7 @@
        #include <stdlib.h>
        #include <unistd.h>
        #include <math.h>
       +#include <limits.h>
        
        #include "arg.h"
        #include "util.h"
       t@@ -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;
       t@@ -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);
 (DIR) diff --git a/sum.1 b/sum.1
       t@@ -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
 (DIR) diff --git a/sum.c b/sum.c
       t@@ -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)
       t@@ -29,7 +55,7 @@ main(void)
                        }
                        nr++;
                }
       -        printarr(vals, nf);
       +        printfarr(fmtstr, vals, nf);
        
                free(line);
                free(vals);
 (DIR) diff --git a/util.c b/util.c
       t@@ -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)
        {
 (DIR) diff --git a/util.h b/util.h
       t@@ -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