treimplement max(1), mean(1), min(1), and sum(1) in C - 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 c0672a06ab06ee7def7d9acd6b728836f6de7397
 (DIR) parent 5ef38a38146fe0d02f11b47687ea034699307c6f
 (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Tue, 31 Aug 2021 14:39:37 +0200
       
       reimplement max(1), mean(1), min(1), and sum(1) in C
       
       Diffstat:
         M Makefile                            |      30 ++++++++++++++++++------------
         D max                                 |      14 --------------
         A max.c                               |      38 +++++++++++++++++++++++++++++++
         D mean                                |      13 -------------
         A mean.c                              |      41 +++++++++++++++++++++++++++++++
         D min                                 |      14 --------------
         A min.c                               |      38 +++++++++++++++++++++++++++++++
         D sum                                 |      13 -------------
         A sum.c                               |      39 +++++++++++++++++++++++++++++++
         A util.c                              |      47 +++++++++++++++++++++++++++++++
         M util.h                              |       4 ++++
       
       11 files changed, 225 insertions(+), 66 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -8,18 +8,19 @@ PREFIX = /usr/local
        MANPREFIX = ${PREFIX}/man
        DOCPREFIX = ${PREFIX}/share/doc/${NAME}
        
       -SCRIPTS =\
       -        histpdf\
       +BIN =\
                max\
                mean\
                min\
       +        rangetest\
                sum\
       -        transpose\
        
       -BIN =\
       -        rangetest\
       +SCRIPTS =\
       +        histpdf\
       +        transpose\
        
       -SRC = ${BIN:=.c}
       +SRC =\
       +        util.c
        
        COMPATSRC =\
                strnlen.c\
       t@@ -45,14 +46,18 @@ DOC =\
        
        all: ${BIN}
        
       -${BIN}: ${LIB} ${@:=.o}
       -
        OBJ = ${SRC:.c=.o} ${COMPATOBJ}
        
        ${OBJ}: ${HDR}
        
       -.o:
       -        ${CC} -o $@ $< ${_LDFLAGS} ${LIB}
       +max: max.o
       +mean: mean.o
       +min: min.o
       +rangetest: rangetest.o
       +sum: sum.o
       +
       +${BIN}: ${LIB} ${OBJ}
       +        ${CC} ${_LDFLAGS} -o $@ ${@:=.o} ${OBJ}
        
        .c.o:
                ${CC} ${_CFLAGS} ${_CPPFLAGS} -o $@ -c $<
       t@@ -83,13 +88,14 @@ uninstall:
        dist:
                rm -rf "${NAME}-${VERSION}"
                mkdir -p "${NAME}-${VERSION}"
       -        cp -rf ${MAN1} ${DOC} ${SRC} ${COMPATSRC} ${SCRIPTS} "${NAME}-${VERSION}"
       +        cp -rf ${MAN1} ${DOC} ${BIN:=.c} ${SRC} ${COMPATSRC} ${SCRIPTS} \
       +                Makefile "${NAME}-${VERSION}"
                # make tarball
                tar cf - "${NAME}-${VERSION}" | \
                        gzip -c > "${NAME}-${VERSION}.tar.gz"
                rm -rf "${NAME}-${VERSION}"
        
        clean:
       -        rm -f ${BIN} ${OBJ} ${LIB}
       +        rm -f ${BIN} ${BIN:=.o} ${OBJ} ${LIB}
        
        .PHONY: install uninstall dist clean
 (DIR) diff --git a/max b/max
       t@@ -1,14 +0,0 @@
       -#!/usr/bin/awk -f
       -{
       -        for (i = 1; i <= NF; i++)
       -                if (NR == 1 || $i > max[i])
       -                        max[i] = $i
       -}
       -END {
       -        for (i = 1; i <= NF; i++) {
       -                printf("%g", max[i])
       -                if (i < NF)
       -                        printf("\t")
       -        }
       -        printf("\n")
       -}
 (DIR) diff --git a/max.c b/max.c
       t@@ -0,0 +1,38 @@
       +#include <err.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <unistd.h>
       +
       +#include "util.h"
       +
       +int
       +main(void)
       +{
       +        size_t i = 0, nf = 0, nr = 0, linesize = 0;
       +        char *line = NULL, *data = NULL;
       +        double val, *vals = NULL;
       +        int offset;
       +
       +        if (pledge("stdio", NULL) == -1)
       +                err(2, "pledge");
       +
       +        while (getline(&line, &linesize, stdin) > 0) {
       +                if (nr == 0)
       +                        if ((nf = allocarr(&vals, line, linesize)) == 0)
       +                                errx(1, "no fields in input");
       +                data = line;
       +                for (i = 0; i < nf; i++) {
       +                        if (!scannextval(&data, &val))
       +                                errx(1, "could not parse line %ld, field %ld", nr + 1, i + 1);
       +                        if (nr == 0 || val > vals[i])
       +                                vals[i] = val;
       +                }
       +                nr++;
       +        }
       +        printarr(vals, nf);
       +
       +        free(line);
       +        free(vals);
       +
       +        return 0;
       +}
 (DIR) diff --git a/mean b/mean
       t@@ -1,13 +0,0 @@
       -#!/usr/bin/awk -f
       -{
       -        for (i = 1; i <= NF; i++)
       -                sum[i] += $i
       -}
       -END {
       -        for (i = 1; i <= NF; i++) {
       -                printf("%g", sum[i] / NR)
       -                if (i < NF)
       -                        printf("\t")
       -        }
       -        printf("\n")
       -}
 (DIR) diff --git a/mean.c b/mean.c
       t@@ -0,0 +1,41 @@
       +#include <err.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <unistd.h>
       +
       +#include "util.h"
       +
       +int
       +main(void)
       +{
       +        size_t i = 0, nf = 0, nr = 0, linesize = 0;
       +        char *line = NULL, *data = NULL;
       +        double val, *vals = NULL;
       +        int offset;
       +
       +        if (pledge("stdio", NULL) == -1)
       +                err(2, "pledge");
       +
       +        while (getline(&line, &linesize, stdin) > 0) {
       +                if (nr == 0)
       +                        if ((nf = allocarr(&vals, line, linesize)) == 0)
       +                                errx(1, "no fields in input");
       +                data = line;
       +                for (i = 0; i < nf; i++) {
       +                        if (!scannextval(&data, &val))
       +                                errx(1, "could not parse line %ld, field %ld", nr + 1, i + 1);
       +                        if (nr == 0)
       +                                vals[i] = 0.0;
       +                        vals[i] += val;
       +                }
       +                nr++;
       +        }
       +        for (i = 0; i < nf; i++)
       +                vals[i] /= (double)nr;
       +        printarr(vals, nf);
       +
       +        free(line);
       +        free(vals);
       +
       +        return 0;
       +}
 (DIR) diff --git a/min b/min
       t@@ -1,14 +0,0 @@
       -#!/usr/bin/awk -f
       -{
       -        for (i = 1; i <= NF; i++)
       -                if (NR == 1 || $i < min[i])
       -                        min[i] = $i
       -}
       -END {
       -        for (i = 1; i <= NF; i++) {
       -                printf("%g", min[i])
       -                if (i < NF)
       -                        printf("\t")
       -        }
       -        printf("\n")
       -}
 (DIR) diff --git a/min.c b/min.c
       t@@ -0,0 +1,38 @@
       +#include <err.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <unistd.h>
       +
       +#include "util.h"
       +
       +int
       +main(void)
       +{
       +        size_t i = 0, nf = 0, nr = 0, linesize = 0;
       +        char *line = NULL, *data = NULL;
       +        double val, *vals = NULL;
       +        int offset;
       +
       +        if (pledge("stdio", NULL) == -1)
       +                err(2, "pledge");
       +
       +        while (getline(&line, &linesize, stdin) > 0) {
       +                if (nr == 0)
       +                        if ((nf = allocarr(&vals, line, linesize)) == 0)
       +                                errx(1, "no fields in input");
       +                data = line;
       +                for (i = 0; i < nf; i++) {
       +                        if (!scannextval(&data, &val))
       +                                errx(1, "could not parse line %ld, field %ld", nr + 1, i + 1);
       +                        if (nr == 0 || val < vals[i])
       +                                vals[i] = val;
       +                }
       +                nr++;
       +        }
       +        printarr(vals, nf);
       +
       +        free(line);
       +        free(vals);
       +
       +        return 0;
       +}
 (DIR) diff --git a/sum b/sum
       t@@ -1,13 +0,0 @@
       -#!/usr/bin/awk -f
       -{
       -        for (i = 1; i <= NF; i++)
       -                sum[i] += $i
       -}
       -END {
       -        for (i = 1; i <= NF; i++) {
       -                printf("%g", sum[i])
       -                if (i < NF)
       -                        printf("\t")
       -        }
       -        printf("\n")
       -}
 (DIR) diff --git a/sum.c b/sum.c
       t@@ -0,0 +1,39 @@
       +#include <err.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <unistd.h>
       +
       +#include "util.h"
       +
       +int
       +main(void)
       +{
       +        size_t i = 0, nf = 0, nr = 0, linesize = 0;
       +        char *line = NULL, *data = NULL;
       +        double val, *vals = NULL;
       +        int offset;
       +
       +        if (pledge("stdio", NULL) == -1)
       +                err(2, "pledge");
       +
       +        while (getline(&line, &linesize, stdin) > 0) {
       +                if (nr == 0)
       +                        if ((nf = allocarr(&vals, line, linesize)) == 0)
       +                                errx(1, "no fields in input");
       +                data = line;
       +                for (i = 0; i < nf; i++) {
       +                        if (!scannextval(&data, &val))
       +                                errx(1, "could not parse line %ld, field %ld", nr + 1, i + 1);
       +                        if (nr == 0)
       +                                vals[i] = 0.0;
       +                        vals[i] += val;
       +                }
       +                nr++;
       +        }
       +        printarr(vals, nf);
       +
       +        free(line);
       +        free(vals);
       +
       +        return 0;
       +}
 (DIR) diff --git a/util.c b/util.c
       t@@ -0,0 +1,47 @@
       +#include <err.h>
       +#include <stdlib.h>
       +#include <stdio.h>
       +
       +#define DELIM '\t'
       +#define DELIMSTR "\t"
       +
       +size_t
       +allocarr(double **arr, const char *str, size_t maxlen)
       +{
       +        size_t i, nf = 0;
       +
       +        if (maxlen > 0)
       +                nf = 1;
       +        for (i = 0; i < maxlen && str[i] != '\0'; i++)
       +                if (str[i] == DELIM)
       +                        nf++;
       +        if (!(*arr = calloc(nf, sizeof(double))))
       +                err(1, "calloc");
       +
       +        return nf;
       +}
       +
       +int
       +scannextval(char **str, double *val)
       +{
       +        int offset;
       +
       +        if (sscanf(*str, "%lg%n", val, &offset) != 1)
       +                return 0;
       +        *str += offset;
       +
       +        return 1;
       +}
       +
       +void
       +printarr(double *arr, size_t len)
       +{
       +        size_t i;
       +
       +        for (i = 0; i < len; i++) {
       +                printf("%g", arr[i]);
       +                if (i < len)
       +                        printf(DELIMSTR);
       +        }
       +        puts("");
       +}
 (DIR) diff --git a/util.h b/util.h
       t@@ -14,4 +14,8 @@ size_t strlcpy(char *dst, const char *src, size_t dsize);
        #undef strnlen
        size_t strnlen(const char *str, size_t maxlen);
        
       +size_t allocarr(double **arr, const char *str, size_t maxlen);
       +int scannextval(char **str, double *val);
       +void printarr(double *arr, size_t len);
       +
        #endif