Add some header declarations to avoid -Wall warnings.
[vms-empire.git] / util.c
1 /*
2  *    Copyright (C) 1987, 1988 Chuck Simmons
3  * 
4  * See the file COPYING, distributed with empire, for restriction
5  * and warranty information.
6  */
7
8 /*
9 util.c -- various utility routines.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <curses.h>     /* Ugh...shouldn't be needed here */
15 #include <ctype.h>
16 #include <signal.h>
17 #include "empire.h"
18 #include "extern.h"
19
20
21 /*
22 Convert a string to uppercase.
23 Shirley this is defined elsewhere?
24 */
25
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <ctype.h>
29
30 void
31 tupper (str)
32 char    *str;
33 {
34         while (*str) {
35                 if (islower (*str)) *str = upper (*str);
36                 str++;
37         }
38 }
39
40 /*
41 Convert a character to uppercase (if it is lowercase)
42 */
43
44 char
45 upper (c)
46 char c;
47 {
48         if (islower (c))
49                 return toupper (c);
50         else return c;
51 }
52
53 /*
54 Report a bug.
55 */
56
57 void
58 assert (expression, file, line)
59 char *expression;
60 char *file;
61 int line;
62 {
63         char buf[STRSIZE];
64
65         (void) move (lines, 0);
66         close_disp ();
67
68         (void) sprintf (buf, "assert failed: file %s line %d: %s",
69                         file, line, expression);
70
71         kill(getpid(), SIGSEGV);        /* core dump */
72 }
73
74 /*
75 End the game by cleaning up the display.
76 */
77
78 void
79 empend ()
80 {
81         close_disp ();
82         exit (0);
83 }
84
85
86 /*
87 Here is a little routine to perform consistency checking on the
88 database.  I'm finding that my database is becoming inconsistent,
89 and I've no idea why.  Possibly this will help.
90
91 We perform the following functions:
92
93 1)  Make sure no list contains loops.
94
95 2)  Make sure every object is in either the free list with 0 hits,
96 or it is in the correct object list and a location list with non-zero hits,
97 and an appropriate owner.
98
99 3)  Make sure every city is on the map.
100
101 4)  Make sure every object is in the correct location and that
102 objects on the map have non-zero hits.
103
104 5)  Make sure every object in a cargo list has a ship pointer.
105
106 6)  Make sure every object with a ship pointer is in that ship's
107 cargo list.
108 */
109
110 static int in_free[LIST_SIZE]; /* TRUE if object in free list */
111 static int in_obj[LIST_SIZE]; /* TRUE if object in obj list */
112 static int in_loc[LIST_SIZE]; /* TRUE if object in a loc list */
113 static int in_cargo[LIST_SIZE]; /* TRUE if object in a cargo list */
114
115 void
116 check () {
117         void check_cargo(), check_obj(), check_obj_cargo();
118         
119         long i, j;
120         piece_info_t *p;
121         
122         /* nothing in any list yet */
123         for (i = 0; i < LIST_SIZE; i++) {
124                 in_free[i] = 0;
125                 in_obj[i] = 0;
126                 in_loc[i] = 0;
127                 in_cargo[i] = 0;
128         }
129                 
130         /* Mark all objects in free list.  Make sure objects in free list
131         have zero hits. */
132         
133         for (p = free_list; p != NULL; p = p->piece_link.next) {
134                 i = p - object;
135                 ASSERT (!in_free[i]);
136                 in_free[i] = 1;
137                 ASSERT (p->hits == 0);
138                 if (p->piece_link.prev)
139                         ASSERT (p->piece_link.prev->piece_link.next == p);
140         }
141         
142         /* Mark all objects in the map.
143         Check that cities are in corect location.
144         Check that objects are in correct location,
145         have a good owner, and good hits. */
146         
147         for (i = 0; i < MAP_SIZE; i++) {
148                 if (map[i].cityp) ASSERT (map[i].cityp->loc == i);
149                 
150                 for (p = map[i].objp; p != NULL; p = p->loc_link.next) {
151                         ASSERT (p->loc == i);
152                         ASSERT (p->hits > 0);
153                         ASSERT (p->owner == USER || p->owner == COMP);
154                                 
155                         j = p - object;
156                         ASSERT (!in_loc[j]);
157                         in_loc[j] = 1;
158                         
159                         if (p->loc_link.prev)
160                                 ASSERT (p->loc_link.prev->loc_link.next == p);
161                 }
162         }
163
164         /* make sure all cities are on map */
165
166         for (i = 0; i < NUM_CITY; i++)
167                 ASSERT (map[city[i].loc].cityp == &(city[i]));
168
169         /* Scan object lists. */
170         
171         check_obj (comp_obj, COMP);
172         check_obj (user_obj, USER);
173         
174         /* Scan cargo lists. */
175         
176         check_cargo (user_obj[TRANSPORT], ARMY);
177         check_cargo (comp_obj[TRANSPORT], ARMY);
178         check_cargo (user_obj[CARRIER], FIGHTER);
179         check_cargo (comp_obj[CARRIER], FIGHTER);
180         
181         /* Make sure all objects with ship pointers are in cargo. */
182
183         check_obj_cargo (comp_obj);
184         check_obj_cargo (user_obj);
185         
186         /* Make sure every object is either free or in loc and obj list. */
187
188         for (i = 0; i < LIST_SIZE; i++)
189                 ASSERT (in_free[i] != (in_loc[i] && in_obj[i]));
190 }
191
192 /*
193 Check object lists.  We look for:
194
195 1)  Loops and bad prev pointers.
196
197 2)  Dead objects.
198
199 3)  Invalid types.
200
201 4)  Invalid owners.
202 */
203
204 void
205 check_obj (list, owner)
206 piece_info_t **list;
207 int owner;
208 {
209         long i, j;
210         piece_info_t *p;
211         
212         for (i = 0; i < NUM_OBJECTS; i++)
213         for (p = list[i]; p != NULL; p = p->piece_link.next) {
214                 ASSERT (p->owner == owner);
215                 ASSERT (p->type == i);
216                 ASSERT (p->hits > 0);
217                 
218                 j = p - object;
219                 ASSERT (!in_obj[j]);
220                 in_obj[j] = 1;
221         
222                 if (p->piece_link.prev)
223                         ASSERT (p->piece_link.prev->piece_link.next == p);
224         }
225 }
226
227 /*
228 Check cargo lists.  We assume object lists are valid.
229 as we will place bits in the 'in_cargo' array that are used by
230 'check_obj'.
231
232 Check for:
233
234 1)  Number of items in list is same as cargo count.
235
236 2)  Type of cargo is correct.
237
238 3)  Location of cargo matches location of ship.
239
240 4)  Ship pointer of cargo points to correct ship.
241
242 5)  There are no loops in cargo list and prev ptrs are correct.
243
244 6)  All cargo is alive.
245 */
246
247 void
248 check_cargo (list, cargo_type)
249 piece_info_t *list;
250 int cargo_type;
251 {
252         piece_info_t *p, *q;
253         long j, count;
254         
255         for (p = list; p != NULL; p = p->piece_link.next) {
256                 count = 0;
257                 for (q = p->cargo; q != NULL; q = q->cargo_link.next) {
258                         count += 1; /* count items in list */
259                         ASSERT (q->type == cargo_type);
260                         ASSERT (q->owner == p->owner);
261                         ASSERT (q->hits > 0);
262                         ASSERT (q->ship == p);
263                         ASSERT (q->loc == p->loc);
264                         
265                         j = q - object;
266                         ASSERT (!in_cargo[j]);
267                         in_cargo[j] = 1;
268
269                         if (p->cargo_link.prev)
270                                 ASSERT (p->cargo_link.prev->cargo_link.next == p);
271                 }
272                 ASSERT (count == p->count);
273         }
274 }
275
276 /*
277 Scan through object lists making sure every object with a ship
278 pointer appears in a cargo list.  We assume object and cargo
279 lists are valid.
280 */
281
282 void
283 check_obj_cargo (list)
284 piece_info_t **list;
285 {
286         piece_info_t *p;
287         long i;
288
289         for (i = 0; i < NUM_OBJECTS; i++)
290         for (p = list[i]; p != NULL; p = p->piece_link.next) {
291                 if (p->ship) ASSERT (in_cargo[p-object]);
292         }
293 }