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 *);