feat: Spaces are allowed before and after the fields in config

This commit is contained in:
DreamMaoMao 2025-05-12 08:14:04 +08:00
parent 0a79024da8
commit bc4f598259

View file

@ -212,6 +212,54 @@ typedef struct {
typedef void (*FuncType)(const Arg *); typedef void (*FuncType)(const Arg *);
Config config; Config config;
// Helper function to trim whitespace from start and end of a string
void trim_whitespace(char *str) {
if (str == NULL || *str == '\0') return;
// Trim leading space
char *start = str;
while (isspace((unsigned char)*start)) {
start++;
}
// Trim trailing space
char *end = str + strlen(str) - 1;
while (end > start && isspace((unsigned char)*end)) {
end--;
}
// Null-terminate the trimmed string
*(end + 1) = '\0';
// Move the trimmed part to the beginning if needed
if (start != str) {
memmove(str, start, end - start + 2); // +2 to include null terminator
}
}
int parse_double_array(const char *input, double *output, int max_count) {
char *dup = strdup(input); // 复制一份用于修改
char *token;
int count = 0;
token = strtok(dup, ",");
while (token != NULL && count < max_count) {
trim_whitespace(token); // 对每一个分割后的 token 去除前后空格
char *endptr;
double val = strtod(token, &endptr);
if (endptr == token || *endptr != '\0') {
fprintf(stderr, "Error: Invalid number in array: %s\n", token);
free(dup);
return -1; // 解析失败
}
output[count++] = val;
token = strtok(NULL, ",");
}
free(dup);
return count;
}
// 清理字符串中的不可见字符(包括 \r, \n, 空格等) // 清理字符串中的不可见字符(包括 \r, \n, 空格等)
char *sanitize_string(char *str) { char *sanitize_string(char *str) {
// 去除首部不可见字符 // 去除首部不可见字符
@ -611,6 +659,10 @@ void parse_config_line(Config *config, const char *line) {
return; return;
} }
// Then trim each part separately
trim_whitespace(key);
trim_whitespace(value);
if (strcmp(key, "animations") == 0) { if (strcmp(key, "animations") == 0) {
config->animations = atoi(value); config->animations = atoi(value);
} else if (strcmp(key, "animation_type_open") == 0) { } else if (strcmp(key, "animation_type_open") == 0) {
@ -638,34 +690,24 @@ void parse_config_line(Config *config, const char *line) {
} else if (strcmp(key, "animation_duration_close") == 0) { } else if (strcmp(key, "animation_duration_close") == 0) {
config->animation_duration_close = atoi(value); config->animation_duration_close = atoi(value);
} else if (strcmp(key, "animation_curve_move") == 0) { } else if (strcmp(key, "animation_curve_move") == 0) {
if (sscanf(value, "%lf,%lf,%lf,%lf", &config->animation_curve_move[0], int num = parse_double_array(value, config->animation_curve_move, 4);
&config->animation_curve_move[1], if (num != 4) {
&config->animation_curve_move[2], fprintf(stderr, "Error: Failed to parse animation_curve_move: %s\n", value);
&config->animation_curve_move[3]) != 4) {
fprintf(stderr, "Error: Invalid animation_curve_move format: %s\n",
value);
} }
} else if (strcmp(key, "animation_curve_open") == 0) { } else if (strcmp(key, "animation_curve_open") == 0) {
if (sscanf(value, "%lf,%lf,%lf,%lf", &config->animation_curve_open[0], int num = parse_double_array(value, config->animation_curve_open, 4);
&config->animation_curve_open[1], if (num != 4) {
&config->animation_curve_open[2], fprintf(stderr, "Error: Failed to parse animation_curve_open: %s\n", value);
&config->animation_curve_open[3]) != 4) {
fprintf(stderr, "Error: Invalid animation_curve_open format: %s\n",
value);
} }
} else if (strcmp(key, "animation_curve_tag") == 0) { } else if (strcmp(key, "animation_curve_tag") == 0) {
if (sscanf(value, "%lf,%lf,%lf,%lf", &config->animation_curve_tag[0], int num = parse_double_array(value, config->animation_curve_tag, 4);
&config->animation_curve_tag[1], &config->animation_curve_tag[2], if (num != 4) {
&config->animation_curve_tag[3]) != 4) { fprintf(stderr, "Error: Failed to parse animation_curve_tag: %s\n", value);
fprintf(stderr, "Error: Invalid animation_curve_tag format: %s\n", value);
} }
} else if (strcmp(key, "animation_curve_close") == 0) { } else if (strcmp(key, "animation_curve_close") == 0) {
if (sscanf(value, "%lf,%lf,%lf,%lf", &config->animation_curve_close[0], int num = parse_double_array(value, config->animation_curve_close, 4);
&config->animation_curve_close[1], if (num != 4) {
&config->animation_curve_close[2], fprintf(stderr, "Error: Failed to parse animation_curve_close: %s\n", value);
&config->animation_curve_close[3]) != 4) {
fprintf(stderr, "Error: Invalid animation_curve_close format: %s\n",
value);
} }
} else if (strcmp(key, "scroller_structs") == 0) { } else if (strcmp(key, "scroller_structs") == 0) {
config->scroller_structs = atoi(value); config->scroller_structs = atoi(value);
@ -925,6 +967,9 @@ void parse_config_line(Config *config, const char *line) {
config->autostart[1], config->autostart[2]) != 3) { config->autostart[1], config->autostart[2]) != 3) {
fprintf(stderr, "Error: Invalid autostart format: %s\n", value); fprintf(stderr, "Error: Invalid autostart format: %s\n", value);
} }
trim_whitespace(config->autostart[0]);
trim_whitespace(config->autostart[1]);
trim_whitespace(config->autostart[2]);
} else if (strcmp(key, "tags") == 0) { } else if (strcmp(key, "tags") == 0) {
config->tag_rules = config->tag_rules =
realloc(config->tag_rules, realloc(config->tag_rules,
@ -949,6 +994,9 @@ void parse_config_line(Config *config, const char *line) {
char *key = token; char *key = token;
char *val = colon + 1; char *val = colon + 1;
trim_whitespace(key);
trim_whitespace(val);
if (strcmp(key, "id") == 0) { if (strcmp(key, "id") == 0) {
rule->id = atoi(val); rule->id = atoi(val);
} else if (strcmp(key, "layout_name") == 0) { } else if (strcmp(key, "layout_name") == 0) {
@ -1002,6 +1050,9 @@ void parse_config_line(Config *config, const char *line) {
char *key = token; char *key = token;
char *val = colon + 1; char *val = colon + 1;
trim_whitespace(key);
trim_whitespace(val);
if (strcmp(key, "isfloating") == 0) { if (strcmp(key, "isfloating") == 0) {
rule->isfloating = atoi(val); rule->isfloating = atoi(val);
} else if (strcmp(key, "title") == 0) { } else if (strcmp(key, "title") == 0) {
@ -1043,6 +1094,8 @@ void parse_config_line(Config *config, const char *line) {
} else if (strcmp(key, "globalkeybinding") == 0) { } else if (strcmp(key, "globalkeybinding") == 0) {
char mod_str[256], keysym_str[256]; char mod_str[256], keysym_str[256];
sscanf(val, "%[^-]-%[a-zA-Z]", mod_str, keysym_str); sscanf(val, "%[^-]-%[a-zA-Z]", mod_str, keysym_str);
trim_whitespace(mod_str);
trim_whitespace(keysym_str);
rule->globalkeybinding.mod = parse_mod(mod_str); rule->globalkeybinding.mod = parse_mod(mod_str);
rule->globalkeybinding.keysym = parse_keysym(keysym_str); rule->globalkeybinding.keysym = parse_keysym(keysym_str);
} }
@ -1051,37 +1104,58 @@ void parse_config_line(Config *config, const char *line) {
} }
config->window_rules_count++; config->window_rules_count++;
} else if (strcmp(key, "monitorrule") == 0) { } else if (strcmp(key, "monitorrule") == 0) {
config->monitor_rules = config->monitor_rules =
realloc(config->monitor_rules, realloc(config->monitor_rules,
(config->monitor_rules_count + 1) * sizeof(ConfigMonitorRule)); (config->monitor_rules_count + 1) * sizeof(ConfigMonitorRule));
if (!config->monitor_rules) { if (!config->monitor_rules) {
fprintf(stderr, "Error: Failed to allocate memory for monitor rules\n"); fprintf(stderr, "Error: Failed to allocate memory for monitor rules\n");
return; return;
} }
ConfigMonitorRule *rule = ConfigMonitorRule *rule = &config->monitor_rules[config->monitor_rules_count];
&config->monitor_rules[config->monitor_rules_count]; memset(rule, 0, sizeof(ConfigMonitorRule));
memset(rule, 0, sizeof(ConfigMonitorRule));
char layout[256], name[256]; // 临时存储每个字段的原始字符串
int parsed = sscanf(value, "%255[^,],%f,%d,%255[^,],%d,%f,%d,%d", name, char raw_name[256], raw_layout[256];
&rule->mfact, &rule->nmaster, layout, &rule->rr, char raw_mfact[256], raw_nmaster[256], raw_rr[256];
&rule->scale, &rule->x, &rule->y); char raw_scale[256], raw_x[256], raw_y[256];
if (parsed == 8) { // 先读取所有字段为字符串
rule->name = strdup(name); int parsed = sscanf(value, "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255s",
rule->layout = strdup(layout); raw_name, raw_mfact, raw_nmaster, raw_layout,
raw_rr, raw_scale, raw_x, raw_y);
if (!rule->name || !rule->layout) { if (parsed == 8) {
// 修剪每个字段的空格
trim_whitespace(raw_name);
trim_whitespace(raw_mfact);
trim_whitespace(raw_nmaster);
trim_whitespace(raw_layout);
trim_whitespace(raw_rr);
trim_whitespace(raw_scale);
trim_whitespace(raw_x);
trim_whitespace(raw_y);
// 转换修剪后的字符串为特定类型
rule->name = strdup(raw_name);
rule->layout = strdup(raw_layout);
rule->mfact = atof(raw_mfact);
rule->nmaster = atoi(raw_nmaster);
rule->rr = atoi(raw_rr);
rule->scale = atof(raw_scale);
rule->x = atoi(raw_x);
rule->y = atoi(raw_y);
if (!rule->name || !rule->layout) {
if (rule->name) if (rule->name)
free((void *)rule->name); free((void *)rule->name);
if (rule->layout) if (rule->layout)
free((void *)rule->layout); free((void *)rule->layout);
fprintf(stderr, "Error: Failed to allocate memory for monitor rule\n"); fprintf(stderr, "Error: Failed to allocate memory for monitor rule\n");
return; return;
} }
config->monitor_rules_count++; config->monitor_rules_count++;
} else { } else {
fprintf(stderr, "Error: Invalid monitorrule format: %s\n", value); fprintf(stderr, "Error: Invalid monitorrule format: %s\n", value);
} }
@ -1092,6 +1166,8 @@ void parse_config_line(Config *config, const char *line) {
fprintf(stderr, "Error: Invalid bind format: %s\n", value); fprintf(stderr, "Error: Invalid bind format: %s\n", value);
return; return;
} }
trim_whitespace(env_type);
trim_whitespace(env_value);
setenv(env_type, env_value, 1); setenv(env_type, env_value, 1);
} else if (strncmp(key, "exec", 9) == 0) { } else if (strncmp(key, "exec", 9) == 0) {
@ -1150,6 +1226,13 @@ void parse_config_line(Config *config, const char *line) {
fprintf(stderr, "Error: Invalid bind format: %s\n", value); fprintf(stderr, "Error: Invalid bind format: %s\n", value);
return; return;
} }
trim_whitespace(mod_str);
trim_whitespace(keysym_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
binding->mod = parse_mod(mod_str); binding->mod = parse_mod(mod_str);
binding->keysym = parse_keysym(keysym_str); binding->keysym = parse_keysym(keysym_str);
@ -1193,6 +1276,13 @@ void parse_config_line(Config *config, const char *line) {
fprintf(stderr, "Error: Invalid mousebind format: %s\n", value); fprintf(stderr, "Error: Invalid mousebind format: %s\n", value);
return; return;
} }
trim_whitespace(mod_str);
trim_whitespace(button_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
binding->mod = parse_mod(mod_str); binding->mod = parse_mod(mod_str);
binding->button = parse_button(button_str); binding->button = parse_button(button_str);
@ -1235,6 +1325,14 @@ void parse_config_line(Config *config, const char *line) {
return; return;
} }
trim_whitespace(mod_str);
trim_whitespace(dir_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
binding->mod = parse_mod(mod_str); binding->mod = parse_mod(mod_str);
binding->dir = parse_direction(dir_str); binding->dir = parse_direction(dir_str);
binding->arg.v = NULL; binding->arg.v = NULL;
@ -1280,6 +1378,15 @@ void parse_config_line(Config *config, const char *line) {
return; return;
} }
trim_whitespace(mod_str);
trim_whitespace(motion_str);
trim_whitespace(fingers_count_str);
trim_whitespace(func_name);
trim_whitespace(arg_value);
trim_whitespace(arg_value2);
trim_whitespace(arg_value3);
trim_whitespace(arg_value4);
binding->mod = parse_mod(mod_str); binding->mod = parse_mod(mod_str);
binding->motion = parse_direction(motion_str); binding->motion = parse_direction(motion_str);
binding->fingers_count = atoi(fingers_count_str); binding->fingers_count = atoi(fingers_count_str);