1 /*
2 * enigma/levelfile.c - provide routines that load a level
3 * configuration file (which points to a set of levels) and a level
4 * file itself.
5 *
6 * Copyright 2000 Simon Tatham. All rights reserved.
7 *
8 * Enigma is licensed under the MIT licence. See the file LICENCE for
9 * details.
10 *
11 * - we are all amf -
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18
19 #include "enigma.h"
20
level_load(char * filename)21 static level *level_load(char *filename) {
22 FILE *fp;
23 char buf[FILENAME_MAX+10];
24 char fname[FILENAME_MAX];
25 level *level;
26 int nlines;
27
28 fname[sizeof(fname)-1] = '\0';
29 strncpy(fname, LEVELDIR, sizeof(fname));
30 strncpy(fname + strlen(fname), filename, sizeof(fname)-strlen(fname));
31 if (fname[sizeof(fname)-1] != '\0') {
32 fatal("File name length overflow");
33 }
34
35 fp = fopen(fname, "r");
36 if (!fp) {
37 fatal("Unable to read level file");
38 }
39
40 level = level_new();
41 level->title = NULL;
42 level->width = level->height = -1;
43 level->flags = 0;
44 nlines = 0;
45
46 while (fgets(buf, sizeof(buf), fp)) {
47 if (buf[strlen(buf)-1] != '\n') {
48 fatal("Line length overflow in level file");
49 }
50 buf[strcspn(buf, "\r\n")] = '\0';
51 if (!buf[0])
52 continue;
53 if (ishdr(buf, "Title: ")) {
54 if (level->title) {
55 fatal("Multiple titles in level file");
56 }
57 level->title = dupstr(buf + 7);
58 } else if (ishdr(buf, "Width: ")) {
59 level->width = atoi(buf + 7);
60 } else if (ishdr(buf, "Height: ")) {
61 level->height = atoi(buf + 8);
62 } else if (ishdr(buf, "Flags: ")) {
63 char *p = buf + 7;
64 char *q;
65
66 while (*p) {
67 while (*p && isspace(*p)) p++;
68 q = p;
69 while (*p && !isspace(*p)) p++;
70 if (*p) *p++ = '\0';
71 if (!strcmp(q, "flimsy-bombs")) {
72 level->flags |= LEVEL_FLIMSY_BOMBS;
73 } else if (!strcmp(q, "relative-priority")) {
74 level->flags |= LEVEL_REL_PRIORITY;
75 } else {
76 fatal("Unknown flag keyword in level file");
77 }
78 }
79 } else if (ishdr(buf, "Map: ")) {
80 if (level->leveldata == NULL) {
81 fatal("Map before size in level file");
82 }
83 if ((int)strlen(buf + 5) != level->width) {
84 fatal("Wrong length map line in level file");
85 }
86 if (nlines >= level->height) {
87 fatal("Too many map lines in level file");
88 }
89 memcpy(level->leveldata + level->width * nlines,
90 buf + 5, level->width);
91 nlines++;
92 } else {
93 fatal("Unrecognised keyword in level file");
94 }
95 if (level->width > 0 && level->height > 0 && level->leveldata == NULL)
96 level_setsize(level, level->width, level->height);
97 }
98 if (nlines < level->height) {
99 fatal("Not enough map lines in level file");
100 }
101
102 fclose(fp);
103
104 {
105 char buf[256], buf2[384];
106 char *err;
107
108 err = validate(level, buf, sizeof(buf));
109 if (err) {
110 sprintf(buf2, "Error in level file '%.64s': %s", filename, err);
111 fatal(buf2);
112 }
113 }
114
115 return level;
116 }
117
levelset_load(char * filename)118 levelset *levelset_load(char *filename) {
119 FILE *fp;
120 char buf[FILENAME_MAX+10];
121 char fname[FILENAME_MAX];
122 levelset *set;
123
124 /*
125 * Sanity-check level set name.
126 */
127 if (filename[strcspn(filename, SETNAME_INVALID)] != '\0') {
128 fatal("Invalid character in level set name");
129 }
130
131 fname[sizeof(fname)-1] = '\0';
132 strncpy(fname, LEVELDIR, sizeof(fname));
133 strncpy(fname + strlen(fname), filename, sizeof(fname)-strlen(fname));
134 strncpy(fname + strlen(fname), ".set", sizeof(fname)-strlen(fname));
135 if (fname[sizeof(fname)-1] != '\0') {
136 fatal("File name length overflow");
137 }
138
139 fp = fopen(fname, "r");
140 if (!fp) {
141 fatal("Unable to read level set file");
142 }
143
144 set = levelset_new();
145 set->title = NULL;
146 set->name = filename;
147
148 while (fgets(buf, sizeof(buf), fp)) {
149 if (buf[strlen(buf)-1] != '\n') {
150 fatal("Line length overflow in level set file");
151 }
152 buf[strcspn(buf, "\r\n")] = '\0';
153 if (!buf[0])
154 continue;
155 if (ishdr(buf, "Title: ")) {
156 if (set->title) {
157 fatal("Multiple titles in level set file");
158 }
159 set->title = dupstr(buf + 7);
160 } else if (ishdr(buf, "Level: ")) {
161 levelset_nlevels(set, set->nlevels+1);
162 set->levels[set->nlevels-1] = level_load(buf + 7);
163 } else {
164 fatal("Unrecognised keyword in level set file");
165 }
166 }
167
168 fclose(fp);
169
170 return set;
171 }
172