UFO: Alien Invasion
Loading...
Searching...
No Matches
shared.cpp
Go to the documentation of this file.
1
5
6/*
7All original material Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9Copyright (C) 1997-2001 Id Software, Inc.
10
11This program is free software; you can redistribute it and/or
12modify it under the terms of the GNU General Public License
13as published by the Free Software Foundation; either version 2
14of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20See the GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software
24Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26*/
27
28#include "shared.h"
29#include "../common/filesys.h"
30#include "../ports/system.h"
31#include "utf8.h"
32
37const char* Com_SkipPath (const char* pathname)
38{
39 char const* const last = strrchr(pathname, '/');
40 return last ? last + 1 : pathname;
41}
42
48char* Com_Chop (char* s)
49{
50 char* right;
51
52 right = s + strlen(s) - 1;
53
54 while (isspace(*right))
55 *right-- = 0;
56
57 return s;
58}
59
65char* Com_Trim (char* s)
66{
67 char* left;
68
69 left = s;
70
71 while (isspace(*left))
72 left++;
73
74 return Com_Chop(left);
75}
76
82char* Com_ConvertToASCII7 (char* s)
83{
84 unsigned int l;
85 const size_t length = strlen(s);
86
87 l = 0;
88 do {
89 int c = s[l];
90 if (c == '\0')
91 break;
92 /* don't allow higher ascii values */
93 if (c >= 127)
94 s[l] = '.';
95 l++;
96 } while (l < length);
97
98 s[l] = '\0';
99
100 return s;
101}
102
106static int Com_FilterAfterStar (const char* pattern, const char* text)
107{
108 register const char* p = pattern, *t = text;
109 register char c, c1;
110
111 while ((c = *p++) == '?' || c == '*')
112 if (c == '?' && *t++ == '\0')
113 return 0;
114
115 if (c == '\0')
116 return 1;
117
118 if (c == '\\')
119 c1 = *p;
120 else
121 c1 = c;
122
123 while (1) {
124 if ((c == '[' || *t == c1) && Com_Filter(p - 1, t))
125 return 1;
126 if (*t++ == '\0')
127 return 0;
128 }
129}
130
145int Com_Filter (const char* pattern, const char* text)
146{
147 register const char* p = pattern, *t = text;
148 register char c;
149
150 while ((c = *p++) != '\0')
151 switch (c) {
152 case '?':
153 if (*t == '\0')
154 return 0;
155 else
156 ++t;
157 break;
158
159 case '\\':
160 if (*p++ != *t++)
161 return 0;
162 break;
163
164 case '*':
165 return Com_FilterAfterStar(p, t);
166
167 case '[':
168 {
169 register char c1 = *t++;
170 int invert;
171
172 if (!c1)
173 return (0);
174
175 invert = ((*p == '!') || (*p == '^'));
176 if (invert)
177 p++;
178
179 c = *p++;
180 while (1) {
181 register char cstart = c, cend = c;
182
183 if (c == '\\') {
184 cstart = *p++;
185 cend = cstart;
186 }
187 if (c == '\0')
188 return 0;
189
190 c = *p++;
191 if (c == '-' && *p != ']') {
192 cend = *p++;
193 if (cend == '\\')
194 cend = *p++;
195 if (cend == '\0')
196 return 0;
197 c = *p++;
198 }
199 if (c1 >= cstart && c1 <= cend)
200 goto match;
201 if (c == ']')
202 break;
203 }
204 if (!invert)
205 return 0;
206 break;
207
208 match:
209 /* Skip the rest of the [...] construct that already matched. */
210 while (c != ']') {
211 if (c == '\0')
212 return 0;
213 c = *p++;
214 if (c == '\0')
215 return 0;
216 else if (c == '\\')
217 ++p;
218 }
219 if (invert)
220 return 0;
221 break;
222 }
223
224 default:
225 if (c != *t++)
226 return 0;
227 }
228
229 return *t == '\0';
230}
231
239void Com_ReplaceFilename (const char* inputPath, const char* expectedFileName, char* outputPath, size_t size)
240{
241 char* slash, *end;
242
243 Q_strncpyz(outputPath, inputPath, size);
244
245 end = outputPath;
246 while ((slash = strchr(end, '/')) != 0)
247 end = slash + 1;
248
249 strcpy(end, expectedFileName);
250}
251
259void Com_StripExtension (const char* in, char* out, const size_t size)
260{
261 char* out_ext = nullptr;
262 int i = 1;
263
264 while (in && *in && i < size) {
265 *out++ = *in++;
266 i++;
267
268 if (*in == '.')
269 out_ext = out;
270 }
271
272 if (out_ext)
273 *out_ext = '\0';
274 else
275 *out = '\0';
276}
277
282const char* Com_GetExtension (const char* path)
283{
284 const char* src = path + strlen(path) - 1;
285 while (*src != '/' && src != path) {
286 if (*src == '.')
287 return src + 1;
288 src--;
289 }
290
291 return nullptr;
292}
293
297void Com_DefaultExtension (char* path, size_t len, const char* extension)
298{
299 char oldPath[MAX_OSPATH];
300 const char* src;
301
302 /* if path doesn't have a .EXT, append extension
303 * (extension should include the .) */
304 src = path + strlen(path) - 1;
305
306 while (*src != '/' && src != path) {
307 if (*src == '.')
308 return;
309 src--;
310 }
311
312 Q_strncpyz(oldPath, path, sizeof(oldPath));
313 Com_sprintf(path, len, "%s%s", oldPath, extension);
314}
315
319void Com_FilePath (const char* in, char* out, size_t size)
320{
321 const char* s = in + strlen(in) - 1;
322
323 while (s != in && *s != '/')
324 s--;
325
326 const size_t pathLength = s - in + 1;
327 if (pathLength <= size)
328 Q_strncpyz(out, in, pathLength);
329 else if (size >= 1)
330 out[0] = '\0';
331}
332
336unsigned int Com_HashKey (const char* name, int hashsize)
337{
338 unsigned int v = 0;
339 for (int i = 0; name[i]; i++) {
340 const unsigned int c = name[i];
341 v = (v + i) * 37 + tolower(c); /* case insensitivity */
342 }
343
344 return v % hashsize;
345}
346
352void Com_MakeTimestamp (char* ts, const size_t tslen)
353{
354 struct tm* t;
355 time_t aclock;
356
357 time(&aclock);
358 t = localtime(&aclock);
359
360 Com_sprintf(ts, tslen, "%4i/%02i/%02i %02i:%02i:%02i", t->tm_year + 1900,
361 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
362}
363
372int Q_FloatSort (const void* float1, const void* float2)
373{
374 return (*(const float*)float1 - *(const float*)float2);
375}
376
385int Q_StringSort (const void* string1, const void* string2)
386{
387 const char* s1 = (const char*)string1;
388 const char* s2 = (const char*)string2;
389 if (*s1 < *s2)
390 return -1;
391 else if (*s1 == *s2) {
392 while (*s1) {
393 s1++;
394 s2++;
395 if (*s1 < *s2)
396 return -1;
397 if (*s1 > *s2)
398 return 1;
399 }
400 return 0;
401 } else
402 return 1;
403}
404
405#define VA_BUFSIZE 4096
410const char* va (const char* format, ...)
411{
412 va_list argptr;
413 /* in case va is called by nested functions */
414 static char string[16][VA_BUFSIZE];
415 static unsigned int index = 0;
416 char* buf;
417
418 buf = string[index & 0x0F];
419 index++;
420
421 va_start(argptr, format);
422 Q_vsnprintf(buf, VA_BUFSIZE, format, argptr);
423 va_end(argptr);
424
425 return buf;
426}
427
428/*
429============================================================================
430LIBRARY REPLACEMENT FUNCTIONS
431============================================================================
432*/
433
438char* Q_strlwr (char* str)
439{
440 char* origs = str;
441 while (*str) {
442 *str = tolower(*str);
443 str++;
444 }
445 return origs;
446}
447
454#ifdef DEBUG
455void Q_strncpyzDebug (char* dest, const char* src, size_t destsize, const char* file, int line)
456#else
457void Q_strncpyz (char* dest, const char* src, size_t destsize)
458#endif
459{
460#ifdef DEBUG
461 if (destsize < 1)
462 Sys_Error("Q_strncpyz: destsize < 1 (%s, %i)", file, line);
463#endif
464 UTF8_strncpyz(dest, src, destsize);
465}
466
475void Q_strcat (char* dest, size_t destsize, const char* format, ...)
476{
477 const size_t dest_length = strlen(dest);
478 if (dest_length >= destsize)
479 Sys_Error("Q_strcat: already overflowed");
480
481 va_list argptr;
482 va_start(argptr, format);
483 Q_vsnprintf(dest + dest_length, destsize - dest_length, format, argptr);
484 va_end(argptr);
485}
486
494bool Com_sprintf (char* dest, size_t size, const char* fmt, ...)
495{
496 va_list ap;
497 int len;
498
499 if (!fmt)
500 return false;
501
502 va_start(ap, fmt);
503 len = Q_vsnprintf(dest, size, fmt, ap);
504 va_end(ap);
505
506 if (len <= size - 1)
507 return true;
508
509 /* number of character */
510 len = size - 1;
511
512 /* check for UTF8 multibyte sequences */
513 if (len > 0 && (unsigned char) dest[len - 1] >= 0x80) {
514 int i = len - 1;
515 while (i > 0 && UTF8_CONTINUATION_BYTE((unsigned char) dest[i]))
516 i--;
517 if (UTF8_char_len(dest[i]) + i > len) {
518 dest[i] = '\0';
519 }
520#ifdef DEBUG
521 else {
522 /* the '\0' is already at the right place */
523 len = i + UTF8_char_len(dest[i]);
524 assert(dest[len] == '\0');
525 }
526#endif
527 }
528
529 return false;
530}
531
535int Q_vsnprintf (char* str, size_t size, const char* format, va_list ap)
536{
537 int len;
538
539#if defined(_WIN32)
540 len = _vsnprintf(str, size, format, ap);
541 str[size - 1] = '\0';
542#ifdef DEBUG
543 if (len == -1)
544 Com_Printf("Q_vsnprintf: string (%.32s...) was truncated (%i) - target buffer too small (" UFO_SIZE_T ")\n", str, len, size);
545#endif
546#else
547 len = vsnprintf(str, size, format, ap);
548#ifdef DEBUG
549 if ((size_t)len >= size)
550 Com_Printf("Q_vsnprintf: string (%.32s...) was truncated (%i) - target buffer too small (" UFO_SIZE_T ")\n", str, len, size);
551#endif
552#endif
553
554 return len;
555}
556
563const char* Q_stristr (const char* str, const char* substr)
564{
565 const size_t sublen = strlen(substr);
566 while (*str) {
567 if (!Q_strncasecmp(str, substr, sublen))
568 break;
569 str++;
570 }
571 if (!(*str))
572 str = nullptr;
573 return str;
574}
575
587char const* Q_strstart (char const* str, char const* start)
588{
589 for (; *start != '\0'; ++str, ++start) {
590 if (*str != *start)
591 return nullptr;
592 }
593 return str;
594}
595
596bool Q_strreplace (const char* source, const char* pattern, const char* replace, char* dest, size_t destsize)
597{
598 if (char const* const hit = strstr(source, pattern)) {
599 int const len = snprintf(dest, destsize, "%.*s%s%s", (int)(hit - source), source, replace, hit + strlen(pattern));
600 return 0 < len && (size_t)len < destsize;
601 } else {
602 return false;
603 }
604}
605
612bool Com_IsValidName (const char* input)
613{
614 /* empty strings are not allowed */
615 if (!Q_strvalid(input))
616 return false;
617 /* names with only _ are not allowed - they would get translated with as empty msgid for gettext */
618 if (Q_streq(input, "_"))
619 return false;
620 /* there may be no quotes in the names - as they are given very often as parameter in the scripts */
621 if (strchr(input, '"') != nullptr)
622 return false;
623 return true;
624}
625
626#ifndef NDEBUG
627void UFO_assert (bool condition, const char* fmt, ...)
628{
629 if (condition)
630 return;
631 char msg[1024];
632 va_list argptr;
633
634 va_start(argptr, fmt);
635 Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
636 va_end(argptr);
637
638 Sys_Error("%s", msg);
639}
640#endif
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
Filesystem header file.
#define MAX_OSPATH
Definition filesys.h:44
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
voidpf void uLong size
Definition ioapi.h:42
voidpf void * buf
Definition ioapi.h:42
void format(__printf__, 1, 2)))
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
QGL_EXTERN GLenum GLuint * dest
Definition r_gl.h:101
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition r_gl.h:110
QGL_EXTERN GLuint index
Definition r_gl.h:110
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
#define Q_strvalid(string)
Definition shared.h:141
#define Q_streq(a, b)
Definition shared.h:136
#define Q_strncasecmp(s1, s2, n)
Definition shared.h:132
char * Q_strlwr(char *str)
Converts a string to lowercase.
Definition shared.cpp:438
char * Com_Chop(char *s)
Removed trailing whitespaces.
Definition shared.cpp:48
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition shared.cpp:259
unsigned int Com_HashKey(const char *name, int hashsize)
returns hash key for a string
Definition shared.cpp:336
bool Com_IsValidName(const char *input)
Checks whether the given input string is allowed to be used as a user-given name string for aircraft,...
Definition shared.cpp:612
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition shared.cpp:37
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
void Com_DefaultExtension(char *path, size_t len, const char *extension)
Sets a default extension if there is none.
Definition shared.cpp:297
int Q_StringSort(const void *string1, const void *string2)
Compare two strings.
Definition shared.cpp:385
void Com_FilePath(const char *in, char *out, size_t size)
Returns the path up to, but not including the last /.
Definition shared.cpp:319
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition shared.cpp:535
const char * Com_GetExtension(const char *path)
Definition shared.cpp:282
char * Com_Trim(char *s)
Removed leading and trailing whitespaces.
Definition shared.cpp:65
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition shared.cpp:475
static int Com_FilterAfterStar(const char *pattern, const char *text)
Like Com_Filter, but match PATTERN against any final segment of TEXT.
Definition shared.cpp:106
void Com_MakeTimestamp(char *ts, const size_t tslen)
Creates a timestamp with date and time at the specified location.
Definition shared.cpp:352
char * Com_ConvertToASCII7(char *s)
Remove high character values and only keep ascii. This can be used to print utf-8 characters to the c...
Definition shared.cpp:82
void UFO_assert(bool condition, const char *fmt,...)
Definition shared.cpp:627
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
void Com_ReplaceFilename(const char *inputPath, const char *expectedFileName, char *outputPath, size_t size)
Replaces the filename from one path with another one.
Definition shared.cpp:239
const char * Q_stristr(const char *str, const char *substr)
Checks in case insensitive manner whether str contains substr.
Definition shared.cpp:563
bool Q_strreplace(const char *source, const char *pattern, const char *replace, char *dest, size_t destsize)
Replaces the first occurence of the given pattern in the source string with the given replace string.
Definition shared.cpp:596
int Com_Filter(const char *pattern, const char *text)
Match the pattern PATTERN against the string TEXT;.
Definition shared.cpp:145
#define VA_BUFSIZE
Definition shared.cpp:405
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
int Q_FloatSort(const void *float1, const void *float2)
Compare two floats.
Definition shared.cpp:372
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
System specific stuff.
#define UFO_SIZE_T
Definition ufotypes.h:89
int UTF8_char_len(unsigned char c)
length of UTF-8 character starting with this byte.
Definition utf8.cpp:109
char * UTF8_strncpyz(char *dest, const char *src, size_t limit)
UTF8 capable string copy function.
Definition utf8.cpp:247
#define UTF8_CONTINUATION_BYTE(c)
Definition utf8.h:35