We can add a date to the history.
[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 {
83     void check_cargo(), check_obj(), check_obj_cargo();
84         
85     long i, j;
86     piece_info_t *p;
87         
88     /* nothing in any list yet */
89     for (i = 0; i < LIST_SIZE; i++) {
90         in_free[i] = 0;
91         in_obj[i] = 0;
92         in_loc[i] = 0;
93         in_cargo[i] = 0;
94     }
95                 
96     /* Mark all objects in free list.  Make sure objects in free list
97        have zero hits. */
98         
99     for (p = free_list; p != NULL; p = p->piece_link.next) {
100         i = p - object;
101         ASSERT (!in_free[i]);
102         in_free[i] = 1;
103         ASSERT (p->hits == 0);
104         if (p->piece_link.prev)
105             ASSERT (p->piece_link.prev->piece_link.next == p);
106     }
107         
108     /* Mark all objects in the map.
109        Check that cities are in corect location.
110        Check that objects are in correct location,
111        have a good owner, and good hits. */
112         
113     for (i = 0; i < MAP_SIZE; i++) {
114         if (map[i].cityp) ASSERT (map[i].cityp->loc == i);
115                 
116         for (p = map[i].objp; p != NULL; p = p->loc_link.next) {
117             ASSERT (p->loc == i);
118             ASSERT (p->hits > 0);
119             ASSERT (p->owner == USER || p->owner == COMP);
120                                 
121             j = p - object;
122             ASSERT (!in_loc[j]);
123             in_loc[j] = 1;
124                         
125             if (p->loc_link.prev)
126                 ASSERT (p->loc_link.prev->loc_link.next == p);
127         }
128     }
129
130     /* make sure all cities are on map */
131
132     for (i = 0; i < NUM_CITY; i++)
133         ASSERT (map[city[i].loc].cityp == &(city[i]));
134
135     /* Scan object lists. */
136         
137     check_obj (comp_obj, COMP);
138     check_obj (user_obj, USER);
139         
140     /* Scan cargo lists. */
141         
142     check_cargo (user_obj[TRANSPORT], ARMY);
143     check_cargo (comp_obj[TRANSPORT], ARMY);
144     check_cargo (user_obj[CARRIER], FIGHTER);
145     check_cargo (comp_obj[CARRIER], FIGHTER);
146         
147     /* Make sure all objects with ship pointers are in cargo. */
148
149     check_obj_cargo (comp_obj);
150     check_obj_cargo (user_obj);
151         
152     /* Make sure every object is either free or in loc and obj list. */
153
154     for (i = 0; i < LIST_SIZE; i++)
155         ASSERT (in_free[i] != (in_loc[i] && in_obj[i]));
156 }
157
158 /*
159 Check object lists.  We look for:
160
161 1)  Loops and bad prev pointers.
162
163 2)  Dead objects.
164
165 3)  Invalid types.
166
167 4)  Invalid owners.
168 */
169
170 void
171 check_obj(piece_info_t **list, int owner)
172 {
173     long i, j;
174     piece_info_t *p;
175         
176     for (i = 0; i < NUM_OBJECTS; i++)
177         for (p = list[i]; p != NULL; p = p->piece_link.next) {
178             ASSERT (p->owner == owner);
179             ASSERT (p->type == i);
180             ASSERT (p->hits > 0);
181                 
182             j = p - object;
183             ASSERT (!in_obj[j]);
184             in_obj[j] = 1;
185         
186             if (p->piece_link.prev)
187                 ASSERT (p->piece_link.prev->piece_link.next == p);
188         }
189 }
190
191 /*
192 Check cargo lists.  We assume object lists are valid.
193 as we will place bits in the 'in_cargo' array that are used by
194 'check_obj'.
195
196 Check for:
197
198 1)  Number of items in list is same as cargo count.
199
200 2)  Type of cargo is correct.
201
202 3)  Location of cargo matches location of ship.
203
204 4)  Ship pointer of cargo points to correct ship.
205
206 5)  There are no loops in cargo list and prev ptrs are correct.
207
208 6)  All cargo is alive.
209 */
210
211 void
212 check_cargo(piece_info_t *list, int cargo_type)
213 {
214     piece_info_t *p, *q;
215     long j, count;
216         
217     for (p = list; p != NULL; p = p->piece_link.next) {
218         count = 0;
219         for (q = p->cargo; q != NULL; q = q->cargo_link.next) {
220             count += 1; /* count items in list */
221             ASSERT (q->type == cargo_type);
222             ASSERT (q->owner == p->owner);
223             ASSERT (q->hits > 0);
224             ASSERT (q->ship == p);
225             ASSERT (q->loc == p->loc);
226                         
227             j = q - object;
228             ASSERT (!in_cargo[j]);
229             in_cargo[j] = 1;
230
231             if (p->cargo_link.prev)
232                 ASSERT (p->cargo_link.prev->cargo_link.next == p);
233         }
234         ASSERT (count == p->count);
235     }
236 }
237
238 /*
239 Scan through object lists making sure every object with a ship
240 pointer appears in a cargo list.  We assume object and cargo
241 lists are valid.
242 */
243
244 void
245 check_obj_cargo(piece_info_t **list)
246 {
247     piece_info_t *p;
248     long i;
249
250     for (i = 0; i < NUM_OBJECTS; i++)
251         for (p = list[i]; p != NULL; p = p->piece_link.next) {
252             if (p->ship) ASSERT (in_cargo[p-object]);
253         }
254 }
255
256 /* end */