ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.11
Committed: Fri Feb 16 19:43:41 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.10: +3 -3 lines
Log Message:
- identified random memory corrutpion bug
- fixed most likely cause for bug above
- rewrote object loader etc. into a simple one-line lookahead
  parser.
- rewrote/cleaned up archetype, treasure, artifact, formula parser.
- some optimisations / cleanups

File Contents

# User Rev Content
1 root 1.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 root 1.4 #include "global.h" // bug in cfperl.h, doesn't include interface_class stuff
26 root 1.1 #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 root 1.4 void
42     object_freezer::put (attachable *ext)
43 root 1.1 {
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 root 1.4 bool
58     object_freezer::save (const char *path)
59 root 1.1 {
60     CALL_BEGIN (3);
61 root 1.4 CALL_ARG_SV (newSVpv (path, 0));
62 root 1.1 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 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.4 int
86     fprintf (object_freezer &freezer, const char *format, ...)
87 root 1.1 {
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 root 1.4 int
101     fputs (const char *s, object_freezer &freezer)
102 root 1.1 {
103     freezer.add (s);
104     }
105    
106     static const char thawer_eof[] = "\n\n\n\0\0\0";
107    
108 root 1.4 object_thawer::object_thawer (const char *path)
109     : name (strdup (path))
110 root 1.1 {
111     static const char eof[] = "\n\n\n\0\0\0";
112    
113 root 1.10 av = 0;
114     text = 0;
115     line = 0;
116 root 1.8 linenum = 0;
117 root 1.1
118 root 1.10 kw = KW_ERROR;
119     kw_str = 0;
120     value = 0;
121    
122 root 1.4 if (path)
123 root 1.1 {
124     CALL_BEGIN (1);
125 root 1.4 CALL_ARG_SV (newSVpv (path, 0));
126 root 1.1 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 root 1.4 : name (strdup ("(memory stream"))
157 root 1.1 {
158     av = perlav;
159     text = newSVpv (data, 0);
160     sv_catpv (text, thawer_eof);
161     line = SvPVbyte_nolen (text);
162     }
163    
164 root 1.4 void
165     object_thawer::get (attachable *obj, int oid)
166 root 1.1 {
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 root 1.6 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 root 1.1 }
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 root 1.4
222     free ((void *)name);
223 root 1.1 }
224    
225 root 1.8 //TODO: remove
226 root 1.4 char *
227     fgets (char *s, int n, object_thawer &thawer)
228 root 1.1 {
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 root 1.8 {
244     ++thawer.linenum;
245     break;
246     }
247 root 1.1 }
248    
249     *q = 0;
250     thawer.line = p;
251    
252     return s == q ? 0 : s;
253     }
254    
255 root 1.8 bool
256 root 1.10 object_thawer::parse_error (const char *type, const char *name, bool skip)
257 root 1.8 {
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 root 1.10 LOG (llevError, "%s:%d error while reading %s '%s', at '%s', aborting load.\n",
270 root 1.8 this->name, linenum,
271 root 1.10 type, name,
272     kw_str ? kw_str : "<file load>");
273 root 1.8 return false;
274    
275     default:
276 root 1.9 LOG (llevError, "%s:%d unexpected line (%s %s) while reading %s '%s', %s.\n",
277 root 1.8 this->name, linenum,
278 root 1.10 kw_str ? kw_str : "<null>",
279     value ? value : "<null>",
280 root 1.8 type, name,
281     skip ? "skipping line" : "aborting load");
282     return skip;
283     }
284     }
285    
286 root 1.10 void
287 root 1.11 object_thawer::next ()
288 root 1.1 {
289     if (!line)
290 root 1.10 {
291     kw = KW_ERROR;
292     return;
293     }
294 root 1.1
295     for (;;)
296     {
297     char *p = line;
298    
299     if (!*p)
300 root 1.10 {
301     kw = KW_EOF;
302     break;
303     }
304 root 1.1
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 root 1.10 value = p;
318 root 1.1
319     while (*p != '\n')
320     p++;
321    
322     *p++ = 0;
323     }
324     else
325 root 1.10 value = 0;
326 root 1.1
327 root 1.8 ++linenum;
328 root 1.1 line [klen] = 0;
329 root 1.10 keyword_idx *kw_idx = kw_lex::match (line, klen);
330 root 1.1
331 root 1.10 //printf ("KV %d<%s,%s>\n", kw ? kw->index : 0, line, value);//D
332 root 1.1
333 root 1.10 kw_str = line;
334 root 1.1 line = p;
335    
336 root 1.10 if (kw_idx)
337     {
338     kw = kw_idx->index;
339     break;
340     }
341     else if (!*kw_str || *kw_str == '#')
342 root 1.1 ; // empty/comment line
343     else
344 root 1.10 {
345     kw = KW_ERROR;
346     break;
347     }
348 root 1.1 }
349     }
350    
351 root 1.4 void
352 root 1.11 object_thawer::skip ()
353 root 1.1 {
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 root 1.10
363 root 1.11 next ();
364 root 1.1 }
365    
366 root 1.4 void
367     object_thawer::get (shstr &sh) const
368 root 1.1 {
369 root 1.10 if (value)
370     sh = value;
371 root 1.1 else
372     {
373     sh = "<value missing>";
374 root 1.10 LOG (llevError, "keyword \"%s\" requires value, substituting with <value missing>\n", kw_str);//TODO: add filename
375 root 1.1 }
376     }
377    
378 root 1.4 void
379     object_thawer::get_ml (keyword kend, shstr &sh)
380 root 1.1 {
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 root 1.8 ++linenum;
391    
392 root 1.1 // 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 root 1.8 // count line numbers
417     while (line < end)
418     linenum += *line++ == '\n';
419    
420     line += keyword_len [kend];
421 root 1.1
422     while (*line++ != '\n')
423     ;
424 root 1.8
425     ++linenum;
426 root 1.1 }
427     }
428    
429 root 1.4 sint32
430     object_thawer::get_sint32 () const
431 root 1.1 {
432 root 1.10 char *p = value;
433 root 1.1
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 root 1.4 sint64
459     object_thawer::get_sint64 () const
460 root 1.1 {
461 root 1.10 return value ? atoll (value) : 0;
462 root 1.1 }
463    
464 root 1.4 double
465     object_thawer::get_double () const
466 root 1.1 {
467 root 1.10 return value ? atof (value) : 0;
468 root 1.1 }
469