UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
shared.cpp
Go to the documentation of this file.
1 
6 /*
7 All original material Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 Copyright (C) 1997-2001 Id Software, Inc.
10 
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, 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 
37 const char* Com_SkipPath (const char* pathname)
38 {
39  char const* const last = strrchr(pathname, '/');
40  return last ? last + 1 : pathname;
41 }
42 
48 char* 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 
65 char* 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 
82 char* 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 
106 static 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 
145 int 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 
239 void 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 
259 void 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 
282 const 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 
297 void 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 
319 void 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 
336 unsigned 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 
352 void 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 
372 int Q_FloatSort (const void* float1, const void* float2)
373 {
374  return (*(const float*)float1 - *(const float*)float2);
375 }
376 
385 int 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
406 
410 const 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 ============================================================================
430 LIBRARY REPLACEMENT FUNCTIONS
431 ============================================================================
432 */
433 
438 char* 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
455 void Q_strncpyzDebug (char* dest, const char* src, size_t destsize, const char* file, int line)
456 #else
457 void 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 
475 void 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 
494 bool 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 
535 int 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 
563 const 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 
587 char 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 
596 bool 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 
612 bool 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
627 void 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
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition: shared.cpp:535
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition: shared.cpp:37
const char * Com_GetExtension(const char *path)
Definition: shared.cpp:282
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
char * UTF8_strncpyz(char *dest, const char *src, size_t limit)
UTF8 capable string copy function.
Definition: utf8.cpp:247
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition: shared.cpp:259
int UTF8_char_len(unsigned char c)
length of UTF-8 character starting with this byte.
Definition: utf8.cpp:109
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
#define MAX_OSPATH
Definition: filesys.h:44
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
char * Com_Trim(char *s)
Removed leading and trailing whitespaces.
Definition: shared.cpp:65
voidpf void * buf
Definition: ioapi.h:42
#define UTF8_CONTINUATION_BYTE(c)
Definition: utf8.h:35
#define Q_strvalid(string)
Definition: shared.h:141
void UFO_assert(bool condition, const char *fmt,...)
Definition: shared.cpp:627
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
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
GLsizei size
Definition: r_gl.h:152
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
#define Q_strncasecmp(s1, s2, n)
Definition: shared.h:132
int Com_Filter(const char *pattern, const char *text)
Match the pattern PATTERN against the string TEXT;.
Definition: shared.cpp:145
const char * Q_stristr(const char *str, const char *substr)
Checks in case insensitive manner whether str contains substr.
Definition: shared.cpp:563
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
QGL_EXTERN GLenum GLuint * dest
Definition: r_gl.h:101
char * Q_strlwr(char *str)
Converts a string to lowercase.
Definition: shared.cpp:438
#define VA_BUFSIZE
Definition: shared.cpp:405
QGL_EXTERN GLuint index
Definition: r_gl.h:110
void Com_MakeTimestamp(char *ts, const size_t tslen)
Creates a timestamp with date and time at the specified location.
Definition: shared.cpp:352
int Q_FloatSort(const void *float1, const void *float2)
Compare two floats.
Definition: shared.cpp:372
void Com_DefaultExtension(char *path, size_t len, const char *extension)
Sets a default extension if there is none.
Definition: shared.cpp:297
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
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
unsigned int Com_HashKey(const char *name, int hashsize)
returns hash key for a string
Definition: shared.cpp:336
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition: shared.cpp:475
#define UFO_SIZE_T
Definition: ufotypes.h:89
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 Q_StringSort(const void *string1, const void *string2)
Compare two strings.
Definition: shared.cpp:385
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
#define Q_streq(a, b)
Definition: shared.h:136
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
char * Com_Chop(char *s)
Removed trailing whitespaces.
Definition: shared.cpp:48
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 format(__printf__, 1, 2)))