#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "ntp_config.h"
#include "ntpsim.h"
#include "ntp_scanner.h"
#include "ntp_parser.h"
#include "ntp_debug.h"
#include "ntp_keyword.h"
#define MAX_LEXEME (1024 + 1)
char yytext[MAX_LEXEME];
extern int input_from_file;
const char special_chars[] = "{}(),;|=";
int get_next_char(void);
static int is_keyword(char *lexeme, follby *pfollowedby);
const char *
keyword(
int token
)
{
int i;
const char *text;
i = token - LOWEST_KEYWORD_ID;
if (i >= 0 && i < COUNTOF(keyword_text))
text = keyword_text[i];
else
text = NULL;
return (text != NULL)
? text
: "(keyword not found)";
}
struct FILE_INFO *
F_OPEN(
const char *path,
const char *mode
)
{
struct FILE_INFO *my_info;
my_info = emalloc(sizeof *my_info);
my_info->line_no = 1;
my_info->col_no = 0;
my_info->prev_line_col_no = 0;
my_info->prev_token_col_no = 0;
my_info->fname = path;
my_info->fd = fopen(path, mode);
if (NULL == my_info->fd) {
free(my_info);
return NULL;
}
return my_info;
}
int
FGETC(
struct FILE_INFO *stream
)
{
int ch = fgetc(stream->fd);
++stream->col_no;
if (ch == '\n') {
stream->prev_line_col_no = stream->col_no;
++stream->line_no;
stream->col_no = 1;
}
return ch;
}
int
UNGETC(
int ch,
struct FILE_INFO *stream
)
{
if (ch == '\n') {
stream->col_no = stream->prev_line_col_no;
stream->prev_line_col_no = -1;
--stream->line_no;
}
--stream->col_no;
return ungetc(ch, stream->fd);
}
int
FCLOSE(
struct FILE_INFO *stream
)
{
int ret_val = fclose(stream->fd);
if (!ret_val)
free(stream);
return ret_val;
}
int
get_next_char(
void
)
{
char ch;
if (input_from_file)
return FGETC(ip_file);
else {
if (remote_config.buffer[remote_config.pos] == '\0')
return EOF;
else {
ip_file->col_no++;
ch = remote_config.buffer[remote_config.pos++];
if (ch == '\n') {
ip_file->prev_line_col_no = ip_file->col_no;
++ip_file->line_no;
ip_file->col_no = 1;
}
return ch;
}
}
}
void
push_back_char(
int ch
)
{
if (input_from_file)
UNGETC(ch, ip_file);
else {
if (ch == '\n') {
ip_file->col_no = ip_file->prev_line_col_no;
ip_file->prev_line_col_no = -1;
--ip_file->line_no;
}
--ip_file->col_no;
remote_config.pos--;
}
}
static int
is_keyword(
char *lexeme,
follby *pfollowedby
)
{
follby fb;
int curr_s;
int token;
int i;
curr_s = SCANNER_INIT_S;
token = 0;
for (i = 0; lexeme[i]; i++) {
while (curr_s && (lexeme[i] != SS_CH(sst[curr_s])))
curr_s = SS_OTHER_N(sst[curr_s]);
if (curr_s && (lexeme[i] == SS_CH(sst[curr_s]))) {
if ('\0' == lexeme[i + 1]
&& FOLLBY_NON_ACCEPTING
!= SS_FB(sst[curr_s])) {
fb = SS_FB(sst[curr_s]);
*pfollowedby = fb;
token = curr_s;
break;
}
curr_s = SS_MATCH_N(sst[curr_s]);
} else
break;
}
return token;
}
static int
is_integer(
char *lexeme
)
{
int i = 0;
if (lexeme[i] == '-')
++i;
for (; lexeme[i]; ++i) {
if (!isdigit(lexeme[i]))
return 0;
}
return 1;
}
static int
is_double(
char *lexeme
)
{
int num_digits = 0;
int i;
i = 0;
if ('+' == lexeme[i] || '-' == lexeme[i])
i++;
for (; lexeme[i] && isdigit(lexeme[i]); i++)
num_digits++;
if ('.' == lexeme[i])
i++;
else
return 0;
for (; lexeme[i] && isdigit(lexeme[i]); i++)
num_digits++;
if (!num_digits)
return 0;
if (!lexeme[i])
return 1;
if ('e' == tolower(lexeme[i]))
i++;
else
return 0;
if ('+' == lexeme[i] || '-' == lexeme[i])
i++;
while (lexeme[i] && isdigit(lexeme[i]))
i++;
if (!lexeme[i])
return 1;
else
return 0;
}
static inline int
is_special(
int ch
)
{
return (int)strchr(special_chars, ch);
}
static int
is_EOC(
int ch
)
{
if ((old_config_style && (ch == '\n')) ||
(!old_config_style && (ch == ';')))
return 1;
return 0;
}
char *
quote_if_needed(char *str)
{
char *ret;
size_t len;
size_t octets;
len = strlen(str);
octets = len + 2 + 1;
ret = emalloc(octets);
if ('"' != str[0]
&& (strcspn(str, special_chars) < len
|| strchr(str, ' ') != NULL)) {
snprintf(ret, octets, "\"%s\"", str);
} else
strncpy(ret, str, octets);
return ret;
}
static int
create_string_token(
char *lexeme
)
{
char *pch;
pch = lexeme;
while (*pch && isspace(*pch))
pch++;
if (!*pch) {
yylval.Integer = T_EOC;
return yylval.Integer;
}
yylval.String = estrdup(lexeme);
return T_String;
}
int
yylex(
void
)
{
int i, instring = 0;
int yylval_was_set = 0;
int token;
int ch;
static follby followedby = FOLLBY_TOKEN;
do {
while (EOF != (ch = get_next_char()) &&
isspace(ch) &&
!is_EOC(ch))
;
if (EOF == ch) {
if (!input_from_file || !curr_include_level)
return 0;
FCLOSE(fp[curr_include_level]);
ip_file = fp[--curr_include_level];
token = T_EOC;
goto normal_return;
} else if (is_EOC(ch)) {
followedby = FOLLBY_TOKEN;
token = T_EOC;
goto normal_return;
} else if (is_special(ch) && FOLLBY_TOKEN == followedby) {
token = ch;
if ('=' == ch)
followedby = FOLLBY_STRING;
yytext[0] = (char)ch;
yytext[1] = '\0';
goto normal_return;
} else
push_back_char(ch);
ip_file->prev_token_line_no = ip_file->line_no;
ip_file->prev_token_col_no = ip_file->col_no;
i = 0;
while (EOF != (ch = get_next_char())) {
yytext[i] = (char)ch;
if (isspace(ch) || is_EOC(ch)
|| '"' == ch
|| (FOLLBY_TOKEN == followedby
&& is_special(ch)))
break;
if ('#' == ch) {
while (EOF != (ch = get_next_char())
&& '\n' != ch)
;
break;
}
i++;
if (i >= COUNTOF(yytext))
goto lex_too_long;
}
if ('"' == ch) {
instring = 1;
while (EOF != (ch = get_next_char()) &&
ch != '"' && ch != '\n') {
yytext[i++] = (char)ch;
if (i >= COUNTOF(yytext))
goto lex_too_long;
}
if ('"' == ch)
ch = get_next_char();
}
if (EOF == ch)
push_back_char('\n');
else
push_back_char(ch);
yytext[i] = '\0';
} while (i == 0);
if (followedby == FOLLBY_TOKEN && !instring) {
token = is_keyword(yytext, &followedby);
if (token)
goto normal_return;
else if (is_integer(yytext)) {
yylval_was_set = 1;
errno = 0;
if ((yylval.Integer = strtol(yytext, NULL, 10)) == 0
&& ((errno == EINVAL) || (errno == ERANGE))) {
msyslog(LOG_ERR,
"Integer cannot be represented: %s",
yytext);
exit(1);
} else {
token = T_Integer;
goto normal_return;
}
}
else if (is_double(yytext)) {
yylval_was_set = 1;
errno = 0;
if ((yylval.Double = atof(yytext)) == 0 && errno == ERANGE) {
msyslog(LOG_ERR,
"Double too large to represent: %s",
yytext);
exit(1);
} else {
token = T_Double;
goto normal_return;
}
} else {
yylval_was_set = 1;
token = create_string_token(yytext);
goto normal_return;
}
}
if ('-' == yytext[0]) {
if ('4' == yytext[1]) {
token = T_Ipv4_flag;
goto normal_return;
} else if ('6' == yytext[1]) {
token = T_Ipv6_flag;
goto normal_return;
}
}
instring = 0;
if (FOLLBY_STRING == followedby)
followedby = FOLLBY_TOKEN;
yylval_was_set = 1;
token = create_string_token(yytext);
normal_return:
if (T_EOC == token)
DPRINTF(4,("\t<end of command>\n"));
else
DPRINTF(4, ("yylex: lexeme '%s' -> %s\n", yytext,
token_name(token)));
if (!yylval_was_set)
yylval.Integer = token;
return token;
lex_too_long:
yytext[min(sizeof(yytext) - 1, 50)] = 0;
msyslog(LOG_ERR,
"configuration item on line %d longer than limit of %lu, began with '%s'",
ip_file->line_no, sizeof(yytext) - 1, yytext);
if (input_from_file)
exit(sizeof(yytext) - 1);
yylval.Integer = 0;
return 0;
}