tRead repositories from configuration file - repo - list/download/sync packs with remote repositories
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit ce27affb8e47c3b19dc0a013dde121a4d80da3d8
 (DIR) parent fc22815052fc6ece27897b0e94c06784a5e9b574
 (HTM) Author: z3bra <willyatmailoodotorg>
       Date:   Fri, 16 Dec 2016 00:09:09 +0100
       
       Read repositories from configuration file
       
       Diffstat:
         M config.mk                           |       1 +
         M mkfile                              |       7 +++++--
         A parse.y                             |     393 +++++++++++++++++++++++++++++++
         M repo.c                              |      39 ++++++++-----------------------
         A repo.conf                           |       1 +
         A repo.h                              |      27 +++++++++++++++++++++++++++
       
       6 files changed, 437 insertions(+), 31 deletions(-)
       ---
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -2,6 +2,7 @@ VERSION = 0.0
        
        CC = cc
        LD = ${CC}
       +YACC = yacc
        
        PREFIX = /usr/local
        MANDIR = ${PREFIX}/man
 (DIR) diff --git a/mkfile b/mkfile
       t@@ -1,13 +1,16 @@
        <config.mk
        
       -repo: repo.o
       +repo: y.tab.o repo.o
                $LD -o $target $prereq $LDFLAGS $LIBS
        
        %.o: %.c
                $CC $CFLAGS -c $stem.c -o $stem.o
        
       +y.tab.c: parse.y
       +        $YACC $prereq
       +
        clean:V:
       -        rm -f *.o repo
       +        rm -f y.tab.c *.o repo
        
        install:V: all
                mkdir -p ${DESTDIR}${PREFIX}/bin
 (DIR) diff --git a/parse.y b/parse.y
       t@@ -0,0 +1,393 @@
       +/*
       + * Copyright (c) 2006 Bob Beck <beck@openbsd.org>
       + * Copyright (c) 2002-2006 Henning Brauer <henning@openbsd.org>
       + * Copyright (c) 2001 Markus Friedl.  All rights reserved.
       + * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
       + * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
       + *
       + * Permission to use, copy, modify, and distribute this software for any
       + * purpose with or without fee is hereby granted, provided that the above
       + * copyright notice and this permission notice appear in all copies.
       + *
       + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
       + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
       + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
       + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
       + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
       + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       + */
       +
       +%{
       +#include <errno.h>
       +#include <ctype.h>
       +#include <stdarg.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +
       +#include "repo.h"
       +
       +static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
       +static struct file {
       +        TAILQ_ENTRY(file) entry;
       +        FILE *stream;
       +        char *name;
       +        int lineno;
       +        int errors;
       +} *file, *topfile;
       +
       +static struct file *pushfile(const char *);
       +static int popfile(void);
       +static int yyparse(void);
       +static int yylex(void);
       +static int yyerror(const char *, ...);
       +static int kwcmp(const void *, const void *);
       +static int lookup(char *);
       +static int lgetc(int);
       +static int lungetc(int);
       +static int findeol(void);
       +
       +static struct repos *repos = NULL;
       +
       +typedef struct {
       +        union {
       +                int number;
       +                char *string;
       +        } v;
       +        int lineno;
       +} YYSTYPE;
       +%}
       +
       +%token REPO ERROR
       +%token <v.string> STRING
       +%token <v.number> NUMBER
       +%%
       +
       +grammar                : /* empty */
       +                | grammar '\n'
       +                | grammar main '\n'
       +                | grammar error '\n' {
       +                        file->errors++;
       +                }
       +                ;
       +
       +main                : REPO STRING {
       +                        addrepo(repos, $2);
       +                }
       +                ;
       +%%
       +
       +struct keywords {
       +        const char *name;
       +        int val;
       +};
       +
       +static int
       +yyerror(const char *fmt, ...)
       +{
       +        char buf[512];
       +        va_list ap;
       +
       +        file->errors++;
       +        va_start(ap, fmt);
       +        if (vsnprintf(buf, sizeof(buf), fmt, ap) < 0)
       +                perror("vsnprintf");
       +        va_end(ap);
       +        fprintf(stderr, "%s:%d: %s\n", file->name, yylval.lineno, buf);
       +        return 0;
       +}
       +
       +static int
       +kwcmp(const void *k, const void *e)
       +{
       +        return strcmp(k, ((const struct keywords *)e)->name);
       +}
       +
       +static int
       +lookup(char *s)
       +{
       +        /* this has to be sorted always */
       +        static const struct keywords keywords[] = {
       +                { "repo", REPO }
       +        };
       +        const struct keywords *p;
       +
       +        p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
       +                    sizeof(keywords[0]), kwcmp);
       +
       +        if (p)
       +                return p->val;
       +        else
       +                return STRING;
       +}
       +
       +#define MAXPUSHBACK 128
       +
       +static unsigned char *parsebuf;
       +static int parseindex;
       +static unsigned char pushback_buffer[MAXPUSHBACK];
       +static int pushback_index = 0;
       +
       +static int
       +lgetc(int quotec)
       +{
       +        int c, next;
       +
       +        if (parsebuf) {
       +                /* Read character from the parsebuffer instead of input. */
       +                if (parseindex >= 0) {
       +                        c = parsebuf[parseindex++];
       +                        if (c != '\0')
       +                                return c;
       +                        parsebuf = NULL;
       +                } else
       +                        parseindex++;
       +        }
       +
       +        if (pushback_index)
       +                return pushback_buffer[--pushback_index];
       +
       +        if (quotec) {
       +                if ((c = getc(file->stream)) == EOF) {
       +                        yyerror("reached end of file while parsing "
       +                            "quoted string");
       +                        if (file == topfile || popfile() == EOF)
       +                                return EOF;
       +                        return quotec;
       +                }
       +                return c;
       +        }
       +
       +        while ((c = getc(file->stream)) == '\\') {
       +                next = getc(file->stream);
       +                if (next != '\n') {
       +                        c = next;
       +                        break;
       +                }
       +                yylval.lineno = file->lineno;
       +                file->lineno++;
       +        }
       +
       +        while (c == EOF) {
       +                if (file == topfile || popfile() == EOF)
       +                        return EOF;
       +                c = getc(file->stream);
       +        }
       +        return c;
       +}
       +
       +static int
       +lungetc(int c)
       +{
       +        if (c == EOF)
       +                return EOF;
       +        if (parsebuf) {
       +                parseindex--;
       +                if (parseindex >= 0)
       +                        return c;
       +        }
       +        if (pushback_index < MAXPUSHBACK-1)
       +                return pushback_buffer[pushback_index++] = c;
       +        else
       +                return EOF;
       +}
       +
       +static int
       +findeol(void)
       +{
       +        int c;
       +
       +        parsebuf = NULL;
       +        pushback_index = 0;
       +
       +        /* skip to either EOF or the first real EOL */
       +        while (1) {
       +                c = lgetc(0);
       +                if (c == '\n') {
       +                        file->lineno++;
       +                        break;
       +                }
       +                if (c == EOF)
       +                        break;
       +        }
       +        return ERROR;
       +}
       +
       +static int
       +yylex(void)
       +{
       +        unsigned char buf[8096];
       +        unsigned char *p;
       +        int quotec, next, c;
       +        int token;
       +
       +        p = buf;
       +        while ((c = lgetc(0)) == ' ' || c == '\t')
       +                ; /* nothing */
       +
       +        yylval.lineno = file->lineno;
       +        if (c == '#')
       +                while ((c = lgetc(0)) != '\n' && c != EOF)
       +                        ; /* nothing */
       +
       +        switch (c) {
       +        case '\'':
       +        case '"':
       +                quotec = c;
       +                while (1) {
       +                        if ((c = lgetc(quotec)) == EOF)
       +                                return 0;
       +                        if (c == '\n') {
       +                                file->lineno++;
       +                                continue;
       +                        } else if (c == '\\') {
       +                                if ((next = lgetc(quotec)) == EOF)
       +                                        return 0;
       +                                if (next == quotec || c == ' ' || c == '\t')
       +                                        c = next;
       +                                else if (next == '\n')
       +                                        continue;
       +                                else
       +                                        lungetc(next);
       +                        } else if (c == quotec) {
       +                                *p = '\0';
       +                                break;
       +                        } else if (c == '\0') {
       +                                yyerror("syntax error");
       +                                return findeol();
       +                        }
       +                        if (p + 1 >= buf + sizeof(buf) - 1) {
       +                                yyerror("string too long");
       +                                return findeol();
       +                        }
       +                        *p++ = c;
       +                }
       +                yylval.v.string = strdup((char *)buf);
       +                if (!yylval.v.string)
       +                        perror("strdup");
       +                return STRING;
       +        }
       +
       +#define allowed_to_end_number(x) \
       +        (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
       +
       +        if (c == '-' || isdigit(c)) {
       +                do {
       +                        *p++ = c;
       +                        if ((unsigned)(p-buf) >= sizeof(buf)) {
       +                                yyerror("string too long");
       +                                return findeol();
       +                        }
       +                } while ((c = lgetc(0)) != EOF && isdigit(c));
       +                lungetc(c);
       +                if (p == buf + 1 && buf[0] == '-')
       +                        goto nodigits;
       +                if (c == EOF || allowed_to_end_number(c)) {
       +
       +                        *p = '\0';
       +                        yylval.v.number = strtoll((char *)buf, NULL, 10);
       +                        if (errno == ERANGE) {
       +                                yyerror("\"%s\" invalid number: %s",
       +                                    buf, strerror(errno));
       +                                return findeol();
       +                        }
       +                        return NUMBER;
       +                } else {
       +nodigits:
       +                        while (p > buf + 1)
       +                                lungetc(*--p);
       +                        c = *--p;
       +                        if (c == '-')
       +                                return c;
       +                }
       +        }
       +
       +#define allowed_in_string(x) \
       +        (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
       +        x != '{' && x != '}' && x != '<' && x != '>' && \
       +        x != '!' && x != '=' && x != '/' && x != '#' && \
       +        x != ','))
       +
       +        if (isalnum(c) || c == ':' || c == '_' || c == '*') {
       +                do {
       +                        *p++ = c;
       +                        if ((unsigned)(p-buf) >= sizeof(buf)) {
       +                                yyerror("string too long");
       +                                return findeol();
       +                        }
       +                } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
       +                lungetc(c);
       +                *p = '\0';
       +                if ((token = lookup((char *)buf)) == STRING)
       +                        if (!(yylval.v.string = strdup((char *)buf)))
       +                                perror("strdup");
       +                return token;
       +        }
       +        if (c == '\n') {
       +                yylval.lineno = file->lineno;
       +                file->lineno++;
       +        }
       +        if (c == EOF)
       +                return 0;
       +        return c;
       +}
       +
       +static struct file *
       +pushfile(const char *name)
       +{
       +        struct file *nfile;
       +
       +        if (!(nfile = calloc(1, sizeof(struct file))))
       +                return NULL;
       +        if (!(nfile->name = strdup(name))) {
       +                free(nfile);
       +                return NULL;
       +        }
       +        if (!(nfile->stream = fopen(nfile->name, "r"))) {
       +                free(nfile->name);
       +                free(nfile);
       +                return NULL;
       +        }
       +        nfile->lineno = 1;
       +        TAILQ_INSERT_TAIL(&files, nfile, entry);
       +        return nfile;
       +}
       +
       +static int
       +popfile(void)
       +{
       +        struct file *prev;
       +
       +        if ((prev = TAILQ_PREV(file, files, entry)))
       +                prev->errors += file->errors;
       +        TAILQ_REMOVE(&files, file, entry);
       +        fclose(file->stream);
       +        free(file->name);
       +        free(file);
       +        file = prev;
       +        return file ? 0 : EOF;
       +}
       +
       +int
       +parseconf(struct repos *rlist, const char *filename)
       +{
       +        int errors = 0;
       +
       +        if (!(file = pushfile(filename))) {
       +                fprintf(stderr, "failed to open %s\n", filename);
       +                return -1;
       +        }
       +        topfile = file;
       +
       +        repos = rlist;
       +
       +        yyparse();
       +        errors = file->errors;
       +        popfile();
       +
       +        if (errors != 0)
       +                return -1;
       +
       +        return errors != 0 ? -1 : 0;
       +}
 (DIR) diff --git a/repo.c b/repo.c
       t@@ -10,29 +10,9 @@
        #include <curl/curl.h>
        
        #include "arg.h"
       -
       -#define LISTFILE   ".list"
       -#define LOCALREPO  "local"
       -#define REMOTEREPO "http://127.0.0.1/pack"
       -
       -struct pack {
       -        char name[LINE_MAX];
       -        char version[LINE_MAX];
       -        char url[PATH_MAX];
       -        TAILQ_ENTRY(pack) entries;
       -};
       -TAILQ_HEAD(packs, pack);
       -
       -struct repo {
       -        char *url;
       -        TAILQ_ENTRY(repo) entries;
       -};
       -TAILQ_HEAD(repos, repo);
       +#include "repo.h"
        
        void usage(char *);
       -struct pack *addpack(struct packs *, char *, char *, char *);
       -struct repo *addrepo(struct repos *, char *);
       -int repolist(struct packs *, char *);
        int download(char *, FILE *);
        
        void
       t@@ -94,7 +74,7 @@ repolist(struct packs *plist, char *local)
                char n[LINE_MAX], v[LINE_MAX], u[PATH_MAX];
                FILE *list;
        
       -        snprintf(fn, PATH_MAX, "%s/%s", local, LISTFILE);
       +        snprintf(fn, PATH_MAX, "%s/%s", local, DEFLISTFILE);
                list = fopen(fn, "r");
                if (!list) {
                        perror(fn);
       t@@ -157,6 +137,7 @@ main (int argc, char *argv[])
        {
                int   sflag = 0, lflag = 0;
                char *argv0, *n;
       +        char *cfgfile = DEFCFGFILE;
                char  fn[PATH_MAX], url[PATH_MAX];
                FILE *fd;
                struct packs plist;
       t@@ -181,25 +162,25 @@ main (int argc, char *argv[])
                        usage(argv0);
                }ARGEND;
        
       -        if (TAILQ_EMPTY(&rlist)) {
       -                addrepo(&rlist, REMOTEREPO);
       -        }
       +        parseconf(&rlist, cfgfile);
       +        if (TAILQ_EMPTY(&rlist))
       +                addrepo(&rlist, DEFREMOTEREPO);
        
                if (sflag) {
       -                snprintf(fn, PATH_MAX, "%s/%s", LOCALREPO, LISTFILE);
       +                snprintf(fn, PATH_MAX, "%s/%s", DEFLOCALREPO, DEFLISTFILE);
                        fd = fopen(fn, "w");
                        if (!fd) {
                                perror(fn);
                                exit(1);
                        }
                        TAILQ_FOREACH(r, &rlist, entries) {
       -                        snprintf(url, PATH_MAX, "%s/%s", r->url, LISTFILE);
       +                        snprintf(url, PATH_MAX, "%s/%s", r->url, DEFLISTFILE);
                                download(url, fd);
                        }
                        fclose(fd);
                }
        
       -        repolist(&plist, LOCALREPO);
       +        repolist(&plist, DEFLOCALREPO);
        
                if (lflag) {
                        TAILQ_FOREACH(p, &plist, entries) {
       t@@ -211,7 +192,7 @@ main (int argc, char *argv[])
                while ((n = *(argv++))) {
                        TAILQ_FOREACH(p, &plist, entries) {
                                if (!strncmp(p->name, n, PATH_MAX)) {
       -                                snprintf(fn, PATH_MAX, "%s/%s", LOCALREPO, basename(p->url));
       +                                snprintf(fn, PATH_MAX, "%s/%s", DEFLOCALREPO, basename(p->url));
                                        fd = fopen(fn, "w");
                                        if (!fd) {
                                                perror(fn);
 (DIR) diff --git a/repo.conf b/repo.conf
       t@@ -0,0 +1 @@
       +repo "http://localhost"
 (DIR) diff --git a/repo.h b/repo.h
       t@@ -0,0 +1,27 @@
       +#include <limits.h>
       +#include <sys/queue.h>
       +
       +#define DEFLISTFILE   ".list"
       +#define DEFLOCALREPO  "local"
       +#define DEFREMOTEREPO "http://127.0.0.1/pack"
       +#define DEFCFGFILE    "repo.conf"
       +
       +struct pack {
       +        char name[LINE_MAX];
       +        char version[LINE_MAX];
       +        char url[PATH_MAX];
       +        TAILQ_ENTRY(pack) entries;
       +};
       +TAILQ_HEAD(packs, pack);
       +
       +struct repo {
       +        char *url;
       +        TAILQ_ENTRY(repo) entries;
       +};
       +TAILQ_HEAD(repos, repo);
       +
       + 
       +struct pack *addpack(struct packs *, char *, char *, char *);
       +struct repo *addrepo(struct repos *, char *);
       +int repolist(struct packs *, char *);
       +int parseconf(struct repos *, const char *);