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