Mercurial > hg > forks > yadex
comparison src/aym.cc @ 33:a68786b9c74b
Oops, used indent with tabs enabled. Remove tabs.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 24 Sep 2011 15:59:33 +0300 |
parents | f5375d9255f0 |
children | 0602d9bf474a |
comparison
equal
deleted
inserted
replaced
32:594dea11ccd9 | 33:a68786b9c74b |
---|---|
1 /* | 1 /* |
2 * aym.cc | 2 * aym.cc |
3 * Misc. functions | 3 * Misc. functions |
4 * AYM 1997-??-?? | 4 * AYM 1997-??-?? |
5 */ | 5 */ |
6 | 6 |
7 | 7 |
8 /* | 8 /* |
9 This file is part of Yadex. | 9 This file is part of Yadex. |
31 #include "yadex.h" | 31 #include "yadex.h" |
32 #include "game.h" | 32 #include "game.h" |
33 | 33 |
34 | 34 |
35 /* | 35 /* |
36 * levelname2levelno | 36 * levelname2levelno |
37 * Used to know if directory entry is ExMy or MAPxy | 37 * Used to know if directory entry is ExMy or MAPxy |
38 * For "ExMy" (case-insensitive), returns 10x + y | 38 * For "ExMy" (case-insensitive), returns 10x + y |
39 * For "ExMyz" (case-insensitive), returns 100*x + 10y + z | 39 * For "ExMyz" (case-insensitive), returns 100*x + 10y + z |
40 * For "MAPxy" (case-insensitive), returns 1000 + 10x + y | 40 * For "MAPxy" (case-insensitive), returns 1000 + 10x + y |
41 * E0My, ExM0, E0Myz, ExM0z are not considered valid names. | 41 * E0My, ExM0, E0Myz, ExM0z are not considered valid names. |
42 * MAP00 is considered a valid name. | 42 * MAP00 is considered a valid name. |
43 * For other names, returns 0. | 43 * For other names, returns 0. |
44 */ | 44 */ |
45 int levelname2levelno(const char *name) | 45 int levelname2levelno(const char *name) |
46 { | 46 { |
47 const unsigned char *s = (const unsigned char *) name; | 47 const unsigned char *s = (const unsigned char *) name; |
48 if (toupper(s[0]) == 'E' | 48 if (toupper(s[0]) == 'E' |
49 && isdigit(s[1]) | 49 && isdigit(s[1]) |
50 && s[1] != '0' | 50 && s[1] != '0' |
51 && toupper(s[2]) == 'M' | 51 && toupper(s[2]) == 'M' |
52 && isdigit(s[3]) && s[3] != '0' && s[4] == '\0') | 52 && isdigit(s[3]) && s[3] != '0' && s[4] == '\0') |
53 return 10 * dectoi(s[1]) + dectoi(s[3]); | 53 return 10 * dectoi(s[1]) + dectoi(s[3]); |
54 if (yg_level_name == YGLN_E1M10 | 54 if (yg_level_name == YGLN_E1M10 |
55 && toupper(s[0]) == 'E' | 55 && toupper(s[0]) == 'E' |
56 && isdigit(s[1]) | 56 && isdigit(s[1]) |
57 && s[1] != '0' | 57 && s[1] != '0' |
58 && toupper(s[2]) == 'M' | 58 && toupper(s[2]) == 'M' |
59 && isdigit(s[3]) && s[3] != '0' && isdigit(s[4]) && s[5] == '\0') | 59 && isdigit(s[3]) && s[3] != '0' && isdigit(s[4]) && s[5] == '\0') |
60 return 100 * dectoi(s[1]) + 10 * dectoi(s[3]) + dectoi(s[4]); | 60 return 100 * dectoi(s[1]) + 10 * dectoi(s[3]) + dectoi(s[4]); |
61 if (toupper(s[0]) == 'M' | 61 if (toupper(s[0]) == 'M' |
62 && toupper(s[1]) == 'A' | 62 && toupper(s[1]) == 'A' |
63 && toupper(s[2]) == 'P' | 63 && toupper(s[2]) == 'P' |
64 && isdigit(s[3]) && isdigit(s[4]) && s[5] == '\0') | 64 && isdigit(s[3]) && isdigit(s[4]) && s[5] == '\0') |
65 return 1000 + 10 * dectoi(s[3]) + dectoi(s[4]); | 65 return 1000 + 10 * dectoi(s[3]) + dectoi(s[4]); |
66 return 0; | 66 return 0; |
67 } | 67 } |
68 | 68 |
69 | 69 |
70 /* | 70 /* |
71 * levelname2rank | 71 * levelname2rank |
72 * Used to sort level names. | 72 * Used to sort level names. |
73 * Identical to levelname2levelno except that, for "ExMy", | 73 * Identical to levelname2levelno except that, for "ExMy", |
74 * it returns 100x + y, so that | 74 * it returns 100x + y, so that |
75 * - f("E1M10") = f("E1M9") + 1 | 75 * - f("E1M10") = f("E1M9") + 1 |
76 * - f("E2M1") > f("E1M99") | 76 * - f("E2M1") > f("E1M99") |
77 * - f("E2M1") > f("E1M99") + 1 | 77 * - f("E2M1") > f("E1M99") + 1 |
78 * - f("MAPxy") > f("ExMy") | 78 * - f("MAPxy") > f("ExMy") |
79 * - f("MAPxy") > f("ExMyz") | 79 * - f("MAPxy") > f("ExMyz") |
80 */ | 80 */ |
81 int levelname2rank(const char *name) | 81 int levelname2rank(const char *name) |
82 { | 82 { |
83 const unsigned char *s = (const unsigned char *) name; | 83 const unsigned char *s = (const unsigned char *) name; |
84 if (toupper(s[0]) == 'E' | 84 if (toupper(s[0]) == 'E' |
85 && isdigit(s[1]) | 85 && isdigit(s[1]) |
86 && s[1] != '0' | 86 && s[1] != '0' |
87 && toupper(s[2]) == 'M' | 87 && toupper(s[2]) == 'M' |
88 && isdigit(s[3]) && s[3] != '0' && s[4] == '\0') | 88 && isdigit(s[3]) && s[3] != '0' && s[4] == '\0') |
89 return 100 * dectoi(s[1]) + dectoi(s[3]); | 89 return 100 * dectoi(s[1]) + dectoi(s[3]); |
90 if (yg_level_name == YGLN_E1M10 | 90 if (yg_level_name == YGLN_E1M10 |
91 && toupper(s[0]) == 'E' | 91 && toupper(s[0]) == 'E' |
92 && isdigit(s[1]) | 92 && isdigit(s[1]) |
93 && s[1] != '0' | 93 && s[1] != '0' |
94 && toupper(s[2]) == 'M' | 94 && toupper(s[2]) == 'M' |
95 && isdigit(s[3]) && s[3] != '0' && isdigit(s[4]) && s[5] == '\0') | 95 && isdigit(s[3]) && s[3] != '0' && isdigit(s[4]) && s[5] == '\0') |
96 return 100 * dectoi(s[1]) + 10 * dectoi(s[3]) + dectoi(s[4]); | 96 return 100 * dectoi(s[1]) + 10 * dectoi(s[3]) + dectoi(s[4]); |
97 if (toupper(s[0]) == 'M' | 97 if (toupper(s[0]) == 'M' |
98 && toupper(s[1]) == 'A' | 98 && toupper(s[1]) == 'A' |
99 && toupper(s[2]) == 'P' | 99 && toupper(s[2]) == 'P' |
100 && isdigit(s[3]) && isdigit(s[4]) && s[5] == '\0') | 100 && isdigit(s[3]) && isdigit(s[4]) && s[5] == '\0') |
101 return 1000 + 10 * dectoi(s[3]) + dectoi(s[4]); | 101 return 1000 + 10 * dectoi(s[3]) + dectoi(s[4]); |
102 return 0; | 102 return 0; |
103 } | 103 } |
104 | 104 |
105 | 105 |
106 /* | 106 /* |
107 * spec_path | 107 * spec_path |
108 * Extract the path of a spec | 108 * Extract the path of a spec |
109 */ | 109 */ |
110 const char *spec_path(const char *spec) | 110 const char *spec_path(const char *spec) |
111 { | 111 { |
112 static char path[Y_PATH + 1]; | 112 static char path[Y_PATH + 1]; |
113 size_t n; | 113 size_t n; |
114 | 114 |
115 *path = '\0'; | 115 *path = '\0'; |
116 strncat(path, spec, sizeof path - 1); | 116 strncat(path, spec, sizeof path - 1); |
117 for (n = strlen(path); n > 0 && !al_fisps(path[n - 1]); n--) | 117 for (n = strlen(path); n > 0 && !al_fisps(path[n - 1]); n--) |
118 ; | 118 ; |
119 path[n] = '\0'; | 119 path[n] = '\0'; |
120 return path; | 120 return path; |
121 } | 121 } |
122 | 122 |
123 | 123 |
124 /* | 124 /* |
125 * fncmp | 125 * fncmp |
126 * Compare two filenames | 126 * Compare two filenames |
127 * For Unix, it's a simple strcmp. | 127 * For Unix, it's a simple strcmp. |
128 * For DOS, it's case insensitive and "/" and "\" are equivalent. | 128 * For DOS, it's case insensitive and "/" and "\" are equivalent. |
129 * FIXME: should canonicalize both names and compare that. | 129 * FIXME: should canonicalize both names and compare that. |
130 */ | 130 */ |
131 int fncmp(const char *name1, const char *name2) | 131 int fncmp(const char *name1, const char *name2) |
132 { | 132 { |
133 #if defined Y_DOS | 133 #if defined Y_DOS |
134 char c1, c2; | 134 char c1, c2; |
135 for (;;) | 135 for (;;) |
136 { | 136 { |
137 c1 = tolower((unsigned char) *name1++); | 137 c1 = tolower((unsigned char) *name1++); |
138 c2 = tolower((unsigned char) *name2++); | 138 c2 = tolower((unsigned char) *name2++); |
139 if (c1 == '\\') | 139 if (c1 == '\\') |
140 c1 = '/'; | 140 c1 = '/'; |
141 if (c2 == '\\') | 141 if (c2 == '\\') |
142 c2 = '/'; | 142 c2 = '/'; |
143 if (c1 != c2) | 143 if (c1 != c2) |
144 return c1 - c2; | 144 return c1 - c2; |
145 if (!c1) | 145 if (!c1) |
146 return 0; | 146 return 0; |
147 } | 147 } |
148 #elif defined Y_UNIX | 148 #elif defined Y_UNIX |
149 return strcmp(name1, name2); | 149 return strcmp(name1, name2); |
150 #endif | 150 #endif |
151 } | 151 } |
152 | 152 |
153 | 153 |
154 /* | 154 /* |
155 * is_absolute | 155 * is_absolute |
156 * Tell whether a file name is absolute or relative. | 156 * Tell whether a file name is absolute or relative. |
157 * | 157 * |
158 * Note: for DOS, a filename of the form "d:foo" is | 158 * Note: for DOS, a filename of the form "d:foo" is |
159 * considered absolute, even though it's technically | 159 * considered absolute, even though it's technically |
160 * relative to the current working directory of "d:". | 160 * relative to the current working directory of "d:". |
161 * My reasoning is that someone who wants to specify a | 161 * My reasoning is that someone who wants to specify a |
162 * name that's relative to one of the standard | 162 * name that's relative to one of the standard |
163 * directories is not going to put a "d:" in front of it. | 163 * directories is not going to put a "d:" in front of it. |
164 */ | 164 */ |
165 int is_absolute(const char *filename) | 165 int is_absolute(const char *filename) |
166 { | 166 { |
167 #if defined Y_UNIX | 167 #if defined Y_UNIX |
168 return *filename == '/'; | 168 return *filename == '/'; |
169 #elif defined Y_DOS | 169 #elif defined Y_DOS |
170 return *filename == '/' | 170 return *filename == '/' |
171 || *filename == '\\' || isalpha(*filename) && filename[1] == ':'; | 171 || *filename == '\\' || isalpha(*filename) && filename[1] == ':'; |
172 #endif | 172 #endif |
173 } | 173 } |
174 | 174 |
175 | 175 |
176 /* | 176 /* |
177 * y_stricmp | 177 * y_stricmp |
178 * A case-insensitive strcmp() | 178 * A case-insensitive strcmp() |
179 * (same thing as DOS stricmp() or GNU strcasecmp()) | 179 * (same thing as DOS stricmp() or GNU strcasecmp()) |
180 */ | 180 */ |
181 int y_stricmp(const char *s1, const char *s2) | 181 int y_stricmp(const char *s1, const char *s2) |
182 { | 182 { |
183 for (;;) | 183 for (;;) |
184 { | 184 { |
185 if (tolower(*s1) != tolower(*s2)) | 185 if (tolower(*s1) != tolower(*s2)) |
186 return (unsigned char) *s1 - (unsigned char) *s2; | 186 return (unsigned char) *s1 - (unsigned char) *s2; |
187 if (!*s1) | 187 if (!*s1) |
188 return *s2 ? -1 : 0; | 188 return *s2 ? -1 : 0; |
189 if (!*s2) | 189 if (!*s2) |
190 return 1; | 190 return 1; |
191 s1++; | 191 s1++; |
192 s2++; | 192 s2++; |
193 } | 193 } |
194 } | 194 } |
195 | 195 |
196 | 196 |
197 /* | 197 /* |
198 * y_strnicmp | 198 * y_strnicmp |
199 * A case-insensitive strncmp() | 199 * A case-insensitive strncmp() |
200 * (same thing as DOS strnicmp() or GNU strncasecmp()) | 200 * (same thing as DOS strnicmp() or GNU strncasecmp()) |
201 */ | 201 */ |
202 int y_strnicmp(const char *s1, const char *s2, size_t len) | 202 int y_strnicmp(const char *s1, const char *s2, size_t len) |
203 { | 203 { |
204 while (len-- > 0) | 204 while (len-- > 0) |
205 { | 205 { |
206 if (tolower(*s1) != tolower(*s2)) | 206 if (tolower(*s1) != tolower(*s2)) |
207 return (unsigned char) *s1 - (unsigned char) *s2; | 207 return (unsigned char) *s1 - (unsigned char) *s2; |
208 if (!*s1) | 208 if (!*s1) |
209 return *s2 ? -1 : 0; | 209 return *s2 ? -1 : 0; |
210 if (!*s2) | 210 if (!*s2) |
211 return 1; | 211 return 1; |
212 s1++; | 212 s1++; |
213 s2++; | 213 s2++; |
214 } | 214 } |
215 return 0; | 215 return 0; |
216 } | 216 } |
217 | 217 |
218 | 218 |
219 /* | 219 /* |
220 * y_snprintf | 220 * y_snprintf |
221 * If available, snprintf(). Else sprintf(). | 221 * If available, snprintf(). Else sprintf(). |
222 */ | 222 */ |
223 int y_snprintf(char *buf, size_t size, const char *fmt, ...) | 223 int y_snprintf(char *buf, size_t size, const char *fmt, ...) |
224 { | 224 { |
225 va_list args; | 225 va_list args; |
226 va_start(args, fmt); | 226 va_start(args, fmt); |
231 #endif | 231 #endif |
232 } | 232 } |
233 | 233 |
234 | 234 |
235 /* | 235 /* |
236 * y_vsnprintf | 236 * y_vsnprintf |
237 * If available, vsnprintf(). Else vsprintf(). | 237 * If available, vsnprintf(). Else vsprintf(). |
238 */ | 238 */ |
239 int y_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | 239 int y_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) |
240 { | 240 { |
241 #ifdef Y_SNPRINTF | 241 #ifdef Y_SNPRINTF |
242 return vsnprintf(buf, size, fmt, args); | 242 return vsnprintf(buf, size, fmt, args); |
245 #endif | 245 #endif |
246 } | 246 } |
247 | 247 |
248 | 248 |
249 /* | 249 /* |
250 * y_strupr | 250 * y_strupr |
251 * Upper-case a string | 251 * Upper-case a string |
252 */ | 252 */ |
253 void y_strupr(char *string) | 253 void y_strupr(char *string) |
254 { | 254 { |
255 while (*string) | 255 while (*string) |
256 { | 256 { |
257 *string = toupper(*string); | 257 *string = toupper(*string); |
258 string++; | 258 string++; |
259 } | 259 } |
260 } | 260 } |
261 | 261 |
262 /* | 262 /* |
263 * is_one_of | 263 * is_one_of |
264 * Return non-zero if <s> is equal (in the strcmp() sense) | 264 * Return non-zero if <s> is equal (in the strcmp() sense) |
265 * to one of the other strings (retrieved from the argument | 265 * to one of the other strings (retrieved from the argument |
266 * list as const char *). The last string must be followed | 266 * list as const char *). The last string must be followed |
267 * by (const char *) 0. | 267 * by (const char *) 0. |
268 */ | 268 */ |
269 int is_one_of(const char *needle, ...) | 269 int is_one_of(const char *needle, ...) |
270 { | 270 { |
271 va_list args; | 271 va_list args; |
272 va_start(args, needle); | 272 va_start(args, needle); |
273 for (;;) | 273 for (;;) |
274 { | 274 { |
275 const char *haystack = va_arg(args, const char *); | 275 const char *haystack = va_arg(args, const char *); |
276 if (haystack == Y_NULL) | 276 if (haystack == Y_NULL) |
277 break; | 277 break; |
278 if (!strcmp(needle, haystack)) | 278 if (!strcmp(needle, haystack)) |
279 return 1; | 279 return 1; |
280 } | 280 } |
281 return 0; | 281 return 0; |
282 } | 282 } |
283 | 283 |
284 | 284 |
285 | 285 |
286 /* | 286 /* |
287 * file_exists | 287 * file_exists |
288 * Check whether a file exists and is readable. | 288 * Check whether a file exists and is readable. |
289 * Returns true if it is, false if it isn't. | 289 * Returns true if it is, false if it isn't. |
290 */ | 290 */ |
291 bool file_exists(const char *filename) | 291 bool file_exists(const char *filename) |
292 { | 292 { |
293 FILE *test; | 293 FILE *test; |
294 | 294 |
295 if ((test = fopen(filename, "rb")) == NULL) | 295 if ((test = fopen(filename, "rb")) == NULL) |
296 return 0; | 296 return 0; |
297 fclose(test); | 297 fclose(test); |
298 return 1; | 298 return 1; |
299 } | 299 } |
300 | 300 |
301 | 301 |
302 /* | 302 /* |
303 * y_filename | 303 * y_filename |
304 * Copies into <buf> a string that is a close as possible | 304 * Copies into <buf> a string that is a close as possible |
305 * to <filename> but is guaranteed to be no longer than | 305 * to <filename> but is guaranteed to be no longer than |
306 * <size> - 1 and contain only printable characters. Non | 306 * <size> - 1 and contain only printable characters. Non |
307 * printable characters are replaced by question marks. | 307 * printable characters are replaced by question marks. |
308 * Excess characters are replaced by an ellipsis. | 308 * Excess characters are replaced by an ellipsis. |
309 */ | 309 */ |
310 void y_filename(char *buf, size_t size, const char *filename) | 310 void y_filename(char *buf, size_t size, const char *filename) |
311 { | 311 { |
312 if (size == 0) | 312 if (size == 0) |
313 return; | 313 return; |
314 if (size == 1) | 314 if (size == 1) |
315 { | 315 { |
316 *buf = '\0'; | 316 *buf = '\0'; |
317 return; | 317 return; |
318 } | 318 } |
319 size_t len = strlen(filename); | 319 size_t len = strlen(filename); |
320 size_t maxlen = size - 1; | 320 size_t maxlen = size - 1; |
321 | 321 |
322 if (len > 3 && maxlen <= 3) // Pathological case, fill with dots | 322 if (len > 3 && maxlen <= 3) // Pathological case, fill with dots |
323 { | 323 { |
324 memset(buf, '.', maxlen); | 324 memset(buf, '.', maxlen); |
325 buf[maxlen] = '\0'; | 325 buf[maxlen] = '\0'; |
326 return; | 326 return; |
327 } | 327 } |
328 | 328 |
329 size_t len1 = len; | 329 size_t len1 = len; |
330 size_t len2 = 0; | 330 size_t len2 = 0; |
331 if (len > maxlen) | 331 if (len > maxlen) |
332 { | 332 { |
333 len1 = (maxlen - 3) / 2; | 333 len1 = (maxlen - 3) / 2; |
334 len2 = maxlen - 3 - len1; | 334 len2 = maxlen - 3 - len1; |
335 } | 335 } |
336 char *p = buf; | 336 char *p = buf; |
337 for (size_t n = 0; n < len1; n++) | 337 for (size_t n = 0; n < len1; n++) |
338 { | 338 { |
339 *p++ = y_isprint(*filename) ? *filename : '?'; | 339 *p++ = y_isprint(*filename) ? *filename : '?'; |
340 filename++; | 340 filename++; |
341 } | 341 } |
342 if (len2 > 0) | 342 if (len2 > 0) |
343 { | 343 { |
344 *p++ = '.'; | 344 *p++ = '.'; |
345 *p++ = '.'; | 345 *p++ = '.'; |
346 *p++ = '.'; | 346 *p++ = '.'; |
347 filename += len - len1 - len2; | 347 filename += len - len1 - len2; |
348 for (size_t n = 0; n < len2; n++) | 348 for (size_t n = 0; n < len2; n++) |
349 { | 349 { |
350 *p++ = y_isprint(*filename) ? *filename : '?'; | 350 *p++ = y_isprint(*filename) ? *filename : '?'; |
351 filename++; | 351 filename++; |
352 } | 352 } |
353 } | 353 } |
354 *p++ = '\0'; | 354 *p++ = '\0'; |
355 } | 355 } |