UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
entitiesdef.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 <string.h>
29 #include <stdlib.h>
30 #include <assert.h>
31 #include <stdio.h>
32 #include <math.h>
33 
34 #include "shared.h" /* needed for strdup() */
35 #include "parse.h"
36 #include "entitiesdef.h"
37 
38 #define ED_MAX_KEYS_PER_ENT 32
39 #define ED_MAX_TOKEN_LEN 512
40 #define ED_MAX_ERR_LEN 512
41 
42 static char lastErr[ED_MAX_ERR_LEN];
47 
52 #define ED_RETURN_ERROR(...) \
53  { \
54  snprintf(lastErr, sizeof(lastErr), __VA_ARGS__); \
55  return ED_ERROR; \
56  }
57 
62 #define ED_TEST_RETURN_ERROR(condition,...) \
63  if (condition) { \
64  snprintf(lastErr, sizeof(lastErr), __VA_ARGS__); \
65  return ED_ERROR; \
66  }
67 
73 #define ED_PASS_ERROR(function_call) \
74  if ((function_call) == ED_ERROR) { \
75  return ED_ERROR; \
76  }
77 
84 #define ED_PASS_ERROR_EXTRAMSG(function_call,...) \
85  if ((function_call) == ED_ERROR) { \
86  snprintf(lastErrExtra, sizeof(lastErr), __VA_ARGS__); \
87  strncat(lastErr, lastErrExtra, sizeof(lastErr) - strlen(lastErr) -1); \
88  return ED_ERROR; \
89  }
90 
95 static int ED_AllocEntityDef (entityKeyDef_t* newKeyDefs, int numKeyDefs, int entityIndex)
96 {
97  entityDef_t* eDef = &entityDefs[entityIndex];
98 
99  /* now we know how many there are in this entity, malloc */
100  eDef->keyDefs = (entityKeyDef_t*) malloc((numKeyDefs + 1) * sizeof(entityKeyDef_t));
101  ED_TEST_RETURN_ERROR(!eDef->keyDefs, "ED_AllocEntityDef: out of memory");
102  eDef->numKeyDefs = numKeyDefs;
103 
104  /* and copy from temp buffer */
105  memcpy(eDef->keyDefs, newKeyDefs, numKeyDefs * sizeof(entityKeyDef_t));
106 
107  /* set nullptrs at the end, to enable looping through using a pointer */
108  OBJZERO(eDef->keyDefs[numKeyDefs]);
109 
110  /* classname is commonly used, put it in its own field, copied from keyDefs[0] */
111  eDef->classname = strdup(eDef->keyDefs->desc);
112  ED_TEST_RETURN_ERROR(!eDef->classname, "ED_AllocEntityDef: out of memory");
113 
114  return ED_OK;
115 }
116 
121 static entityKeyDef_t* ED_FindKeyDefInArray (entityKeyDef_t keyDefs[], int numDefs, const char* name, int parseMode)
122 {
123  for (int i = 0; i < numDefs; i++) {
124  const entityKeyDef_t* keyDef = &keyDefs[i];
125  /* names equal. both abstract or both not abstract */
126  if (Q_streq(keyDef->name, name) && !((keyDef->flags ^ parseMode) & ED_ABSTRACT)) {
127  return &keyDefs[i];
128  }
129  }
130  return nullptr;
131 }
132 
138 static int ED_Type2Constant (const char* strType)
139 {
140  if (Q_streq(strType, "V_FLOAT"))
141  return ED_TYPE_FLOAT;
142  else if (Q_streq(strType, "V_INT"))
143  return ED_TYPE_INT;
144  else if (Q_streq(strType, "V_BOOL"))
145  return ED_TYPE_BOOL;
146  else if (Q_streq(strType, "V_STRING"))
147  return ED_TYPE_STRING;
148 
149  ED_RETURN_ERROR("ED_Type2Constant: type string not recognised: \"%s\"", strType);
150 }
151 
157 static const char* ED_Constant2Type (int constInt)
158 {
159  switch (constInt) {
160  case ED_TYPE_FLOAT:
161  return "V_FLOAT";
162  case ED_TYPE_BOOL:
163  return "V_BOOL";
164  case ED_TYPE_INT:
165  return "V_INT";
166  case ED_TYPE_STRING:
167  return "V_STRING";
168  default:
169  snprintf(lastErr, sizeof(lastErr), "ED_Constant2Type: constant not recognised");
170  return nullptr;
171  }
172 }
173 
183 static int ED_GetIntVectorFromString (const char* str, int v[], const int n)
184 {
185  int i;
186  const char* buf_p = str;
187 
188  for (i = 0; buf_p; i++) {
189  const char* tok = Com_Parse(&buf_p);
190  if (tok[0] == '\0')
191  break; /* previous tok was the last real one, don't waste time */
192  ED_TEST_RETURN_ERROR(i >= n, "ED_GetIntVectorFromString: v[%i] too small for ints from string \"%s\"", n, str);
193  v[i] = atoi(tok);
194  }
195  ED_TEST_RETURN_ERROR(i != n, "ED_GetIntVectorFromString: v[%i] wrong size for ints from string \"%s\"", n, str);
196  return ED_OK;
197 }
198 
208 int ED_GetIntVector (const entityKeyDef_t* kd, int v[], const int n)
209 {
211  return ED_OK;
212 }
213 
226 static int ED_CheckNumber (const char* value, const int floatOrInt, const int insistPositive, int_float_tu* parsedNumber)
227 {
228  char* end_p;
229  /* V_INTs are protected from octal and hex as strtol with base 10 is used.
230  * this test is useful for V_INT, as it gives a specific error message.
231  * V_FLOATs are not protected from hex, inf, nan, so this check is here.
232  * strstr is used for hex, as 0x may not be the start of the string.
233  * eg -0x0.2 is a negative hex float */
234  ED_TEST_RETURN_ERROR(value[0] == 'i' || value[0] == 'I' || value[0] == 'n' || value[0] == 'N'
235  || strstr(value, "0x") || strstr(value, "0X"),
236  "infinity, NaN, hex (0x...) not allowed. found \"%s\"", value);
237  switch (floatOrInt) {
238  case ED_TYPE_FLOAT:
239  parsedNumber->f = strtof(value, &end_p);
240  ED_TEST_RETURN_ERROR(insistPositive && parsedNumber->f < 0.0f, "ED_CheckNumber: not positive %s", value);
241  break;
242  case ED_TYPE_BOOL:
243  parsedNumber->i = (int)strtol(value, &end_p, 10);
244  ED_TEST_RETURN_ERROR(parsedNumber->i < 0 || parsedNumber->i > 1, "ED_CheckNumber: no boolean %s", value);
245  break;
246  case ED_TYPE_INT:
247  parsedNumber->i = (int)strtol(value, &end_p, 10);
248  ED_TEST_RETURN_ERROR(insistPositive && parsedNumber->i < 0, "ED_CheckNumber: not positive %s", value);
249  break;
250  default:
251  ED_RETURN_ERROR("ED_CheckNumber: type to test against not recognised");
252  }
253  /* if strto* did not use the whole token, then there is some non-number part to it */
254  ED_TEST_RETURN_ERROR(strlen(value) != (unsigned int)(end_p-value),
255  "problem with numeric value: \"%s\" declared as %s. (might be relevant: only use whitespace to delimit values)",
256  value, ED_Constant2Type(floatOrInt));
257  return ED_OK;
258 }
259 
269 static int ED_CheckRange (const entityKeyDef_t* keyDef, const int type, const int index, int_float_tu parsedNumber)
270 {
271  /* there may be a range for each element of the value, or there may only be one */
272  const int useRangeIndex = (keyDef->numRanges == 1) ? 0 : index;
273  entityKeyRange_t* kr;
274  const float discreteFloatEpsilon = 0.0001f;
275  if (0 == keyDef->numRanges)
276  return ED_OK; /* if no range defined, that is OK */
277  assert(useRangeIndex < keyDef->numRanges);
278  kr = keyDef->ranges[useRangeIndex];
279  switch (type) {
280  case ED_TYPE_BOOL:
281  return ED_OK;
282  case ED_TYPE_FLOAT:
283  if (kr->continuous) {
284  ED_TEST_RETURN_ERROR(parsedNumber.f < kr->fArr[0] || parsedNumber.f > kr->fArr[1],
285  "ED_CheckRange: %.1f out of range, \"%s\" in %s",
286  parsedNumber.f, kr->str, keyDef->name);
287  return ED_OK;
288  } else {
289  for (int j = 0; j < kr->numElements; j++)
290  if (fabs(parsedNumber.f - kr->fArr[j]) < discreteFloatEpsilon)
291  return ED_OK;
292  }
293  break;
294  case ED_TYPE_INT:
295  if (kr->continuous) {
296  ED_TEST_RETURN_ERROR(parsedNumber.i < kr->iArr[0] || parsedNumber.i > kr->iArr[1],
297  "ED_CheckRange: %i out of range, \"%s\" in %s",
298  parsedNumber.i, kr->str, keyDef->name);
299  return ED_OK;
300  } else {
301  for (int j = 0; j < kr->numElements; j++)
302  if (kr->iArr[j] == parsedNumber.i)
303  return ED_OK;
304  }
305  break;
306  default:
307  ED_RETURN_ERROR( "ED_CheckRange: type to test against not recognised in %s", keyDef->name);
308  }
309  ED_RETURN_ERROR("ED_CheckRange: value not specified in range definition, \"%s\" in %s",
310  kr->str, keyDef->name);
311 }
312 
321 static int ED_CheckNumericType (const entityKeyDef_t* keyDef, const char* value, const int type)
322 {
323  int i = 0;
324  static char tokBuf[64];
325  const char* buf_p = tokBuf;
326 
327  strncpy(tokBuf, value, sizeof(tokBuf));
328  assert(type == ED_TYPE_INT || type == ED_TYPE_FLOAT || type == ED_TYPE_BOOL);
329  while (buf_p) {
330  const char* tok = Com_Parse(&buf_p);
331  int_float_tu parsedNumber;
332  if (tok[0] == '\0')
333  break; /* previous tok was the last real one, don't waste time */
334 
335  ED_PASS_ERROR_EXTRAMSG(ED_CheckNumber(tok, type, keyDef->flags & ED_INSIST_POSITIVE, &parsedNumber),
336  " in key \"%s\"", keyDef->name);
337 
338  ED_PASS_ERROR(ED_CheckRange(keyDef, type, i, parsedNumber));
339 
340  i++;
341  }
342 
343  ED_TEST_RETURN_ERROR(i != keyDef->vLen, "ED_CheckNumericType: %i elements in vector that should have %i for \"%s\" key",
344  i, keyDef->vLen, keyDef->name);
345 
346  return ED_OK;
347 }
348 
357 int ED_Check (const char* classname, const char* key, const char* value)
358 {
359  const entityKeyDef_t* kd = ED_GetKeyDef(classname, key, 0);
360  if (!kd)
361  return ED_ERROR;
362 
363  return ED_CheckKey(kd, value);
364 }
365 
372 int ED_CheckKey (const entityKeyDef_t* kd, const char* value)
373 {
374  ED_TEST_RETURN_ERROR(!kd, "ED_CheckTypeEntityKey: null key def");
375  switch (kd->flags & ED_KEY_TYPE) {
376  case ED_TYPE_FLOAT:
377  return ED_CheckNumericType(kd, value, ED_TYPE_FLOAT);
378  case ED_TYPE_INT:
379  return ED_CheckNumericType(kd, value, ED_TYPE_INT);
380  case ED_TYPE_BOOL:
381  return ED_CheckNumericType(kd, value, ED_TYPE_BOOL);
382  case ED_TYPE_STRING:
383  case 0: /* string is the default */
384  return ED_OK; /* all strings are good */
385  default:
386  ED_RETURN_ERROR("ED_CheckTypeEntityKey: type not recognised in key def");
387  }
388 }
389 
394 static int ED_ParseType (entityKeyDef_t* kd, const char* parsedToken)
395 {
396  static char tokBuf[64];
397  const char* buf_p;
398  int type;
399  int vectorLen;
400  const char* partToken;
401  int_float_tu parsedNumber;
402 
403  /* need a copy, as parsedToken is held in a static buffer in the
404  * Com_Parse function */
405  ED_TEST_RETURN_ERROR((strlen(parsedToken) + 1) > sizeof(tokBuf),
406  "ED_ParseType: type string too long for buffer for key %s", kd->name);
407  strncpy(tokBuf, parsedToken, sizeof(tokBuf));
408  tokBuf[sizeof(tokBuf) - 1] = '\0';
409  buf_p = tokBuf;
410 
411  partToken = Com_Parse(&buf_p);
412 
413  if (Q_streq("SIGNED", partToken)) {
414  partToken = Com_Parse(&buf_p);/* get next token */
415  } else if (Q_streq("UNSIGNED", partToken)) {
416  kd->flags |= ED_INSIST_POSITIVE;
417  partToken = Com_Parse(&buf_p);
418  }
419 
420  if (partToken[0] != '\0') {
421  type = ED_Type2Constant(partToken);
422  ED_PASS_ERROR(type);
423  } else {/* default is string */
424  type = ED_TYPE_STRING;
425  }
426 
427  kd->flags |= type;
428  partToken = Com_Parse(&buf_p);
429  vectorLen = atoi(partToken);
430  if (vectorLen)
431  ED_TEST_RETURN_ERROR(ED_ERROR == ED_CheckNumber(partToken, ED_TYPE_INT, 1, &parsedNumber),
432  "ED_ParseType: problem with vector length \"%s\" in key %s",
433  partToken, kd->name);
434  kd->vLen = strlen(partToken) ? (vectorLen ? vectorLen : 1) : 1; /* default is 1 */
435  return ED_OK;
436 }
437 
442 static int ED_Block2Constant (const char* blockName)
443 {
444  if (Q_streq("optional", blockName))
445  return ED_OPTIONAL;
446  else if (Q_streq("mandatory", blockName))
447  return ED_MANDATORY;
448  else if (Q_streq("abstract", blockName))
449  return ED_ABSTRACT;
450  else if (Q_streq("default", blockName))
451  return ED_DEFAULT;
452  else if (Q_streq("type", blockName))
453  return ED_MODE_TYPE;
454  else if (Q_streq("range", blockName))
455  return ED_RANGE;
456  else
457  ED_RETURN_ERROR("parse mode not recognised");
458 }
459 
465 static const char* ED_Constant2Block (int constInt)
466 {
467  switch (constInt) {
468  case ED_OPTIONAL:
469  return "optional";
470  case ED_MANDATORY:
471  return "mandatory";
472  case ED_ABSTRACT:
473  return "abstract";
474  case ED_DEFAULT:
475  return "default";
476  case ED_MODE_TYPE:
477  return "type";
478  case ED_RANGE:
479  return "range";
480  default:
481  snprintf(lastErr, sizeof(lastErr), "ED_Constant2Block: constant not recognised");
482  return nullptr;
483  }
484 }
485 
486 static int ED_AllocRange (entityKeyDef_t* kd, const char* rangeStr)
487 {
488  entityKeyRange_t** newRanges;
489  /* start a new range */
490  char* newStr = strdup(rangeStr);
491  entityKeyRange_t* newRange = (entityKeyRange_t*)malloc(sizeof(entityKeyRange_t));
492  OBJZERO(*newRange);
493  /* resize array of pointers */
494  newRanges = (entityKeyRange_t**)malloc((kd->numRanges + 1) * sizeof(entityKeyRange_t*));
495  if(!newRanges || !newStr || !newRange) {
496  free(newRanges);
497  free(newRange);
498  free(newStr);
499  ED_RETURN_ERROR("ED_AllocRange: out of memory");
500  }
501  newRange->str = newStr;
502  newRanges[kd->numRanges] = newRange;
503  if (kd->ranges) {
504  memcpy(newRanges, kd->ranges, kd->numRanges * sizeof(entityKeyRange_t*));
505  free(kd->ranges);
506  }
507  kd->numRanges++;
508  kd->ranges = newRanges;
509  return ED_OK;
510 }
511 
515 static int ED_PairParsed (entityKeyDef_t keyDefsBuf[], int* numKeyDefsSoFar_p,
516  const char* newName, const char* newVal, const int mode)
517 {
518  /* check if there is already a key def */
519  entityKeyDef_t* keyDef = ED_FindKeyDefInArray(keyDefsBuf, *numKeyDefsSoFar_p, newName, mode);
520 
521  /* create one if required */
522  if (!keyDef) {
523  keyDef = &keyDefsBuf[(*numKeyDefsSoFar_p)++];
524  ED_TEST_RETURN_ERROR(*numKeyDefsSoFar_p >= ED_MAX_KEYS_PER_ENT, "ED_PairParsed: too many keys for buffer");
525  keyDef->name = strdup(newName);
526  ED_TEST_RETURN_ERROR(!keyDef->name, "ED_PairParsed: out of memory");
527  }
528 
529  /* multiple range defs are permitted, different elements can have different ranges */
530  ED_TEST_RETURN_ERROR(keyDef->flags & mode & ~ED_RANGE,
531  "Duplicate %s for %s key. second value: %s", ED_Constant2Block(mode), newName, newVal);
532 
533  keyDef->flags |= mode;
534 
535  /* store information */
536  switch (mode) {
537  case ED_MANDATORY:
538  case ED_OPTIONAL:
539  case ED_ABSTRACT: /* intentional fall-through */
540  keyDef->desc = strdup(newVal);
541  ED_TEST_RETURN_ERROR(!keyDef->desc, "ED_PairParsed: out of memory while storing string.");
542  return ED_OK;
543  case ED_DEFAULT:
544  keyDef->defaultVal = strdup(newVal);
545  ED_TEST_RETURN_ERROR(!keyDef->defaultVal, "ED_PairParsed: out of memory while storing string.");
546  return ED_OK;
547  case ED_MODE_TYPE:
548  /* only optional or mandatory keys may have types, not possible to test for this here,
549  * as the type block may come before the optional or mandatory block */
550  ED_PASS_ERROR(ED_ParseType(keyDef, newVal));
551  return ED_OK;
552  case ED_RANGE:
553  /* only typed keys may have ranges, this may only be tested after
554  * the whole ent has been parsed: the blocks may come in any order */
555  ED_PASS_ERROR(ED_AllocRange(keyDef, newVal));
556  return ED_OK;
557  default:
558  ED_RETURN_ERROR("ED_PairParsed: parse mode not recognised");
559  }
560 }
561 
565 static int ED_ParseEntities (const char** data_p)
566 {
567  int braceLevel = 0;
568  int tokensOnLevel0 = 0;
569  int mode = ED_ABSTRACT;
571  char lastTokenBuf[ED_MAX_TOKEN_LEN];
572  int keyIndex = 0;
573  int toggle = 0; /* many lines should have a pair of tokens on, this toggles 0, 1 to indicate progress */
574 
575  while (data_p) {
576  const char* parsedToken = Com_Parse(data_p);
577  toggle ^= 1;
578 
579  if (parsedToken[0] == '\0' && braceLevel == 0)
580  break;
581 
582  if (parsedToken[0] == '{') {
583  braceLevel++;
584  ED_TEST_RETURN_ERROR(braceLevel > 2, "Too many open braces, nested %i deep", braceLevel);
585  ED_TEST_RETURN_ERROR(!toggle, "ED_ParseEntities: Incorrect number of tokens before '{'");
586  toggle ^= 1; /* reset, as toggle is only for counting proper text tokens, not braces */
587  tokensOnLevel0 = 0;
588  continue;
589  }
590 
591  if (parsedToken[0] == '}') {
592  braceLevel--;
593  ED_TEST_RETURN_ERROR(braceLevel < 0, "Too many close braces. after %i entities", numEntityDefs);
594  toggle ^= 1; /* reset, as toggle is only for counting proper text tokens, not braces */
595  if (braceLevel == 0) { /* finished parsing entity def and prepare for the next one */
596  ED_PASS_ERROR(ED_AllocEntityDef(keyDefBuf, keyIndex, numEntityDefs));
597  numEntityDefs++;
598  ED_TEST_RETURN_ERROR(numEntityDefs >= ED_MAX_DEFS, "ED_ParseEntities: too many entity defs for buffer");
599  }
600  if (braceLevel == 1) /* ending a default, mandatory, etc block, go back to default parse mode */
601  mode = ED_ABSTRACT;
602 
603  continue;
604  }
605 
606  if (braceLevel == 0) {
607  if (tokensOnLevel0 == 0 && !Q_streq(parsedToken, "entity"))
608  ED_RETURN_ERROR( "Next entity expected, found \"%s\"", parsedToken);
609 
610  if (tokensOnLevel0 == 1) {/* classname of entity, start parsing new entity */
611  const entityDef_t* prevED = ED_GetEntityDef(parsedToken);
612  ED_TEST_RETURN_ERROR(prevED, "ED_ParseEntities: duplicate entity definition \"%s\"", parsedToken);
613  OBJZERO(keyDefBuf); /* ensure pointers are not carried over from previous entity */
614  keyIndex = 0;
615  ED_PASS_ERROR(ED_PairParsed(keyDefBuf, &keyIndex, "classname", parsedToken, ED_MANDATORY));
616  mode = ED_ABSTRACT;
617  }
618 
619  if (tokensOnLevel0 > 1)
620  ED_RETURN_ERROR( "Start of entity block expected found \"%s\"", parsedToken);
621 
622  tokensOnLevel0++;
623  } else { /* braceLevel > 0 */
624  const int newMode = ED_Block2Constant(parsedToken);
625  if (ED_ERROR == newMode) { /* must be a key name or value */
626  if (toggle) { /* store key name til after next token is parsed */
627  if ('\0' == parsedToken[0])
628  ED_RETURN_ERROR("key name null string, \"\", or missing closing brace");
629  strncpy(lastTokenBuf, parsedToken, sizeof(lastTokenBuf));
630  lastTokenBuf[sizeof(lastTokenBuf) - 1] = '\0';
631  } else { /* store key-value pair in buffer until whole entity is parsed */
632  ED_PASS_ERROR(ED_PairParsed(keyDefBuf, &keyIndex, lastTokenBuf, parsedToken, mode));
633  }
634  } else {
635  mode = newMode;
636  toggle ^= 1; /* start of a mode changing block is the only time that only one non-brace token is on a line */
637  }
638  }
639  }
640 
641  return ED_OK;
642 }
643 
649 static int ED_CheckDefaultTypes (void)
650 {
651  const entityDef_t* ed;
652  const entityKeyDef_t* kd;
653  for (ed = entityDefs; ed->numKeyDefs; ed++)
654  for (kd = ed->keyDefs; kd->name; kd++)
655  if (kd->defaultVal)
657  " while checking default block entry agrees with type")
658 
659  return ED_OK;
660 }
661 
668 static int ED_ProcessRanges (void)
669 {
670  static int ibuf[32];
671  static float fbuf[32];
672 
673  for (entityDef_t* ed = entityDefs; ed->numKeyDefs; ed++) {
674  for (entityKeyDef_t* kd = ed->keyDefs; kd->name; kd++) {
675  const int keyType = kd->flags & ED_KEY_TYPE;
676  for (int i = 0; i < kd->numRanges ;i++) {
677  int numElements = 0;
678  entityKeyRange_t* kr = kd->ranges[i];
679  const char* tmpRange_p = kr->str;
680  ED_TEST_RETURN_ERROR(!keyType || (keyType & ED_TYPE_STRING), "ED_ProcessRanges: ranges may not be specified for strings. note that V_STRING is the default type. %s in %s",
681  kd->name, ed->classname);
682  while (tmpRange_p) {
683  int_float_tu parsedNumber;
684  const char* tok = Com_Parse(&tmpRange_p);
685  if (tok[0] == '\0')
686  break;
687  if (Q_streq("-", tok)) {
688  kr->continuous = 1;
689  ED_TEST_RETURN_ERROR(numElements != 1, "ED_ProcessRanges: problem with continuous range, \"%s\" in %s in %s",
690  kr->str, kd->name, ed->classname);
691  continue;
692  }
693  ED_PASS_ERROR(ED_CheckNumber(tok, keyType, kd->flags & ED_INSIST_POSITIVE, &parsedNumber));
694  switch (keyType) {
695  case ED_TYPE_BOOL:
696  case ED_TYPE_INT:
697  ibuf[numElements++] = atoi(tok);
698  break;
699  case ED_TYPE_FLOAT:
700  fbuf[numElements++] = atof(tok);
701  break;
702  default:
703  ED_RETURN_ERROR("ED_ProcessRanges: unexpected type");
704  }
705  }
706  kr->numElements = numElements;
707  ED_TEST_RETURN_ERROR(kr->continuous && numElements != 2,
708  "ED_ProcessRanges: continuous range should only have 2 elements, upper and lower bounds, \"%s\" in %s in %s",
709  kr->str, kd->name, ed->classname);
710  if (ED_TYPE_INT == keyType || ED_TYPE_BOOL == keyType) {
711  const size_t size = numElements * sizeof(int);
712  kr->iArr = (int*)malloc(size);
713  ED_TEST_RETURN_ERROR(!kr->iArr, "ED_ProcessRanges: out of memory");
714  memcpy(kr->iArr, ibuf, size);
715  } else { /* ED_TYPE_FLOAT */
716  const size_t size = numElements * sizeof(float);
717  kr->fArr = (float*)malloc(size);
718  ED_TEST_RETURN_ERROR(!kr->fArr, "ED_ProcessRanges: out of memory");
719  memcpy(kr->fArr, fbuf, size);
720  }
721  }
722  ED_TEST_RETURN_ERROR(kd->numRanges && kd->numRanges != 1 && kd->vLen != kd->numRanges,
723  "ED_ProcessRanges: if range definitions are supplied, "
724  "there must be one (which is applied to each element of a vector), "
725  "or one for each element of the vector. "
726  "%s in %s has %i elements in vector and %i range definitions",
727  ed->classname, kd->name, kd->vLen, kd->numRanges);
728  }
729  }
730  return ED_OK;
731 }
732 
738 int ED_Parse (const char* data_p)
739 {
740  /* only do this once, repeat calls are OK */
741  static int done = 0;
742  if (done)
743  return ED_OK;
744 
745  snprintf(lastErr, sizeof(lastErr), "no error");
746  /* Zero out so that looping through the ones that have already
747  * been parsed is possible while the rest are parsed */
748  OBJZERO(entityDefs);
749  numEntityDefs = 0;
750 
752  ED_TEST_RETURN_ERROR(numEntityDefs == 0, "ED_Parse: Zero entity definitions found");
753 
755 
757 
758  done = 1; /* do not do it again */
759 
760  return ED_OK;
761 }
762 
763 const char* ED_GetLastError (void)
764 {
765  return lastErr;
766 }
767 
775 const entityKeyDef_t* ED_GetKeyDef (const char* classname, const char* keyname, const int abstract)
776 {
777  const entityDef_t* ed = ED_GetEntityDef(classname);
778  return ED_GetKeyDefEntity(ed, keyname, abstract);
779 }
780 
789 const entityKeyDef_t* ED_GetKeyDefEntity (const entityDef_t* ed, const char* keyname, const int abstract)
790 {
791  const entityKeyDef_t* kd;
792 
793  if (!ed)
794  return nullptr;
795 
796  for (kd = ed->keyDefs; kd->name; kd++)
797  if (Q_streq(keyname, kd->name)) {
798  if (abstract) {
799  if (kd->flags & ED_ABSTRACT)
800  return kd;
801  } else {
802  if (!(kd->flags & ED_ABSTRACT))
803  return kd;
804  }
805  }
806 
807  snprintf(lastErr, sizeof(lastErr), "ED_GetKeyDefEntity: no key definition for %s found in entity %s entities.ufo", keyname, ed->classname);
808  return nullptr;
809 }
810 
815 const entityDef_t* ED_GetEntityDef (const char* classname)
816 {
817  const entityDef_t* ed;
818 
819  for (ed = entityDefs; ed->numKeyDefs; ed++)
820  if (Q_streq(classname, ed->classname))
821  return ed;
822 
823  snprintf(lastErr, sizeof(lastErr), "ED_GetEntityDef: no entity definition for %s found in entities.ufo", classname);
824  return nullptr;
825 }
826 
827 void ED_Free (void)
828 {
829  if (numEntityDefs) {
830  for (entityDef_t* ed = entityDefs; ed->numKeyDefs; ++ed) {
831  free(ed->classname);
832  for (entityKeyDef_t* kd = ed->keyDefs; kd->name; ++kd) {
833  free(kd->name);
834  free(kd->desc);
835  free(kd->defaultVal);
836  if (kd->numRanges) {
837  for (int i = 0; i < kd->numRanges ;i++) {
838  entityKeyRange_t* kr = kd->ranges[i];
839  free(kr->iArr);
840  free(kr->fArr);
841  free(kr->str);
842  free(kr);
843  }
844  free(kd->ranges);
845  }
846  }
847  free(ed->keyDefs);
848  }
849  }
850 }
int ED_CheckKey(const entityKeyDef_t *kd, const char *value)
as ED_Check, but where the entity and key are known, so takes different arguments.
static int ED_AllocEntityDef(entityKeyDef_t *newKeyDefs, int numKeyDefs, int entityIndex)
allocate space for key defs etc, pointers for which are stored in the entityDef_t ...
Definition: entitiesdef.cpp:95
#define ED_OPTIONAL
Definition: entitiesdef.h:35
static int ED_GetIntVectorFromString(const char *str, int v[], const int n)
parses an int array from a string
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
const entityKeyDef_t * ED_GetKeyDefEntity(const entityDef_t *ed, const char *keyname, const int abstract)
searches for the parsed key def, when the entity def is known
static int ED_CheckNumericType(const entityKeyDef_t *keyDef, const char *value, const int type)
tests if a value string matches the type for this key. this includes each element of a numeric array...
const entityDef_t * ED_GetEntityDef(const char *classname)
searches for the parsed entity def by classname
char * defaultVal
Definition: entitiesdef.h:66
static char lastErrExtra[ED_MAX_ERR_LEN]
Definition: entitiesdef.cpp:43
static int ED_CheckNumber(const char *value, const int floatOrInt, const int insistPositive, int_float_tu *parsedNumber)
checks that a string represents a single number
static int ED_CheckDefaultTypes(void)
checks if the default block entries meet the type and range definitions.
Shared parsing functions.
entityDef_t entityDefs[ED_MAX_DEFS+1]
Definition: entitiesdef.cpp:46
#define ED_MAX_TOKEN_LEN
Definition: entitiesdef.cpp:39
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
#define ED_INSIST_POSITIVE
Definition: entitiesdef.h:44
#define ED_RETURN_ERROR(...)
write an error message and exit the current function returning ED_ERROR
Definition: entitiesdef.cpp:52
Handles definition of entities, parsing them from entities.ufo.
#define ED_TYPE_FLOAT
Definition: entitiesdef.h:38
static int ED_PairParsed(entityKeyDef_t keyDefsBuf[], int *numKeyDefsSoFar_p, const char *newName, const char *newVal, const int mode)
static int ED_ParseType(entityKeyDef_t *kd, const char *parsedToken)
takes a type string (eg "V_FLOAT 6") and configures entity def
#define ED_RANGE
Definition: entitiesdef.h:43
unsigned int key
Definition: cl_input.cpp:68
static const char * ED_Constant2Block(int constInt)
converts an internal constant integer to a string representation of a type (eg V_FLOAT) ...
static int ED_Block2Constant(const char *blockName)
converts a block name (eg "optional") to an constant (eg ED_OPTIONAL).
#define ED_MODE_TYPE
Definition: entitiesdef.h:42
GLsizei size
Definition: r_gl.h:152
#define OBJZERO(obj)
Definition: shared.h:178
#define ED_MAX_KEYS_PER_ENT
Definition: entitiesdef.cpp:38
static int ED_Type2Constant(const char *strType)
converts a string representation of a type (eg V_FLOAT) to the appropriate internal constant integer ...
#define ED_KEY_TYPE
Definition: entitiesdef.h:48
static int ED_ProcessRanges(void)
finish parsing ranges. Could not be done earlier as would not have necessarily known types and defaul...
static int ED_ParseEntities(const char **data_p)
#define ED_DEFAULT
Definition: entitiesdef.h:41
#define ED_MAX_ERR_LEN
Definition: entitiesdef.cpp:40
void ED_Free(void)
int numEntityDefs
Definition: entitiesdef.cpp:45
int numKeyDefs
Definition: entitiesdef.h:76
int ED_Check(const char *classname, const char *key, const char *value)
tests if a value string matches the type for this key. Also checks the value against the range...
#define ED_PASS_ERROR_EXTRAMSG(function_call,...)
if the function returns ED_ERROR, then the function that the macro is in also returns ED_ERROR...
Definition: entitiesdef.cpp:84
int ED_Parse(const char *data_p)
char parsedToken[MAX_TOKEN_CHARS]
Definition: scriplib.cpp:45
#define ED_PASS_ERROR(function_call)
if the function returns ED_ERROR, then the function that the macro is in also returns ED_ERROR...
Definition: entitiesdef.cpp:73
QGL_EXTERN GLuint index
Definition: r_gl.h:110
const entityKeyDef_t * ED_GetKeyDef(const char *classname, const char *keyname, const int abstract)
searches for the parsed key def
#define ED_TYPE_STRING
Definition: entitiesdef.h:40
static int ED_CheckRange(const entityKeyDef_t *keyDef, const int type, const int index, int_float_tu parsedNumber)
check a value against the range for the key
char * classname
Definition: entitiesdef.h:74
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition: parse.cpp:107
static entityKeyDef_t * ED_FindKeyDefInArray(entityKeyDef_t keyDefs[], int numDefs, const char *name, int parseMode)
search for an existing keyDef to add a new parsed pair info to.
const char * ED_GetLastError(void)
#define ED_TYPE_INT
Definition: entitiesdef.h:39
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define ED_TYPE_BOOL
Definition: entitiesdef.h:45
#define ED_ABSTRACT
Definition: entitiesdef.h:37
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
const char int mode
Definition: ioapi.h:41
#define ED_OK
Definition: entitiesdef.h:33
int ED_GetIntVector(const entityKeyDef_t *kd, int v[], const int n)
parses a value from the definition
struct entityKeyDef_s entityKeyDef_t
#define Q_streq(a, b)
Definition: shared.h:136
static const char * ED_Constant2Type(int constInt)
converts an internal constant integer to a string representation of a type (eg V_FLOAT) ...
#define ED_TEST_RETURN_ERROR(condition,...)
test a condition, write an error message and exit the current function with ED_ERROR ...
Definition: entitiesdef.cpp:62
#define ED_MANDATORY
Definition: entitiesdef.h:36
static int ED_AllocRange(entityKeyDef_t *kd, const char *rangeStr)
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
entityKeyRange_t ** ranges
Definition: entitiesdef.h:69
#define ED_ERROR
Definition: entitiesdef.h:32
#define ED_MAX_DEFS
Definition: entitiesdef.h:30
entityKeyDef_t * keyDefs
Definition: entitiesdef.h:75
static char lastErr[ED_MAX_ERR_LEN]
Definition: entitiesdef.cpp:42