Files
ctpv/config.c
Nikita Ivanov d6d2ae46d9 Fix
2022-06-08 11:30:29 +05:00

234 lines
4.3 KiB
C

#include "ctpv.h"
#include "lexer.h"
#include "error.h"
#include "preview.h"
#define CHECK(f, cond) \
do { \
int x = (f); \
if (cond) \
return x; \
} while (0)
#define CHECK_OK(f) CHECK(f, x != STAT_OK)
#define CHECK_NULL(f) CHECK(f, x != STAT_NULL)
#define CHECK_OK_NULL(f) CHECK(f, x != STAT_OK || x != STAT_NULL)
enum {
STAT_OK,
STAT_ERR,
STAT_NULL,
};
static Lexer *lexer;
static Token token;
static VectorPreview *previews;
static void any_type_null(char **s)
{
if (*s && strcmp(*s, any_type) == 0)
*s = NULL;
}
static void add_preview(char *name, char *script, char *type, char *subtype,
char *ext)
{
any_type_null(&type);
any_type_null(&subtype);
if (subtype && strcmp(subtype, any_type) == 0)
subtype = NULL;
Preview p = (Preview){
.name = name,
.script = script,
.script_len = strlen(script) + 1,
.type = type,
.subtype = subtype,
.ext = ext,
.priority = 1 /* custom previews are always prioritized */
};
vectorPreview_append(previews, p);
}
static inline void next_token(void)
{
token = lexer_get_token(lexer);
}
static int accept(enum TokenType type)
{
if (token.type == type) {
next_token();
return STAT_OK;
}
return STAT_NULL;
}
static int expect(enum TokenType type)
{
if (accept(type) == STAT_OK)
return STAT_OK;
if (token.type == TOK_ERR)
return STAT_ERR;
PARSEERROR(token, "unexpected token: %s, expected: %s",
lexer_token_type_str(token.type),
lexer_token_type_str(type));
return STAT_ERR;
}
static inline char *get_str(Token tok)
{
return lexer_get_string(lexer, tok);
}
static int preview_type_ext(char **ext)
{
CHECK_OK(accept(TOK_DOT));
Token tok = token;
CHECK_OK(expect(TOK_STR));
*ext = get_str(tok);
return STAT_OK;
}
static int preview_type_mime_part(char **s)
{
*s = NULL;
CHECK_NULL(accept(TOK_STAR));
Token t = token;
CHECK_OK(expect(TOK_STR));
*s = get_str(t);
return STAT_OK;
}
static int preview_type_mime(char **type, char **subtype)
{
CHECK_OK(preview_type_mime_part(type));
CHECK_OK(expect(TOK_SLASH));
CHECK_OK(preview_type_mime_part(subtype));
return STAT_OK;
}
static int preview_type(char **type, char **subtype, char **ext)
{
CHECK_NULL(preview_type_ext(ext));
return preview_type_mime(type, subtype);
}
static int new_preview(void)
{
Token name = token;
CHECK_OK(expect(TOK_STR));
char *type = NULL;
char *subtype = NULL;
char *ext = NULL;
CHECK_OK(preview_type(&type, &subtype, &ext));
CHECK_OK(expect(TOK_BLK_OPEN));
Token script = token;
CHECK_OK(expect(TOK_STR));
CHECK_OK(expect(TOK_BLK_CLS));
add_preview(get_str(name), get_str(script), type, subtype, ext);
return STAT_OK;
}
static int priority(Token tok)
{
PARSEERROR(tok, "priority is not supported yet");
return STAT_ERR;
}
static int command(void)
{
Token cmd = token;
CHECK_OK(expect(TOK_STR));
char *cmd_str = get_str(cmd);
if (strcmp(cmd_str, "preview") == 0)
return new_preview();
else if (strcmp(cmd_str, "priority") == 0)
return priority(cmd);
PARSEERROR(cmd, "unknown command: %s", cmd_str);
return STAT_ERR;
}
static int end(void)
{
while (1) {
if (accept(TOK_NEW_LN) != STAT_OK)
break;
}
return STAT_OK;
}
static int commands(void)
{
accept(TOK_NEW_LN);
while (1) {
CHECK_NULL(accept(TOK_EOF));
CHECK_OK(command());
CHECK_OK(end());
}
}
static int parse(void)
{
#ifndef PARSE_DEBUG
next_token();
if (commands() == STAT_ERR)
return ERR;
#endif
#ifdef PARSE_DEBUG
while (1) {
next_token();
if (token.type == TOK_EOF)
break;
printf("%s\n", lexer_token_type_str(token.type));
}
#endif
return OK;
}
int config_load(VectorPreview *prevs, char *filename)
{
int ret = OK;
FILE *f = fopen(filename, "r");
ERRCHK_GOTO(!f, ret, exit, FUNCFAILED("fopen"), ERRNOS);
lexer = lexer_init(f);
previews = prevs;
ERRCHK_GOTO_OK(parse(), ret, file);
file:
fclose(f);
exit:
return ret;
}
void config_cleanup(void)
{
if (lexer)
lexer_free(lexer);
}