Quake II RTX doxygen  1.0 dev
utils.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 #include "shared/shared.h"
20 #include "common/utils.h"
21 
22 /*
23 ==============================================================================
24 
25  WILDCARD COMPARE
26 
27 ==============================================================================
28 */
29 
30 static qboolean match_raw(int c1, int c2, qboolean ignorecase)
31 {
32  if (c1 != c2) {
33  if (!ignorecase) {
34  return qfalse;
35  }
36 #ifdef _WIN32
37  // ugly hack for file listing
38  c1 = c1 == '\\' ? '/' : Q_tolower(c1);
39  c2 = c2 == '\\' ? '/' : Q_tolower(c2);
40 #else
41  c1 = Q_tolower(c1);
42  c2 = Q_tolower(c2);
43 #endif
44  if (c1 != c2) {
45  return qfalse;
46  }
47  }
48 
49  return qtrue;
50 }
51 
52 static qboolean match_char(int c1, int c2, qboolean ignorecase)
53 {
54  if (c1 == '?') {
55  return !!c2; // match any char except NUL
56  }
57 
58  return match_raw(c1, c2, ignorecase);
59 }
60 
61 static qboolean match_part(const char *filter, const char *string,
62  size_t len, qboolean ignorecase)
63 {
64  qboolean match;
65 
66  do {
67  // skip over escape character
68  if (*filter == '\\') {
69  filter++;
70  match = match_raw(*filter, *string, ignorecase);
71  } else {
72  match = match_char(*filter, *string, ignorecase);
73  }
74 
75  if (!match) {
76  return qfalse;
77  }
78 
79  filter++;
80  string++;
81  } while (--len);
82 
83  return qtrue;
84 }
85 
86 // match the longest possible part
87 static const char *match_filter(const char *filter, const char *string,
88  size_t len, qboolean ignorecase)
89 {
90  const char *ret = NULL;
91  size_t remaining = strlen(string);
92 
93  while (remaining >= len) {
94  if (match_part(filter, string, len, ignorecase)) {
95  string += len;
96  remaining -= len;
97  ret = string;
98  continue;
99  }
100  string++;
101  remaining--;
102  }
103 
104  return ret;
105 }
106 
107 /*
108 =================
109 Com_WildCmpEx
110 
111 Wildcard compare. Returns true if string matches the pattern, false otherwise.
112 
113 - 'term' is handled as an additional filter terminator (besides NUL).
114 - '*' matches any substring, including the empty string, but prefers longest
115 possible substrings.
116 - '?' matches any single character except NUL.
117 - '\\' can be used to escape any character, including itself. any special
118 characters lose their meaning in this case.
119 
120 =================
121 */
122 qboolean Com_WildCmpEx(const char *filter, const char *string,
123  int term, qboolean ignorecase)
124 {
125  const char *sub;
126  size_t len;
127  qboolean match;
128 
129  while (*filter && *filter != term) {
130  if (*filter == '*') {
131  // skip consecutive wildcards
132  do {
133  filter++;
134  } while (*filter == '*');
135 
136  // scan out filter part to match
137  for (sub = filter, len = 0; *filter && *filter != term && *filter != '*'; filter++, len++) {
138  // skip over escape character
139  if (*filter == '\\') {
140  filter++;
141  if (!*filter) {
142  break;
143  }
144  }
145  }
146 
147  // wildcard at the end matches everything
148  if (!len) {
149  return qtrue;
150  }
151 
152  string = match_filter(sub, string, len, ignorecase);
153  if (!string) {
154  return qfalse;
155  }
156  } else {
157  // skip over escape character
158  if (*filter == '\\') {
159  filter++;
160  if (!*filter) {
161  break;
162  }
163  match = match_raw(*filter, *string, ignorecase);
164  } else {
165  match = match_char(*filter, *string, ignorecase);
166  }
167 
168  // match single character
169  if (!match) {
170  return qfalse;
171  }
172 
173  filter++;
174  string++;
175  }
176  }
177 
178  // match NUL at the end
179  return !*string;
180 }
181 
182 /*
183 ==============================================================================
184 
185  MISC
186 
187 ==============================================================================
188 */
189 
190 const char *const colorNames[10] = {
191  "black", "red", "green", "yellow",
192  "blue", "cyan", "magenta", "white",
193  "alt", "none"
194 };
195 
196 /*
197 ================
198 Com_ParseColor
199 
200 Parses color name or index up to the maximum allowed index.
201 Returns COLOR_NONE in case of error.
202 ================
203 */
204 color_index_t Com_ParseColor(const char *s, color_index_t last)
205 {
206  color_index_t i;
207 
208  if (COM_IsUint(s)) {
209  i = strtoul(s, NULL, 10);
210  return i > last ? COLOR_NONE : i;
211  }
212 
213  for (i = 0; i <= last; i++) {
214  if (!strcmp(colorNames[i], s)) {
215  return i;
216  }
217  }
218 
219  return COLOR_NONE;
220 }
221 
222 #if REF_GL
223 /*
224 ================
225 Com_ParseExtensionString
226 
227 Helper function to parse an OpenGL-style extension string.
228 ================
229 */
230 unsigned Com_ParseExtensionString(const char *s, const char *const extnames[])
231 {
232  unsigned mask;
233  const char *p;
234  size_t l1, l2;
235  int i;
236 
237  if (!s) {
238  return 0;
239  }
240 
241  mask = 0;
242  while (*s) {
243  p = Q_strchrnul(s, ' ');
244  l1 = p - s;
245  for (i = 0; extnames[i]; i++) {
246  l2 = strlen(extnames[i]);
247  if (l1 == l2 && !memcmp(s, extnames[i], l1)) {
248  mask |= 1 << i;
249  break;
250  }
251  }
252  if (!*p) {
253  break;
254  }
255  s = p + 1;
256  }
257 
258  return mask;
259 }
260 #endif
261 
262 /*
263 ================
264 Com_PlayerToEntityState
265 
266 Restores entity origin and angles from player state
267 ================
268 */
269 void Com_PlayerToEntityState(const player_state_t *ps, entity_state_t *es)
270 {
271  vec_t pitch;
272 
273  VectorScale(ps->pmove.origin, 0.125f, es->origin);
274 
275  pitch = ps->viewangles[PITCH];
276  if (pitch > 180) {
277  pitch -= 360;
278  }
279  es->angles[PITCH] = pitch / 3;
280  es->angles[YAW] = ps->viewangles[YAW];
281  es->angles[ROLL] = 0;
282 }
283 
284 #if USE_CLIENT || USE_MVD_CLIENT
285 /*
286 ================
287 Com_ParseTimespec
288 
289 Parses time/frame specification for seeking in demos.
290 Does not check for integer overflow...
291 ================
292 */
293 qboolean Com_ParseTimespec(const char *s, int *frames)
294 {
295  unsigned long c1, c2, c3;
296  char *p;
297 
298  c1 = strtoul(s, &p, 10);
299  if (!*p) {
300  *frames = c1 * 10; // sec
301  return qtrue;
302  }
303 
304  if (*p == '.') {
305  c2 = strtoul(p + 1, &p, 10);
306  if (*p)
307  return qfalse;
308  *frames = c1 * 10 + c2; // sec.frac
309  return qtrue;
310  }
311 
312  if (*p == ':') {
313  c2 = strtoul(p + 1, &p, 10);
314  if (!*p) {
315  *frames = c1 * 600 + c2 * 10; // min:sec
316  return qtrue;
317  }
318 
319  if (*p == '.') {
320  c3 = strtoul(p + 1, &p, 10);
321  if (*p)
322  return qfalse;
323  *frames = c1 * 600 + c2 * 10 + c3; // min:sec.frac
324  return qtrue;
325  }
326 
327  return qfalse;
328  }
329 
330  return qfalse;
331 }
332 #endif
333 
334 /*
335 ================
336 Com_HashString
337 ================
338 */
339 unsigned Com_HashString(const char *s, unsigned size)
340 {
341  unsigned hash, c;
342 
343  hash = 0;
344  while (*s) {
345  c = *s++;
346  hash = 127 * hash + c;
347  }
348 
349  hash = (hash >> 20) ^(hash >> 10) ^ hash;
350  return hash & (size - 1);
351 }
352 
353 /*
354 ================
355 Com_HashStringLen
356 
357 A case-insensitive version of Com_HashString that hashes up to 'len'
358 characters.
359 ================
360 */
361 unsigned Com_HashStringLen(const char *s, size_t len, unsigned size)
362 {
363  unsigned hash, c;
364 
365  hash = 0;
366  while (*s && len--) {
367  c = Q_tolower(*s++);
368  hash = 127 * hash + c;
369  }
370 
371  hash = (hash >> 20) ^(hash >> 10) ^ hash;
372  return hash & (size - 1);
373 }
374 
375 /*
376 ===============
377 Com_PageInMemory
378 
379 ===============
380 */
382 
383 void Com_PageInMemory(void *buffer, size_t size)
384 {
385  int i;
386 
387  for (i = size - 1; i > 0; i -= 4096)
388  paged_total += ((byte *)buffer)[i];
389 }
390 
391 size_t Com_FormatTime(char *buffer, size_t size, time_t t)
392 {
393  int sec, min, hour, day;
394 
395  min = t / 60; sec = t % 60;
396  hour = min / 60; min %= 60;
397  day = hour / 24; hour %= 24;
398 
399  if (day) {
400  return Q_scnprintf(buffer, size, "%d+%d:%02d.%02d", day, hour, min, sec);
401  }
402  if (hour) {
403  return Q_scnprintf(buffer, size, "%d:%02d.%02d", hour, min, sec);
404  }
405  return Q_scnprintf(buffer, size, "%02d.%02d", min, sec);
406 }
407 
408 size_t Com_FormatTimeLong(char *buffer, size_t size, time_t t)
409 {
410  int sec, min, hour, day;
411  size_t len;
412 
413  if (!t) {
414  return Q_scnprintf(buffer, size, "0 secs");
415  }
416 
417  min = t / 60; sec = t % 60;
418  hour = min / 60; min %= 60;
419  day = hour / 24; hour %= 24;
420 
421  len = 0;
422 
423  if (day) {
424  len += Q_scnprintf(buffer + len, size - len,
425  "%d day%s%s", day, day == 1 ? "" : "s", (hour || min || sec) ? ", " : "");
426  }
427  if (hour) {
428  len += Q_scnprintf(buffer + len, size - len,
429  "%d hour%s%s", hour, hour == 1 ? "" : "s", (min || sec) ? ", " : "");
430  }
431  if (min) {
432  len += Q_scnprintf(buffer + len, size - len,
433  "%d min%s%s", min, min == 1 ? "" : "s", sec ? ", " : "");
434  }
435  if (sec) {
436  len += Q_scnprintf(buffer + len, size - len,
437  "%d sec%s", sec, sec == 1 ? "" : "s");
438  }
439 
440  return len;
441 }
442 
443 size_t Com_TimeDiff(char *buffer, size_t size, time_t *p, time_t now)
444 {
445  time_t diff;
446 
447  if (*p > now) {
448  *p = now;
449  }
450  diff = now - *p;
451  return Com_FormatTime(buffer, size, diff);
452 }
453 
454 size_t Com_TimeDiffLong(char *buffer, size_t size, time_t *p, time_t now)
455 {
456  time_t diff;
457 
458  if (*p > now) {
459  *p = now;
460  }
461  diff = now - *p;
462  return Com_FormatTimeLong(buffer, size, diff);
463 }
464 
465 size_t Com_FormatSize(char *dest, size_t destsize, off_t bytes)
466 {
467  if (bytes >= 10000000) {
468  return Q_scnprintf(dest, destsize, "%dM", (int)(bytes / 1000000));
469  }
470  if (bytes >= 1000000) {
471  return Q_scnprintf(dest, destsize, "%.1fM", (float)bytes / 1000000);
472  }
473  if (bytes >= 1000) {
474  return Q_scnprintf(dest, destsize, "%dK", (int)(bytes / 1000));
475  }
476  if (bytes >= 0) {
477  return Q_scnprintf(dest, destsize, "%d", (int)bytes);
478  }
479  return Q_scnprintf(dest, destsize, "???");
480 }
481 
482 size_t Com_FormatSizeLong(char *dest, size_t destsize, off_t bytes)
483 {
484  if (bytes >= 10000000) {
485  return Q_scnprintf(dest, destsize, "%d MB", (int)(bytes / 1000000));
486  }
487  if (bytes >= 1000000) {
488  return Q_scnprintf(dest, destsize, "%.1f MB", (float)bytes / 1000000);
489  }
490  if (bytes >= 1000) {
491  return Q_scnprintf(dest, destsize, "%d kB", (int)(bytes / 1000));
492  }
493  if (bytes >= 0) {
494  return Q_scnprintf(dest, destsize, "%d byte%s",
495  (int)bytes, bytes == 1 ? "" : "s");
496  }
497  return Q_scnprintf(dest, destsize, "unknown size");
498 }
499 
500 
Com_ParseColor
color_index_t Com_ParseColor(const char *s, color_index_t last)
Definition: utils.c:204
Com_TimeDiff
size_t Com_TimeDiff(char *buffer, size_t size, time_t *p, time_t now)
Definition: utils.c:443
Com_FormatTimeLong
size_t Com_FormatTimeLong(char *buffer, size_t size, time_t t)
Definition: utils.c:408
Com_FormatSizeLong
size_t Com_FormatSizeLong(char *dest, size_t destsize, off_t bytes)
Definition: utils.c:482
colorNames
const char *const colorNames[10]
Definition: utils.c:190
Com_HashString
unsigned Com_HashString(const char *s, unsigned size)
Definition: utils.c:339
Com_PlayerToEntityState
void Com_PlayerToEntityState(const player_state_t *ps, entity_state_t *es)
Definition: utils.c:269
Com_HashStringLen
unsigned Com_HashStringLen(const char *s, size_t len, unsigned size)
Definition: utils.c:361
match_filter
static const char * match_filter(const char *filter, const char *string, size_t len, qboolean ignorecase)
Definition: utils.c:87
Q_strchrnul
char * Q_strchrnul(const char *s, int c)
Definition: shared.c:879
paged_total
int paged_total
Definition: utils.c:381
Com_FormatTime
size_t Com_FormatTime(char *buffer, size_t size, time_t t)
Definition: utils.c:391
Com_TimeDiffLong
size_t Com_TimeDiffLong(char *buffer, size_t size, time_t *p, time_t now)
Definition: utils.c:454
Com_WildCmpEx
qboolean Com_WildCmpEx(const char *filter, const char *string, int term, qboolean ignorecase)
Definition: utils.c:122
match_part
static qboolean match_part(const char *filter, const char *string, size_t len, qboolean ignorecase)
Definition: utils.c:61
COM_IsUint
qboolean COM_IsUint(const char *s)
Definition: shared.c:330
c
statCounters_t c
Definition: main.c:30
match_raw
static qboolean match_raw(int c1, int c2, qboolean ignorecase)
Definition: utils.c:30
diff
static q_noinline int diff(uint32_t A_u32, uint32_t B_u32)
Definition: hq2x.c:55
Com_FormatSize
size_t Com_FormatSize(char *dest, size_t destsize, off_t bytes)
Definition: utils.c:465
match_char
static qboolean match_char(int c1, int c2, qboolean ignorecase)
Definition: utils.c:52
Com_PageInMemory
void Com_PageInMemory(void *buffer, size_t size)
Definition: utils.c:383
Q_scnprintf
size_t Q_scnprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:867