add tests and cleanup I/O function - ics2txt - convert icalendar .ics file to plain text
 (HTM) git clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ics2txt
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
       ---
 (DIR) commit a7b4ceeaf4a57476c0952e0da2def5f92bdfdb9f
 (DIR) parent 94bccd0b9ea7049ebeec4fcf2416f6f0b7d221b5
 (HTM) Author: Josuah Demangeon <me@josuah.net>
       Date:   Sun, 28 Jun 2020 10:34:46 +0200
       
       add tests and cleanup I/O function
       
       Diffstat:
         M ics2tsv.c                           |       7 +++++--
         M src/ical.c                          |      72 +++++++++----------------------
         M src/ical.h                          |       2 +-
         M src/map.c                           |       6 ++++++
         M src/map.h                           |       1 +
         M src/util.c                          |       5 +++--
         A test/map.c                          |      18 ++++++++++++++++++
         A test/random-ics.awk                 |      40 +++++++++++++++++++++++++++++++
       
       8 files changed, 94 insertions(+), 57 deletions(-)
       ---
 (DIR) diff --git a/ics2tsv.c b/ics2tsv.c
       @@ -1,4 +1,5 @@
        #include <stdio.h>
       +#include <stdlib.h>
        
        #include "ical.h"
        #include "log.h"
       @@ -8,17 +9,19 @@ int
        print_ical_to_tsv(FILE *fp)
        {
                struct ical_contentline contentline;
       -        char *line = NULL;
       +        char *line = NULL, *ln = NULL;
                size_t sz = 0;
                ssize_t r;
        
                ical_init_contentline(&contentline);
        
       -        while ((r = ical_read_line(&line, &sz, fp)) > 0) {
       +        while ((r = ical_read_line(&line, &ln, &sz, fp)) > 0) {
                        debug("readling line \"%s\"", line);
                        if (ical_parse_contentline(&contentline, line) < 0)
                                die("parsing line \"%s\"", line);
                }
       +        free(line);
       +        free(ln);
                return r;
        }
        
 (DIR) diff --git a/src/ical.c b/src/ical.c
       @@ -8,38 +8,28 @@
        #include "util.h"
        
        int
       -ical_read_line(char **line, size_t *sz, FILE *fp)
       +ical_read_line(char **line, char **ln, size_t *sz, FILE *fp)
        {
       -        ssize_t r;
       -        char *tail = NULL;
       -        size_t tail_sz = 0;
       -        int c, ret = -1;
       +        int c;
       +        void *v;
        
       -        if ((r = getline(line, sz, fp)) <= 0)
       -                return r;
       -        strchomp(*line);
       -
       -        for (;;) {
       -                if ((c = fgetc(fp)) == EOF) {
       -                        ret = ferror(fp) ? -1 : 0;
       -                        goto end;
       -                }
       -                if (c != ' ')
       -                        break;
       -                if ((r = getline(&tail, &tail_sz, fp)) <= 0) {
       -                        ret = r;
       -                        goto end;
       -                }
       -                strchomp(tail);
       -                if (strappend(line, tail) < 0)
       -                        goto end;
       -        }
       +        if ((v = realloc(*line, 1)) == NULL)
       +                return -1;
       +        *line = v;
       +        (*line)[0] = '\0';
       +
       +        do {
       +                if (getline(ln, sz, fp) <= 0)
       +                        return ferror(fp) ? -1 : 0;
       +                strchomp(*ln);
       +                if (strappend(line, *ln) < 0)
       +                        return -1;
       +                if ((c = fgetc(fp)) == EOF)
       +                        return ferror(fp) ? -1 : 1;
       +        } while (c == ' ');
        
       -        ret = 1;
       -end:
       -        free(tail);
                ungetc(c, fp);
       -        return ret;
       +        return 1;
        }
        
        int
       @@ -48,48 +38,26 @@ ical_parse_contentline(struct ical_contentline *contentline, char *line)
                char *column, *equal, *param, *cp;
                size_t sz;
        
       -        debug("0");
       -
                if ((column = strchr(line, ':')) == NULL)
                        return -1;
                *column = '\0';
       -
       -        {
       -                size_t len;
       -
       -                debug("1.1");
       -                len = strlen(column + 1);
       -                debug("1.2");
       -        }
       -        
       -
                if ((contentline->value = strdup(column + 1)) == NULL)
                        return -1;
        
       -        debug("2");
       -
       -        cp = strchr(line, ';');
       -        cp = (cp == NULL) ? (NULL) : (cp + 1);
       -
       -        debug("3");
       -
       +        if ((cp = strchr(line, ';')) != NULL)
       +                cp++;
                while ((param = strsep(&cp, ";")) != NULL) {
                        if ((equal = strchr(param, '=')) == NULL)
                                return -1;
                        *equal = '\0';
       -
                        if (map_set(&contentline->param, param, equal + 1) < 0)
                                return -1;
                }
        
       -        debug("4");
       -
                sz = sizeof(contentline->name);
                if (strlcpy(contentline->name, line, sz) >= sz)
                        return errno=EMSGSIZE, -1;
        
       -        debug("5");
       -
                return 0;
        }
        
 (DIR) diff --git a/src/ical.h b/src/ical.h
       @@ -17,7 +17,7 @@ struct ical_contentline {
        };
        
        /** src/ical.c **/
       -int ical_read_line(char **line, size_t *sz, FILE *fp);
       +int ical_read_line(char **line, char **ln, size_t *sz, FILE *fp);
        int ical_parse_contentline(struct ical_contentline *contentline, char *line);
        void ical_init_contentline(struct ical_contentline *contentline);
        void ical_free_contentline(struct ical_contentline *contentline);
 (DIR) diff --git a/src/map.c b/src/map.c
       @@ -87,6 +87,12 @@ map_del(struct map *map, char *key)
        }
        
        void
       +map_init(struct map *map)
       +{
       +        memset(map, 0, sizeof(*map));
       +}
       +
       +void
        map_free_values(struct map *map)
        {
                for (size_t i = 0; i < map->len; i++)
 (DIR) diff --git a/src/map.h b/src/map.h
       @@ -17,6 +17,7 @@ struct map {
        void * map_get(struct map *map, char *key);
        int map_set(struct map *map, char *key, void *value);
        int map_del(struct map *map, char *key);
       +void map_init(struct map *map);
        void map_free_values(struct map *map);
        void map_free(struct map *map);
        
 (DIR) diff --git a/src/util.c b/src/util.c
       @@ -10,7 +10,8 @@ strlcpy(char *buf, char const *str, size_t sz)
        {
                size_t len, cpy;
        
       -        cpy = ((len = strlen(str)) > sz) ? (sz) : (len);
       +        len = strlen(str);
       +        cpy = (len > sz) ? (sz) : (len);
                memcpy(buf, str, cpy + 1);
                buf[sz - 1] = '\0';
                return len;
       @@ -54,7 +55,7 @@ strappend(char **base_p, char const *s)
                size_t base_len, s_len;
                void *v;
        
       -        base_len = strlen(*base_p);
       +        base_len = (*base_p == NULL) ? (0) : (strlen(*base_p));
                s_len = strlen(s);
        
                if ((v = realloc(*base_p, base_len + s_len + 1)) == NULL)
 (DIR) diff --git a/test/map.c b/test/map.c
       @@ -0,0 +1,18 @@
       +#include <string.h>
       +#include <stdio.h>
       +
       +#include "map.h"
       +
       +int main(int argc, char **argv) {
       +        struct map map;
       +
       +        memset(&map, 0, sizeof(map));
       +
       +        for (argv++; *argv != NULL; argv++)
       +                if (map_set(&map, *argv, "abra") < 0)
       +                        return 1;
       +
       +        fprintf(stdout, ".");
       +
       +        return 0;
       +}
 (DIR) diff --git a/test/random-ics.awk b/test/random-ics.awk
       @@ -0,0 +1,40 @@
       +#!/usr/bin/awk -f
       +
       +function random(n) {
       +        "exec od -An </dev/urandom" | getline num
       +        return num % n
       +}
       +
       +BEGIN {
       +        data = "exec tr -cd -- '-a-zA-Z0-9\n' </dev/urandom"
       +
       +        first = 1
       +        while (data | getline) {
       +                if (random(2) && !first) {
       +                        print(" " $0)
       +                        continue
       +                }
       +                first = 0
       +
       +                col = random(26) + 1
       +                out = substr($0, 1, col)
       +                $0 = substr($0, col + 1)
       +                n = random(30)
       +                for (i = 0; i <= n; i++) {
       +                        col = random(30) + 5
       +                        if (length($0) < col)
       +                                continue
       +                        eq = random(int(col / 2)) + 1
       +                        out = out substr($0, 1, eq) "=" substr($1, eq + 1, col) ";"
       +                        $0 = substr($0, col + 1)
       +                }
       +                out = out $0 ":"
       +                data | getline
       +                out = out $0
       +                if (out ~ "\n" || out !~ ":")
       +                        exit(1)
       +                print(out)
       +        }
       +
       +        close(cmd)
       +}