1 /*
2 * cmdlib.c -- functions common to all of the utilities
3 * $Id: cmdlib.c 5898 2017-07-16 08:29:20Z sezero $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 * Copyright (C) 2005-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
25 // HEADER FILES ------------------------------------------------------------
26
27 #include "q_stdinc.h"
28 #include "compiler.h"
29 #include "arch_def.h"
30 #include "cmdlib.h"
31 #include "q_ctype.h"
32 #ifdef PLATFORM_WINDOWS
33 #include <windows.h>
34 #endif
35 #ifdef PLATFORM_DOS
36 #include <time.h>
37 #endif
38 #ifdef PLATFORM_OS2
39 #include <sys/timeb.h>
40 #endif
41 #ifdef PLATFORM_UNIX
42 #include <sys/time.h>
43 #include <time.h>
44 #endif
45 #ifdef PLATFORM_AMIGA
46 #include <proto/exec.h>
47 #include <proto/dos.h>
48 #include <proto/timer.h>
49 #include <time.h>
50 #endif
51
52 // PUBLIC DATA DEFINITIONS -------------------------------------------------
53
54 int myargc;
55 char **myargv;
56
57 char com_token[1024];
58
59 // PRIVATE DATA DEFINITIONS ------------------------------------------------
60
61 #ifdef PLATFORM_AMIGA
62 struct timerequest *timerio;
63 struct MsgPort *timerport;
64 #if defined(__MORPHOS__) || defined(__VBCC__)
65 struct Library *TimerBase;
66 #else
67 struct Device *TimerBase;
68 #endif
69 #endif /* _AMIGA */
70
71 // REPLACEMENTS FOR LIBRARY FUNCTIONS --------------------------------------
72
q_strcasecmp(const char * s1,const char * s2)73 int q_strcasecmp(const char * s1, const char * s2)
74 {
75 const char * p1 = s1;
76 const char * p2 = s2;
77 char c1, c2;
78
79 if (p1 == p2)
80 return 0;
81
82 do
83 {
84 c1 = q_tolower (*p1++);
85 c2 = q_tolower (*p2++);
86 if (c1 == '\0')
87 break;
88 } while (c1 == c2);
89
90 return (int)(c1 - c2);
91 }
92
q_strncasecmp(const char * s1,const char * s2,size_t n)93 int q_strncasecmp(const char *s1, const char *s2, size_t n)
94 {
95 const char * p1 = s1;
96 const char * p2 = s2;
97 char c1, c2;
98
99 if (p1 == p2 || n == 0)
100 return 0;
101
102 do
103 {
104 c1 = q_tolower (*p1++);
105 c2 = q_tolower (*p2++);
106 if (c1 == '\0' || c1 != c2)
107 break;
108 } while (--n > 0);
109
110 return (int)(c1 - c2);
111 }
112
q_strlwr(char * str)113 char *q_strlwr (char *str)
114 {
115 char *c;
116 c = str;
117 while (*c)
118 {
119 *c = q_tolower(*c);
120 c++;
121 }
122 return str;
123 }
124
q_strupr(char * str)125 char *q_strupr (char *str)
126 {
127 char *c;
128 c = str;
129 while (*c)
130 {
131 *c = q_toupper(*c);
132 c++;
133 }
134 return str;
135 }
136
qerr_strlcat(const char * caller,int linenum,char * dst,const char * src,size_t size)137 size_t qerr_strlcat (const char *caller, int linenum,
138 char *dst, const char *src, size_t size)
139 {
140 size_t ret = q_strlcat (dst, src, size);
141 if (ret >= size)
142 COM_Error("%s: %d: string buffer overflow!", caller, linenum);
143 return ret;
144 }
145
qerr_strlcpy(const char * caller,int linenum,char * dst,const char * src,size_t size)146 size_t qerr_strlcpy (const char *caller, int linenum,
147 char *dst, const char *src, size_t size)
148 {
149 size_t ret = q_strlcpy (dst, src, size);
150 if (ret >= size)
151 COM_Error("%s: %d: string buffer overflow!", caller, linenum);
152 return ret;
153 }
154
qerr_snprintf(const char * caller,int linenum,char * str,size_t size,const char * format,...)155 int qerr_snprintf (const char *caller, int linenum,
156 char *str, size_t size, const char *format, ...)
157 {
158 int ret;
159 va_list argptr;
160
161 va_start (argptr, format);
162 ret = q_vsnprintf (str, size, format, argptr);
163 va_end (argptr);
164
165 if ((size_t)ret >= size)
166 COM_Error("%s: %d: string buffer overflow!", caller, linenum);
167 return ret;
168 }
169
170
171 /*
172 ==============
173 COM_GetTime
174
175 ==============
176 */
177 #if defined(PLATFORM_WINDOWS)
COM_GetTime(void)178 double COM_GetTime (void)
179 {
180 /* http://www.codeproject.com/KB/datetime/winapi_datetime_ops.aspx
181 * It doesn't matter that the offset is Jan 1, 1601, result
182 * is the number of 100 nanosecond units, 100ns * 10,000 = 1ms. */
183 SYSTEMTIME st;
184 FILETIME ft;
185 ULARGE_INTEGER ul1;
186
187 GetLocalTime(&st);
188 SystemTimeToFileTime(&st, &ft);
189 ul1.HighPart = ft.dwHighDateTime;
190 ul1.LowPart = ft.dwLowDateTime;
191
192 return (double)ul1.QuadPart / 10000000.0;
193 }
194
195 #elif defined(PLATFORM_DOS)
COM_GetTime(void)196 double COM_GetTime (void)
197 {
198 /* See DJGPP uclock() man page for its limitations */
199 return (double) uclock() / (double) UCLOCKS_PER_SEC;
200 }
201
202 #elif defined(PLATFORM_OS2)
COM_GetTime(void)203 double COM_GetTime (void)
204 {
205 struct timeb tb;
206 ftime (&tb);
207 return tb.time + tb.millitm / 1000.0;
208 }
209
210 #elif defined(PLATFORM_UNIX)
COM_GetTime(void)211 double COM_GetTime (void)
212 {
213 struct timeval tv;
214 gettimeofday (&tv, NULL);
215 return tv.tv_sec + tv.tv_usec / 1000000.0;
216 }
217
218 #elif defined(PLATFORM_AMIGA)
AMIGA_TimerCleanup(void)219 static void AMIGA_TimerCleanup (void)
220 {
221 if (TimerBase)
222 {
223 /*
224 if (!CheckIO((struct IORequest *) timerio)
225 {
226 AbortIO((struct IORequest *) timerio);
227 WaitIO((struct IORequest *) timerio);
228 }
229 */
230 WaitIO((struct IORequest *) timerio);
231 CloseDevice((struct IORequest *) timerio);
232 DeleteIORequest((struct IORequest *) timerio);
233 DeleteMsgPort(timerport);
234 TimerBase = NULL;
235 }
236 }
237
AMIGA_TimerInit(void)238 static void AMIGA_TimerInit (void)
239 {
240 if ((timerport = CreateMsgPort()))
241 {
242 if ((timerio = (struct timerequest *)CreateIORequest(timerport, sizeof(struct timerequest))))
243 {
244 if (OpenDevice((STRPTR) TIMERNAME, UNIT_MICROHZ,
245 (struct IORequest *) timerio, 0) == 0)
246 {
247 #if defined(__MORPHOS__) || defined(__VBCC__)
248 TimerBase = (struct Library *)timerio->tr_node.io_Device;
249 #else
250 TimerBase = timerio->tr_node.io_Device;
251 #endif
252 }
253 else
254 {
255 DeleteIORequest((struct IORequest *)timerio);
256 DeleteMsgPort(timerport);
257 }
258 }
259 else
260 {
261 DeleteMsgPort(timerport);
262 }
263 }
264
265 if (!TimerBase)
266 COM_Error("Can't open timer.device");
267
268 atexit (AMIGA_TimerCleanup);
269 /* 1us wait, for timer cleanup success */
270 timerio->tr_node.io_Command = TR_ADDREQUEST;
271 timerio->tr_time.tv_secs = 0;
272 timerio->tr_time.tv_micro = 1;
273 SendIO((struct IORequest *) timerio);
274 WaitIO((struct IORequest *) timerio);
275 }
276
COM_GetTime(void)277 double COM_GetTime (void)
278 {
279 struct timeval tv;
280 if (!TimerBase)
281 AMIGA_TimerInit();
282 GetSysTime(&tv);
283 return tv.tv_secs + tv.tv_micro / 1000000.0;
284 }
285
286 #else /* GENERIC CASE: */
COM_GetTime(void)287 double COM_GetTime (void)
288 {
289 time_t t;
290 time(&t);
291 return t;
292 }
293 #endif /* COM_GetTime () */
294
295 /*
296 ==============
297 COM_Parse
298
299 Parse a token out of a string
300 ==============
301 */
COM_Parse(const char * data)302 const char *COM_Parse (const char *data)
303 {
304 int c;
305 int len;
306
307 len = 0;
308 com_token[0] = 0;
309
310 if (!data)
311 return NULL;
312
313 // skip whitespace
314 skipwhite:
315 while ((c = *data) <= ' ')
316 {
317 if (c == 0)
318 return NULL; // end of file
319 data++;
320 }
321
322 // skip // comments
323 if (c == '/' && data[1] == '/')
324 {
325 while (*data && *data != '\n')
326 data++;
327 goto skipwhite;
328 }
329
330 // skip /*..*/ comments
331 if (c == '/' && data[1] == '*')
332 {
333 data += 2;
334 while (*data && !(*data == '*' && data[1] == '/'))
335 data++;
336 if (*data)
337 data += 2;
338 goto skipwhite;
339 }
340
341 // handle quoted strings specially
342 if (c == '\"')
343 {
344 data++;
345 while (1)
346 {
347 if ((c = *data) != 0)
348 ++data;
349 if (c == '\"' || !c)
350 {
351 com_token[len] = 0;
352 return data;
353 }
354 com_token[len] = c;
355 len++;
356 }
357 }
358
359 // parse single characters
360 if (c == '{' || c == '}' || c == '(' || c == ')' || c == '\'' || c == ':')
361 {
362 com_token[len] = c;
363 len++;
364 com_token[len] = 0;
365 return data+1;
366 }
367
368 // parse a regular word
369 do
370 {
371 com_token[len] = c;
372 data++;
373 len++;
374 c = *data;
375 if (c == '{' || c == '}' || c == '(' || c == ')' || c == '\'' || c == ':')
376 break;
377 } while (c > 32);
378
379 com_token[len] = 0;
380 return data;
381 }
382
383 /*
384 ==============
385 COM_Error
386
387 For abnormal program terminations.
388 ==============
389 */
COM_Error(const char * error,...)390 void COM_Error (const char *error, ...)
391 {
392 va_list argptr;
393
394 printf ("*** ERROR: ***\n");
395 va_start (argptr, error);
396 vprintf (error, argptr);
397 va_end (argptr);
398 printf ("\n\n");
399 exit (1);
400 }
401
402 /*
403 ==============
404 SafeMalloc
405 ==============
406 */
SafeMalloc(size_t size)407 void *SafeMalloc (size_t size)
408 {
409 void *ptr = calloc(1, size);
410 if (!ptr)
411 COM_Error ("%s failed for %lu bytes.", __thisfunc__, (unsigned long)size);
412 return ptr;
413 }
414
415 /*
416 ==============
417 SafeStrdup
418 ==============
419 */
SafeStrdup(const char * str)420 char *SafeStrdup (const char *str)
421 {
422 size_t sz = strlen(str) + 1;
423 char *ptr = (char *) malloc(sz);
424 if (!ptr)
425 COM_Error ("%s failed for %lu bytes.", __thisfunc__, (unsigned long)sz);
426 memcpy (ptr, str, sz);
427 return ptr;
428 }
429
430 /*
431 ==============
432 CheckParm
433
434 Checks for the given parameter in the program's command line arguments.
435 Returns the argument number (1 to argc-1) or 0 if not present.
436 ==============
437 */
CheckParm(const char * check)438 int CheckParm (const char *check)
439 {
440 int i;
441
442 for (i = 1; i < myargc; i++)
443 {
444 if (!q_strcasecmp(check, myargv[i]))
445 return i;
446 }
447 return 0;
448 }
449
450 /*
451 ==============
452 ParseNum / ParseHex
453 ==============
454 */
ParseHex(const char * hex)455 int ParseHex (const char *hex)
456 {
457 const char *str;
458 int num;
459
460 num = 0;
461 str = hex;
462
463 while (*str)
464 {
465 num <<= 4;
466 if (*str >= '0' && *str <= '9')
467 num += *str-'0';
468 else if (*str >= 'a' && *str <= 'f')
469 num += 10 + *str-'a';
470 else if (*str >= 'A' && *str <= 'F')
471 num += 10 + *str-'A';
472 else
473 COM_Error ("Bad hex number: %s",hex);
474 str++;
475 }
476
477 return num;
478 }
479
ParseNum(const char * str)480 int ParseNum (const char *str)
481 {
482 if (str[0] == '$')
483 return ParseHex (str+1);
484 if (str[0] == '0' && str[1] == 'x')
485 return ParseHex (str+2);
486 return atoi (str);
487 }
488
489