diff --git a/include/system4/ini.h b/include/system4/ini.h index 6726cd7..ea61f20 100644 --- a/include/system4/ini.h +++ b/include/system4/ini.h @@ -61,7 +61,12 @@ struct ini_entry { struct ini_value value; }; -struct ini_entry *ini_parse(const char *path, size_t *nr_entries); +enum ini_error { + INI_FILE_ERROR = -1, + INI_DATA_ERROR = -2, +}; + +struct ini_entry *ini_parse(const char *path, int *nr_entries); struct ini_entry *ini_make_entry(struct string *name, struct ini_value value); void ini_free_entry(struct ini_entry *entry); diff --git a/src/ini.c b/src/ini.c index 9661f2c..bcb6f13 100644 --- a/src/ini.c +++ b/src/ini.c @@ -24,6 +24,7 @@ #include "ini_parser.tab.h" extern FILE *yini_in; +extern unsigned long yini_line; static void list_assign(struct ini_value *list, size_t i, struct ini_value *item) { @@ -39,12 +40,15 @@ static void list_assign(struct ini_value *list, size_t i, struct ini_value *item list->list[i] = *item; } -struct ini_entry *ini_parse(const char *path, size_t *nr_entries) +struct ini_entry *ini_parse(const char *path, int *nr_entries) { struct ini_entry _e; - if (!(yini_in = fopen(path, "rb"))) - ERROR("failed to open '%s': %s", path, strerror(errno)); + if (!(yini_in = fopen(path, "rb"))) { + *nr_entries = INI_FILE_ERROR; + return NULL; + } + yini_line = 1; yini_parse(); kvec_t(struct ini_entry) entries; @@ -65,8 +69,10 @@ struct ini_entry *ini_parse(const char *path, size_t *nr_entries) struct ini_entry *other = &kv_A(entries, i); if (strcmp(e->name->text, other->name->text)) continue; - if (other->value.type != INI_LIST) - ERROR("list assignment to non-list: %s[%" SIZE_T_FMT "]", e->name, e->value._list_pos); + if (other->value.type != INI_LIST) { + WARNING("ignoring list assignment to non-list: %s[%" SIZE_T_FMT "]", e->name, e->value._list_pos); + goto end_list_assign; + } free_string(e->name); list = other; break; @@ -87,6 +93,7 @@ struct ini_entry *ini_parse(const char *path, size_t *nr_entries) } list_assign(&list->value, e->value._list_pos, e->value._list_value); + end_list_assign: free(e->value._list_value); free(e); } diff --git a/src/ini_lexer.l b/src/ini_lexer.l index 71ebd9e..cac2850 100644 --- a/src/ini_lexer.l +++ b/src/ini_lexer.l @@ -52,7 +52,7 @@ true return TRUE; false return FALSE; Formation return FORMATION; [0-9]+ yini_lval.i = atoi(yini_text); return INTEGER; -[a-zA-Z]+[a-zA-Z0-9]* yini_lval.s = make_string(yini_text, yini_leng); return IDENTIFIER; +[a-zA-Z]+[a-zA-Z0-9_-]* yini_lval.s = make_string(yini_text, yini_leng); return IDENTIFIER; \" string_buf_ptr = string_buf; BEGIN(str); diff --git a/src/system4.c b/src/system4.c index 6ef392a..1db07cc 100644 --- a/src/system4.c +++ b/src/system4.c @@ -95,10 +95,12 @@ static int ini_integer(struct ini_entry *entry) static void read_config(const char *path) { - size_t ini_size; + int ini_size; struct ini_entry *ini = ini_parse(path, &ini_size); + if (!ini) + ERROR("Failed to read %s", path); - for (size_t i = 0; i < ini_size; i++) { + for (int i = 0; i < ini_size; i++) { if (!strcmp(ini[i].name->text, "GameName")) { config.game_name = strdup(ini_string(&ini[i])->text); } else if (!strcmp(ini[i].name->text, "CodeName")) { @@ -115,6 +117,40 @@ static void read_config(const char *path) free(ini); } +static void read_user_config_file(const char *path) +{ + int ini_size; + struct ini_entry *ini = ini_parse(path, &ini_size); + if (!ini) + return; + + for (int i = 0; i < ini_size; i++) { + if (!strcmp(ini[i].name->text, "font-mincho")) { + font_paths[FONT_MINCHO] = xstrdup(ini_string(&ini[i])->text); + } else if (!strcmp(ini[i].name->text, "font-gothic")) { + font_paths[FONT_GOTHIC] = xstrdup(ini_string(&ini[i])->text); + } + ini_free_entry(&ini[i]); + } + free(ini); +} + +static void read_user_config(void) +{ + char *path; + + // global config + path = xmalloc(PATH_MAX); + snprintf(path, PATH_MAX-1, "%s/.xsys4rc", config.home_dir); + read_user_config_file(path); + free(path); + + // game-specific config + path = gamedir_path(".xsys4rc"); + read_user_config_file(path); + free(path); +} + static char *ald_filenames[ALDFILETYPE_MAX][ALD_FILEMAX]; static int ald_count[ALDFILETYPE_MAX]; @@ -329,6 +365,9 @@ int main(int argc, char *argv[]) int err = AIN_SUCCESS; bool audit = false; + char *font_mincho = NULL; + char *font_gothic = NULL; + while (1) { static struct option long_options[] = { { "help", no_argument, 0, LOPT_HELP }, @@ -357,10 +396,10 @@ int main(int argc, char *argv[]) #endif break; case LOPT_FONT_MINCHO: - font_paths[FONT_MINCHO] = optarg; + font_mincho = optarg; break; case LOPT_FONT_GOTHIC: - font_paths[FONT_GOTHIC] = optarg; + font_gothic = optarg; break; } } @@ -394,6 +433,14 @@ int main(int argc, char *argv[]) #endif config_init(); + read_user_config(); + + // NOTE: some command line options are handled here so that they + // will override settings from .xsys4rc files + if (font_mincho) + font_paths[FONT_MINCHO] = font_mincho; + if (font_gothic) + font_paths[FONT_GOTHIC] = font_gothic; if (!(ain = ain_open(ainfile, &err))) { ERROR("%s", ain_strerror(err)); diff --git a/src/tools/ainedit/pje.c b/src/tools/ainedit/pje.c index dbc1d3e..a6fe301 100644 --- a/src/tools/ainedit/pje.c +++ b/src/tools/ainedit/pje.c @@ -142,10 +142,10 @@ static void pje_string_list(struct ini_entry *entry, struct string_list *out) static void pje_parse(const char *path, struct pje_config *config) { - size_t ini_size; + int ini_size; struct ini_entry *ini = ini_parse(path, &ini_size); - for (size_t i = 0; i < ini_size; i++) { + for (int i = 0; i < ini_size; i++) { if (!strcmp(ini[i].name->text, "ProjectName")) { config->project_name = pje_string(&ini[i]); } else if (!strcmp(ini[i].name->text, "CodeName")) { @@ -200,10 +200,10 @@ static void pje_parse(const char *path, struct pje_config *config) static void pje_parse_inc(const char *path, struct inc_config *config) { - size_t ini_size; + int ini_size; struct ini_entry *ini = ini_parse(path, &ini_size); - for (size_t i = 0; i < ini_size; i++) { + for (int i = 0; i < ini_size; i++) { if (!strcmp(ini[i].name->text, "Source")) { pje_string_list(&ini[i], &config->source); } else if (!strcmp(ini[i].name->text, "SystemSource")) {