/* * Copyright (c) 2009-2011 Alex Hornung . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "parser.h" #define _iswhitespace(X) ((((X) == ' ') || ((X) == '\t'))?1:0) static int line_no = 1; static int iswhitespace(char c) { return _iswhitespace(c); } static int iscomma(char c) { return (c == ','); } void syntax_error(const char *fmt, ...) { char buf[1024]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); errx(1, "syntax error on line %d: %s\n", line_no, buf); } int entry_check_num_args(char **tokens, int num) { int i; for (i = 0; tokens[i] != NULL; i++) ; if (i < num) { syntax_error("at least %d tokens were expected but only %d " "were found", num, i); return 1; } return 0; } static int line_tokenize(char *buffer, int (*is_sep)(char), char comment_char, char **tokens) { int c, n, i; int quote = 0; i = strlen(buffer) + 1; c = 0; /* Skip leading white-space */ while ((_iswhitespace(buffer[c])) && (c < i)) c++; /* * If this line effectively (after indentation) begins with the comment * character, we ignore the rest of the line. */ if (buffer[c] == comment_char) return 0; tokens[0] = &buffer[c]; for (n = 1; c < i; c++) { if (buffer[c] == '"') { quote = !quote; if (quote) { if ((c >= 1) && (&buffer[c] != tokens[n-1])) { #if 0 syntax_error("stray opening quote not " "at beginning of token"); /* NOTREACHED */ #endif } else { tokens[n-1] = &buffer[c+1]; } } else { if ((c < i-1) && (!is_sep(buffer[c+1]))) { #if 0 syntax_error("stray closing quote not " "at end of token"); /* NOTREACHED */ #endif } else { buffer[c] = '\0'; } } } if (quote) { continue; } if (is_sep(buffer[c])) { buffer[c++] = '\0'; while ((_iswhitespace(buffer[c])) && (c < i)) c++; tokens[n++] = &buffer[c--]; } } tokens[n] = NULL; if (quote) { tokens[0] = NULL; return 0; } return n; } static int process_line(FILE* fd, parser_t parser, void *arg) { char buffer[4096]; char *tokens[256]; int c, n, i = 0; int ret = 0; while (((c = fgetc(fd)) != EOF) && (c != '\n')) { buffer[i++] = (char)c; if (i == (sizeof(buffer) -1)) break; } buffer[i] = '\0'; if (feof(fd) || ferror(fd)) ret = 1; n = line_tokenize(buffer, &iswhitespace, '#', tokens); /* * If there are not enough arguments for any function or it is * a line full of whitespaces, we just return here. Or if a * quote wasn't closed. */ if ((n < 1) || (tokens[0][0] == '\0')) return ret; parser(arg, tokens); return ret; } int parse_options(char *str, char **options) { int i; i = line_tokenize(str, &iscomma, '#', options); if (i == 0) syntax_error("Invalid expression in options token"); /* NOTREACHED */ return i; } int process_file(const char *file, parser_t parser, void *arg, int *nlines) { FILE *fd; line_no = 0; fd = fopen(file, "r"); if (fd == NULL) err(1, "fopen"); /* NOTREACHED */ while (process_line(fd, parser, arg) == 0) ++line_no; fclose(fd); if (nlines != NULL) *nlines = line_no; return 0; }