]> git.pond.sub.org Git - empserver/blob - src/lib/common/xdump.c
WIP empdump, %a
[empserver] / src / lib / common / xdump.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2008, 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, 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 to dump for country CNUM.
86  * If HUMAN, dump in human-readable format.
87  * Dump is to be delivered through callback PR.
88  * Return XD.
89  */
90 struct xdstr *
91 xdinit(struct xdstr *xd, natid cnum, int human, void (*pr)(char *fmt, ...))
92 {
93     xd->cnum = cnum;
94     xd->divine = getnatp(cnum)->nat_stat == STAT_GOD;
95     xd->human = human;
96     xd->pr = pr;
97     return xd;
98 }
99
100 /*
101  * Evaluate a attribute of an object into VAL, return VAL.
102  * XD is the xdump descriptor.
103  * TYPE is the attribute's type.
104  * PTR points to the context object.
105  * The attribute is stored there at offset OFF + IDX * S, where S is
106  * its size.
107  * LEN is the #array elements if it is an array, else zero.
108  */
109 struct valstr *
110 xdeval(struct valstr *val, struct xdstr *xd,
111        nsc_type type, void *ptr, ptrdiff_t off, int idx, int len)
112 {
113     val->val_type = type;
114     val->val_cat = NSC_OFF;
115     val->val_as.sym.off = off;
116     val->val_as.sym.len = len;
117     val->val_as.sym.idx = idx;
118     nstr_exec_val(val, xd->cnum, ptr, NSC_NOTYPE);
119     return val;                 /* FIXME nstr_exec_val() should return VAL */
120 }
121
122 /*
123  * Dump string STR to XD with funny characters escaped.
124  * Dump at most N characters.
125  */
126 static void
127 xdpresc(struct xdstr *xd, char *str, size_t n)
128 {
129     unsigned char *s, *e, *l;
130
131     s = (unsigned char *)str;
132     l = s + n;
133     for (;;) {
134         for (e = s;
135              e < l && *e != '"' && *e != '\\' && isgraph(*e);
136              ++e)
137             ;
138         xd->pr("%.*s", (int)(e-s), s);
139         if (e < l && *e)
140             xd->pr("\\%03o", *e++);
141         else
142             break;
143         s = e;
144     }
145 }
146
147 /* Dump VAL in machine readable format, prefixed with SEP, return " ".  */
148 static char *
149 xdprval_nosym(struct xdstr *xd, struct valstr *val, char *sep)
150 {
151     switch (val->val_type) {
152     case NSC_LONG:
153         xd->pr("%s%ld", sep, val->val_as.lng);
154         break;
155     case NSC_DOUBLE:
156 #if 1 /* TODO have %a */
157         xd->pr("%s%a", sep, val->val_as.dbl);
158 #else
159         xd->pr("%s%#g", sep, val->val_as.dbl);
160 #endif
161         break;
162     case NSC_STRING:
163         if (val->val_as.str.base) {
164             xd->pr("%s\"", sep);
165             xdpresc(xd, val->val_as.str.base, val->val_as.str.maxsz);
166             xd->pr("\"");
167         } else
168             xd->pr("%snil", sep);
169         break;
170     default:
171         CANT_REACH();
172         xd->pr("0");
173     }
174     return " ";
175 }
176
177 /*
178  * Dump symbol with value KEY from symbol table TYPE to XD.
179  * Prefix with SEP, return " ".
180  */
181 static char *
182 xdprsym(struct xdstr *xd, int key, int type, char *sep)
183 {
184     char *sym = symbol_by_value(key, ef_ptr(type, 0));
185
186     if (CANT_HAPPEN(!sym))
187         xd->pr("%s%ld", sep, key);
188     else {
189         xd->pr("%s", sep);
190         xdpresc(xd, sym, INT_MAX);
191     }
192     return " ";
193 }
194
195 /*
196  * Dump VAL prefixed with SEP, return " ".
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, char *sep)
201 {
202     unsigned long bit;
203     struct castr *ca_sym;
204     char *sym;
205
206     if (xd->human && val->val_type == NSC_LONG && ca->ca_table != EF_BAD) {
207         ca_sym = ef_cadef(ca->ca_table);
208         if (ca_sym != symbol_ca)
209             ;
210         else if (ca->ca_flags & NSC_BITS) {
211             xd->pr("%s(", sep);
212             sep = "";
213             for (bit = 1; bit; bit <<= 1) {
214                 if (bit & val->val_as.lng)
215                     sep = xdprsym(xd, bit, ca->ca_table, sep);
216             }
217             xd->pr(")");
218             return " ";
219         } else
220             return xdprsym(xd, val->val_as.lng, ca->ca_table, sep);
221     }
222
223     return xdprval_nosym(xd, val, sep);
224 }
225
226 /*
227  * Dump VAL prefixed with SEP, return " ".
228  * XD must not be human-readable.
229  */
230 char *
231 xdprval(struct xdstr *xd, struct valstr *val, char *sep)
232 {
233     CANT_HAPPEN(xd->human);
234     return xdprval_nosym(xd, val, sep);
235 }
236
237 /*
238  * Dump field values of a context object to XD.
239  * CA[] describes fields.
240  * PTR points to context object.
241  */
242 void
243 xdflds(struct xdstr *xd, struct castr ca[], void *ptr)
244 {
245     int i, j, n;
246     struct valstr val;
247     char *sep = "";
248
249     for (i = 0; ca[i].ca_name; ++i) {
250         if (ca[i].ca_flags & NSC_DEITY && !xd->divine)
251             continue;
252         if (ca[i].ca_flags & NSC_EXTRA)
253             continue;
254         n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
255         j = 0;
256         do {
257             xdeval(&val, xd,
258                    ca[i].ca_type, ptr, ca[i].ca_off, j, ca[i].ca_len);
259             sep = xdprval_sym(xd, &val, &ca[i], sep);
260         } while (++j < n);
261     }
262 }
263
264 /*
265  * Dump header for dump NAME to XD.
266  * If META, it's for the meta-data dump rather than the data dump.
267  */
268 void
269 xdhdr(struct xdstr *xd, char *name, int meta)
270 {
271     if (xd->human) {
272         xd->pr("config %s\n", name);
273     } else
274         xd->pr("XDUMP %s%s %ld\n",
275                meta ? "meta " : "", name, (long)time(NULL));
276 }
277
278 /*
279  * Dump column header to XD.
280  * CA[] describes fields.
281  * Does nothing unless XD is human-readable.
282  */
283 void
284 xdcolhdr(struct xdstr *xd, struct castr ca[])
285 {
286     int i, j, n;
287     char *sep = "";
288
289     if (!xd->human)
290         return;
291
292     for (i = 0; ca[i].ca_name; ++i) {
293         if (ca[i].ca_flags & NSC_DEITY && !xd->divine)
294             continue;
295         if (ca[i].ca_flags & NSC_EXTRA)
296             continue;
297         n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
298         if (n) {
299             for (j = 0; j < n; j++) {
300                 xd->pr("%s%s(%d)",sep, ca[i].ca_name, j);
301                 sep = " ";
302             }
303         } else {
304             xd->pr("%s%s", sep, ca[i].ca_name);
305             sep = " ";
306         }
307     }
308     xd->pr("\n");
309 }
310
311 /* Dump footer for a dump that dumped N objects to XD.  */
312 void
313 xdftr(struct xdstr *xd, int n)
314 {
315     if (xd->human)
316         xd->pr("/config\n");
317     else
318         xd->pr("/%d\n", n);
319 }
320
321 /*
322  * Dump meta-data for items of type TYPE to XD.
323  * Return RET_OK.
324  */
325 int
326 xdmeta(struct xdstr *xd, int type)
327 {
328     struct castr *ca = ef_cadef(type);
329     int i;
330     int n = 0;
331
332     if (!ca)
333         return RET_SYN;
334
335     xdhdr(xd, ef_nameof(type), 1);
336     xdcolhdr(xd, ca);
337
338     for (i = 0; ca[i].ca_name; i++) {
339         if (ca[i].ca_flags & NSC_DEITY && !xd->divine)
340             continue;
341         if (ca[i].ca_flags & NSC_EXTRA)
342             continue;
343         xdflds(xd, mdchr_ca, &ca[i]);
344         xd->pr("\n");
345         n++;
346     }
347
348     xdftr(xd, n);
349
350     return RET_OK;
351 }