/* * enigma/levelfile.c - provide routines that load a level * configuration file (which points to a set of levels) and a level * file itself. * * Copyright 2000 Simon Tatham. All rights reserved. * * Enigma is licensed under the MIT licence. See the file LICENCE for * details. * * - we are all amf - */ #include #include #include #include #include "enigma.h" static level *level_load(char *filename) { FILE *fp; char buf[FILENAME_MAX+10]; char fname[FILENAME_MAX]; level *level; int nlines; fname[sizeof(fname)-1] = '\0'; strncpy(fname, LEVELDIR, sizeof(fname)); strncpy(fname + strlen(fname), filename, sizeof(fname)-strlen(fname)); if (fname[sizeof(fname)-1] != '\0') { fatal("File name length overflow"); } fp = fopen(fname, "r"); if (!fp) { fatal("Unable to read level file"); } level = level_new(); level->title = NULL; level->width = level->height = -1; level->flags = 0; nlines = 0; while (fgets(buf, sizeof(buf), fp)) { if (buf[strlen(buf)-1] != '\n') { fatal("Line length overflow in level file"); } buf[strcspn(buf, "\r\n")] = '\0'; if (!buf[0]) continue; if (ishdr(buf, "Title: ")) { if (level->title) { fatal("Multiple titles in level file"); } level->title = dupstr(buf + 7); } else if (ishdr(buf, "Width: ")) { level->width = atoi(buf + 7); } else if (ishdr(buf, "Height: ")) { level->height = atoi(buf + 8); } else if (ishdr(buf, "Flags: ")) { char *p = buf + 7; char *q; while (*p) { while (*p && isspace(*p)) p++; q = p; while (*p && !isspace(*p)) p++; if (*p) *p++ = '\0'; if (!strcmp(q, "flimsy-bombs")) { level->flags |= LEVEL_FLIMSY_BOMBS; } else if (!strcmp(q, "relative-priority")) { level->flags |= LEVEL_REL_PRIORITY; } else { fatal("Unknown flag keyword in level file"); } } } else if (ishdr(buf, "Map: ")) { if (level->leveldata == NULL) { fatal("Map before size in level file"); } if ((int)strlen(buf + 5) != level->width) { fatal("Wrong length map line in level file"); } if (nlines >= level->height) { fatal("Too many map lines in level file"); } memcpy(level->leveldata + level->width * nlines, buf + 5, level->width); nlines++; } else { fatal("Unrecognised keyword in level file"); } if (level->width > 0 && level->height > 0 && level->leveldata == NULL) level_setsize(level, level->width, level->height); } if (nlines < level->height) { fatal("Not enough map lines in level file"); } fclose(fp); { char buf[256], buf2[384]; char *err; err = validate(level, buf, sizeof(buf)); if (err) { sprintf(buf2, "Error in level file '%.64s': %s", filename, err); fatal(buf2); } } return level; } levelset *levelset_load(char *filename) { FILE *fp; char buf[FILENAME_MAX+10]; char fname[FILENAME_MAX]; levelset *set; /* * Sanity-check level set name. */ if (filename[strcspn(filename, SETNAME_INVALID)] != '\0') { fatal("Invalid character in level set name"); } fname[sizeof(fname)-1] = '\0'; strncpy(fname, LEVELDIR, sizeof(fname)); strncpy(fname + strlen(fname), filename, sizeof(fname)-strlen(fname)); strncpy(fname + strlen(fname), ".set", sizeof(fname)-strlen(fname)); if (fname[sizeof(fname)-1] != '\0') { fatal("File name length overflow"); } fp = fopen(fname, "r"); if (!fp) { fatal("Unable to read level set file"); } set = levelset_new(); set->title = NULL; set->name = filename; while (fgets(buf, sizeof(buf), fp)) { if (buf[strlen(buf)-1] != '\n') { fatal("Line length overflow in level set file"); } buf[strcspn(buf, "\r\n")] = '\0'; if (!buf[0]) continue; if (ishdr(buf, "Title: ")) { if (set->title) { fatal("Multiple titles in level set file"); } set->title = dupstr(buf + 7); } else if (ishdr(buf, "Level: ")) { levelset_nlevels(set, set->nlevels+1); set->levels[set->nlevels-1] = level_load(buf + 7); } else { fatal("Unrecognised keyword in level set file"); } } fclose(fp); return set; }