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