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 }