c-scripting/mr4th/mr4th_cmdln.c

295 lines
7.8 KiB
C

////////////////////////////////
// Functions: Command Line Parsing
MR4TH_SYMBOL MR4TH_READ_ONLY
CMDLN_Params cmdln__params_nil = {0};
#define cmdln_params_nil (CMDLN_Params*)(&cmdln__params_nil)
MR4TH_SYMBOL CMDLN*
cmdln_from_args(Arena *arena, String8List *args){
CMDLN *cmdln = push_array(arena, CMDLN, 1);
cmdln->raw = str8_list_copy(arena, args);
String8Node *node = cmdln->raw.first;
// first string is 'program'
if (node != 0){
cmdln->program = node->string;
node = node->next;
}
// consume string nodes
B32 forced_input = 0;
for (;node != 0;){
String8 string = str8_skip_chop_whitespace(node->string);
node = node->next;
// check if argument is a flag
B32 is_flag = 0;
if (!forced_input){
is_flag = (string.size != 0 && string.str[0] == '-');
}
// parse flag
if (is_flag){
// long flag
B32 is_long_flag = (string.size > 1 && string.str[1] == '-');
if (is_long_flag){
// end 'normal' mode
B32 double_dash = (string.size == 2);
if (double_dash){
forced_input = 1;
}
// parse long flag
if (!double_dash){
String8 flag_whole = str8_skip(string, 2);
// parameter delimter
U64 delim = flag_whole.size;
for (U8 *ptr = flag_whole.str, *opl = flag_whole.str + flag_whole.size;
ptr < opl; ptr += 1){
if (*ptr == '=' || *ptr == ':'){
delim = (U64)(ptr - flag_whole.str);
break;
}
}
// split flag at delimiter
String8 flag_name = str8_prefix(flag_whole, delim);
String8 flag_param = str8_skip(flag_whole, delim + 1);
// if have a param delimiter at end
// then use the next argument as the flag_param
if (delim == flag_whole.size - 1){
if (node != 0){
flag_param = node->string;
node = node->next;
}
}
// parse parameters
CMDLN_Params *params = cmdln_params_from_string(arena, flag_param);
// store flag node
{
CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1);
SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode);
cmdlnnode->string = flag_name;
cmdlnnode->params = params;
cmdln->flag_count += 1;
}
}
}
// short flags
if (!is_long_flag){
String8 short_flags = str8_skip(string, 1);
U8 *flag = short_flags.str;
U8 *flagopl = short_flags.str + short_flags.size;
for (; flag < flagopl; flag += 1){
U8 *flagptr = flag;
// check for parameters
String8 flag_param = {0};
if (flag + 1 < flagopl &&
(flag[1] == '=' || flag[1] == ':')){
flag_param = str8_range(flag + 2, flagopl);
if (flag_param.size == 0){
if (node != 0){
flag_param = node->string;
node = node->next;
}
}
// kill the flag loop after finding parameters
flag = flagopl;
}
// parse parameters
CMDLN_Params *params = cmdln_params_from_string(arena, flag_param);
// store flag node
{
CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1);
SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode);
cmdlnnode->string = str8(flagptr, 1);
cmdlnnode->params = params;
cmdln->flag_count += 1;
}
}
}
}
// parse input
if (!is_flag){
String8 input_string = string;
// store input node
{
CMDLN_Node *cmdlnnode = push_array(arena, CMDLN_Node, 1);
SLLQueuePush(cmdln->first, cmdln->last, cmdlnnode);
cmdlnnode->string = input_string;
cmdln->input_count += 1;
}
}
}
// pointer arrays
cmdln->inputs = push_array(arena, CMDLN_Node*, cmdln->input_count);
cmdln->flags = push_array(arena, CMDLN_Node*, cmdln->flag_count);
{
CMDLN_Node **inputptr = cmdln->inputs;
CMDLN_Node **flagptr = cmdln->flags;
for (CMDLN_Node *node = cmdln->first;
node != 0;
node = node->next){
if (node->params == 0){
*inputptr = node;
inputptr += 1;
}
else{
*flagptr = node;
flagptr += 1;
}
}
}
return(cmdln);
}
MR4TH_SYMBOL CMDLN_Params*
cmdln_params_from_string(Arena *arena, String8 flag_param){
CMDLN_Params *params = cmdln_params_nil;
if (flag_param.size > 0){
params = push_array(arena, CMDLN_Params, 1);
params->raw = flag_param;
params->list = str8_split(arena, flag_param, (U8*)",", 1);
}
return(params);
}
MR4TH_SYMBOL U64
cmdln_input_count(CMDLN *cmdln){
return(cmdln->input_count);
}
MR4TH_SYMBOL String8
cmdln_input_from_idx(CMDLN *cmdln, U64 idx){
String8 result = {0};
if (idx < cmdln->input_count){
result = cmdln->inputs[idx]->string;
}
return(result);
}
MR4TH_SYMBOL U64
cmdln_flag_count(CMDLN *cmdln){
return(cmdln->flag_count);
}
MR4TH_SYMBOL CMDLN_Flag*
cmdln_flag_from_idx(CMDLN *cmdln, U64 idx){
CMDLN_Flag *result = 0;
if (idx < cmdln->flag_count){
result = cmdln->flags[idx];
}
return(result);
}
MR4TH_SYMBOL CMDLN_Params*
cmdln_get_params(CMDLN *cmdln, String8 flagstr, char abbrev){
CMDLN_Params *result = 0;
for (CMDLN_Node *node = cmdln->first;
node != 0;
node = node->next){
if (node->params != 0){
if (str8_match(flagstr, node->string, 0) ||
(node->string.size == 1 && node->string.str[0] == (U8)abbrev)){
result = node->params;
break;
}
}
}
return(result);
}
MR4TH_SYMBOL B32
cmdln_has_flag(CMDLN *cmdln, String8 flagstr, char abbrev){
CMDLN_Params *params = cmdln_get_params(cmdln, flagstr, abbrev);
B32 result = (params != 0);
return(result);
}
MR4TH_SYMBOL String8
cmdln_get_str8(CMDLN *cmdln, String8 flagstr, char abbrev){
CMDLN_Params *params = cmdln_get_params(cmdln, flagstr, abbrev);
String8 result = {0};
if (params != 0){
result = params->raw;
}
return(result);
}
MR4TH_SYMBOL S64
cmdln_get_s64(CMDLN *cmdln, String8 flagstr, char abbrev){
String8 str = cmdln_get_str8(cmdln, flagstr, abbrev);
S64 result = cmdln_s64_from_str8(str);
return(result);
}
MR4TH_SYMBOL F64
cmdln_get_f64(CMDLN *cmdln, String8 flagstr, char abbrev){
String8 str = cmdln_get_str8(cmdln, flagstr, abbrev);
F64 result = cmdln_f64_from_str8(str);
return(result);
}
MR4TH_SYMBOL S64
cmdln_s64_from_str8(String8 valstr){
S64 result = s64_from_str8_c_syntax(valstr);
return(result);
}
MR4TH_SYMBOL F64
cmdln_f64_from_str8(String8 valstr){
F64 result = f64_from_str8(valstr);
return(result);
}
MR4TH_SYMBOL void
cmdln_dump(Arena *arena, String8List *out, CMDLN *cmdln, U32 indent){
// raw
str8_list_pushf(arena, out, "%Nraw:\n", indent);
for (String8Node *node = cmdln->raw.first;
node != 0;
node = node->next){
str8_list_pushf(arena, out, "%N%S\n", indent + 1, node->string);
}
// program
str8_list_pushf(arena, out, "%Nprogram: %S\n", indent, cmdln->program);
// input nodes
str8_list_pushf(arena, out, "%Nnodes:\n", indent);
for (CMDLN_Node *cmdlnnode = cmdln->first;
cmdlnnode != 0;
cmdlnnode = cmdlnnode->next){
if (cmdlnnode->params == 0){
str8_list_pushf(arena, out, "%N[input] %S\n", indent + 1, cmdlnnode->string);
}
else{
str8_list_pushf(arena, out, "%N[flag ] %S\n", indent + 1, cmdlnnode->string);
for (String8Node *node = cmdlnnode->params->list.first;
node != 0;
node = node->next){
str8_list_pushf(arena, out, "%N[param] %S\n", indent + 2, node->string);
}
}
}
}