/* * Copyright 2023 Oleg Borodin */ #include #include #include #include #include #include #include #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_STR:{ *(char **)(parser->bindarr[i].ref) = strcopy(val); free(key); free(val); break; } case CLVALTYPE_INT:{ for (size_t i = 0; i < strlen(val); i++) { if (isdigit(val[i]) == 0 && val[i] != '-' ) { log_error("wrong integer value: %s = %s", key, val); //return -1; } } char* eptr = NULL; *(int *)(parser->bindarr[i].ref) = (int)strtol(val, &eptr, 10); 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 value: %s = %s", key, val); //return -1; } free(key); free(val); break; } } } } } return 0; } void clparser_destroy(clparser_t * parser) { free(parser->bindarr); }