Bug Summary

File:tools/ufo2map/check/checkentities.cpp
Location:line 197, column 2
Description:Function call argument is an uninitialized value

Annotated Source Code

1/**
2 * @file
3 */
4
5/*
6All original material Copyright (C) 2002-2011 UFO: Alien Invasion.
7
8Copyright (C) 1997-2001 Id Software, Inc.
9
10This program is free software; you can redistribute it and/or
11modify it under the terms of the GNU General Public License
12as published by the Free Software Foundation; either version 2
13of the License, or (at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25*/
26
27#include "checkentities.h"
28#include "../../../shared/mathlib.h"
29#include "../../../shared/entitiesdef.h"
30#include "../common/shared.h"
31#include "../bsp.h"
32#include "checklib.h"
33
34#define MIN_TILE_SIZE256 256 /**< @todo take this datum from the correct place */
35
36static int numToMoveToWorldspawn = 0;
37
38static void Check_MapSize (vec3_t mapSize);
39mapbrush_t **Check_ExtraBrushesForWorldspawn (int *numBrushes);
40
41
42/**
43 * @brief see if the entity is am actor start point
44 * @note starts with "info_" and contains "_start"
45 * @return true if this is a start point
46 */
47static bool Check_IsInfoStart(const char *classname)
48{
49 return Q_strstart(classname, "info_") && strstr(classname, "_start");
50}
51
52/**
53 * @brief check alignment using abstract size and mandatory origin
54 * @return true if OK
55 * @todo check for brush intersection as well as alignment, and move
56 * to a good position if bad.
57 */
58static bool Check_InfoStartAligned (const entityDef_t *ed, const entity_t *e)
59{
60 static int size[6];
61 const entityKeyDef_t *sizeKd = ED_GetKeyDefEntity(ed, "size", 1); /* 1 means find abstract version of key */
62 if (ED_GetIntVector(sizeKd, size, (int)(sizeof(size) / sizeof(int))) == ED_ERROR-1)
63 Sys_Error("%s", ED_GetLastError());
64
65 return (((int)e->origin[0] - size[0]) % UNIT_SIZE32 == 0)
66 && (((int)e->origin[1] - size[1]) % UNIT_SIZE32 == 0);
67}
68
69/**
70 * @brief check targets exist (targetname), and check targetnames are targetted (target)
71 * @return false if there is a problem.
72 */
73static bool Check_TargetExists (const epair_t *kvp)
74{
75 const char *thisKey = kvp->key;
76 const char *value = kvp->value;
77 const char *otherKey = Q_streq("target", thisKey)(strcmp("target", thisKey) == 0) ? "targetname" : "target";
78 int i;
79
80 for (i = 0; i < num_entities; i++) {
81 const entity_t *e = &entities[i];
82 const char *searchVal = ValueForKey(e, otherKey);
83
84 if (searchVal && Q_streq(searchVal, value)(strcmp(searchVal, value) == 0))
85 return true;
86 }
87
88 return false;
89}
90
91static void Check_EntityWithBrushes (entity_t *e, const char *classname, int entnum)
92{
93 if (!e->numbrushes) {
94 Check_Printf(VERB_CHECK, true, entnum, -1, "%s with no brushes given - will be deleted\n", classname);
95 e->skip = true;
96 return;
97 }
98
99 if (e->numbrushes > 1 && Q_streq(classname, "func_breakable")(strcmp(classname, "func_breakable") == 0)) {
100 Check_Printf(VERB_CHECK, false, entnum, -1, "func_breakable with more than one brush given (might break pathfinding)\n");
101 }
102
103 if (e->numbrushes == 1 && Q_streq(classname, "func_group")(strcmp(classname, "func_group") == 0)) {
104 Check_Printf(VERB_CHECK, true, entnum, -1, "%s with one brush only - will be moved to worldspawn\n", classname);
105 numToMoveToWorldspawn++;
106 e->skip = true;
107 }
108}
109
110/**
111 * @brief Perform an entity check
112 */
113void CheckEntities (void)
114{
115 int i;
116
117 Check_InitEntityDefs();
118
119 for (i = 0; i < num_entities; i++) {
120 entity_t *e = &entities[i];
121 const char *name = ValueForKey(e, "classname");
122 const entityDef_t *ed = ED_GetEntityDef(name);
123 const epair_t *kvp;
124 const entityKeyDef_t *kd;
125
126 if (!ed) { /* check that a definition exists */
127 Check_Printf(VERB_CHECK, false, i, -1, "Not defined in entities.ufo: %s\n", name);
128 continue;
129 }
130
131 /* check alignment of info_.+_start */
132 if (Check_IsInfoStart(name) && !Check_InfoStartAligned(ed, e))
133 Check_Printf(VERB_CHECK, false, i, -1, "Misaligned %s\n", name);
134
135 if (Q_strstart(name, "func_")) /* func_* entities should have brushes */
136 Check_EntityWithBrushes(e, name, i);
137
138 /* check all keys in the entity - make sure they are OK */
139 for (kvp = e->epairs; kvp; kvp = kvp->next) {
140 kd = ED_GetKeyDefEntity(ed, kvp->key, 0); /* zero means ignore abstract (radiant only) keys */
141
142 if (!kd) { /* make sure it has a definition */
143 Check_Printf(VERB_CHECK, false, i, -1, "Not defined in entities.ufo: %s in %s\n", kvp->key,name);
144 continue;
145 }
146
147 if (ED_CheckKey(kd, kvp->value) == ED_ERROR-1) { /* check values against type and range definitions in entities.ufo */
148 Check_Printf(VERB_CHECK, false, i, -1, "%s\n", ED_GetLastError());
149 continue;
150 }
151
152 if (Q_streq("target", kvp->key)(strcmp("target", kvp->key) == 0) || Q_streq("targetname", kvp->key)(strcmp("targetname", kvp->key) == 0)) {
153 if (!Check_TargetExists(kvp)) {
154 Check_Printf(VERB_CHECK, false, i, -1,
155 "%s with %s of %s: no corresponding entity with %s with matching value\n",
156 ed->classname, kvp->key, kvp->value, Q_streq("target", kvp->key)(strcmp("target", kvp->key) == 0) ? "targetname" : "target");
157 }
158 }
159 }
160
161 /* check keys in the entity definition - make sure mandatory ones are present */
162 for (kd = ed->keyDefs; kd->name; kd++) {
163 if (kd->flags & ED_MANDATORY(1<<1)) {
164 const char *keyNameInEnt = ValueForKey(e, kd->name);
165 if (keyNameInEnt[0] == '\0') {
166 const char *defaultVal = kd->defaultVal;
167 const bool hasDefault = defaultVal ? true : false;
168 Check_Printf(VERB_CHECK, hasDefault, i, -1, "Mandatory key missing from entity: %s in %s", kd->name, name);
169 if (defaultVal) {
170 Check_Printf(VERB_CHECK, hasDefault, i, -1, ", supplying default: %s", defaultVal);
171 SetKeyValue(e, kd->name, defaultVal);
172 }
173 Check_Printf(VERB_CHECK, hasDefault, i, -1, "\n");
174 }
175 }
176 }
177 }
178}
179
180
181/**
182 * @brief print map stats on -stats
183 */
184void Check_Stats(void) {
185 vec3_t worldSize;
186 int i, j;
187 int *entNums;
188
189 Check_InitEntityDefs();
190
191 entNums = Mem_AllocTypeN(int, numEntityDefs)((int*)_Mem_Alloc(((sizeof(int) * (numEntityDefs))),true,(com_genericPool
),(0),"src/tools/ufo2map/check/checkentities.cpp",191))
;
192
193 Check_MapSize(worldSize);
194 Verb_Printf(VERB_NORMAL, " Number of brushes: %i\n",nummapbrushes);
195 Verb_Printf(VERB_NORMAL, " Number of planes: %i\n",nummapplanes);
196 Verb_Printf(VERB_NORMAL, " Number of brush sides: %i\n",nummapbrushsides);
197 Verb_Printf(VERB_NORMAL, " Map size (units): %.0f %.0f %.0f\n", worldSize[0], worldSize[1], worldSize[2]);
Function call argument is an uninitialized value
198 Verb_Printf(VERB_NORMAL, " Map size (fields): %.0f %.0f %.0f\n", worldSize[0] / UNIT_SIZE32, worldSize[1] / UNIT_SIZE32, worldSize[2] / UNIT_HEIGHT64);
199 Verb_Printf(VERB_NORMAL, " Map size (tiles): %.0f %.0f %.0f\n", worldSize[0] / (MIN_TILE_SIZE256), worldSize[1] / (MIN_TILE_SIZE256), worldSize[2] / UNIT_HEIGHT64);
200 Verb_Printf(VERB_NORMAL, " Number of entities: %i\n", num_entities);
201
202 /* count number of each type of entity */
203 for (i = 0; i < num_entities; i++) {
204 const char *name = ValueForKey(&entities[i], "classname");
205
206 for (j = 0; j < numEntityDefs; j++)
207 if (Q_streq(name, entityDefs[j].classname)(strcmp(name, entityDefs[j].classname) == 0)) {
208 entNums[j]++;
209 break;
210 }
211 if (j == numEntityDefs) {
212 Com_Printf("Check_Stats: entity '%s' not recognised\n", name);
213 }
214
215 }
216
217 /* print number of each type of entity */
218 for (j = 0; j < numEntityDefs; j++)
219 if (entNums[j])
220 Com_Printf("%27s: %i\n", entityDefs[j].classname, entNums[j]);
221
222 Mem_Free(entNums)_Mem_Free((entNums),"src/tools/ufo2map/check/checkentities.cpp"
,222)
;
223}
224
225
226/** needs to be done here, on map brushes as worldMins and worldMaxs from levels.c
227 * are only calculated on BSPing
228 * @param[out] mapSize the returned size in map units
229 */
230static void Check_MapSize (vec3_t mapSize)
231{
232 int i, bi, vi;
233 vec3_t mins, maxs;
234
235 VectorSet(mins, 0, 0, 0)((mins)[0]=(0), (mins)[1]=(0), (mins)[2]=(0));
236 VectorSet(maxs, 0, 0, 0)((maxs)[0]=(0), (maxs)[1]=(0), (maxs)[2]=(0));
237
238 for (i = 0; i < nummapbrushes; i++) {
239 const mapbrush_t *brush = &mapbrushes[i];
240
241 for (bi = 0; bi < brush->numsides; bi++) {
242 const winding_t *winding = brush->original_sides[bi].winding;
243
244 for (vi = 0; vi < winding->numpoints; vi++)
245 AddPointToBounds(winding->p[vi], mins, maxs);
246 }
247 }
248
249 VectorSubtract(maxs, mins, mapSize)((mapSize)[0]=(maxs)[0]-(mins)[0],(mapSize)[1]=(maxs)[1]-(mins
)[1],(mapSize)[2]=(maxs)[2]-(mins)[2])
;
250}
251
252/**
253 * @brief single brushes in func_groups are moved to worldspawn. this function allocates space for
254 * pointers to those brushes. called when the .map is written back in map.c
255 * @return a pointer to the array of pointers to brushes to be included in worldspawn.
256 * @param[out] numBrushes the number of brushes
257 */
258mapbrush_t **Check_ExtraBrushesForWorldspawn (int *numBrushes)
259{
260 int i, j;
261 mapbrush_t **brushesToMove;
262
263 *numBrushes = numToMoveToWorldspawn;
264
265 if (!numToMoveToWorldspawn)
266 return NULL__null;
267
268 brushesToMove = Mem_AllocTypeN(mapbrush_t *, numToMoveToWorldspawn)((mapbrush_t **)_Mem_Alloc(((sizeof(mapbrush_t *) * (numToMoveToWorldspawn
))),true,(com_genericPool),(0),"src/tools/ufo2map/check/checkentities.cpp"
,268))
;
269 if (!brushesToMove)
270 Sys_Error("Check_ExtraBrushesForWorldspawn: out of memory");
271
272 /* 0 is the world - start at 1 */
273 for (i = 1, j = 0; i < num_entities; i++) {
274 const entity_t *e = &entities[i];
275 const char *name = ValueForKey(e, "classname");
276
277 if (e->numbrushes == 1 && Q_streq(name, "func_group")(strcmp(name, "func_group") == 0)) {
278 assert(j < numToMoveToWorldspawn)(__builtin_expect(!(j < numToMoveToWorldspawn), 0) ? __assert_rtn
(__func__, "src/tools/ufo2map/check/checkentities.cpp", 278, "j < numToMoveToWorldspawn"
) : (void)0)
;
279 brushesToMove[j++] = &mapbrushes[e->firstbrush];
280 }
281 }
282
283 return brushesToMove;
284}