ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.17
Committed: Mon Apr 23 18:09:57 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.16: +1 -1 lines
Log Message:
- add format utility function.
- split dynbuf into dynbuf and dynbuf_text.
- use dynbuf_text for examine strings instead of
  outputting each line seperately. tried to use stringstreams
  but they add insane overheads (as does std::string, but less so).

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 root 1.17 : dynbuf_text (128 * 1024, 64 * 1024)
32 root 1.1 {
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 root 1.13
67     return 1;
68 root 1.1 }
69    
70 root 1.4 char *
71     object_freezer::as_string ()
72 root 1.1 {
73     CALL_BEGIN (2);
74     CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
75     CALL_ARG_SV (newRV_inc ((SV *)av));
76     CALL_CALL ("cf::object_freezer_as_string", G_SCALAR);
77    
78     char *res = count > 0
79 root 1.3 ? strdup (SvPVX (POPs))
80 root 1.1 : strdup ("[fatal error]");
81    
82     CALL_END;
83    
84     return res;
85     }
86    
87 root 1.13 void
88 root 1.4 fprintf (object_freezer &freezer, const char *format, ...)
89 root 1.1 {
90     va_list ap;
91    
92     va_start (ap, format);
93    
94     int len = vsnprintf ((char *)freezer.force (1024), 1024, format, ap);
95    
96     if (len >= 0)
97     freezer.alloc (len);
98    
99     va_end (ap);
100     }
101    
102 pippijn 1.12 // XXX: function not returning an int
103 root 1.13 void
104 root 1.4 fputs (const char *s, object_freezer &freezer)
105 root 1.1 {
106     freezer.add (s);
107     }
108    
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     SvCUR_set (text, len);
147     memcpy (SvPVX (text), sv_, len);
148     memcpy (SvEND (text), eof, sizeof (eof)); // just to be sure
149    
150     line = SvPVX (text);
151     }
152     }
153    
154     CALL_END;
155     }
156     }
157    
158     object_thawer::object_thawer (const char *data, AV *perlav)
159 root 1.4 : name (strdup ("(memory stream"))
160 root 1.1 {
161     av = perlav;
162     text = newSVpv (data, 0);
163     sv_catpv (text, thawer_eof);
164     line = SvPVbyte_nolen (text);
165     }
166    
167 root 1.4 void
168     object_thawer::get (attachable *obj, int oid)
169 root 1.1 {
170     if (!av || oid < 0) // this is actually an error of sorts
171     return;
172    
173     SV **svp = av_fetch ((AV *)av, oid, 0);
174    
175     if (!svp || !SvROK (*svp))
176     {
177 root 1.15 LOG (llevError, "trying to thaw duplicate or never-issued oid %d, ignoring.\n", oid);
178 root 1.1 return;
179     }
180    
181     if (!SvROK (*svp))
182     {
183 root 1.15 LOG (llevError, "deserialised perl object is not an RV\n");
184 root 1.1 return;
185     }
186    
187     HV *hv = (HV *)SvRV (*svp);
188    
189     if (SvTYPE (hv) != SVt_PVHV)
190     {
191 root 1.15 LOG (llevError, "deserialised perl object is not a PVHV\n");
192 root 1.1 return;
193     }
194    
195     if (obj->self)
196     {
197     // the hard way(?)
198    
199 root 1.6 CALL_BEGIN (2);
200     CALL_ARG_SV (newRV_inc ((SV *)obj->self));
201     CALL_ARG_SV (newRV_inc ((SV *)hv));
202     PUTBACK;
203     call_method ("thawer_merge", G_DISCARD | G_EVAL);
204     SPAGAIN;
205     CALL_END;
206 root 1.1 }
207     else
208     {
209     // the easy way(?)
210    
211     obj->self = hv;
212     SvRV_set (*svp, &PL_sv_undef);
213    
214     sv_magicext ((SV *)obj->self, 0, PERL_MAGIC_ext, &attachable::vtbl, (char *)obj, 0);
215     }
216    
217     obj->reattach ();
218     }
219    
220     object_thawer::~object_thawer ()
221     {
222     if (text) SvREFCNT_dec (text);
223     if (av) SvREFCNT_dec (av);
224 root 1.4
225     free ((void *)name);
226 root 1.1 }
227    
228 root 1.8 //TODO: remove
229 root 1.4 char *
230     fgets (char *s, int n, object_thawer &thawer)
231 root 1.1 {
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 root 1.8 {
247     ++thawer.linenum;
248     break;
249     }
250 root 1.1 }
251    
252     *q = 0;
253     thawer.line = p;
254    
255     return s == q ? 0 : s;
256     }
257    
258 root 1.8 bool
259 root 1.10 object_thawer::parse_error (const char *type, const char *name, bool skip)
260 root 1.8 {
261     if (!type) type = "file section";
262     if (!name) name = "generic";
263    
264     switch (kw)
265     {
266     case KW_EOF:
267     LOG (llevError, "%s:%d end of file while reading %s '%s', aborting load.\n",
268     this->name, linenum, type, name);
269     return false;
270    
271     case KW_ERROR:
272 root 1.10 LOG (llevError, "%s:%d error while reading %s '%s', at '%s', aborting load.\n",
273 root 1.8 this->name, linenum,
274 root 1.10 type, name,
275     kw_str ? kw_str : "<file load>");
276 root 1.8 return false;
277    
278     default:
279 root 1.9 LOG (llevError, "%s:%d unexpected line (%s %s) while reading %s '%s', %s.\n",
280 root 1.8 this->name, linenum,
281 root 1.10 kw_str ? kw_str : "<null>",
282     value ? value : "<null>",
283 root 1.8 type, name,
284     skip ? "skipping line" : "aborting load");
285     return skip;
286     }
287     }
288    
289 root 1.10 void
290 root 1.11 object_thawer::next ()
291 root 1.1 {
292     if (!line)
293 root 1.10 {
294     kw = KW_ERROR;
295     return;
296     }
297 root 1.1
298     for (;;)
299     {
300     char *p = line;
301    
302 root 1.16 if (*p <= ' ')
303     {
304     // skip whitespace (only some files need this)
305     while (*p == ' ' || *p == '\t')
306     p++;
307    
308     line = p;
309     }
310    
311 root 1.1 if (!*p)
312 root 1.10 {
313     kw = KW_EOF;
314     break;
315     }
316 root 1.1
317     // parse keyword
318     while (*p > ' ')
319     p++;
320    
321     int klen = p - line;
322    
323 root 1.16 value = 0;
324    
325 root 1.1 if (*p++ != '\n')
326     {
327     // parse value
328 root 1.16 while (*(unsigned char *)p <= ' ' && *p != '\n')
329 root 1.1 ++p;
330    
331 root 1.10 value = p;
332 root 1.1
333     while (*p != '\n')
334     p++;
335    
336     *p++ = 0;
337     }
338    
339 root 1.8 ++linenum;
340 root 1.1 line [klen] = 0;
341 root 1.10 keyword_idx *kw_idx = kw_lex::match (line, klen);
342 root 1.1
343 root 1.10 //printf ("KV %d<%s,%s>\n", kw ? kw->index : 0, line, value);//D
344 root 1.1
345 root 1.10 kw_str = line;
346 root 1.1 line = p;
347    
348 root 1.10 if (kw_idx)
349     {
350     kw = kw_idx->index;
351     break;
352     }
353     else if (!*kw_str || *kw_str == '#')
354 root 1.1 ; // empty/comment line
355     else
356 root 1.10 {
357     kw = KW_ERROR;
358     break;
359     }
360 root 1.1 }
361     }
362    
363 root 1.4 void
364 root 1.11 object_thawer::skip ()
365 root 1.1 {
366     shstr ml;
367    
368     switch (kw)
369     {
370     case KW_msg: get_ml (KW_endmsg , ml); break;
371     case KW_lore: get_ml (KW_endlore , ml); break;
372     case KW_maplore: get_ml (KW_endmaplore, ml); break;
373 pippijn 1.14 default: break;
374 root 1.1 }
375 root 1.10
376 root 1.11 next ();
377 root 1.1 }
378    
379 root 1.4 void
380     object_thawer::get (shstr &sh) const
381 root 1.1 {
382 root 1.10 if (value)
383     sh = value;
384 root 1.1 else
385     {
386     sh = "<value missing>";
387 root 1.10 LOG (llevError, "keyword \"%s\" requires value, substituting with <value missing>\n", kw_str);//TODO: add filename
388 root 1.1 }
389     }
390    
391 root 1.4 void
392     object_thawer::get_ml (keyword kend, shstr &sh)
393 root 1.1 {
394     char kw[128];
395    
396     int klen = keyword_len [kend];
397    
398     kw [0] = '\n';
399     memcpy (kw + 1, keyword_str [kend], klen);
400     kw [klen + 1] = '\n';
401     kw [klen + 2] = 0;
402    
403 root 1.8 ++linenum;
404    
405 root 1.1 // first test for completely empty msg... "endXXX\n"
406     if (!strncmp (line, kw + 1, klen + 1))
407     {
408     sh = 0;
409    
410     line += klen + 1;
411    
412     return;
413     }
414     else
415     {
416     // multi-line strings are delimited by "\nendXXX\n" or "endXXX\n" (NULL)
417    
418     char *end = strstr (line, kw);
419    
420     if (!end)
421     {
422     sh = 0;
423     return;
424     }
425    
426     *end = 0;
427     sh = line;
428    
429 root 1.8 // count line numbers
430     while (line < end)
431     linenum += *line++ == '\n';
432    
433     line += keyword_len [kend];
434 root 1.1
435     while (*line++ != '\n')
436     ;
437 root 1.8
438     ++linenum;
439 root 1.1 }
440     }
441    
442 root 1.4 sint32
443     object_thawer::get_sint32 () const
444 root 1.1 {
445 root 1.10 char *p = value;
446 root 1.1
447     if (!p)
448     return 0;
449    
450     sint32 val = 0;
451     bool negate;
452    
453     if (*p == '-')
454     {
455     negate = true;
456     ++p;
457     }
458     else
459     negate = false;
460    
461     do
462     {
463     val *= 10;
464     val += *p++ - '0';
465     }
466     while (*p);
467    
468     return negate ? -val : val;
469     }
470    
471 root 1.4 sint64
472     object_thawer::get_sint64 () const
473 root 1.1 {
474 root 1.10 return value ? atoll (value) : 0;
475 root 1.1 }
476    
477 root 1.4 double
478     object_thawer::get_double () const
479 root 1.1 {
480 root 1.10 return value ? atof (value) : 0;
481 root 1.1 }
482