1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00
elinks/src/util/scanner.c
Witold Filipczyk 0fea79cc8f [cflags] Removed -Wno-pointer-sign
Likely some new bugs were introduced by this change.
The long term goal is clean compilation by g++.
2021-01-02 16:20:27 +01:00

178 lines
4.0 KiB
C

/** A pretty generic scanner
* @file */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include "elinks.h"
#include "util/error.h"
#include "util/scanner.h"
#include "util/string.h"
int
map_scanner_string(struct scanner *scanner,
const char *ident, const char *end,
int base_type)
{
const struct scanner_string_mapping *mappings = scanner->info->mappings;
int length = end - ident;
for (; mappings->name; mappings++) {
if (mappings->base_type == base_type
&& !c_strlcasecmp(mappings->name, -1, ident, length))
return mappings->type;
}
return base_type;
}
struct scanner_token *
skip_scanner_tokens(struct scanner *scanner, int skipto, int precedence)
{
struct scanner_token *token = get_scanner_token(scanner);
/* Skip tokens while handling some basic precedens of special chars
* so we don't skip to long. */
while (token) {
if (token->type == skipto
|| token->precedence > precedence)
break;
token = get_next_scanner_token(scanner);
}
return (token && token->type == skipto)
? get_next_scanner_token(scanner) : NULL;
}
#ifdef DEBUG_SCANNER
void
dump_scanner(struct scanner *scanner)
{
unsigned char buffer[MAX_STR_LEN];
struct scanner_token *token = scanner->current;
struct scanner_token *table_end = scanner->table + scanner->tokens;
char *srcpos = token->string, *bufpos = buffer;
int src_lookahead = 50;
int token_lookahead = 4;
int srclen;
if (!scanner_has_tokens(scanner)) return;
memset(buffer, 0, MAX_STR_LEN);
for (; token_lookahead > 0 && token < table_end; token++, token_lookahead--) {
int buflen = MAX_STR_LEN - (bufpos - buffer);
int added = snprintf(bufpos, buflen, "[%.*s] ", token->length, token->string);
bufpos += added;
}
if (scanner->tokens > token_lookahead) {
memcpy(bufpos, "... ", 4);
bufpos += 4;
}
srclen = strlen(srcpos);
int_upper_bound(&src_lookahead, srclen);
*bufpos++ = '[';
/* Compress the lookahead string */
for (; src_lookahead > 0; src_lookahead--, srcpos++, bufpos++) {
if (*srcpos == '\n' || *srcpos == '\r' || *srcpos == '\t') {
*bufpos++ = '\\';
*bufpos = *srcpos == '\n' ? 'n'
: (*srcpos == '\r' ? 'r' : 't');
} else {
*bufpos = *srcpos;
}
}
if (srclen > src_lookahead)
memcpy(bufpos, "...]", 4);
else
memcpy(bufpos, "]", 2);
errfile = scanner->file, errline = scanner->line;
elinks_wdebug("%s", buffer);
}
struct scanner_token *
get_scanner_token_debug(struct scanner *scanner)
{
if (!scanner_has_tokens(scanner)) return NULL;
dump_scanner(scanner);
/* Make sure we do not return invalid tokens */
assert(!scanner_has_tokens(scanner)
|| scanner->current->type != 0);
return get_scanner_token(scanner);
}
#endif
/** @name Initializers
* @{ */
static inline void
init_scanner_info(struct scanner_info *scanner_info)
{
const struct scan_table_info *info = scanner_info->scan_table_info;
int *scan_table = scanner_info->scan_table;
int i;
if (!info) return;
for (i = 0; info[i].type != SCAN_END; i++) {
const union scan_table_data *data = &info[i].data;
if (info[i].type == SCAN_RANGE) {
int index = *data->range.start;
assert(index > 0);
assert(data->range.end < SCAN_TABLE_SIZE);
assert(index <= data->range.end);
for (; index <= data->range.end; index++)
scan_table[index] |= info[i].bits;
} else {
char *string = info[i].data.string.source;
int pos = info[i].data.string.length - 1;
assert(info[i].type == SCAN_STRING && pos >= 0);
for (; pos >= 0; pos--)
scan_table[(unsigned char)string[pos]] |= info[i].bits;
}
}
}
void
init_scanner(struct scanner *scanner, struct scanner_info *scanner_info,
const char *string, const char *end)
{
if (!scanner_info->initialized) {
init_scanner_info(scanner_info);
scanner_info->initialized = 1;
}
memset(scanner, 0, sizeof(*scanner));
scanner->string = string;
scanner->position = string;
scanner->end = end ? end : string + strlen(string);
scanner->current = scanner->table;
scanner->info = scanner_info;
scanner->info->scan(scanner);
}
/** @} */