]> git.pond.sub.org Git - empserver/blob - src/lib/common/xdump.c
4093dcde1e737e19fcae91ed5a7d01db29a2b794
[empserver] / src / lib / common / xdump.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2009, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  xdump.c: Extended dumps
29  *
30  *  Known contributors to this file:
31  *     Markus Armbruster, 2004-2008
32  */
33
34 /*
35  * Dump everything under the sun
36  *
37  * Static game data (configuration):
38  * - Item characteristics: ichr[]
39  * - Land unit characteristics: lchr[]
40  * - Nuke characteristics: nchr[]
41  * - Plane characteristics: plchr[]
42  * - Product characteristics: pchr[]
43  * - Sector designation characteristics: dchr[]
44  * - Sector infrastructure characteristics: intrchr[]
45  * - Ship characteristics: mchr[]
46  * - News item characteristics: rpt[]
47  * - News page headings: page_headings[]
48  * - Commands: player_coms[] (TODO)
49  * - Update schedule: update_time[] (not really static)
50  * - Configuration: configkeys[]
51  *
52  * Dynamic game data:
53  * - Sectors: EF_SECTOR (superseding dump)
54  * - Land units: EF_LAND (superseding ldump)
55  * - Lost: EF_LOST (superseding lost)
56  * - Nukes: EF_NUKE (superseding ndump)
57  * - Planes: EF_PLANE (superseding pdump)
58  * - Ships: EF_SHIP (superseding sdump)
59  * - News: EF_NEWS
60  * - Treaties: EF_TREATY
61  * - Power: EF_POWER (TODO)
62  * - Nations: EF_NATION
63  * - Loans: EF_LOAN
64  * - Map: EF_MAP (TODO)
65  * - Bmap: EF_BMAP (TODO)
66  * - Market: EF_COMM
67  */
68
69 /*
70  * See doc/xdump for motivation, syntax, semantics, and rationale.
71  * Make sure to keep it up-to-date!
72  */
73
74 /* TODO don't dump stuff that's useless due to options */
75
76 #include <config.h>
77
78 #include <ctype.h>
79 #include <limits.h>
80 #include "file.h"
81 #include "nat.h"
82 #include "xdump.h"
83
84 /*
85  * Initialize XD.
86  * Translate dump for country CNUM, except when CNUM is NATID_BAD.
87  * If HUMAN, dump in human-readable format.
88  * Dump is to be delivered through callback PR.
89  * Return XD.
90  */
91 struct xdstr *
92 xdinit(struct xdstr *xd, natid cnum, int human, void (*pr)(char *fmt, ...))
93 {
94     xd->cnum = cnum;
95     xd->divine = cnum == NATID_BAD || getnatp(cnum)->nat_stat == STAT_GOD;
96     xd->human = human;
97     xd->pr = pr;
98     return xd;
99 }
100
101 /*
102  * Evaluate a attribute of an object into VAL, return VAL.
103  * CA describes the attribute.
104  * XD is the xdump descriptor.
105  * PTR points to the context object.
106  * IDX is the index within the attribute.
107  */
108 static struct valstr *
109 xdeval(struct valstr *val, struct xdstr *xd,
110        struct castr *ca, void *ptr, int idx)
111 {
112     nstr_mksymval(val, ca, idx);
113     return nstr_exec_val(val, xd->cnum, ptr, NSC_NOTYPE);
114 }
115
116 /*
117  * Dump string STR to XD with funny characters escaped.
118  * Dump at most N characters.
119  */
120 static void
121 xdpresc(struct xdstr *xd, char *str, size_t n)
122 {
123     unsigned char *s, *e, *l;
124
125     s = (unsigned char *)str;
126     l = s + n;
127     for (;;) {
128         for (e = s;
129              e < l && *e != '"' && *e != '\\' && isgraph(*e);
130              ++e)
131             ;
132         xd->pr("%.*s", (int)(e-s), s);
133         if (e < l && *e)
134             xd->pr("\\%03o", *e++);
135         else
136             break;
137         s = e;
138     }
139 }
140
141 /*
142  * Dump VAL prefixed with SEP to XD, in machine readable format.
143  * VAL must be evaluated.
144  * Return " ".
145  */
146 static char *
147 xdprval_nosym(struct xdstr *xd, struct valstr *val, char *sep)
148 {
149     if (CANT_HAPPEN(val->val_cat != NSC_VAL)) {
150         xd->pr("%snil", sep);
151         return " ";
152     }
153
154     switch (val->val_type) {
155     case NSC_LONG:
156         xd->pr("%s%ld", sep, val->val_as.lng);
157         break;
158     case NSC_DOUBLE:
159         xd->pr("%s%#g", sep, val->val_as.dbl);
160         break;
161     case NSC_STRING:
162         if (val->val_as.str.base) {
163             xd->pr("%s\"", sep);
164             xdpresc(xd, val->val_as.str.base, val->val_as.str.maxsz);
165             xd->pr("\"");
166         } else
167             xd->pr("%snil", sep);
168         break;
169     default:
170         CANT_REACH();
171         xd->pr("%snil", sep);
172     }
173     return " ";
174 }
175
176 /*
177  * Dump symbol with value KEY from symbol table TYPE to XD.
178  * Prefix with SEP, return " ".
179  */
180 static char *
181 xdprsym(struct xdstr *xd, int key, int type, char *sep)
182 {
183     char *sym = symbol_by_value(key, ef_ptr(type, 0));
184
185     if (CANT_HAPPEN(!sym))
186         xd->pr("%s%d", sep, key);
187     else {
188         xd->pr("%s", sep);
189         xdpresc(xd, sym, INT_MAX);
190     }
191     return " ";
192 }
193
194 /*
195  * Dump VAL prefixed with SEP to XD, return " ".
196  * VAL must be evaluated.
197  * CA describes the field from which the value was fetched.
198  */
199 static char *
200 xdprval_sym(struct xdstr *xd, struct valstr *val, struct castr *ca,
201             char *sep)
202 {
203     unsigned long bit;
204
205     if (CANT_HAPPEN(val->val_cat != NSC_VAL)) {
206         xd->pr("%snil", sep);
207         return " ";
208     }
209
210     if (!xd->human || val->val_type != NSC_LONG
211         || ca->ca_table == EF_BAD || ef_cadef(ca->ca_table) != symbol_ca)
212         return xdprval_nosym(xd, val, sep);
213
214     if (ca->ca_flags & NSC_BITS) {
215         xd->pr("%s(", sep);
216         sep = "";
217         for (bit = 1; bit; bit <<= 1) {
218             if (bit & val->val_as.lng)
219                 sep = xdprsym(xd, bit, ca->ca_table, sep);
220         }
221         xd->pr(")");
222         return " ";
223     }
224
225     return xdprsym(xd, val->val_as.lng, ca->ca_table, sep);
226 }
227
228 /*
229  * Dump field values of a context object to XD.
230  * CA[] describes fields.
231  * PTR points to context object.
232  */
233 void
234 xdflds(struct xdstr *xd, struct castr ca[], void *ptr)
235 {
236     int i, j, n;
237     struct valstr val;
238     char *sep = "";
239
240     for (i = 0; ca[i].ca_name; ++i) {
241         if (ca[i].ca_flags & NSC_DEITY && !xd->divine)
242             continue;
243         if (ca[i].ca_flags & NSC_EXTRA)
244             continue;
245         n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
246         j = 0;
247         do {
248             xdeval(&val, xd, &ca[i], ptr, j);
249             sep = xdprval_sym(xd, &val, &ca[i], sep);
250         } while (++j < n);
251     }
252 }
253
254 /*
255  * Dump header for dump NAME to XD.
256  * If META, it's for the meta-data dump rather than the data dump.
257  */
258 void
259 xdhdr(struct xdstr *xd, char *name, int meta)
260 {
261     if (xd->human) {
262         xd->pr("config %s\n", name);
263     } else
264         xd->pr("XDUMP %s%s %ld\n",
265                meta ? "meta " : "",
266                name, (long)time(NULL));
267 }
268
269 /*
270  * Dump column header to XD.
271  * CA[] describes fields.
272  * Does nothing unless XD is human-readable.
273  */
274 void
275 xdcolhdr(struct xdstr *xd, struct castr ca[])
276 {
277     int i, j, n;
278     char *sep = "";
279
280     if (!xd->human)
281         return;
282
283     for (i = 0; ca[i].ca_name; ++i) {
284         if (ca[i].ca_flags & NSC_DEITY && !xd->divine)
285             continue;
286         if (ca[i].ca_flags & NSC_EXTRA)
287             continue;
288         n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
289         if (n) {
290             for (j = 0; j < n; j++) {
291                 xd->pr("%s%s(%d)",sep, ca[i].ca_name, j);
292                 sep = " ";
293             }
294         } else {
295             xd->pr("%s%s", sep, ca[i].ca_name);
296             sep = " ";
297         }
298     }
299     xd->pr("\n");
300 }
301
302 /* Dump footer for a dump that dumped N objects to XD.  */
303 void
304 xdftr(struct xdstr *xd, int n)
305 {
306     if (xd->human)
307         xd->pr("/config\n");
308     else
309         xd->pr("/%d\n", n);
310 }
311
312 /*
313  * Dump meta-data for items of type TYPE to XD.
314  * Return RET_SYN when TYPE doesn't have meta-data, else RET_OK.
315  */
316 int
317 xdmeta(struct xdstr *xd, int type)
318 {
319     struct castr *ca = ef_cadef(type);
320     int i;
321     int n = 0;
322
323     if (!ca)
324         return RET_SYN;
325
326     xdhdr(xd, ef_nameof(type), 1);
327     xdcolhdr(xd, ca);
328
329     for (i = 0; ca[i].ca_name; i++) {
330         if (ca[i].ca_flags & NSC_DEITY && !xd->divine)
331             continue;
332         if (ca[i].ca_flags & NSC_EXTRA)
333             continue;
334         xdflds(xd, mdchr_ca, &ca[i]);
335         xd->pr("\n");
336         n++;
337     }
338
339     xdftr(xd, n);
340
341     return RET_OK;
342 }