ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.33
Committed: Mon Oct 12 14:00:59 2009 UTC (14 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82, rel-2_81, rel-2_90
Changes since 1.32: +7 -6 lines
Log Message:
clarify license

File Contents

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