tparse.y - repo - list/download/sync packs with remote repositories
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
       tparse.y (8106B)
       ---
            1 /*
            2  * Copyright (c) 2006 Bob Beck <beck@openbsd.org>
            3  * Copyright (c) 2002-2006 Henning Brauer <henning@openbsd.org>
            4  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
            5  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
            6  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
            7  *
            8  * Permission to use, copy, modify, and distribute this software for any
            9  * purpose with or without fee is hereby granted, provided that the above
           10  * copyright notice and this permission notice appear in all copies.
           11  *
           12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
           13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
           14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
           15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
           16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
           17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
           18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
           19  */
           20 
           21 %{
           22 #include <errno.h>
           23 #include <ctype.h>
           24 #include <stdarg.h>
           25 #include <stdio.h>
           26 #include <stdlib.h>
           27 #include <string.h>
           28 
           29 #include "repo.h"
           30 
           31 static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
           32 static struct file {
           33         TAILQ_ENTRY(file) entry;
           34         FILE *stream;
           35         char *name;
           36         int lineno;
           37         int errors;
           38 } *file, *topfile;
           39 
           40 static struct file *pushfile(const char *);
           41 static int popfile(void);
           42 static int yyparse(void);
           43 static int yylex(void);
           44 static int yyerror(const char *, ...);
           45 static int kwcmp(const void *, const void *);
           46 static int lookup(char *);
           47 static int lgetc(int);
           48 static int lungetc(int);
           49 static int findeol(void);
           50 
           51 static struct repos *repos = NULL;
           52 static char         *local = NULL;
           53 static int          *insecure = NULL;
           54 
           55 typedef struct {
           56         union {
           57                 int number;
           58                 char *string;
           59         } v;
           60         int lineno;
           61 } YYSTYPE;
           62 %}
           63 
           64 %token REPO LOCAL INSECURE ERROR
           65 %token <v.string> STRING
           66 %token <v.number> NUMBER
           67 %%
           68 
           69 grammar                : /* empty */
           70                 | grammar '\n'
           71                 | grammar main '\n'
           72                 | grammar error '\n' {
           73                         file->errors++;
           74                 }
           75                 ;
           76 
           77 main                : REPO STRING {
           78                         addrepo(repos, $2);
           79                 }
           80                 | LOCAL STRING {
           81                         strncpy(local, $2, PATH_MAX);
           82                 }
           83                 | INSECURE NUMBER {
           84                         *insecure = $2;
           85                 }
           86                 ;
           87 %%
           88 
           89 struct keywords {
           90         const char *name;
           91         int val;
           92 };
           93 
           94 static int
           95 yyerror(const char *fmt, ...)
           96 {
           97         char buf[512];
           98         va_list ap;
           99 
          100         file->errors++;
          101         va_start(ap, fmt);
          102         if (vsnprintf(buf, sizeof(buf), fmt, ap) < 0)
          103                 perror("vsnprintf");
          104         va_end(ap);
          105         fprintf(stderr, "%s:%d: %s\n", file->name, yylval.lineno, buf);
          106         return 0;
          107 }
          108 
          109 static int
          110 kwcmp(const void *k, const void *e)
          111 {
          112         return strcmp(k, ((const struct keywords *)e)->name);
          113 }
          114 
          115 static int
          116 lookup(char *s)
          117 {
          118         /* this has to be sorted always */
          119         static const struct keywords keywords[] = {
          120                 { "local",    LOCAL   },
          121                 { "repo",     REPO    },
          122                 { "insecure", INSECURE  }
          123         };
          124         const struct keywords *p;
          125 
          126         p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
          127                     sizeof(keywords[0]), kwcmp);
          128 
          129         if (p)
          130                 return p->val;
          131         else
          132                 return STRING;
          133 }
          134 
          135 #define MAXPUSHBACK 128
          136 
          137 static unsigned char *parsebuf;
          138 static int parseindex;
          139 static unsigned char pushback_buffer[MAXPUSHBACK];
          140 static int pushback_index = 0;
          141 
          142 static int
          143 lgetc(int quotec)
          144 {
          145         int c, next;
          146 
          147         if (parsebuf) {
          148                 /* Read character from the parsebuffer instead of input. */
          149                 if (parseindex >= 0) {
          150                         c = parsebuf[parseindex++];
          151                         if (c != '\0')
          152                                 return c;
          153                         parsebuf = NULL;
          154                 } else
          155                         parseindex++;
          156         }
          157 
          158         if (pushback_index)
          159                 return pushback_buffer[--pushback_index];
          160 
          161         if (quotec) {
          162                 if ((c = getc(file->stream)) == EOF) {
          163                         yyerror("reached end of file while parsing "
          164                             "quoted string");
          165                         if (file == topfile || popfile() == EOF)
          166                                 return EOF;
          167                         return quotec;
          168                 }
          169                 return c;
          170         }
          171 
          172         while ((c = getc(file->stream)) == '\\') {
          173                 next = getc(file->stream);
          174                 if (next != '\n') {
          175                         c = next;
          176                         break;
          177                 }
          178                 yylval.lineno = file->lineno;
          179                 file->lineno++;
          180         }
          181 
          182         while (c == EOF) {
          183                 if (file == topfile || popfile() == EOF)
          184                         return EOF;
          185                 c = getc(file->stream);
          186         }
          187         return c;
          188 }
          189 
          190 static int
          191 lungetc(int c)
          192 {
          193         if (c == EOF)
          194                 return EOF;
          195         if (parsebuf) {
          196                 parseindex--;
          197                 if (parseindex >= 0)
          198                         return c;
          199         }
          200         if (pushback_index < MAXPUSHBACK-1)
          201                 return pushback_buffer[pushback_index++] = c;
          202         else
          203                 return EOF;
          204 }
          205 
          206 static int
          207 findeol(void)
          208 {
          209         int c;
          210 
          211         parsebuf = NULL;
          212         pushback_index = 0;
          213 
          214         /* skip to either EOF or the first real EOL */
          215         while (1) {
          216                 c = lgetc(0);
          217                 if (c == '\n') {
          218                         file->lineno++;
          219                         break;
          220                 }
          221                 if (c == EOF)
          222                         break;
          223         }
          224         return ERROR;
          225 }
          226 
          227 static int
          228 yylex(void)
          229 {
          230         unsigned char buf[8096];
          231         unsigned char *p;
          232         int quotec, next, c;
          233         int token;
          234 
          235         p = buf;
          236         while ((c = lgetc(0)) == ' ' || c == '\t')
          237                 ; /* nothing */
          238 
          239         yylval.lineno = file->lineno;
          240         if (c == '#')
          241                 while ((c = lgetc(0)) != '\n' && c != EOF)
          242                         ; /* nothing */
          243 
          244         switch (c) {
          245         case '\'':
          246         case '"':
          247                 quotec = c;
          248                 while (1) {
          249                         if ((c = lgetc(quotec)) == EOF)
          250                                 return 0;
          251                         if (c == '\n') {
          252                                 file->lineno++;
          253                                 continue;
          254                         } else if (c == '\\') {
          255                                 if ((next = lgetc(quotec)) == EOF)
          256                                         return 0;
          257                                 if (next == quotec || c == ' ' || c == '\t')
          258                                         c = next;
          259                                 else if (next == '\n')
          260                                         continue;
          261                                 else
          262                                         lungetc(next);
          263                         } else if (c == quotec) {
          264                                 *p = '\0';
          265                                 break;
          266                         } else if (c == '\0') {
          267                                 yyerror("syntax error");
          268                                 return findeol();
          269                         }
          270                         if (p + 1 >= buf + sizeof(buf) - 1) {
          271                                 yyerror("string too long");
          272                                 return findeol();
          273                         }
          274                         *p++ = c;
          275                 }
          276                 yylval.v.string = strdup((char *)buf);
          277                 if (!yylval.v.string)
          278                         perror("strdup");
          279                 return STRING;
          280         }
          281 
          282 #define allowed_to_end_number(x) \
          283         (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
          284 
          285         if (c == '-' || isdigit(c)) {
          286                 do {
          287                         *p++ = c;
          288                         if ((unsigned)(p-buf) >= sizeof(buf)) {
          289                                 yyerror("string too long");
          290                                 return findeol();
          291                         }
          292                 } while ((c = lgetc(0)) != EOF && isdigit(c));
          293                 lungetc(c);
          294                 if (p == buf + 1 && buf[0] == '-')
          295                         goto nodigits;
          296                 if (c == EOF || allowed_to_end_number(c)) {
          297 
          298                         *p = '\0';
          299                         yylval.v.number = strtoll((char *)buf, NULL, 10);
          300                         if (errno == ERANGE) {
          301                                 yyerror("\"%s\" invalid number: %s",
          302                                     buf, strerror(errno));
          303                                 return findeol();
          304                         }
          305                         return NUMBER;
          306                 } else {
          307 nodigits:
          308                         while (p > buf + 1)
          309                                 lungetc(*--p);
          310                         c = *--p;
          311                         if (c == '-')
          312                                 return c;
          313                 }
          314         }
          315 
          316 #define allowed_in_string(x) \
          317         (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
          318         x != '{' && x != '}' && x != '<' && x != '>' && \
          319         x != '!' && x != '=' && x != '/' && x != '#' && \
          320         x != ','))
          321 
          322         if (isalnum(c) || c == ':' || c == '_' || c == '*') {
          323                 do {
          324                         *p++ = c;
          325                         if ((unsigned)(p-buf) >= sizeof(buf)) {
          326                                 yyerror("string too long");
          327                                 return findeol();
          328                         }
          329                 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
          330                 lungetc(c);
          331                 *p = '\0';
          332                 if ((token = lookup((char *)buf)) == STRING)
          333                         if (!(yylval.v.string = strdup((char *)buf)))
          334                                 perror("strdup");
          335                 return token;
          336         }
          337         if (c == '\n') {
          338                 yylval.lineno = file->lineno;
          339                 file->lineno++;
          340         }
          341         if (c == EOF)
          342                 return 0;
          343         return c;
          344 }
          345 
          346 static struct file *
          347 pushfile(const char *name)
          348 {
          349         struct file *nfile;
          350 
          351         if (!(nfile = calloc(1, sizeof(struct file))))
          352                 return NULL;
          353         if (!(nfile->name = strdup(name))) {
          354                 free(nfile);
          355                 return NULL;
          356         }
          357         if (!(nfile->stream = fopen(nfile->name, "r"))) {
          358                 free(nfile->name);
          359                 free(nfile);
          360                 return NULL;
          361         }
          362         nfile->lineno = 1;
          363         TAILQ_INSERT_TAIL(&files, nfile, entry);
          364         return nfile;
          365 }
          366 
          367 static int
          368 popfile(void)
          369 {
          370         struct file *prev;
          371 
          372         if ((prev = TAILQ_PREV(file, files, entry)))
          373                 prev->errors += file->errors;
          374         TAILQ_REMOVE(&files, file, entry);
          375         fclose(file->stream);
          376         free(file->name);
          377         free(file);
          378         file = prev;
          379         return file ? 0 : EOF;
          380 }
          381 
          382 int
          383 parseconf(struct repos *rlist, char *localrepo, int *untrust, const char *filename)
          384 {
          385         int errors = 0;
          386 
          387         if (!(file = pushfile(filename))) {
          388                 fprintf(stderr, "failed to open %s\n", filename);
          389                 return -1;
          390         }
          391         topfile = file;
          392 
          393         repos    = rlist;
          394         local    = localrepo;
          395         insecure = untrust;
          396 
          397         yyparse();
          398         errors = file->errors;
          399         popfile();
          400 
          401         if (errors != 0)
          402                 return -1;
          403 
          404         return errors != 0 ? -1 : 0;
          405 }