From: Eric Branlund Date: Sun, 25 Aug 2019 07:30:24 +0000 (-0700) Subject: Since ANGBAND_GRAF in Hengband is not the preference file name, added an extra field... X-Git-Tag: version-1-6-2a~22 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=97204d37dcf2cb988f598afd2194e782e3ae50fd;p=hengbandforosx%2Fhengbandosx.git Since ANGBAND_GRAF in Hengband is not the preference file name, added an extra field in the configuration to be what ANGBAND_GRAF will be assigned for a tile set. Largely replaced the implementation in grafmode.c with something that will work with Hengband's routines. If Hengband chooses to adopt the datafile.h/datafile.c parsing from Angband, then it would make sense to go back to Angband's version of grafmode.c. --- diff --git a/src/grafmode.c b/src/grafmode.c index ea95d0242..c5ae2766b 100644 --- a/src/grafmode.c +++ b/src/grafmode.c @@ -15,215 +15,492 @@ * and not for profit purposes provided that this copyright and statement * are included in all such copies. Other copyrights may also apply. */ - +/* + * Imported from Angband 4.2.0 to support main-cocoa.m for Hengband. Did not + * bring over the datafile parsing (datafile.h and datafile.c) so the + * implementation here is different from that in Angband. + */ #include "angband.h" -#include "datafile.h" #include "grafmode.h" -#include "init.h" + +#define GFPARSE_HAVE_NOTHING (0) +#define GFPARSE_HAVE_NAME (1) +#define GFPARSE_HAVE_DIR (2) +#define GFPARSE_HAVE_SIZE (4) +#define GFPARSE_HAVE_PREF (8) +#define GFPARSE_HAVE_EXTRA (16) +#define GFPARSE_HAVE_GRAF (32) + +typedef struct GrafModeParserState { + graphics_mode* list; + char* file_name; + int dir_len; + int line_no; + int stage; + errr result; +} GrafModeParserState; + + +/* This is the global state exposed to Angband. */ graphics_mode *graphics_modes; graphics_mode *current_graphics_mode = NULL; int graphics_mode_high_id; -static enum parser_error parse_graf_name(struct parser *p) { - graphics_mode *list = parser_priv(p); - graphics_mode *mode = mem_zalloc(sizeof(graphics_mode)); - if (!mode) { - return PARSE_ERROR_OUT_OF_MEMORY; - } - mode->pNext = list; - mode->grafID = parser_getuint(p, "index"); - strncpy(mode->menuname, parser_getstr(p, "menuname"), 32); - - mode->alphablend = 0; - mode->overdrawRow = 0; - mode->overdrawMax = 0; - strncpy(mode->file, "", 32); - strncpy(mode->pref, "none", 32); - - parser_setpriv(p, mode); - return PARSE_ERROR_NONE; -} - -static enum parser_error parse_graf_directory(struct parser *p) { - graphics_mode *mode = parser_priv(p); - const char *dir = parser_getsym(p, "dirname"); - if (!mode) { - return PARSE_ERROR_INVALID_VALUE; - } - /* Build a usable path */ - path_build(mode->path, sizeof(mode->path), ANGBAND_DIR_TILES, dir); - - return PARSE_ERROR_NONE; +static int check_last_mode(GrafModeParserState* pgps) { + int result = 0; + + if ((pgps->stage & GFPARSE_HAVE_DIR) == 0) { + result = 1; + msg_format("no directory set for tile set, %s, in %s", + pgps->list->menuname, pgps->file_name); + } + if ((pgps->stage & GFPARSE_HAVE_SIZE) == 0) { + result = 1; + msg_format("no size set for tile set, %s, in %s", + pgps->list->menuname, pgps->file_name); + } + if ((pgps->stage & GFPARSE_HAVE_PREF) == 0) { + result = 1; + msg_format("no preference file for tile set, %s, in %s", + pgps->list->menuname, pgps->file_name); + } + if ((pgps->stage & GFPARSE_HAVE_GRAF) == 0) { + result = 1; + msg_format("no graf string set for tile set, %s, in %s", + pgps->list->menuname, pgps->file_name); + } + return result; } -static enum parser_error parse_graf_size(struct parser *p) { - graphics_mode *mode = parser_priv(p); - if (!mode) { - return PARSE_ERROR_INVALID_VALUE; - } - mode->cell_width = parser_getuint(p, "wid"); - mode->cell_height = parser_getuint(p, "hgt"); - strncpy(mode->file, parser_getstr(p, "filename"), 32); - return PARSE_ERROR_NONE; -} -static enum parser_error parse_graf_pref(struct parser *p) { - graphics_mode *mode = parser_priv(p); - if (!mode) { - return PARSE_ERROR_INVALID_VALUE; +static void parse_line(GrafModeParserState* pgps, const char* line) { + static const char whitespc[] = " \t\v\f"; + int offset = 0; + int stage; + + while (line[offset] && strchr(whitespc, line[offset]) != 0) { + ++offset; + } + if (! line[offset] || line[offset] == '#') { + return; + } + + if (strncmp(line + offset, "name:", 5) == 0) { + stage = GFPARSE_HAVE_NAME; + offset += 5; + } else if (strncmp(line + offset, "directory:", 10) == 0) { + stage = GFPARSE_HAVE_DIR; + offset += 10; + } else if (strncmp(line + offset, "size:", 5) == 0) { + stage = GFPARSE_HAVE_SIZE; + offset += 5; + } else if (strncmp(line + offset, "pref:", 5) == 0) { + stage = GFPARSE_HAVE_PREF; + offset += 5; + } else if (strncmp(line + offset, "extra:", 6) == 0) { + stage = GFPARSE_HAVE_EXTRA; + offset += 6; + } else if (strncmp(line + offset, "graf:", 5) == 0) { + stage = GFPARSE_HAVE_GRAF; + offset += 5; + } else { + msg_format("Unexpected data at line %d of %s", pgps->line_no, + pgps->file_name); + pgps->result = 1; + return; + } + + if (stage == GFPARSE_HAVE_NAME) { + graphics_mode *new_mode; + + if (pgps->stage != GFPARSE_HAVE_NOTHING) { + if (check_last_mode(pgps) != 0) { + pgps->result = 1; + } } - strncpy(mode->pref, parser_getstr(p, "prefname"), 32); - return PARSE_ERROR_NONE; -} -static enum parser_error parse_graf_extra(struct parser *p) { - graphics_mode *mode = parser_priv(p); - if (!mode) { - return PARSE_ERROR_INVALID_VALUE; + pgps->stage = GFPARSE_HAVE_NAME; + new_mode = (graphics_mode *) malloc(sizeof(graphics_mode)); + if (new_mode == 0) { + pgps->result = 1; + msg_format("failed memory allocation for tile set " + "information at line %d of %s", pgps->line_no, + pgps->file_name); + return; } - mode->alphablend = parser_getuint(p, "alpha"); - mode->overdrawRow = parser_getuint(p, "row"); - mode->overdrawMax = parser_getuint(p, "max"); - return PARSE_ERROR_NONE; -} - -static struct parser *init_parse_grafmode(void) { - struct parser *p = parser_new(); - parser_setpriv(p, NULL); - - parser_reg(p, "name uint index str menuname", parse_graf_name); - parser_reg(p, "directory sym dirname", parse_graf_directory); - parser_reg(p, "size uint wid uint hgt str filename", parse_graf_size); - parser_reg(p, "pref str prefname", parse_graf_pref); - parser_reg(p, "extra uint alpha uint row uint max", parse_graf_extra); - - return p; -} - -static errr finish_parse_grafmode(struct parser *p) { - graphics_mode *mode, *n; - int max = 0; - int count = 0; - int i; - - /* See how many graphics modes we have and what the highest index is */ - if (p) { - mode = parser_priv(p); - while (mode) { - if (mode->grafID > max) { - max = mode->grafID; + new_mode->pNext = pgps->list; + new_mode->grafID = 0; + new_mode->alphablend = 0; + new_mode->overdrawRow = 0; + new_mode->overdrawMax = 0; + new_mode->cell_width = 0; + new_mode->cell_height = 0; + new_mode->path[0] = '\0'; + new_mode->pref[0] = '\0'; + new_mode->file[0] = '\0'; + new_mode->menuname[0] = '\0'; + new_mode->graf[0] = '\0'; + pgps->list = new_mode; + } else { + if (pgps->stage == GFPARSE_HAVE_NOTHING) { + pgps->result = 1; + msg_format("values set before tile set name given at line %d" + " of %s", pgps->line_no, pgps->file_name); + return; + } + if (pgps->stage & stage) { + msg_format("values set more than once for tile set, %s, at line " + " %d of %s", pgps->list->menuname, pgps->line_no, + pgps->file_name); + } + } + + switch (stage) { + case GFPARSE_HAVE_NAME: + { + unsigned int id; + int nscan; + + if (sscanf(line + offset, "%u:%n", &id, &nscan) == 1) { + if (id > 255) { + pgps->result = 1; + msg_format("ID greater than 255 for tile set at line" + " %d of %s", pgps->line_no, pgps->file_name); + } else if (id == GRAPHICS_NONE) { + pgps->result = 1; + msg_format("ID of tile set matches value, %d, reserved " + " for no graphics at line %d of %s", + GRAPHICS_NONE, pgps->line_no, pgps->file_name); + } else { + graphics_mode *mode = pgps->list->pNext; + + while (1) { + if (mode == 0) { + break; + } + if (mode->grafID == id) { + pgps->result = 1; + msg_format("ID for tile set, %s, at line %d of %s" + " is the same as for tile set %s", + pgps->list->menuname, pgps->line_no, + pgps->file_name, mode->menuname); + break; } - count++; mode = mode->pNext; + } + pgps->list->grafID = id; + } + offset += nscan; + if (strlen(line + offset) >= sizeof(pgps->list->menuname)) { + pgps->result = 1; + msg_format("name is too long for tile set at line %d" + " of %s", pgps->line_no, pgps->file_name); + } else if (line[offset] == '\0') { + pgps->result = 1; + msg_format("empty name for tile set at line %d of %s", + pgps->line_no, pgps->file_name); + } else { + strcpy(pgps->list->menuname, line + offset); } + } else { + pgps->result = 1; + msg_format("malformed ID for tile set at line %d of %s", + pgps->line_no, pgps->file_name); + } } - - /* Copy the loaded modes to the global variable */ - if (graphics_modes) { - close_graphics_modes(); + break; + + case GFPARSE_HAVE_DIR: + { + size_t len = strlen(line + offset); + size_t sep_len = strlen(PATH_SEP); + + if (len >= sizeof(pgps->list->path) || + len + pgps->dir_len + sep_len >= sizeof(pgps->list->path)) { + pgps->result = 1; + msg_format("directory name is too long for tile set, %s, at" + " line %d of %s", pgps->list->menuname, + pgps->line_no, pgps->file_name); + } else if (line[offset] == '\0') { + pgps->result = 1; + msg_format("empty directory name for tile set, %s, at line" + " line %d of %s", pgps->list->menuname, + pgps->line_no, pgps->file_name); + } else { + /* + * Temporarily hack the path to list.txt so it is not necessary + * to separately store the base directory for the tile files. + */ + char chold = pgps->file_name[pgps->dir_len]; + + pgps->file_name[pgps->dir_len] = '\0'; + path_build( + pgps->list->path, + sizeof(pgps->list->path), + pgps->file_name, + line + offset + ); + pgps->file_name[pgps->dir_len] = chold; + } } - - graphics_modes = mem_zalloc(sizeof(graphics_mode) * (count+1)); - if (p) { - mode = parser_priv(p); - for (i = count-1; i >= 0; i--, mode = mode->pNext) { - memcpy(&(graphics_modes[i]), mode, sizeof(graphics_mode)); - graphics_modes[i].pNext = &(graphics_modes[i+1]); + break; + + case GFPARSE_HAVE_SIZE: + { + unsigned w, h; + int nscan; + + if (sscanf(line + offset, "%u:%u:%n", &w, &h, &nscan) == 2) { + if (w > 0) { + pgps->list->cell_width = w; + } else { + pgps->result = 1; + msg_format("zero width for tile set, %s, at line" + " %d of %s", pgps->list->menuname, + pgps->line_no, pgps->file_name); + } + if (h > 0) { + pgps->list->cell_height = h; + } else { + pgps->result = 1; + msg_format("zero height for tile set, %s, at line" + " %d of %s", pgps->list->menuname, + pgps->line_no, pgps->file_name); } + offset += nscan; + if (strlen(line + offset) >= sizeof(pgps->list->file)) { + pgps->result = 1; + msg_format("file name is too long for tile set, %s," + " at line %d of %s", pgps->list->menuname, + pgps->line_no, pgps->file_name); + } else if (line[offset] == '\0') { + pgps->result = 1; + msg_format("empty file name for tile set, %s, at line %d" + " of %s", pgps->list->menuname, pgps->line_no, + pgps->file_name); + } else { + (void) strcpy(pgps->list->file, line + offset); + } + } else { + pgps->result = 1; + msg_format("malformed dimensions for tile set, %s, at line" + " %d of %s", pgps->list->menuname, pgps->line_no, + pgps->file_name); + } } - - /* Hardcode the no graphics option */ - graphics_modes[count].pNext = NULL; - graphics_modes[count].grafID = GRAPHICS_NONE; - graphics_modes[count].alphablend = 0; - graphics_modes[count].overdrawRow = 0; - graphics_modes[count].overdrawMax = 0; - strncpy(graphics_modes[count].pref, "none", 8); - strncpy(graphics_modes[count].path, "", 32); - strncpy(graphics_modes[count].file, "", 32); - strncpy(graphics_modes[count].menuname, "None", 32); - - graphics_mode_high_id = max; - - /* Set the default graphics mode to be no graphics */ - current_graphics_mode = &(graphics_modes[count]); - - if (p) { - mode = parser_priv(p); - while (mode) { - n = mode->pNext; - mem_free(mode); - mode = n; + break; + + case GFPARSE_HAVE_PREF: + if (strlen(line + offset) >= sizeof(pgps->list->pref)) { + pgps->result = 1; + msg_format("preference file name is too long for tile set, %s, " + "at line %d of %s", pgps->list->menuname, pgps->line_no, + pgps->file_name); + } else if (line[offset] == '\0') { + pgps->result = 1; + msg_format("empty preference file name for tile set, %s, " + "at line %d of %s", pgps->list->menuname, pgps->line_no, + pgps->file_name); + } else { + strcpy(pgps->list->pref, line + offset); + } + break; + + case GFPARSE_HAVE_EXTRA: + { + unsigned int alpha, startdbl, enddbl; + int nscan; + + if (sscanf(line + offset, "%u:%u:%u%n", + &alpha, &startdbl, &enddbl, &nscan) == 3 && + (line[offset + nscan] == '\0' || + strchr(whitespc, line[offset + nscan]) != 0 || + line[offset + nscan] == '#')) { + if (startdbl > 255 || enddbl > 255) { + pgps->result = 1; + msg_format("overdrawMax or overdrawRow is greater than" + " 255 for tiles set, %s, at line %d of %s", + pgps->list->menuname, pgps->line_no, + pgps->file_name); + } else if (enddbl < startdbl) { + pgps->result = 1; + msg_format("overdrawMax less than overdrawRow for tile" + "set, %s, at line %d of %s", + pgps->list->menuname, pgps->line_no, + pgps->file_name); + } else { + pgps->list->alphablend = (alpha != 0); + pgps->list->overdrawRow = startdbl; + pgps->list->overdrawMax = enddbl; } - - parser_setpriv(p, NULL); - parser_destroy(p); + } else { + pgps->result = 1; + msg_format("malformed data for tile set, %s, at line %d of" + " %s", pgps->list->menuname, pgps->line_no, + pgps->file_name); + } } - return PARSE_ERROR_NONE; -} + break; + + case GFPARSE_HAVE_GRAF: + if (strlen(line + offset) >= sizeof(pgps->list->graf)) { + pgps->result = 1; + msg_format("graf string is too long for tile set, %s, at line %d" + " of %s", pgps->list->menuname, pgps->line_no, + pgps->file_name); + } else if (line[offset] == '\0') { + pgps->result = 1; + msg_format("empty graf string for tile set, %s, at line %d of %s", + pgps->list->menuname, pgps->line_no, pgps->file_name); + } else { + strcpy(pgps->list->graf, line + offset); + } + break; + } -static void print_error(const char *name, struct parser *p) { - struct parser_state s; - parser_getstate(p, &s); - msg("Parse error in %s line %d column %d: %s: %s", name, - s.line, s.col, s.msg, parser_error_str[s.error]); - event_signal(EVENT_MESSAGE_FLUSH); + if (pgps->result == 0) { + pgps->stage |= stage; + } } -bool init_graphics_modes(void) { - char buf[1024]; - - ang_file *f; - struct parser *p; - errr e = 0; - int line_no = 0; +static void finish_parse_grafmode(GrafModeParserState* pgps, + int transfer_results) { + /* + * Check what was read for the last mode parsed, since parse_line did + * not. + */ + if (transfer_results) { + if (pgps->list == 0 || pgps->stage == GFPARSE_HAVE_NOTHING) { + msg_format("no graphics modes in %s", pgps->file_name); + } else { + if (check_last_mode(pgps) != 0) { + transfer_results = 0; + pgps->result = 1; + } + } + } - /* Build the filename */ - path_build(buf, sizeof(buf), ANGBAND_DIR_TILES, "list.txt"); + if (transfer_results) { + graphics_mode *mode = pgps->list; + int max = GRAPHICS_NONE; + int count = 0; + graphics_mode *new_list; + + while (mode) { + if (mode->grafID > max) { + max = mode->grafID; + } + ++count; + mode = mode->pNext; + } - f = file_open(buf, MODE_READ, FTYPE_TEXT); - if (!f) { - msg("Cannot open '%s'.", buf); - finish_parse_grafmode(NULL); + /* Assemble the modes into a contiguous block of memory. */ + new_list = (graphics_mode *) + malloc(sizeof(graphics_mode) * (count + 1)); + if (new_list != 0) { + int i; + + mode = pgps->list; + for (i = count - 1; i >= 0; --i, mode = mode->pNext) { + memcpy(&(new_list[i]), mode, sizeof(graphics_mode)); + new_list[i].pNext = &(new_list[i + 1]); + } + + /* Hardcode the no graphics option. */ + new_list[count].pNext = NULL; + new_list[count].grafID = GRAPHICS_NONE; + new_list[count].alphablend = 0; + new_list[count].overdrawRow = 0; + new_list[count].overdrawMax = 0; + strncpy( + new_list[count].pref, "none", sizeof(new_list[count].pref)); + strncpy( + new_list[count].path, "", sizeof(new_list[count].path)); + strncpy( + new_list[count].file, "", sizeof(new_list[count].file)); + strncpy( + new_list[count].menuname, + "Classic ASCII", + sizeof(new_list[count].menuname) + ); + strncpy( + new_list[count].graf, "ascii", sizeof(new_list[count].graf)); + + /* Release the old global state. */ + close_graphics_modes(); + + graphics_modes = new_list; + graphics_mode_high_id = max; + /* Set the default graphics mode to be no graphics */ + current_graphics_mode = &(graphics_modes[count]); } else { - char line[1024]; + pgps->result = 1; + msg_print("failed memory allocation for new graphics modes"); + } + } - p = init_parse_grafmode(); - while (file_getl(f, line, sizeof line)) { - line_no++; + /* Release the memory allocated for parsing the file. */ + while (pgps->list != 0) { + graphics_mode *mode = pgps->list; + + pgps->list = mode->pNext; + free(mode); + } +} - e = parser_parse(p, line); - if (e != PARSE_ERROR_NONE) { - print_error(buf, p); - break; - } - } - finish_parse_grafmode(p); - file_close(f); +bool init_graphics_modes(void) { + char buf[1024]; + char line[1024]; + GrafModeParserState gps = { 0, buf, 0, 0, GFPARSE_HAVE_NOTHING, 0 }; + FILE *f; + + /* Build the filename */ + path_build(line, sizeof(line), ANGBAND_DIR_XTRA, "graf"); + gps.dir_len = strlen(line); + path_build(buf, sizeof(buf), line, "list.txt"); + + f = my_fopen(buf, "r"); + if (!f) { + msg_format("Cannot open '%s'.", buf); + gps.result = 1; + } else { + while (my_fgets(f, line, sizeof line) == 0) { + ++gps.line_no; + parse_line(&gps, line); + if (gps.result != 0) { + break; + } } - /* Result */ - return e == PARSE_ERROR_NONE; + finish_parse_grafmode(&gps, gps.result == 0); + my_fclose(f); + } + + /* Result */ + return gps.result == 0; } + void close_graphics_modes(void) { - if (graphics_modes) { - mem_free(graphics_modes); - graphics_modes = NULL; - } + if (graphics_modes) { + free(graphics_modes); + graphics_modes = NULL; + } + current_graphics_mode = NULL; } + graphics_mode *get_graphics_mode(byte id) { - graphics_mode *test = graphics_modes; - while (test) { - if (test->grafID == id) { - return test; - } - test = test->pNext; + graphics_mode *test = graphics_modes; + while (test) { + if (test->grafID == id) { + return test; } - return NULL; + test = test->pNext; + } + return NULL; } diff --git a/src/grafmode.h b/src/grafmode.h index 3cb022ff1..1c22f0c50 100644 --- a/src/grafmode.h +++ b/src/grafmode.h @@ -56,6 +56,11 @@ typedef struct _graphics_mode { char pref[32]; char file[32]; char menuname[32]; + /* + * This is a hack for Hengband: ANGBAND_GRAF set to this rather + * then the pref field above. + */ + char graf[32]; } graphics_mode; extern graphics_mode *graphics_modes;