1 /*
2 * common.c -- misc utility functions used in client and server
3 * $Id: common.c 5530 2016-03-15 14:00:06Z sezero $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 * Copyright (C) 2008-2012 O.Sezer <sezero@users.sourceforge.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * See the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "quakedef.h"
25 #include "q_ctype.h"
26 #include "filenames.h"
27
28
29 int safemode;
30
31
32 /*
33 ============================================================================
34
35 REPLACEMENT FUNCTIONS
36
37 ============================================================================
38 */
39
q_strcasecmp(const char * s1,const char * s2)40 int q_strcasecmp(const char * s1, const char * s2)
41 {
42 const char * p1 = s1;
43 const char * p2 = s2;
44 char c1, c2;
45
46 if (p1 == p2)
47 return 0;
48
49 do
50 {
51 c1 = q_tolower (*p1++);
52 c2 = q_tolower (*p2++);
53 if (c1 == '\0')
54 break;
55 } while (c1 == c2);
56
57 return (int)(c1 - c2);
58 }
59
q_strncasecmp(const char * s1,const char * s2,size_t n)60 int q_strncasecmp(const char *s1, const char *s2, size_t n)
61 {
62 const char * p1 = s1;
63 const char * p2 = s2;
64 char c1, c2;
65
66 if (p1 == p2 || n == 0)
67 return 0;
68
69 do
70 {
71 c1 = q_tolower (*p1++);
72 c2 = q_tolower (*p2++);
73 if (c1 == '\0' || c1 != c2)
74 break;
75 } while (--n > 0);
76
77 return (int)(c1 - c2);
78 }
79
q_strlwr(char * str)80 char *q_strlwr (char *str)
81 {
82 char *c;
83 c = str;
84 while (*c)
85 {
86 *c = q_tolower(*c);
87 c++;
88 }
89 return str;
90 }
91
q_strupr(char * str)92 char *q_strupr (char *str)
93 {
94 char *c;
95 c = str;
96 while (*c)
97 {
98 *c = q_toupper(*c);
99 c++;
100 }
101 return str;
102 }
103
104 #ifdef __DJGPP__ /* override stock DJGPP versions of str[n]icmp by our q_str[n]casecmp: */
105 #ifdef __cplusplus
106 extern "C" {
107 #endif
108 int __stricmp(const char *, const char *) __attribute__((alias("q_strcasecmp")));
109 int stricmp(const char *, const char *) __attribute__((alias("q_strcasecmp")));
110 int strcasecmp(const char *, const char *) __attribute__((alias("q_strcasecmp")));
111 int __strnicmp(const char *, const char *, size_t) __attribute__((alias("q_strncasecmp")));
112 int strnicmp(const char *, const char *, size_t) __attribute__((alias("q_strncasecmp")));
113 int strncasecmp(const char *, const char *, size_t) __attribute__((alias("q_strncasecmp")));
114 char *strlwr(char *) __attribute__((alias("q_strlwr")));
115 char *strupr(char *) __attribute__((alias("q_strlwr")));
116 #ifdef __cplusplus
117 }
118 #endif
119 #endif
120
qerr_strlcat(const char * caller,int linenum,char * dst,const char * src,size_t size)121 size_t qerr_strlcat (const char *caller, int linenum,
122 char *dst, const char *src, size_t size)
123 {
124 size_t ret = q_strlcat (dst, src, size);
125 if (ret >= size)
126 Sys_Error("%s: %d: string buffer overflow!", caller, linenum);
127 return ret;
128 }
129
qerr_strlcpy(const char * caller,int linenum,char * dst,const char * src,size_t size)130 size_t qerr_strlcpy (const char *caller, int linenum,
131 char *dst, const char *src, size_t size)
132 {
133 size_t ret = q_strlcpy (dst, src, size);
134 if (ret >= size)
135 Sys_Error("%s: %d: string buffer overflow!", caller, linenum);
136 return ret;
137 }
138
qerr_snprintf(const char * caller,int linenum,char * str,size_t size,const char * format,...)139 int qerr_snprintf (const char *caller, int linenum,
140 char *str, size_t size, const char *format, ...)
141 {
142 int ret;
143 va_list argptr;
144
145 va_start (argptr, format);
146 ret = q_vsnprintf (str, size, format, argptr);
147 va_end (argptr);
148
149 if ((size_t)ret >= size)
150 Sys_Error("%s: %d: string buffer overflow!", caller, linenum);
151 return ret;
152 }
153
154
155 /*
156 ============================================================================
157
158 MISC UTILITY FUNCTIONS
159
160 ============================================================================
161 */
162
163 /*
164 ============
165 va
166
167 does a varargs printf into a temp buffer. cycles between
168 4 different static buffers. the number of buffers cycled
169 is defined in VA_NUM_BUFFS.
170 ============
171 */
172 #define VA_NUM_BUFFS 4
173 #define VA_BUFFERLEN 1024
174
get_va_buffer(void)175 static char *get_va_buffer(void)
176 {
177 static char va_buffers[VA_NUM_BUFFS][VA_BUFFERLEN];
178 static int buffer_idx = 0;
179 buffer_idx = (buffer_idx + 1) & (VA_NUM_BUFFS - 1);
180 return va_buffers[buffer_idx];
181 }
182
va(const char * format,...)183 char *va (const char *format, ...)
184 {
185 va_list argptr;
186 char *va_buf;
187
188 va_buf = get_va_buffer ();
189 va_start (argptr, format);
190 if (q_vsnprintf(va_buf, VA_BUFFERLEN, format, argptr) >= VA_BUFFERLEN)
191 Con_DPrintf("%s: overflow (string truncated)\n", __thisfunc__);
192 va_end (argptr);
193
194 return va_buf;
195 }
196
197
198 /*============================================================================
199 quick'n'dirty string comparison function for use with qsort
200 ============================================================================*/
201
COM_StrCompare(const void * arg1,const void * arg2)202 int COM_StrCompare (const void *arg1, const void *arg2)
203 {
204 return q_strcasecmp ( *(char **) arg1, *(char **) arg2);
205 }
206
207
208 /*============================================================================
209 FileName Processing utilities
210 ============================================================================*/
211
212 /*
213 ============
214 COM_SkipPath
215 ============
216 */
COM_SkipPath(const char * pathname)217 const char *COM_SkipPath (const char *pathname)
218 {
219 const char *last;
220
221 last = pathname;
222 while (*pathname)
223 {
224 if (IS_DIR_SEPARATOR(*pathname))
225 last = pathname + 1;
226 pathname++;
227 }
228 return last;
229 }
230
231 /*
232 ============
233 COM_StripExtension
234 ============
235 */
COM_StripExtension(const char * in,char * out,size_t outsize)236 void COM_StripExtension (const char *in, char *out, size_t outsize)
237 {
238 int length;
239
240 if (!*in)
241 {
242 *out = '\0';
243 return;
244 }
245 if (in != out) /* copy when not in-place editing */
246 q_strlcpy (out, in, outsize);
247 length = (int)strlen(out) - 1;
248 while (length > 0 && out[length] != '.')
249 {
250 --length;
251 if (IS_DIR_SEPARATOR(out[length]))
252 return; /* no extension */
253 }
254 if (length > 0)
255 out[length] = '\0';
256 }
257
258 /*
259 ============
260 COM_FileGetExtension - doesn't return NULL
261 ============
262 */
COM_FileGetExtension(const char * in)263 const char *COM_FileGetExtension (const char *in)
264 {
265 const char *src;
266 size_t len;
267
268 len = strlen(in);
269 if (len < 2) /* nothing meaningful */
270 return "";
271
272 src = in + len - 1;
273 while (src != in && src[-1] != '.')
274 src--;
275 if (src == in || FIND_FIRST_DIRSEP(src) != NULL || HAS_DRIVE_SPEC(src))
276 return ""; /* no extension, or parent directory has a dot */
277
278 return src;
279 }
280
281 /*
282 ============
283 COM_ExtractExtension
284 ============
285 */
COM_ExtractExtension(const char * in,char * out,size_t outsize)286 void COM_ExtractExtension (const char *in, char *out, size_t outsize)
287 {
288 const char *ext = COM_FileGetExtension (in);
289 if (! *ext)
290 *out = '\0';
291 else
292 q_strlcpy (out, ext, outsize);
293 }
294
295 /*
296 ============
297 COM_FileBase
298 take 'somedir/otherdir/filename.ext',
299 write only 'filename' to the output
300 ============
301 */
COM_FileBase(const char * in,char * out,size_t outsize)302 void COM_FileBase (const char *in, char *out, size_t outsize)
303 {
304 COM_StripExtension (COM_SkipPath(in), out, outsize);
305 }
306
307 /*
308 ==================
309 COM_DefaultExtension
310 if path doesn't have a .EXT, append extension
311 (extension should include the leading ".")
312 ==================
313 */
314 #if 0 /* can be dangerous */
315 void COM_DefaultExtension (char *path, const char *extension, size_t len)
316 {
317 char *src;
318
319 if (!*path) return;
320 src = path + strlen(path) - 1;
321
322 while (!IS_DIR_SEPARATOR(*src) && src != path)
323 {
324 if (*src == '.')
325 return; // it has an extension
326 src--;
327 }
328
329 qerr_strlcat(__thisfunc__, __LINE__, path, extension, len);
330 }
331 #endif
332
333 /*
334 ==================
335 COM_AddExtension
336 if path extension doesn't match .EXT, append it
337 (extension should include the leading ".")
338 ==================
339 */
COM_AddExtension(char * path,const char * extension,size_t len)340 void COM_AddExtension (char *path, const char *extension, size_t len)
341 {
342 if (strcmp(COM_FileGetExtension(path), extension + 1) != 0)
343 qerr_strlcat(__thisfunc__, __LINE__, path, extension, len);
344 }
345
346
347 /*
348 ============================================================================
349
350 STRING PARSING FUNCTIONS
351
352 ============================================================================
353 */
354
355 char com_token[1024];
356
357 /*
358 ==============
359 COM_Parse
360
361 Parse a token out of a string
362 ==============
363 */
COM_Parse(const char * data)364 const char *COM_Parse (const char *data)
365 {
366 int c;
367 int len;
368
369 len = 0;
370 com_token[0] = 0;
371
372 if (!data)
373 return NULL;
374
375 // skip whitespace
376 skipwhite:
377 while ((c = *data) <= ' ')
378 {
379 if (c == 0)
380 return NULL; // end of file
381 data++;
382 }
383
384 // skip // comments
385 if (c == '/' && data[1] == '/')
386 {
387 while (*data && *data != '\n')
388 data++;
389 goto skipwhite;
390 }
391
392 // skip /*..*/ comments
393 if (c == '/' && data[1] == '*')
394 {
395 data += 2;
396 while (*data && !(*data == '*' && data[1] == '/'))
397 data++;
398 if (*data)
399 data += 2;
400 goto skipwhite;
401 }
402
403 // handle quoted strings specially
404 if (c == '\"')
405 {
406 data++;
407 while (1)
408 {
409 if ((c = *data) != 0)
410 ++data;
411 if (c == '\"' || !c)
412 {
413 com_token[len] = 0;
414 return data;
415 }
416 com_token[len] = c;
417 len++;
418 }
419 }
420
421 #if 0
422 // parse single characters
423 if (c == '{' || c == '}' || c == '(' || c == ')' || c == '\'' || c == ':')
424 {
425 com_token[len] = c;
426 len++;
427 com_token[len] = 0;
428 return data+1;
429 }
430 #endif
431
432 // parse a regular word
433 do
434 {
435 com_token[len] = c;
436 data++;
437 len++;
438 c = *data;
439 #if 0
440 if (c == '{' || c == '}' || c == '(' || c == ')' || c == '\'' || c == ':')
441 break;
442 #endif
443 } while (c > 32);
444
445 com_token[len] = 0;
446 return data;
447 }
448
449
450 /*
451 ============================================================================
452
453 COMMAND LINE PROCESSING FUNCTIONS
454
455 ============================================================================
456 */
457
458 /*
459 ================
460 COM_CheckParm
461
462 Returns the position (1 to argc-1) in the program's argument list
463 where the given parameter apears, or 0 if not present
464 ================
465 */
COM_CheckParm(const char * parm)466 int COM_CheckParm (const char *parm)
467 {
468 int i;
469
470 for (i = 1; i < com_argc; i++)
471 {
472 if (!com_argv[i])
473 continue; // NEXTSTEP sometimes clears appkit vars.
474 if (!strcmp (parm,com_argv[i]))
475 return i;
476 }
477
478 return 0;
479 }
480
COM_Cmdline_f(void)481 static void COM_Cmdline_f (void)
482 {
483 int i;
484
485 Con_Printf ("cmdline was:");
486 for (i = 0; (i < MAX_NUM_ARGVS) && (i < com_argc); i++)
487 {
488 if (com_argv[i])
489 Con_Printf (" %s", com_argv[i]);
490 }
491 Con_Printf ("\n");
492 }
493
494 /*
495 ============================================================================
496
497 INIT, ETC..
498
499 ============================================================================
500 */
501
COM_ValidateByteorder(void)502 void COM_ValidateByteorder (void)
503 {
504 const char *endianism[] = { "BE", "LE", "PDP", "Unknown" };
505 const char *tmp;
506
507 ByteOrder_Init ();
508 switch (host_byteorder)
509 {
510 case BIG_ENDIAN:
511 tmp = endianism[0];
512 break;
513 case LITTLE_ENDIAN:
514 tmp = endianism[1];
515 break;
516 case PDP_ENDIAN:
517 tmp = endianism[2];
518 host_byteorder = -1; /* not supported */
519 break;
520 default:
521 tmp = endianism[3];
522 break;
523 }
524 if (host_byteorder < 0)
525 Sys_Error ("%s: Unsupported byte order [%s]", __thisfunc__, tmp);
526 Sys_Printf("Detected byte order: %s\n", tmp);
527 #if !ENDIAN_RUNTIME_DETECT
528 if (host_byteorder != BYTE_ORDER)
529 {
530 const char *tmp2;
531
532 switch (BYTE_ORDER)
533 {
534 case BIG_ENDIAN:
535 tmp2 = endianism[0];
536 break;
537 case LITTLE_ENDIAN:
538 tmp2 = endianism[1];
539 break;
540 case PDP_ENDIAN:
541 tmp2 = endianism[2];
542 break;
543 default:
544 tmp2 = endianism[3];
545 break;
546 }
547 Sys_Error ("Detected byte order %s doesn't match compiled %s order!", tmp, tmp2);
548 }
549 #endif /* ENDIAN_RUNTIME_DETECT */
550 }
551
552 /*
553 ================
554 COM_Init
555 ================
556 */
COM_Init(void)557 void COM_Init (void)
558 {
559 Cmd_AddCommand ("cmdline", COM_Cmdline_f);
560
561 safemode = COM_CheckParm ("-safe");
562 }
563
564