From: Tracey Emery Subject: Re: Make gotweb config parsing work with last diff To: gameoftrees@openbsd.org Date: Fri, 19 Jun 2020 16:48:27 -0600 On Fri, Jun 19, 2020 at 02:44:49PM -0600, Tracey Emery wrote: > Hello, > > This builds on top of the last diff, making gotweb use the new library > function. > > Ok? > > -- > > Tracey Emery Sorry, I forgot that we don't require a config file for gotweb. So, I reworked this slightly by adding a new error code and a note to remind myself of this "feature." Ok? -- Tracey Emery diff 340049eaf7e8e13e7a671bdc7774b91628c7863d /home/tracey/src/got blob - 1bfc514197abcd84859f193604c899656ca61ca6 file + gotweb/gotweb.c --- gotweb/gotweb.c +++ gotweb/gotweb.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -42,12 +43,11 @@ #include #include #include +#include "got_config_parse.h" #include #include -#include "gotweb.h" - #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif @@ -57,7 +57,7 @@ struct gw_trans { TAILQ_HEAD(dirs, gw_dir) gw_dirs; struct got_repository *repo; struct gw_dir *gw_dir; - struct gotweb_conf *gw_conf; + struct gotweb_config *gw_conf; struct ktemplate *gw_tmpl; struct khtmlreq *gw_html_req; struct kreq *gw_req; @@ -4656,7 +4656,7 @@ main(int argc, char *argv[]) } if ((gw_trans->gw_conf = - malloc(sizeof(struct gotweb_conf))) == NULL) { + malloc(sizeof(struct gotweb_config))) == NULL) { gw_malloc = 0; error = got_error_from_errno("malloc"); goto done; @@ -4680,7 +4680,8 @@ main(int argc, char *argv[]) gw_trans->gw_tmpl->keysz = TEMPL__MAX; gw_trans->gw_tmpl->arg = gw_trans; gw_trans->gw_tmpl->cb = gw_template; - error = parse_conf(GOTWEB_CONF, gw_trans->gw_conf); + + error = got_config_parse_gotweb_config(&gw_trans->gw_conf, GOTWEB_CONF); if (error) goto done; @@ -4700,7 +4701,6 @@ done: free(gw_trans->gw_conf->got_site_link); free(gw_trans->gw_conf->got_logo); free(gw_trans->gw_conf->got_logo_url); - free(gw_trans->gw_conf); free(gw_trans->commit_id); free(gw_trans->next_id); free(gw_trans->next_prev_id); blob - a2b02715b9a59a20e78eac7a01d868854f4fd3ac file + /dev/null --- gotweb/gotweb.h +++ gotweb/gotweb.h @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2019, 2020 Tracey Emery - * Copyright (c) 2018, 2019 Stefan Sperling - * - * 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. - */ - -#ifndef GOTWEB_H -#define GOTWEB_H - -#include - -#include - -#define GOTWEB_CONF "/etc/gotweb.conf" -#define GOTWEB_TMPL_DIR "/cgi-bin/gw_tmpl" -#define GOTWEB "/cgi-bin/gotweb/gotweb" - -#define GOTWEB_GOT_DIR ".got" -#define GOTWEB_GIT_DIR ".git" - -#define D_GOTPATH "/got/public" -#define D_SITENAME "Gotweb" -#define D_SITEOWNER "Got Owner" -#define D_SITELINK "Repos" -#define D_GOTLOGO "got.png" -#define D_GOTURL "https://gameoftrees.org" - -#define D_SHOWROWNER true -#define D_SHOWSOWNER true -#define D_SHOWAGE true -#define D_SHOWDESC true -#define D_SHOWURL true -#define D_MAXREPO 0 -#define D_MAXREPODISP 25 -#define D_MAXSLCOMMDISP 10 -#define D_MAXCOMMITDISP 25 - -#define BUFFER_SIZE 2048 - -struct gotweb_conf { - char *got_repos_path; - char *got_site_name; - char *got_site_owner; - char *got_site_link; - char *got_logo; - char *got_logo_url; - - size_t got_max_repos; - size_t got_max_repos_display; - size_t got_max_commits_display; - - bool got_show_site_owner; - bool got_show_repo_owner; - bool got_show_repo_age; - bool got_show_repo_description; - bool got_show_repo_cloneurl; -}; - -const struct got_error* parse_conf(const char *, struct gotweb_conf *); - -#endif /* GOTWEB_H */ blob - 2271bbde9b190920695f4451cfe046353cbe8ec7 file + /dev/null --- gotweb/parse.y +++ gotweb/parse.y @@ -1,517 +0,0 @@ -/* - * Copyright (c) 2019 Tracey Emery - * Copyright (c) 2002, 2003, 2004 Henning Brauer - * 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gotweb.h" - -TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -static struct file { - TAILQ_ENTRY(file) entry; - FILE *stream; - char *name; - int lineno; - int errors; - const struct got_error* error; -} *file, *topfile; -struct file *pushfile(const char *); -int popfile(void); -int yyparse(void); -int yylex(void); -int yyerror(const char *, ...) - __attribute__((__format__ (printf, 1, 2))) - __attribute__((__nonnull__ (1))); -int kw_cmp(const void *, const void *); -int lookup(char *); -int lgetc(int); -int lungetc(int); -int findeol(void); - -static const struct got_error* gerror = NULL; -char *syn_err; - -struct gotweb_conf *gw_conf; - -typedef struct { - union { - int64_t number; - char *string; - } v; - int lineno; -} YYSTYPE; - -%} - -%token GOT_WWW_PATH GOT_MAX_REPOS GOT_SITE_NAME GOT_SITE_OWNER GOT_SITE_LINK -%token GOT_LOGO GOT_LOGO_URL GOT_SHOW_REPO_OWNER GOT_SHOW_REPO_AGE -%token GOT_SHOW_REPO_DESCRIPTION GOT_MAX_REPOS_DISPLAY GOT_REPOS_PATH -%token GOT_MAX_COMMITS_DISPLAY ON ERROR GOT_SHOW_SITE_OWNER -%token GOT_SHOW_REPO_CLONEURL -%token STRING -%token NUMBER -%type boolean -%% - -grammar : /* empty */ - | grammar '\n' - | grammar main '\n' - | grammar error '\n' { file->errors++; } - ; - -boolean : STRING { - if (strcasecmp($1, "true") == 0 || - strcasecmp($1, "yes") == 0) - $$ = 1; - else if (strcasecmp($1, "false") == 0 || - strcasecmp($1, "off") == 0 || - strcasecmp($1, "no") == 0) - $$ = 0; - else { - yyerror("invalid boolean value '%s'", $1); - free($1); - YYERROR; - } - free($1); - } - | ON { $$ = 1; } - ; - -main : GOT_REPOS_PATH STRING { - if ((gw_conf->got_repos_path = strdup($2)) == NULL) - errx(1, "out of memory"); - } - | GOT_MAX_REPOS NUMBER { - if ($2 > 0) - gw_conf->got_max_repos = $2; - } - | GOT_SITE_NAME STRING { - if ((gw_conf->got_site_name = strdup($2)) == NULL) - errx(1, "out of memory"); - } - | GOT_SITE_OWNER STRING { - if ((gw_conf->got_site_owner = strdup($2)) == NULL) - errx(1, "out of memory"); - } - | GOT_SITE_LINK STRING { - if ((gw_conf->got_site_link = strdup($2)) == NULL) - errx(1, "out of memory"); - } - | GOT_LOGO STRING { - if ((gw_conf->got_logo = strdup($2)) == NULL) - errx(1, "out of memory"); - } - | GOT_LOGO_URL STRING { - if ((gw_conf->got_logo_url = strdup($2)) == NULL) - errx(1, "out of memory"); - } - | GOT_SHOW_SITE_OWNER boolean { - gw_conf->got_show_site_owner = $2; - } - | GOT_SHOW_REPO_OWNER boolean { - gw_conf->got_show_repo_owner = $2; - } - | GOT_SHOW_REPO_AGE boolean { gw_conf->got_show_repo_age = $2; } - | GOT_SHOW_REPO_DESCRIPTION boolean { - gw_conf->got_show_repo_description = $2; - } - | GOT_SHOW_REPO_CLONEURL boolean { - gw_conf->got_show_repo_cloneurl = $2; - } - | GOT_MAX_REPOS_DISPLAY NUMBER { - if ($2 > 0) - gw_conf->got_max_repos_display = $2; - } - | GOT_MAX_COMMITS_DISPLAY NUMBER { - if ($2 > 0) - gw_conf->got_max_commits_display = $2; - } - ; - -%% - -struct keywords { - const char *k_name; - int k_val; -}; - -int -yyerror(const char *fmt, ...) -{ - va_list ap; - char *msg = NULL; - static char err_msg[512]; - - file->errors++; - va_start(ap, fmt); - if (vasprintf(&msg, fmt, ap) == -1) - errx(1, "yyerror vasprintf"); - va_end(ap); - snprintf(err_msg, sizeof(err_msg), "%s:%d: %s", file->name, - yylval.lineno, msg); - gerror = got_error_from_errno2("parse_error", err_msg); - - free(msg); - return (0); -} - -int -kw_cmp(const void *k, const void *e) -{ - return (strcmp(k, ((const struct keywords *)e)->k_name)); -} - -int -lookup(char *s) -{ - /* this has to be sorted always */ - static const struct keywords keywords[] = { - { "got_logo", GOT_LOGO }, - { "got_logo_url", GOT_LOGO_URL }, - { "got_max_commits_display", GOT_MAX_COMMITS_DISPLAY }, - { "got_max_repos", GOT_MAX_REPOS }, - { "got_max_repos_display", GOT_MAX_REPOS_DISPLAY }, - { "got_repos_path", GOT_REPOS_PATH }, - { "got_show_repo_age", GOT_SHOW_REPO_AGE }, - { "got_show_repo_cloneurl", GOT_SHOW_REPO_CLONEURL }, - { "got_show_repo_description", GOT_SHOW_REPO_DESCRIPTION }, - { "got_show_repo_owner", GOT_SHOW_REPO_OWNER }, - { "got_show_site_owner", GOT_SHOW_SITE_OWNER }, - { "got_site_link", GOT_SITE_LINK }, - { "got_site_name", GOT_SITE_NAME }, - { "got_site_owner", GOT_SITE_OWNER }, - }; - const struct keywords *p; - - p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), - sizeof(keywords[0]), kw_cmp); - - if (p) - return (p->k_val); - else - return (STRING); -} - -#define MAXPUSHBACK 128 - -u_char *parsebuf; -int parseindex; -u_char pushback_buffer[MAXPUSHBACK]; -int pushback_index = 0; - -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); -} - -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); -} - -int -findeol(void) -{ - int c; - - parsebuf = NULL; - - /* skip to either EOF or the first real EOL */ - while (1) { - if (pushback_index) - c = pushback_buffer[--pushback_index]; - else - c = lgetc(0); - if (c == '\n') { - file->lineno++; - break; - } - if (c == EOF) - break; - } - return (ERROR); -} - -int -yylex(void) -{ - u_char buf[8096]; - u_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 || next == ' ' || - next == '\t') - c = next; - else if (next == '\n') { - file->lineno++; - 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(buf); - if (yylval.v.string == NULL) - errx(1, "yylex: strdup"); - return (STRING); - } - -#define allowed_to_end_number(x) \ - (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') - - if (c == '-' || isdigit(c)) { - do { - *p++ = c; - if ((size_t)(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)) { - const char *errstr = NULL; - - *p = '\0'; - yylval.v.number = strtonum(buf, LLONG_MIN, - LLONG_MAX, &errstr); - if (errstr) { - yyerror("\"%s\" invalid number: %s", - buf, errstr); - 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 ((size_t)(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(buf)) == STRING) - if ((yylval.v.string = strdup(buf)) == NULL) - errx(1, "yylex: strdup"); - return (token); - } - if (c == '\n') { - yylval.lineno = file->lineno; - file->lineno++; - } - if (c == EOF) - return (0); - return (c); -} - -struct file * -pushfile(const char *name) -{ - struct file *nfile; - - if ((nfile = calloc(1, sizeof(struct file))) == NULL) { - gerror = got_error(GOT_ERR_NO_SPACE); - return (NULL); - } - if ((nfile->name = strdup(name)) == NULL) { - gerror = got_error(GOT_ERR_NO_SPACE); - free(nfile); - return (NULL); - } - if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { - gerror = got_error_from_errno2("parse_conf", nfile->name); - free(nfile->name); - free(nfile); - return (NULL); - } - nfile->lineno = 1; - TAILQ_INSERT_TAIL(&files, nfile, entry); - return (nfile); -} - -int -popfile(void) -{ - struct file *prev; - - if ((prev = TAILQ_PREV(file, files, entry)) != NULL) - prev->errors += file->errors; - - TAILQ_REMOVE(&files, file, entry); - fclose(file->stream); - free(file->name); - free(file); - file = prev; - return (file ? 0 : EOF); -} - -const struct got_error* -parse_conf(const char *filename, struct gotweb_conf *gconf) -{ - static const struct got_error* error = NULL; - - gw_conf = gconf; - if ((gw_conf->got_repos_path = strdup(D_GOTPATH)) == NULL) - err(1, "strdup"); - if ((gw_conf->got_site_name = strdup(D_SITENAME)) == NULL) - err(1, "strdup"); - if ((gw_conf->got_site_owner = strdup(D_SITEOWNER)) == NULL) - err(1, "strdup"); - if ((gw_conf->got_site_link = strdup(D_SITELINK)) == NULL) - err(1, "strdup"); - if ((gw_conf->got_logo = strdup(D_GOTLOGO)) == NULL) - err(1, "strdup"); - if ((gw_conf->got_logo_url = strdup(D_GOTURL)) == NULL) - err(1, "strdup"); - gw_conf->got_show_site_owner = D_SHOWSOWNER; - gw_conf->got_show_repo_owner = D_SHOWROWNER; - gw_conf->got_show_repo_age = D_SHOWAGE; - gw_conf->got_show_repo_description = D_SHOWDESC; - gw_conf->got_show_repo_cloneurl = D_SHOWURL; - gw_conf->got_max_repos = D_MAXREPO; - gw_conf->got_max_repos_display = D_MAXREPODISP; - gw_conf->got_max_commits_display = D_MAXCOMMITDISP; - if ((file = pushfile(filename)) == NULL) { - goto done; - } - topfile = file; - - yyparse(); - popfile(); - if (gerror) - error = gerror; -done: - return error; -} blob - 86074676dcb36a4dac9544e5dc676523abe57cab file + include/got_config_parse.h --- include/got_config_parse.h +++ include/got_config_parse.h @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + struct got_config_list_entry { TAILQ_ENTRY(got_config_list_entry) entry; const char *remote; @@ -24,9 +26,59 @@ struct got_config_list_entry { }; TAILQ_HEAD(got_config_list, got_config_list_entry); +#define GOTWEB_CONF "/etc/gotweb.conf" +#define GOTWEB_TMPL_DIR "/cgi-bin/gw_tmpl" +#define GOTWEB "/cgi-bin/gotweb/gotweb" + +#define GOTWEB_GOT_DIR ".got" +#define GOTWEB_GIT_DIR ".git" + +#define D_GOTPATH "/got/public" +#define D_SITENAME "Gotweb" +#define D_SITEOWNER "Got Owner" +#define D_SITELINK "Repos" +#define D_GOTLOGO "got.png" +#define D_GOTURL "https://gameoftrees.org" + +#define D_SHOWROWNER true +#define D_SHOWSOWNER true +#define D_SHOWAGE true +#define D_SHOWDESC true +#define D_SHOWURL true +#define D_MAXREPO 0 +#define D_MAXREPODISP 25 +#define D_MAXSLCOMMDISP 10 +#define D_MAXCOMMITDISP 25 + +struct gotweb_config { + char *got_repos_path; + char *got_site_name; + char *got_site_owner; + char *got_site_link; + char *got_logo; + char *got_logo_url; + + size_t got_max_repos; + size_t got_max_repos_display; + size_t got_max_commits_display; + + bool got_show_site_owner; + bool got_show_repo_owner; + bool got_show_repo_age; + bool got_show_repo_description; + bool got_show_repo_cloneurl; +}; + /* * Parse individual gotconfig repository files * Load got_config_list_entry struct and insert to got_config_list TAILQ */ const struct got_error* got_config_parse_got_config(struct got_config_list **, + char *filename); + +/* + * Parse gotweb configuration + * Loads gotweb_config struct + */ +const struct got_error* got_config_parse_gotweb_config(struct gotweb_config **, char *filename); blob - de101511cf4ff533f885dcc7bbd634aa195dc840 file + include/got_error.h --- include/got_error.h +++ include/got_error.h @@ -142,6 +142,7 @@ #define GOT_ERR_FETCH_BAD_REF 125 #define GOT_ERR_TREE_ENTRY_TYPE 126 #define GOT_ERR_PARSE_Y_YY 127 +#define GOT_ERR_NO_CONFIG_FILE 128 static const struct got_error { int code; @@ -290,6 +291,7 @@ static const struct got_error { { GOT_ERR_FETCH_BAD_REF, "reference cannot be fetched" }, { GOT_ERR_TREE_ENTRY_TYPE, "unexpected tree entry type" }, { GOT_ERR_PARSE_Y_YY, "yyerror error" }, + { GOT_ERR_NO_CONFIG_FILE, "config file does not exist" }, }; /* blob - dd1e0a6c7c9c05d864b33e126456dcef12734744 file + lib/parse.y --- lib/parse.y +++ lib/parse.y @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -84,10 +85,13 @@ int symset(const char *, const char *, int); char *symget(const char *); const struct got_error* gerror = NULL; -struct got_config_list_entry *gotconfig; + +struct got_config_list_entry *got_config; struct got_config_list got_config_list; -static const struct got_error* new_remote(struct got_config_list_entry **); +static const struct got_error* new_remote(struct got_config_list_entry **); +struct gotweb_config gw_conf; + typedef struct { union { int64_t number; @@ -99,22 +103,102 @@ typedef struct { %} %token ERROR +%token GOT_WWW_PATH GOT_MAX_REPOS GOT_SITE_NAME GOT_SITE_OWNER GOT_SITE_LINK +%token GOT_LOGO GOT_LOGO_URL GOT_SHOW_REPO_OWNER GOT_SHOW_REPO_AGE +%token GOT_SHOW_REPO_DESCRIPTION GOT_MAX_REPOS_DISPLAY GOT_REPOS_PATH +%token GOT_MAX_COMMITS_DISPLAY ON GOT_SHOW_SITE_OWNER +%token GOT_SHOW_REPO_CLONEURL %token REMOTE REPOSITORY SERVER PROTOCOL USER %token STRING %token NUMBER +%type boolean %% grammar : /* empty */ | grammar '\n' + | grammar main '\n' | grammar remote '\n' ; +boolean : STRING { + if (strcasecmp($1, "true") == 0 || + strcasecmp($1, "yes") == 0) + $$ = 1; + else if (strcasecmp($1, "false") == 0 || + strcasecmp($1, "off") == 0 || + strcasecmp($1, "no") == 0) + $$ = 0; + else { + yyerror("invalid boolean value '%s'", $1); + free($1); + YYERROR; + } + free($1); + } + | ON { $$ = 1; } + ; +main : GOT_REPOS_PATH STRING { + gw_conf.got_repos_path = strdup($2); + if (gw_conf.got_repos_path== NULL) + errx(1, "out of memory"); + } + | GOT_MAX_REPOS NUMBER { + if ($2 > 0) + gw_conf.got_max_repos = $2; + } + | GOT_SITE_NAME STRING { + gw_conf.got_site_name = strdup($2); + if (gw_conf.got_site_name == NULL) + errx(1, "out of memory"); + } + | GOT_SITE_OWNER STRING { + gw_conf.got_site_owner = strdup($2); + if (gw_conf.got_site_owner == NULL) + errx(1, "out of memory"); + } + | GOT_SITE_LINK STRING { + gw_conf.got_site_link = strdup($2); + if (gw_conf.got_site_link == NULL) + errx(1, "out of memory"); + } + | GOT_LOGO STRING { + gw_conf.got_logo = strdup($2); + if (gw_conf.got_logo== NULL) + errx(1, "out of memory"); + } + | GOT_LOGO_URL STRING { + gw_conf.got_logo_url = strdup($2); + if (gw_conf.got_logo_url== NULL) + errx(1, "out of memory"); + } + | GOT_SHOW_SITE_OWNER boolean { + gw_conf.got_show_site_owner = $2; + } + | GOT_SHOW_REPO_OWNER boolean { + gw_conf.got_show_repo_owner = $2; + } + | GOT_SHOW_REPO_AGE boolean { gw_conf.got_show_repo_age = $2; } + | GOT_SHOW_REPO_DESCRIPTION boolean { + gw_conf.got_show_repo_description = $2; + } + | GOT_SHOW_REPO_CLONEURL boolean { + gw_conf.got_show_repo_cloneurl = $2; + } + | GOT_MAX_REPOS_DISPLAY NUMBER { + if ($2 > 0) + gw_conf.got_max_repos_display = $2; + } + | GOT_MAX_COMMITS_DISPLAY NUMBER { + if ($2 > 0) + gw_conf.got_max_commits_display = $2; + } + ; remoteopts2 : remoteopts2 remoteopts1 nl | remoteopts1 optnl ; remoteopts1 : REPOSITORY STRING { - gotconfig->repository = strdup($2); - if (gotconfig->repository == NULL) { + got_config->repository = strdup($2); + if (got_config->repository == NULL) { free($2); yyerror("strdup"); YYERROR; @@ -122,8 +206,8 @@ remoteopts1 : REPOSITORY STRING { free($2); } | SERVER STRING { - gotconfig->server = strdup($2); - if (gotconfig->server == NULL) { + got_config->server = strdup($2); + if (got_config->server == NULL) { free($2); yyerror("strdup"); YYERROR; @@ -131,8 +215,8 @@ remoteopts1 : REPOSITORY STRING { free($2); } | PROTOCOL STRING { - gotconfig->protocol = strdup($2); - if (gotconfig->protocol == NULL) { + got_config->protocol = strdup($2); + if (got_config->protocol == NULL) { free($2); yyerror("strdup"); YYERROR; @@ -140,8 +224,8 @@ remoteopts1 : REPOSITORY STRING { free($2); } | USER STRING { - gotconfig->user = strdup($2); - if (gotconfig->user == NULL) { + got_config->user = strdup($2); + if (got_config->user == NULL) { free($2); yyerror("strdup"); YYERROR; @@ -152,21 +236,21 @@ remoteopts1 : REPOSITORY STRING { remote : REMOTE STRING { static const struct got_error* error; - error = new_remote(&gotconfig); + error = new_remote(&got_config); if (error) { free($2); yyerror("%s", error->msg); YYERROR; } - gotconfig->remote = strdup($2); - if (gotconfig->remote == NULL) { + got_config->remote = strdup($2); + if (got_config->remote == NULL) { free($2); yyerror("strdup"); YYERROR; } free($2); } '{' optnl remoteopts2 '}' { - TAILQ_INSERT_TAIL(&got_config_list, gotconfig, entry); + TAILQ_INSERT_TAIL(&got_config_list, got_config, entry); } ; optnl : '\n' optnl @@ -215,11 +299,25 @@ lookup(char *s) { /* This has to be sorted always. */ static const struct keywords keywords[] = { - {"protocol", PROTOCOL}, - {"remote", REMOTE}, - {"repository", REPOSITORY}, - {"server", SERVER}, - {"user", USER}, + { "got_logo", GOT_LOGO }, + { "got_logo_url", GOT_LOGO_URL }, + { "got_max_commits_display", GOT_MAX_COMMITS_DISPLAY }, + { "got_max_repos", GOT_MAX_REPOS }, + { "got_max_repos_display", GOT_MAX_REPOS_DISPLAY }, + { "got_repos_path", GOT_REPOS_PATH }, + { "got_show_repo_age", GOT_SHOW_REPO_AGE }, + { "got_show_repo_cloneurl", GOT_SHOW_REPO_CLONEURL }, + { "got_show_repo_description", GOT_SHOW_REPO_DESCRIPTION }, + { "got_show_repo_owner", GOT_SHOW_REPO_OWNER }, + { "got_show_site_owner", GOT_SHOW_SITE_OWNER }, + { "got_site_link", GOT_SITE_LINK }, + { "got_site_name", GOT_SITE_NAME }, + { "got_site_owner", GOT_SITE_OWNER }, + { "protocol", PROTOCOL }, + { "remote", REMOTE }, + { "repository", REPOSITORY }, + { "server", SERVER }, + { "user", USER }, }; const struct keywords *p; @@ -506,9 +604,9 @@ pushfile(struct file **nfile, const char *name) char *msg = NULL; if (asprintf(&msg, "%s", (*nfile)->name) == -1) return got_error_from_errno("asprintf"); + error = got_error_msg(GOT_ERR_NO_CONFIG_FILE, msg); free((*nfile)->name); free((*nfile)); - error = got_error_from_errno(msg); free(msg); return error; } @@ -526,10 +624,10 @@ pushfile(struct file **nfile, const char *name) } static const struct got_error* -new_remote(struct got_config_list_entry **gotconfig) { +new_remote(struct got_config_list_entry **got_config) { const struct got_error* error = NULL; - if (((*gotconfig) = calloc(1, sizeof(struct got_config_list_entry))) == + if (((*got_config) = calloc(1, sizeof(struct got_config_list_entry))) == NULL) error = got_error_from_errno("calloc"); return error; @@ -578,6 +676,48 @@ got_config_parse_got_config(struct got_config_list **c return gerror; } +const struct got_error* +got_config_parse_gotweb_config(struct gotweb_config **gconf, char *filename) +{ + if ((gw_conf.got_repos_path = strdup(D_GOTPATH)) == NULL) + err(1, "strdup"); + if ((gw_conf.got_site_name = strdup(D_SITENAME)) == NULL) + err(1, "strdup"); + if ((gw_conf.got_site_owner = strdup(D_SITEOWNER)) == NULL) + err(1, "strdup"); + if ((gw_conf.got_site_link = strdup(D_SITELINK)) == NULL) + err(1, "strdup"); + if ((gw_conf.got_logo = strdup(D_GOTLOGO)) == NULL) + err(1, "strdup"); + if ((gw_conf.got_logo_url = strdup(D_GOTURL)) == NULL) + err(1, "strdup"); + gw_conf.got_show_site_owner = D_SHOWSOWNER; + gw_conf.got_show_repo_owner = D_SHOWROWNER; + gw_conf.got_show_repo_age = D_SHOWAGE; + gw_conf.got_show_repo_description = D_SHOWDESC; + gw_conf.got_show_repo_cloneurl = D_SHOWURL; + gw_conf.got_max_repos = D_MAXREPO; + gw_conf.got_max_repos_display = D_MAXREPODISP; + gw_conf.got_max_commits_display = D_MAXCOMMITDISP; + + /* + * We don't require that the gotweb config file exists + * So reset gerror if it doesn't exist and goto done. + */ + gerror = pushfile(&file, filename); + if (gerror && gerror->code == GOT_ERR_NO_CONFIG_FILE) { + gerror = NULL; + goto done; + } else if (gerror) + return gerror; + topfile = file; + + yyparse(); + popfile(); +done: + *gconf = &gw_conf; + return gerror; +} int symset(const char *nam, const char *val, int persist) {