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