#include #include #include #include #include #include #include typedef struct slice { char* ref; size_t len; } slice_t; typedef struct pair { slice_t key; slice_t value; } pair_t; pair_t* global_arg_table = NULL; size_t args_count = 0; void parse_config_file(const char* filename) { FILE* file = fopen(filename, "r"); if (!file) { fprintf(stderr, "failed to open config file: %s\n", filename); exit(1); } char* line = NULL; size_t len = 0; ssize_t read; size_t new_args_count = args_count; while ((read = getline(&line, &len, file)) != -1) { if (read > 0 && line[0] != '#' && line[0] != '\n') { new_args_count++; } } rewind(file); if (new_args_count > args_count) { pair_t* new_table = realloc(global_arg_table, new_args_count * sizeof(pair_t)); if (!new_table) { fprintf(stderr, "realloc failed for config file parsing\n"); fclose(file); free(line); exit(1); } global_arg_table = new_table; } while ((read = getline(&line, &len, file)) != -1) { if (read <= 1 || line[0] == '#' || line[0] == '\n') continue; if (line[read - 1] == '\n') line[read - 1] = '\0'; char* current = line; char* eq_sign = strchr(current, '='); if (eq_sign == NULL) { fprintf(stderr, "config file error: expected 'key=value' in '%s'\n", current); continue; } // key size_t key_len = eq_sign - current; size_t key_start = 0; while (key_start < key_len && isspace(current[key_start])) { key_start++; key_len--; } while (key_len > 0 && isspace(current[key_start + key_len - 1])) { key_len--; } if (key_len == 0) { fprintf(stderr, "config file error: empty key in '%s'\n", current); continue; } // value size_t value_start = eq_sign - current + 1; size_t value_len = strlen(current) - value_start; while (value_start < strlen(current) && isspace(current[value_start])) { value_start++; value_len--; } while (value_len > 0 && isspace(current[value_start + value_len - 1])) { value_len--; } // store char* key_str = strndup(current + key_start, key_len); char* value_str = strndup(current + value_start, value_len); if (!key_str || !value_str) { fprintf(stderr, "strndup failed for config file parsing\n"); free(key_str); free(value_str); fclose(file); free(line); exit(1); } global_arg_table[args_count].key.ref = key_str; global_arg_table[args_count].key.len = key_len; global_arg_table[args_count].value.ref = value_str; global_arg_table[args_count].value.len = value_len; args_count++; } fclose(file); free(line); } void parse_arguments(int argc, char** argv) { if (argc <= 1) return; global_arg_table = calloc(argc - 1, sizeof(pair_t)); if (!global_arg_table) { fprintf(stderr, "calloc failed for argument parsing\n"); exit(1); } for (int i = 1; i < argc; i++) { char* current = argv[i]; char* eq_sign = strchr(current, '='); if (eq_sign == NULL) { printf( "argument error: " "moonpaste expects named arguments with values. example: 'foo=bar'\n" " in '%s'", current); exit(1); } // Key size_t key_len = eq_sign - current; size_t key_start = 0; while (key_start < key_len && isspace(current[key_start])) { key_start++; key_len--; } while (key_len > 0 && isspace(current[key_start + key_len - 1])) { key_len--; } if (key_len == 0) { printf( "argument error: empty key\n" " in '%s'\n", current); exit(1); } // value size_t value_start = eq_sign - current + 1; size_t value_len = strlen(current) - value_start; while (value_start < strlen(current) && isspace(current[value_start])) { value_start++; value_len--; } while (value_len > 0 && isspace(current[value_start + value_len - 1])) { value_len--; } // config file if (key_len == 6 && strncmp(current + key_start, "config", 6) == 0) { char* config_file = strndup(current + value_start, value_len); if (!config_file) { fprintf(stderr, "strndup failed for config file path\n"); exit(1); } parse_config_file(config_file); free(config_file); continue; } // store global_arg_table[args_count].key.ref = current + key_start; global_arg_table[args_count].key.len = key_len; global_arg_table[args_count].value.ref = current + value_start; global_arg_table[args_count].value.len = value_len; args_count++; } } char* get_config(char* key, bool mandatory) { size_t len = strlen(key); for (int i = 0; i < args_count; i++) { if (global_arg_table[i].key.len != len) continue; if (strncmp(key, global_arg_table[i].key.ref, len) != 0) continue; char* new_str = strndup(global_arg_table[i].value.ref, global_arg_table[i].value.len); if (!new_str && mandatory) { fprintf(stderr, "strndup failed for config value\n"); exit(1); } return new_str; // free me! } if (!mandatory) return NULL; fprintf(stderr, "program expected argument %s but did not receive it.\n", key); return NULL; }