194 lines
4.9 KiB
C
194 lines
4.9 KiB
C
/*
|
|
* Copyright 2023 Oleg Borodin <borodin@unix7.org>
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include <logger.h>
|
|
#include <clparser.h>
|
|
|
|
#define INIT_BSIZE 64
|
|
|
|
|
|
static char* strcopy(char* src) {
|
|
size_t srcsize = strlen(src) + 1;
|
|
char* dst = malloc(srcsize);
|
|
|
|
memset(dst, '\0', srcsize);
|
|
strcpy(dst, src);
|
|
return dst;
|
|
}
|
|
|
|
static char* strconcat(char** str, int num) {
|
|
size_t tsize = 0;
|
|
size_t size[num];
|
|
|
|
for (int i = 0; i < num; i++) {
|
|
size[i] = 0;
|
|
if (str[i] != NULL) {
|
|
size[i] = strlen(str[i]);
|
|
tsize += size[i];
|
|
}
|
|
}
|
|
tsize++;
|
|
char* dst = malloc(tsize);
|
|
|
|
memset(dst, '\0', tsize);
|
|
int pos = 0;
|
|
|
|
for (int i = 0; i < num; i++) {
|
|
if (str[i] != NULL) {
|
|
strcpy(&dst[pos], str[i]);
|
|
pos += size[i];
|
|
}
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
void clparser_init(clparser_t * parser, cllexer_t * lexer) {
|
|
parser->lexer = lexer;
|
|
parser->bindarr = malloc(sizeof(clbind_t) * INIT_BSIZE);
|
|
parser->bindcapa = INIT_BSIZE;
|
|
parser->bindsize = 0;
|
|
}
|
|
|
|
void clparser_bind(clparser_t * parser, int type, char* key, void* ref) {
|
|
if (parser->bindsize >= parser->bindcapa) {
|
|
return; // TODO
|
|
}
|
|
clbind_t* b = &(parser->bindarr[parser->bindsize]);
|
|
|
|
b->type = type;
|
|
b->key = key;
|
|
b->ref = ref;
|
|
parser->bindsize++;
|
|
}
|
|
|
|
#define MAX_TOKEN_SIZE 1024
|
|
|
|
static int clparser_compile(clparser_t * parser, char* arg, char** refkey, char** refval) {
|
|
cllexer_t* lex = parser->lexer;
|
|
|
|
cllexer_reset(lex, arg);
|
|
|
|
char token[MAX_TOKEN_SIZE];
|
|
int type = 0;
|
|
int pos = 0;
|
|
|
|
char* key;
|
|
char* vals[2] = { NULL };
|
|
|
|
while ((type = cllexer_gettoken(lex, token)) != CLLEXTOK_END) {
|
|
switch (pos) {
|
|
// POS 0
|
|
case 0:{
|
|
if (type == CLLEXTOK_KEY) {
|
|
pos++;
|
|
} else {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
// POS 1
|
|
case 1:{
|
|
if (type == CLLEXTOK_WORD) {
|
|
key = strcopy(token);
|
|
pos++;
|
|
} else {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
// POS 2
|
|
case 2:{
|
|
if (type == CLLEXTOK_SEP) {
|
|
pos++;
|
|
} else {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
// POS 3
|
|
case 3:{
|
|
if (type == CLLEXTOK_WORD || type == CLLEXTOK_KEY) {
|
|
pos++;
|
|
vals[0] = strcopy(token);
|
|
} else {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
// POS 4
|
|
case 4:{
|
|
if (type == CLLEXTOK_WORD) {
|
|
pos++;
|
|
vals[1] = strcopy(token);
|
|
} else {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
default:{
|
|
return -1;
|
|
|
|
}
|
|
}
|
|
}
|
|
*refkey = key;
|
|
*refval = strconcat(vals, 2);
|
|
free(vals[0]);
|
|
free(vals[1]);
|
|
return 0;
|
|
}
|
|
|
|
int clparser_parse(clparser_t * parser, char** argv, int argc) {
|
|
for (int i = 0; i < argc; i++) {
|
|
char* key;
|
|
char* val;
|
|
|
|
if (clparser_compile(parser, argv[i], &key, &val) < 0) {
|
|
return -1;
|
|
}
|
|
for (int i = 0; i < parser->bindsize; i++) {
|
|
if (strcmp(parser->bindarr[i].key, key) == 0) {
|
|
switch (parser->bindarr[i].type) {
|
|
case CLVALTYPE_INT:{
|
|
char* eptr = NULL;
|
|
*(int *)(parser->bindarr[i].ref) = (int)strtol(val, &eptr, 10);
|
|
free(key);
|
|
free(val);
|
|
break;
|
|
}
|
|
case CLVALTYPE_STR:{
|
|
*(char **)(parser->bindarr[i].ref) = strcopy(val);
|
|
free(key);
|
|
free(val);
|
|
break;
|
|
}
|
|
case CLVALTYPE_BOOL:{
|
|
*(bool*)(parser->bindarr[i].ref) = false;
|
|
if (strcmp(val, "true") == 0) {
|
|
*(bool*)(parser->bindarr[i].ref) = true;
|
|
} else if (strcmp(val, "false") == 0) {
|
|
*(bool*)(parser->bindarr[i].ref) = false;
|
|
} else {
|
|
log_error("wrong boolean key value: %s = %s", key, val);
|
|
}
|
|
free(key);
|
|
free(val);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void clparser_destroy(clparser_t * parser) {
|
|
free(parser->bindarr);
|
|
}
|