#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <err.h>
#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;
while ((_iswhitespace(buffer[c])) && (c < i)) c++;
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");
#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");
#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 ((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");
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");
while (process_line(fd, parser, arg) == 0)
++line_no;
fclose(fd);
if (nlines != NULL)
*nlines = line_no;
return 0;
}