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