ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.10
Committed: Thu Feb 15 21:07:49 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.9: +47 -29 lines
Log Message:
- use a simpler, less fancy loader base design (basically a one-line-lookahead
  top-down parser).

File Contents

# Content
1 /*****************************************************************************/
2 /* CrossFire, A roguelike realtime multiplayer game */
3 /*****************************************************************************/
4
5 /*
6 * This code is placed under the GNU General Public Licence (GPL)
7 *
8 * Copyright (C) 2006 by Marc Lehmann <crossfire@schmorp.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include "global.h" // bug in cfperl.h, doesn't include interface_class stuff
26 #include "logger.h"
27 #include "cfperl.h"
28 #include "kw_hash.h"
29
30 object_freezer::object_freezer ()
31 : dynbuf (128 * 1024, 64 * 1024)
32 {
33 av = newAV ();
34 }
35
36 object_freezer::~object_freezer ()
37 {
38 SvREFCNT_dec (av);
39 }
40
41 void
42 object_freezer::put (attachable *ext)
43 {
44 ext->optimise ();
45
46 if (ext->self)
47 {
48 int idx = AvFILLp ((AV *)av) + 1;
49 av_store (av, idx, newRV_inc ((SV *)ext->self));
50
51 add ((void *)"oid ", 4);
52 add ((sint32)idx);
53 add ('\n');
54 }
55 }
56
57 bool
58 object_freezer::save (const char *path)
59 {
60 CALL_BEGIN (3);
61 CALL_ARG_SV (newSVpv (path, 0));
62 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
63 CALL_ARG_SV (newRV_inc ((SV *)av));
64 CALL_CALL ("cf::object_freezer_save", G_VOID | G_DISCARD);
65 CALL_END;
66 }
67
68 char *
69 object_freezer::as_string ()
70 {
71 CALL_BEGIN (2);
72 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
73 CALL_ARG_SV (newRV_inc ((SV *)av));
74 CALL_CALL ("cf::object_freezer_as_string", G_SCALAR);
75
76 char *res = count > 0
77 ? strdup (SvPVX (POPs))
78 : strdup ("[fatal error]");
79
80 CALL_END;
81
82 return res;
83 }
84
85 int
86 fprintf (object_freezer &freezer, const char *format, ...)
87 {
88 va_list ap;
89
90 va_start (ap, format);
91
92 int len = vsnprintf ((char *)freezer.force (1024), 1024, format, ap);
93
94 if (len >= 0)
95 freezer.alloc (len);
96
97 va_end (ap);
98 }
99
100 int
101 fputs (const char *s, object_freezer &freezer)
102 {
103 freezer.add (s);
104 }
105
106 static const char thawer_eof[] = "\n\n\n\0\0\0";
107
108 object_thawer::object_thawer (const char *path)
109 : name (strdup (path))
110 {
111 static const char eof[] = "\n\n\n\0\0\0";
112
113 av = 0;
114 text = 0;
115 line = 0;
116 linenum = 0;
117
118 kw = KW_ERROR;
119 kw_str = 0;
120 value = 0;
121
122 if (path)
123 {
124 CALL_BEGIN (1);
125 CALL_ARG_SV (newSVpv (path, 0));
126 CALL_CALL ("cf::object_thawer_load", G_ARRAY);
127
128 if (count == 2)
129 {
130 // second value - perl objects
131 {
132 SV *sv = POPs;
133 if (SvROK (sv))
134 av = (AV *)SvREFCNT_inc (SvRV (sv));
135 }
136
137 // first value - text part, pad with 3 zeroes
138 {
139 SV *sv = POPs;
140 STRLEN len;
141 char *sv_ = SvPVbyte (sv, len);
142 text = newSV (len + sizeof (eof));
143 SvCUR_set (text, len);
144 memcpy (SvPVX (text), sv_, len);
145 memcpy (SvEND (text), eof, sizeof (eof)); // just to be sure
146
147 line = SvPVX (text);
148 }
149 }
150
151 CALL_END;
152 }
153 }
154
155 object_thawer::object_thawer (const char *data, AV *perlav)
156 : name (strdup ("(memory stream"))
157 {
158 av = perlav;
159 text = newSVpv (data, 0);
160 sv_catpv (text, thawer_eof);
161 line = SvPVbyte_nolen (text);
162 }
163
164 void
165 object_thawer::get (attachable *obj, int oid)
166 {
167 if (!av || oid < 0) // this is actually an error of sorts
168 return;
169
170 SV **svp = av_fetch ((AV *)av, oid, 0);
171
172 if (!svp || !SvROK (*svp))
173 {
174 printf ("trying to thaw duplicate or never-issued oid %d, ignoring.\n", oid);
175 return;
176 }
177
178 if (!SvROK (*svp))
179 {
180 LOG (llevError, "deserialised perl object is not an RV");
181 return;
182 }
183
184 HV *hv = (HV *)SvRV (*svp);
185
186 if (SvTYPE (hv) != SVt_PVHV)
187 {
188 LOG (llevError, "deserialised perl object is not a PVHV");
189 return;
190 }
191
192 if (obj->self)
193 {
194 // the hard way(?)
195
196 CALL_BEGIN (2);
197 CALL_ARG_SV (newRV_inc ((SV *)obj->self));
198 CALL_ARG_SV (newRV_inc ((SV *)hv));
199 PUTBACK;
200 call_method ("thawer_merge", G_DISCARD | G_EVAL);
201 SPAGAIN;
202 CALL_END;
203 }
204 else
205 {
206 // the easy way(?)
207
208 obj->self = hv;
209 SvRV_set (*svp, &PL_sv_undef);
210
211 sv_magicext ((SV *)obj->self, 0, PERL_MAGIC_ext, &attachable::vtbl, (char *)obj, 0);
212 }
213
214 obj->reattach ();
215 }
216
217 object_thawer::~object_thawer ()
218 {
219 if (text) SvREFCNT_dec (text);
220 if (av) SvREFCNT_dec (av);
221
222 free ((void *)name);
223 }
224
225 //TODO: remove
226 char *
227 fgets (char *s, int n, object_thawer &thawer)
228 {
229 char *p = thawer.line;
230 char *q = s;
231
232 if (!p)
233 return 0;
234
235 while (--n)
236 {
237 if (!*p)
238 break;
239
240 *q++ = *p;
241
242 if (*p++ == '\n')
243 {
244 ++thawer.linenum;
245 break;
246 }
247 }
248
249 *q = 0;
250 thawer.line = p;
251
252 return s == q ? 0 : s;
253 }
254
255 bool
256 object_thawer::parse_error (const char *type, const char *name, bool skip)
257 {
258 if (!type) type = "file section";
259 if (!name) name = "generic";
260
261 switch (kw)
262 {
263 case KW_EOF:
264 LOG (llevError, "%s:%d end of file while reading %s '%s', aborting load.\n",
265 this->name, linenum, type, name);
266 return false;
267
268 case KW_ERROR:
269 LOG (llevError, "%s:%d error while reading %s '%s', at '%s', aborting load.\n",
270 this->name, linenum,
271 type, name,
272 kw_str ? kw_str : "<file load>");
273 return false;
274
275 default:
276 LOG (llevError, "%s:%d unexpected line (%s %s) while reading %s '%s', %s.\n",
277 this->name, linenum,
278 kw_str ? kw_str : "<null>",
279 value ? value : "<null>",
280 type, name,
281 skip ? "skipping line" : "aborting load");
282 return skip;
283 }
284 }
285
286 void
287 object_thawer::next_kv ()
288 {
289 if (!line)
290 {
291 kw = KW_ERROR;
292 return;
293 }
294
295 for (;;)
296 {
297 char *p = line;
298
299 if (!*p)
300 {
301 kw = KW_EOF;
302 break;
303 }
304
305 // parse keyword
306 while (*p > ' ')
307 p++;
308
309 int klen = p - line;
310
311 if (*p++ != '\n')
312 {
313 // parse value
314 while (*(unsigned char *)p <= ' ' && *p != '\n') // skip 0x01 .. 0x20
315 ++p;
316
317 value = p;
318
319 while (*p != '\n')
320 p++;
321
322 *p++ = 0;
323 }
324 else
325 value = 0;
326
327 ++linenum;
328 line [klen] = 0;
329 keyword_idx *kw_idx = kw_lex::match (line, klen);
330
331 //printf ("KV %d<%s,%s>\n", kw ? kw->index : 0, line, value);//D
332
333 kw_str = line;
334 line = p;
335
336 if (kw_idx)
337 {
338 kw = kw_idx->index;
339 break;
340 }
341 else if (!*kw_str || *kw_str == '#')
342 ; // empty/comment line
343 else
344 {
345 kw = KW_ERROR;
346 break;
347 }
348 }
349 }
350
351 void
352 object_thawer::skip_kv ()
353 {
354 shstr ml;
355
356 switch (kw)
357 {
358 case KW_msg: get_ml (KW_endmsg , ml); break;
359 case KW_lore: get_ml (KW_endlore , ml); break;
360 case KW_maplore: get_ml (KW_endmaplore, ml); break;
361 }
362
363 next_kv ();
364 }
365
366 void
367 object_thawer::get (shstr &sh) const
368 {
369 if (value)
370 sh = value;
371 else
372 {
373 sh = "<value missing>";
374 LOG (llevError, "keyword \"%s\" requires value, substituting with <value missing>\n", kw_str);//TODO: add filename
375 }
376 }
377
378 void
379 object_thawer::get_ml (keyword kend, shstr &sh)
380 {
381 char kw[128];
382
383 int klen = keyword_len [kend];
384
385 kw [0] = '\n';
386 memcpy (kw + 1, keyword_str [kend], klen);
387 kw [klen + 1] = '\n';
388 kw [klen + 2] = 0;
389
390 ++linenum;
391
392 // first test for completely empty msg... "endXXX\n"
393 if (!strncmp (line, kw + 1, klen + 1))
394 {
395 sh = 0;
396
397 line += klen + 1;
398
399 return;
400 }
401 else
402 {
403 // multi-line strings are delimited by "\nendXXX\n" or "endXXX\n" (NULL)
404
405 char *end = strstr (line, kw);
406
407 if (!end)
408 {
409 sh = 0;
410 return;
411 }
412
413 *end = 0;
414 sh = line;
415
416 // count line numbers
417 while (line < end)
418 linenum += *line++ == '\n';
419
420 line += keyword_len [kend];
421
422 while (*line++ != '\n')
423 ;
424
425 ++linenum;
426 }
427 }
428
429 sint32
430 object_thawer::get_sint32 () const
431 {
432 char *p = value;
433
434 if (!p)
435 return 0;
436
437 sint32 val = 0;
438 bool negate;
439
440 if (*p == '-')
441 {
442 negate = true;
443 ++p;
444 }
445 else
446 negate = false;
447
448 do
449 {
450 val *= 10;
451 val += *p++ - '0';
452 }
453 while (*p);
454
455 return negate ? -val : val;
456 }
457
458 sint64
459 object_thawer::get_sint64 () const
460 {
461 return value ? atoll (value) : 0;
462 }
463
464 double
465 object_thawer::get_double () const
466 {
467 return value ? atof (value) : 0;
468 }
469