ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.36
Committed: Fri Mar 26 01:04:45 2010 UTC (14 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.35: +1 -1 lines
Log Message:
update copyright for up to 2010

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 *
6 * Deliantra is free software: you can redistribute it and/or modify it under
7 * the terms of the Affero GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * 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 Affero GNU General Public License
17 * and the GNU General Public License along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 * The authors can be reached via e-mail to <support@deliantra.net>
21 */
22
23 #include "global.h" // bug in cfperl.h, doesn't include interface_class stuff
24 #include "logger.h"
25 #include "cfperl.h"
26 #include "kw_hash.h"
27
28 object_freezer::object_freezer ()
29 : dynbuf_text (128 * 1024, 64 * 1024)
30 {
31 av = newAV ();
32 }
33
34 object_freezer::~object_freezer ()
35 {
36 SvREFCNT_dec (av);
37 }
38
39 void
40 object_freezer::put_ (attachable *ext)
41 {
42 ext->optimise ();
43
44 if (ext->self)
45 {
46 int idx = AvFILLp ((AV *)av) + 1;
47 av_store (av, idx, newRV_inc ((SV *)ext->self));
48
49 put (KW(oid), sint32(idx));
50 }
51 }
52
53 bool
54 object_freezer::save (const char *path)
55 {
56 CALL_BEGIN (3);
57 CALL_ARG_SV (newSVpv (path, 0));
58 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
59 CALL_ARG_SV (newRV_inc ((SV *)av));
60 CALL_CALL ("cf::object_freezer_save", G_VOID | G_DISCARD);
61 CALL_END;
62
63 return 1;
64 }
65
66 char *
67 object_freezer::as_string ()
68 {
69 CALL_BEGIN (2);
70 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
71 CALL_ARG_SV (newRV_inc ((SV *)av));
72 CALL_CALL ("cf::object_freezer_as_string", G_SCALAR);
73
74 char *res = count > 0
75 ? strdup (SvPVX (POPs))
76 : strdup ("[fatal error]");
77
78 CALL_END;
79
80 return res;
81 }
82
83 #if 0
84 void
85 fprintf (object_freezer &freezer, const char *format, ...)
86 {
87 va_list ap;
88
89 va_start (ap, format);
90
91 int len = vsnprintf ((char *)freezer.force (1024), 1024, format, ap);
92
93 if (len >= 0)
94 freezer.alloc (len);
95
96 va_end (ap);
97 }
98
99 // XXX: function not returning an int
100 void
101 fputs (const char *s, object_freezer &freezer)
102 {
103 freezer.add (s);
104 }
105 #endif
106
107 static const char thawer_eof[] = "\n\n\n\0\0\0";
108
109 object_thawer::object_thawer (const char *path)
110 : name (strdup (path))
111 {
112 av = 0;
113 text = 0;
114 line = 0;
115 linenum = 0;
116
117 kw = KW_ERROR;
118 kw_str = 0;
119 value = 0;
120
121 if (path)
122 {
123 CALL_BEGIN (1);
124 CALL_ARG_SV (newSVpv (path, 0));
125 CALL_CALL ("cf::object_thawer_load", G_ARRAY);
126
127 if (count == 2)
128 {
129 // second value - perl objects
130 {
131 SV *sv = POPs;
132 if (SvROK (sv))
133 av = (AV *)SvREFCNT_inc (SvRV (sv));
134 }
135
136 // first value - text part, pad with 3 zeroes
137 {
138 SV *sv = POPs;
139 STRLEN len;
140 char *sv_ = SvPVbyte (sv, len);
141 text = newSV (len + sizeof (thawer_eof));
142 SvCUR_set (text, len + sizeof (thawer_eof));
143 memcpy (SvPVX (text), sv_, len);
144 memcpy (SvPVX (text) + len, thawer_eof, sizeof (thawer_eof));
145
146 line = SvPVX (text);
147 next ();
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 next ();
163 }
164
165 void
166 object_thawer::get (attachable *obj, int oid)
167 {
168 if (!av || oid < 0) // this is actually an error of sorts
169 return;
170
171 SV **svp = av_fetch ((AV *)av, oid, 0);
172
173 if (!svp || !SvROK (*svp))
174 {
175 LOG (llevError, "trying to thaw duplicate or never-issued oid %d, ignoring.\n", oid);
176 return;
177 }
178
179 if (!SvROK (*svp))
180 {
181 LOG (llevError, "deserialised perl object is not an RV\n");
182 return;
183 }
184
185 HV *hv = (HV *)SvRV (*svp);
186
187 if (SvTYPE (hv) != SVt_PVHV)
188 {
189 LOG (llevError, "deserialised perl object is not a PVHV\n");
190 return;
191 }
192
193 if (obj->self)
194 {
195 // the hard way(?)
196
197 CALL_BEGIN (2);
198 CALL_ARG_SV (newRV_inc ((SV *)obj->self));
199 CALL_ARG_SV (newRV_inc ((SV *)hv));
200 PUTBACK;
201 call_method ("thawer_merge", G_DISCARD | G_EVAL);
202 SPAGAIN;
203 CALL_END;
204 }
205 else
206 {
207 // the easy way(?)
208
209 obj->self = hv;
210 SvRV_set (*svp, &PL_sv_undef);
211
212 sv_magicext ((SV *)obj->self, 0, PERL_MAGIC_ext, &attachable::vtbl, (char *)obj, 0);
213 }
214
215 obj->reattach ();
216 }
217
218 object_thawer::~object_thawer ()
219 {
220 if (text) SvREFCNT_dec (text);
221 if (av) SvREFCNT_dec (av);
222
223 resolve_delayed_derefs (false);
224
225 free ((void *)name);
226 }
227
228 //TODO: remove
229 char *
230 fgets (char *s, int n, object_thawer &thawer)
231 {
232 char *p = thawer.line;
233 char *q = s;
234
235 if (!p)
236 return 0;
237
238 while (--n)
239 {
240 if (!*p)
241 break;
242
243 *q++ = *p;
244
245 if (*p++ == '\n')
246 {
247 ++thawer.linenum;
248 break;
249 }
250 }
251
252 *q = 0;
253 thawer.line = p;
254
255 return s == q ? 0 : s;
256 }
257
258 void
259 object_thawer::parse_warn (const char *msg)
260 {
261 LOG (llevWarn, "%s:%d, \"%s %s\": %s\n",
262 this->name, linenum,
263 kw_str ? kw_str : "<null>",
264 value ? value : "<null>",
265 msg);
266 }
267
268 bool
269 object_thawer::parse_error (const char *type, const char *name, bool skip)
270 {
271 if (!type) type = "file section";
272 if (!name) name = "generic";
273
274 switch (kw)
275 {
276 case KW_EOF:
277 LOG (llevError, "%s:%d end of file while reading %s '%s', aborting load.\n",
278 this->name, linenum, type, name);
279 return false;
280
281 case KW_ERROR:
282 LOG (llevError, "%s:%d error while reading %s '%s', at '%s', aborting load.\n",
283 this->name, linenum,
284 type, name,
285 kw_str ? kw_str : "<file load>");
286 return false;
287
288 default:
289 LOG (llevError, "%s:%d unexpected line (%s %s) while reading %s '%s', %s.\n",
290 this->name, linenum,
291 kw_str ? kw_str : "<null>",
292 value ? value : "<null>",
293 type, name,
294 skip ? "skipping line" : "aborting load");
295 return skip;
296 }
297 }
298
299 void
300 object_thawer::next ()
301 {
302 if (!line)
303 {
304 kw = KW_ERROR;
305 return;
306 }
307
308 for (;;)
309 {
310 char *p = line;
311
312 if (*p <= ' ')
313 {
314 // skip whitespace (only some files need this)
315 while (*p == ' ' || *p == '\t')
316 p++;
317
318 line = p;
319 }
320
321 if (!*p)
322 {
323 kw = KW_EOF;
324 break;
325 }
326
327 // parse keyword
328 while (*p > ' ')
329 p++;
330
331 int klen = p - line;
332
333 value_nn = "";
334 value = 0;
335
336 if (*p++ != '\n')
337 {
338 // parse value
339 while (*(unsigned char *)p <= ' ' && *p != '\n')
340 ++p;
341
342 value_nn = value = p;
343
344 while (*p != '\n')
345 p++;
346
347 *p++ = 0;
348 }
349
350 ++linenum;
351 line [klen] = 0;
352 keyword_idx *kw_idx = kw_lex::match (line, klen);
353
354 kw_str = line;
355 line = p;
356
357 if (kw_idx)
358 {
359 kw = kw_idx->index;
360 break;
361 }
362 else if (!*kw_str || *kw_str == '#')
363 ; // empty/comment line
364 else
365 {
366 kw = KW_ERROR;
367 break;
368 }
369 }
370 }
371
372 void
373 object_thawer::skip ()
374 {
375 shstr ml;
376
377 switch (kw)
378 {
379 case KW_msg: get_ml (KW_endmsg , ml); break;
380 case KW_lore: get_ml (KW_endlore , ml); break;
381 case KW_maplore: get_ml (KW_endmaplore, ml); break;
382 default: break;
383 }
384
385 next ();
386 }
387
388 void
389 object_thawer::skip_block ()
390 {
391 // must not stop at KW_ERROR, as those signify custom keys
392 while (kw != KW_EOF)
393 {
394 keyword w = kw;
395 skip ();
396
397 if (0 && (w == KW_map || w == KW_arch || w == KW_object || w == KW_region))
398 skip_block ();
399 else if (w == KW_end)
400 break;
401 }
402 }
403
404 void
405 object_thawer::get_ml (keyword kend, shstr &sh)
406 {
407 char kw[128];
408
409 int klen = keyword_len [kend];
410
411 kw [0] = '\n';
412 memcpy (kw + 1, keyword_str [kend], klen);
413 kw [klen + 1] = '\n';
414 kw [klen + 2] = 0;
415
416 ++linenum;
417
418 // first test for completely empty msg... "endXXX\n"
419 if (!strncmp (line, kw + 1, klen + 1))
420 {
421 sh = 0;
422
423 line += klen + 1;
424
425 return;
426 }
427 else
428 {
429 // multi-line strings are delimited by "\nendXXX\n" or "endXXX\n" (NULL)
430
431 char *end = strstr (line, kw);
432
433 if (!end)
434 {
435 sh = 0;
436 return;
437 }
438
439 *end = 0;
440 sh = line;
441
442 // count line numbers
443 while (line < end)
444 linenum += *line++ == '\n';
445
446 line += keyword_len [kend];
447
448 while (*line++ != '\n')
449 ;
450
451 ++linenum;
452 }
453 }
454
455 sint32
456 object_thawer::get_sint32 () const
457 {
458 const char *p = value_nn;
459
460 sint32 val = 0;
461 bool negate;
462
463 if (*p == '-')
464 {
465 negate = true;
466 ++p;
467 }
468 else
469 negate = false;
470
471 do
472 {
473 val *= 10;
474 val += *p++ - '0';
475 }
476 while (*p);
477
478 return negate ? -val : val;
479 }
480
481 void
482 object_thawer::delayed_deref (attachable *op, object_ptr &ptr, const char *ref)
483 {
484 op->refcnt_inc ();
485 delayed_ref r = { op, &ptr, ref ? strdup (ref) : 0 };
486 delrefs.push_back (r);
487 ptr = 0;
488 }
489
490 void
491 object_thawer::resolve_delayed_derefs (bool deref)
492 {
493 while (!delrefs.empty ())
494 {
495 delayed_ref r = delrefs.back ();
496 delrefs.pop_back ();
497
498 if (deref)
499 *r.ptr = object::deref (r.ref);
500
501 free ((void *)r.ref);
502 r.op->refcnt_dec ();
503 }
504 }