* 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 tile 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;
}