mirror of
https://github.com/NikitaIvanovV/ctpv.git
synced 2024-11-24 13:53:07 +01:00
Make config reading functions re-entrant
This commit is contained in:
parent
3cfe9a5f79
commit
a187ad9dde
224
src/config.c
224
src/config.c
@ -1,6 +1,7 @@
|
||||
#include "ctpv.h"
|
||||
#include "lexer.h"
|
||||
#include "error.h"
|
||||
#include "config.h"
|
||||
#include "preview.h"
|
||||
|
||||
#define CHECK(f, cond) \
|
||||
@ -13,9 +14,9 @@
|
||||
#define CHECK_OK(f) CHECK(f, x == STAT_OK)
|
||||
#define CHECK_NULL(f) CHECK(f, x == STAT_NULL)
|
||||
|
||||
#define EXPECT(x) CHECK_OK(expect(x))
|
||||
#define ACCEPT(x) CHECK_OK(accept(x))
|
||||
#define NOT_ACCEPT(x) CHECK_NULL(accept(x))
|
||||
#define EXPECT(c, x) CHECK_OK(expect(c, x))
|
||||
#define ACCEPT(c, x) CHECK_OK(accept(c, x))
|
||||
#define NOT_ACCEPT(c, x) CHECK_NULL(accept(c, x))
|
||||
|
||||
#define DEF_OPTION(name, type, val) { (#name), (type), { .val = &ctpv.opts.name } }
|
||||
#define DEF_OPTION_BOOL(name) DEF_OPTION(name, OPTION_BOOL, i)
|
||||
@ -24,6 +25,12 @@
|
||||
|
||||
#define TYPE_SET_EMPTY (struct TypeSet){ NULL, NULL, NULL }
|
||||
|
||||
struct Parser {
|
||||
Lexer *lexer;
|
||||
Token token;
|
||||
VectorPreview *previews;
|
||||
};
|
||||
|
||||
struct Option {
|
||||
char *name;
|
||||
enum {
|
||||
@ -47,10 +54,6 @@ enum {
|
||||
STAT_NULL,
|
||||
};
|
||||
|
||||
static Lexer *lexer;
|
||||
static Token token;
|
||||
static VectorPreview *previews;
|
||||
|
||||
static struct Option options[] = {
|
||||
DEF_OPTION_BOOL(forcekitty),
|
||||
DEF_OPTION_BOOL(forcekittyanim),
|
||||
@ -66,10 +69,10 @@ static void any_type_null(char **s)
|
||||
*s = NULL;
|
||||
}
|
||||
|
||||
static void add_preview(char *name, char *script, struct TypeSet *set,
|
||||
static void add_preview(Parser *ctx, char *name, char *script, struct TypeSet *set,
|
||||
unsigned int set_len)
|
||||
{
|
||||
if (!previews)
|
||||
if (!ctx->previews)
|
||||
return;
|
||||
|
||||
size_t script_len = strlen(script) + 1;
|
||||
@ -90,131 +93,131 @@ static void add_preview(char *name, char *script, struct TypeSet *set,
|
||||
.priority = 0
|
||||
};
|
||||
|
||||
vectorPreview_append(previews, p);
|
||||
vectorPreview_append(ctx->previews, p);
|
||||
}
|
||||
}
|
||||
|
||||
static int add_priority(char *name, int priority)
|
||||
static int add_priority(Parser *ctx, char *name, int priority)
|
||||
{
|
||||
if (!previews)
|
||||
if (!ctx->previews)
|
||||
return OK;
|
||||
|
||||
int found = 0;
|
||||
|
||||
for (size_t i = 0; i < previews->len; i++) {
|
||||
if (strcmp(previews->buf[i].name, name) != 0)
|
||||
for (size_t i = 0; i < ctx->previews->len; i++) {
|
||||
if (strcmp(ctx->previews->buf[i].name, name) != 0)
|
||||
continue;
|
||||
|
||||
previews->buf[i].priority = priority;
|
||||
ctx->previews->buf[i].priority = priority;
|
||||
found = 1;
|
||||
}
|
||||
|
||||
return found ? OK : ERR;
|
||||
}
|
||||
|
||||
static int remove_preview(char *name)
|
||||
static int remove_preview(Parser *ctx, char *name)
|
||||
{
|
||||
if (!previews)
|
||||
if (!ctx->previews)
|
||||
return OK;
|
||||
|
||||
int found = 0;
|
||||
|
||||
for (ssize_t i = previews->len - 1; i >= 0; i--) {
|
||||
if (strcmp(previews->buf[i].name, name) != 0)
|
||||
for (ssize_t i = ctx->previews->len - 1; i >= 0; i--) {
|
||||
if (strcmp(ctx->previews->buf[i].name, name) != 0)
|
||||
continue;
|
||||
|
||||
vectorPreview_remove(previews, i);
|
||||
vectorPreview_remove(ctx->previews, i);
|
||||
found = 1;
|
||||
}
|
||||
|
||||
return found ? OK : ERR;
|
||||
}
|
||||
|
||||
static inline void next_token(void)
|
||||
static inline void next_token(Parser *ctx)
|
||||
{
|
||||
token = lexer_get_token(lexer);
|
||||
ctx->token = lexer_get_token(ctx->lexer);
|
||||
}
|
||||
|
||||
static int accept(enum TokenType type)
|
||||
static int accept(Parser *ctx, enum TokenType type)
|
||||
{
|
||||
if (token.type == type) {
|
||||
next_token();
|
||||
if (ctx->token.type == type) {
|
||||
next_token(ctx);
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
return STAT_NULL;
|
||||
}
|
||||
|
||||
static int expect(enum TokenType type)
|
||||
static int expect(Parser *ctx, enum TokenType type)
|
||||
{
|
||||
if (accept(type) == STAT_OK)
|
||||
if (accept(ctx, type) == STAT_OK)
|
||||
return STAT_OK;
|
||||
|
||||
if (token.type == TOK_ERR)
|
||||
if (ctx->token.type == TOK_ERR)
|
||||
return STAT_ERR;
|
||||
|
||||
PARSEERROR(token, "unexpected token: %s, expected: %s",
|
||||
lexer_token_type_str(token.type),
|
||||
PARSEERROR(ctx->token, "unexpected token: %s, expected: %s",
|
||||
lexer_token_type_str(ctx->token.type),
|
||||
lexer_token_type_str(type));
|
||||
return STAT_ERR;
|
||||
}
|
||||
|
||||
static int preview_type_ext(char **ext)
|
||||
static int preview_type_ext(Parser *ctx, char **ext)
|
||||
{
|
||||
ACCEPT(TOK_DOT);
|
||||
ACCEPT(ctx, TOK_DOT);
|
||||
|
||||
Token tok = token;
|
||||
EXPECT(TOK_STR);
|
||||
Token tok = ctx->token;
|
||||
EXPECT(ctx, TOK_STR);
|
||||
*ext = tok.val.s;
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int preview_type_mime_part(char **s)
|
||||
static int preview_type_mime_part(Parser *ctx, char **s)
|
||||
{
|
||||
NOT_ACCEPT(TOK_STAR);
|
||||
NOT_ACCEPT(ctx, TOK_STAR);
|
||||
|
||||
Token tok = token;
|
||||
EXPECT(TOK_STR);
|
||||
Token tok = ctx->token;
|
||||
EXPECT(ctx, TOK_STR);
|
||||
*s = tok.val.s;
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int preview_type_mime(char **type, char **subtype)
|
||||
static int preview_type_mime(Parser *ctx, char **type, char **subtype)
|
||||
{
|
||||
CHECK_OK(preview_type_mime_part(type));
|
||||
EXPECT(TOK_SLASH);
|
||||
CHECK_OK(preview_type_mime_part(subtype));
|
||||
CHECK_OK(preview_type_mime_part(ctx, type));
|
||||
EXPECT(ctx, TOK_SLASH);
|
||||
CHECK_OK(preview_type_mime_part(ctx, subtype));
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static inline void num_is_text(void)
|
||||
static inline void num_is_text(Parser *ctx)
|
||||
{
|
||||
lexer_set_opts(lexer, LEX_OPT_NUMISTEXT);
|
||||
lexer_set_opts(ctx->lexer, LEX_OPT_NUMISTEXT);
|
||||
}
|
||||
|
||||
static inline void reset_lexer_opts(void)
|
||||
static inline void reset_lexer_opts(Parser *ctx)
|
||||
{
|
||||
lexer_set_opts(lexer, LEX_OPT_NONE);
|
||||
lexer_set_opts(ctx->lexer, LEX_OPT_NONE);
|
||||
}
|
||||
|
||||
static int preview_type(struct TypeSet *set)
|
||||
static int preview_type(Parser *ctx, struct TypeSet *set)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*set = TYPE_SET_EMPTY;
|
||||
|
||||
num_is_text();
|
||||
num_is_text(ctx);
|
||||
|
||||
if ((ret = preview_type_ext(&set->ext)) != STAT_NULL)
|
||||
if ((ret = preview_type_ext(ctx, &set->ext)) != STAT_NULL)
|
||||
goto exit;
|
||||
|
||||
ret = preview_type_mime(&set->type, &set->subtype);
|
||||
ret = preview_type_mime(ctx, &set->type, &set->subtype);
|
||||
|
||||
exit:
|
||||
reset_lexer_opts();
|
||||
reset_lexer_opts(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -228,10 +231,10 @@ static struct Option *get_option(char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int cmd_set(void)
|
||||
static int cmd_set(Parser *ctx)
|
||||
{
|
||||
Token name = token;
|
||||
EXPECT(TOK_STR);
|
||||
Token name = ctx->token;
|
||||
EXPECT(ctx, TOK_STR);
|
||||
|
||||
struct Option *opt = get_option(name.val.s);
|
||||
if (!opt) {
|
||||
@ -239,18 +242,18 @@ static int cmd_set(void)
|
||||
return STAT_ERR;
|
||||
}
|
||||
|
||||
Token value = token;
|
||||
Token value = ctx->token;
|
||||
|
||||
switch (opt->arg_type) {
|
||||
case OPTION_BOOL:
|
||||
*opt->arg_val.i = accept(TOK_INT) == STAT_OK ? value.val.i : 1;
|
||||
*opt->arg_val.i = accept(ctx, TOK_INT) == STAT_OK ? value.val.i : 1;
|
||||
break;
|
||||
case OPTION_INT:
|
||||
EXPECT(TOK_INT);
|
||||
EXPECT(ctx, TOK_INT);
|
||||
*opt->arg_val.i = value.val.i;
|
||||
break;
|
||||
case OPTION_STR:
|
||||
EXPECT(TOK_STR);
|
||||
EXPECT(ctx, TOK_STR);
|
||||
*opt->arg_val.s = value.val.s;
|
||||
break;
|
||||
default:
|
||||
@ -261,42 +264,42 @@ static int cmd_set(void)
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int cmd_preview(void)
|
||||
static int cmd_preview(Parser *ctx)
|
||||
{
|
||||
Token name = token;
|
||||
EXPECT(TOK_STR);
|
||||
Token name = ctx->token;
|
||||
EXPECT(ctx, TOK_STR);
|
||||
|
||||
struct TypeSet types[16];
|
||||
unsigned int types_len = 0;
|
||||
|
||||
while (accept(TOK_BLK_OPEN) == STAT_NULL) {
|
||||
while (accept(ctx, TOK_BLK_OPEN) == STAT_NULL) {
|
||||
if (types_len >= LEN(types)) {
|
||||
PARSEERROR(name, "a preview can only have up through %lu types",
|
||||
LEN(types));
|
||||
return STAT_ERR;
|
||||
}
|
||||
|
||||
CHECK_OK(preview_type(types + types_len++));
|
||||
CHECK_OK(preview_type(ctx, types + types_len++));
|
||||
}
|
||||
|
||||
Token script = token;
|
||||
EXPECT(TOK_STR);
|
||||
Token script = ctx->token;
|
||||
EXPECT(ctx, TOK_STR);
|
||||
|
||||
EXPECT(TOK_BLK_CLS);
|
||||
EXPECT(ctx, TOK_BLK_CLS);
|
||||
|
||||
add_preview(name.val.s, script.val.s, types, types_len);
|
||||
add_preview(ctx, name.val.s, script.val.s, types, types_len);
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int cmd_priority(Token tok)
|
||||
static int cmd_priority(Parser *ctx)
|
||||
{
|
||||
Token name = token;
|
||||
EXPECT(TOK_STR);
|
||||
Token name = ctx->token;
|
||||
EXPECT(ctx, TOK_STR);
|
||||
|
||||
Token number = token;
|
||||
int i = accept(TOK_INT) == STAT_OK ? number.val.i : 1;
|
||||
Token number = ctx->token;
|
||||
int i = accept(ctx, TOK_INT) == STAT_OK ? number.val.i : 1;
|
||||
|
||||
if (add_priority(name.val.s, i) != OK) {
|
||||
if (add_priority(ctx, name.val.s, i) != OK) {
|
||||
PARSEERROR(name, "preview '%s' not found", name.val.s);
|
||||
return STAT_ERR;
|
||||
}
|
||||
@ -304,12 +307,12 @@ static int cmd_priority(Token tok)
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int cmd_remove(Token tok)
|
||||
static int cmd_remove(Parser *ctx)
|
||||
{
|
||||
Token name = token;
|
||||
EXPECT(TOK_STR);
|
||||
Token name = ctx->token;
|
||||
EXPECT(ctx, TOK_STR);
|
||||
|
||||
if (remove_preview(name.val.s) != OK) {
|
||||
if (remove_preview(ctx, name.val.s) != OK) {
|
||||
PARSEERROR(name, "preview '%s' not found", name.val.s);
|
||||
return STAT_ERR;
|
||||
}
|
||||
@ -317,58 +320,58 @@ static int cmd_remove(Token tok)
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int command(void)
|
||||
static int command(Parser *ctx)
|
||||
{
|
||||
Token cmd = token;
|
||||
EXPECT(TOK_STR);
|
||||
Token cmd = ctx->token;
|
||||
EXPECT(ctx, TOK_STR);
|
||||
|
||||
if (strcmp(cmd.val.s, "set") == 0)
|
||||
return cmd_set();
|
||||
return cmd_set(ctx);
|
||||
else if (strcmp(cmd.val.s, "preview") == 0)
|
||||
return cmd_preview();
|
||||
return cmd_preview(ctx);
|
||||
else if (strcmp(cmd.val.s, "priority") == 0)
|
||||
return cmd_priority(cmd);
|
||||
return cmd_priority(ctx);
|
||||
else if (strcmp(cmd.val.s, "remove") == 0)
|
||||
return cmd_remove(cmd);
|
||||
return cmd_remove(ctx);
|
||||
|
||||
PARSEERROR(cmd, "unknown command: %s", cmd.val.s);
|
||||
return STAT_ERR;
|
||||
}
|
||||
|
||||
static void newlines(void)
|
||||
static void newlines(Parser *ctx)
|
||||
{
|
||||
while (1) {
|
||||
if (accept(TOK_NEW_LN) != STAT_OK)
|
||||
if (accept(ctx, TOK_NEW_LN) != STAT_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int end(void)
|
||||
static int end(Parser *ctx)
|
||||
{
|
||||
NOT_ACCEPT(TOK_EOF);
|
||||
EXPECT(TOK_NEW_LN);
|
||||
NOT_ACCEPT(ctx, TOK_EOF);
|
||||
EXPECT(ctx, TOK_NEW_LN);
|
||||
|
||||
newlines();
|
||||
newlines(ctx);
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
static int commands(void)
|
||||
static int commands(Parser *ctx)
|
||||
{
|
||||
newlines();
|
||||
newlines(ctx);
|
||||
|
||||
while (1) {
|
||||
NOT_ACCEPT(TOK_EOF);
|
||||
CHECK_OK(command());
|
||||
CHECK_OK(end());
|
||||
NOT_ACCEPT(ctx, TOK_EOF);
|
||||
CHECK_OK(command(ctx));
|
||||
CHECK_OK(end(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
static int parse(void)
|
||||
static int parse(Parser *ctx)
|
||||
{
|
||||
#ifdef DEBUG_LEXER
|
||||
while (1) {
|
||||
next_token();
|
||||
next_token(ctx);
|
||||
if (token.type == TOK_EOF)
|
||||
break;
|
||||
printf("%s", lexer_token_type_str(token.type));
|
||||
@ -386,25 +389,30 @@ static int parse(void)
|
||||
}
|
||||
#endif
|
||||
#ifndef DEBUG_LEXER
|
||||
next_token();
|
||||
if (commands() == STAT_ERR)
|
||||
next_token(ctx);
|
||||
if (commands(ctx) == STAT_ERR)
|
||||
return ERR;
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int config_load(VectorPreview *prevs, char *filename)
|
||||
int config_load(Parser **ctx, VectorPreview *prevs, char *filename)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
FILE *f;
|
||||
ERRCHK_GOTO_ERN(!(f = fopen(filename, "r")), ret, exit);
|
||||
|
||||
lexer = lexer_init(f);
|
||||
previews = prevs;
|
||||
if (!(*ctx = malloc(sizeof(**ctx)))) {
|
||||
FUNCFAILED("malloc", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
ERRCHK_GOTO_OK(parse(), ret, file);
|
||||
(*ctx)->lexer = lexer_init(f);
|
||||
(*ctx)->previews = prevs;
|
||||
|
||||
ERRCHK_GOTO_OK(parse(*ctx), ret, file);
|
||||
|
||||
file:
|
||||
fclose(f);
|
||||
@ -413,11 +421,13 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void config_cleanup(void)
|
||||
void config_cleanup(Parser *ctx)
|
||||
{
|
||||
if (!lexer)
|
||||
if (!ctx->lexer)
|
||||
return;
|
||||
|
||||
lexer_free(lexer);
|
||||
lexer = NULL;
|
||||
lexer_free(ctx->lexer);
|
||||
ctx->lexer = NULL;
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
@ -3,7 +3,9 @@
|
||||
|
||||
#include "preview.h"
|
||||
|
||||
int config_load(VectorPreview *prevs, char *filename);
|
||||
void config_cleanup(void);
|
||||
typedef struct Parser Parser;
|
||||
|
||||
int config_load(Parser **ctx, VectorPreview *prevs, char *filename);
|
||||
void config_cleanup(Parser *ctx);
|
||||
|
||||
#endif
|
||||
|
@ -26,12 +26,15 @@ const char any_type[] = ANY_TYPE;
|
||||
|
||||
static magic_t magic;
|
||||
|
||||
static Parser *parser;
|
||||
|
||||
static VectorPreview *previews;
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
previews_cleanup();
|
||||
config_cleanup();
|
||||
if (parser)
|
||||
config_cleanup(parser);
|
||||
if (magic != NULL)
|
||||
magic_close(magic);
|
||||
if (previews)
|
||||
@ -74,7 +77,7 @@ static int config(int prevs)
|
||||
char config_file[FILENAME_MAX];
|
||||
get_config_file(config_file, LEN(config_file));
|
||||
|
||||
ERRCHK_RET_OK(config_load(prevs ? previews : NULL, config_file));
|
||||
ERRCHK_RET_OK(config_load(&parser, prevs ? previews : NULL, config_file));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user