ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.9
Committed: Thu Feb 1 19:17:03 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.8: +1 -1 lines
Log Message:
goof

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 if (path)
119 {
120 CALL_BEGIN (1);
121 CALL_ARG_SV (newSVpv (path, 0));
122 CALL_CALL ("cf::object_thawer_load", G_ARRAY);
123
124 if (count == 2)
125 {
126 // second value - perl objects
127 {
128 SV *sv = POPs;
129 if (SvROK (sv))
130 av = (AV *)SvREFCNT_inc (SvRV (sv));
131 }
132
133 // first value - text part, pad with 3 zeroes
134 {
135 SV *sv = POPs;
136 STRLEN len;
137 char *sv_ = SvPVbyte (sv, len);
138 text = newSV (len + sizeof (eof));
139 SvCUR_set (text, len);
140 memcpy (SvPVX (text), sv_, len);
141 memcpy (SvEND (text), eof, sizeof (eof)); // just to be sure
142
143 line = SvPVX (text);
144 }
145 }
146
147 CALL_END;
148 }
149 }
150
151 object_thawer::object_thawer (const char *data, AV *perlav)
152 : name (strdup ("(memory stream"))
153 {
154 av = perlav;
155 text = newSVpv (data, 0);
156 sv_catpv (text, thawer_eof);
157 line = SvPVbyte_nolen (text);
158 }
159
160 void
161 object_thawer::get (attachable *obj, int oid)
162 {
163 if (!av || oid < 0) // this is actually an error of sorts
164 return;
165
166 SV **svp = av_fetch ((AV *)av, oid, 0);
167
168 if (!svp || !SvROK (*svp))
169 {
170 printf ("trying to thaw duplicate or never-issued oid %d, ignoring.\n", oid);
171 return;
172 }
173
174 if (!SvROK (*svp))
175 {
176 LOG (llevError, "deserialised perl object is not an RV");
177 return;
178 }
179
180 HV *hv = (HV *)SvRV (*svp);
181
182 if (SvTYPE (hv) != SVt_PVHV)
183 {
184 LOG (llevError, "deserialised perl object is not a PVHV");
185 return;
186 }
187
188 if (obj->self)
189 {
190 // the hard way(?)
191
192 CALL_BEGIN (2);
193 CALL_ARG_SV (newRV_inc ((SV *)obj->self));
194 CALL_ARG_SV (newRV_inc ((SV *)hv));
195 PUTBACK;
196 call_method ("thawer_merge", G_DISCARD | G_EVAL);
197 SPAGAIN;
198 CALL_END;
199 }
200 else
201 {
202 // the easy way(?)
203
204 obj->self = hv;
205 SvRV_set (*svp, &PL_sv_undef);
206
207 sv_magicext ((SV *)obj->self, 0, PERL_MAGIC_ext, &attachable::vtbl, (char *)obj, 0);
208 }
209
210 obj->reattach ();
211 }
212
213 object_thawer::~object_thawer ()
214 {
215 if (text) SvREFCNT_dec (text);
216 if (av) SvREFCNT_dec (av);
217
218 free ((void *)name);
219 }
220
221 //TODO: remove
222 char *
223 fgets (char *s, int n, object_thawer &thawer)
224 {
225 char *p = thawer.line;
226 char *q = s;
227
228 if (!p)
229 return 0;
230
231 while (--n)
232 {
233 if (!*p)
234 break;
235
236 *q++ = *p;
237
238 if (*p++ == '\n')
239 {
240 ++thawer.linenum;
241 break;
242 }
243 }
244
245 *q = 0;
246 thawer.line = p;
247
248 return s == q ? 0 : s;
249 }
250
251 bool
252 object_thawer::parse_error (keyword kw, const char *type, const char *name, bool skip)
253 {
254 if (!type) type = "file section";
255 if (!name) name = "generic";
256
257 switch (kw)
258 {
259 case KW_EOF:
260 LOG (llevError, "%s:%d end of file while reading %s '%s', aborting load.\n",
261 this->name, linenum, type, name);
262 return false;
263
264 case KW_ERROR:
265 LOG (llevError, "%s:%d errornous line (%s) while reading %s '%s', aborting load.\n",
266 this->name, linenum,
267 last_keyword ? last_keyword : "<null>",
268 type, name);
269 return false;
270
271 default:
272 LOG (llevError, "%s:%d unexpected line (%s %s) while reading %s '%s', %s.\n",
273 this->name, linenum,
274 last_keyword ? last_keyword : "<null>",
275 last_value ? last_value : "<null>",
276 type, name,
277 skip ? "skipping line" : "aborting load");
278 return skip;
279 }
280 }
281
282 keyword
283 object_thawer::get_kv ()
284 {
285 if (!line)
286 return KW_EOF;
287
288 for (;;)
289 {
290 char *p = line;
291
292 if (!*p)
293 return KW_EOF;
294
295 // parse keyword
296 while (*p > ' ')
297 p++;
298
299 int klen = p - line;
300
301 if (*p++ != '\n')
302 {
303 // parse value
304 while (*(unsigned char *)p <= ' ' && *p != '\n') // skip 0x01 .. 0x20
305 ++p;
306
307 last_value = p;
308
309 while (*p != '\n')
310 p++;
311
312 *p++ = 0;
313 }
314 else
315 last_value = 0;
316
317 ++linenum;
318 line [klen] = 0;
319 keyword_idx *kw = kw_lex::match (line, klen);
320
321 //printf ("KV %d<%s,%s>\n", kw ? kw->index : 0, line, last_value);//D
322
323 last_keyword = line;
324 line = p;
325
326 if (kw)
327 return kw->index;
328 else if (!*last_keyword || *last_keyword == '#')
329 ; // empty/comment line
330 else
331 return KW_ERROR;
332 }
333 }
334
335 void
336 object_thawer::skip_kv (keyword kw)
337 {
338 shstr ml;
339
340 switch (kw)
341 {
342 case KW_msg: get_ml (KW_endmsg , ml); break;
343 case KW_lore: get_ml (KW_endlore , ml); break;
344 case KW_maplore: get_ml (KW_endmaplore, ml); break;
345 }
346 }
347
348 void
349 object_thawer::get (shstr &sh) const
350 {
351 if (last_value)
352 sh = last_value;
353 else
354 {
355 sh = "<value missing>";
356 LOG (llevError, "keyword \"%s\" requires value, substituting with <value missing>\n", last_keyword);//TODO: add filename
357 }
358 }
359
360 void
361 object_thawer::get_ml (keyword kend, shstr &sh)
362 {
363 char kw[128];
364
365 int klen = keyword_len [kend];
366
367 kw [0] = '\n';
368 memcpy (kw + 1, keyword_str [kend], klen);
369 kw [klen + 1] = '\n';
370 kw [klen + 2] = 0;
371
372 ++linenum;
373
374 // first test for completely empty msg... "endXXX\n"
375 if (!strncmp (line, kw + 1, klen + 1))
376 {
377 sh = 0;
378
379 line += klen + 1;
380
381 return;
382 }
383 else
384 {
385 // multi-line strings are delimited by "\nendXXX\n" or "endXXX\n" (NULL)
386
387 char *end = strstr (line, kw);
388
389 if (!end)
390 {
391 sh = 0;
392 return;
393 }
394
395 *end = 0;
396 sh = line;
397
398 // count line numbers
399 while (line < end)
400 linenum += *line++ == '\n';
401
402 line += keyword_len [kend];
403
404 while (*line++ != '\n')
405 ;
406
407 ++linenum;
408 }
409 }
410
411 sint32
412 object_thawer::get_sint32 () const
413 {
414 char *p = last_value;
415
416 if (!p)
417 return 0;
418
419 sint32 val = 0;
420 bool negate;
421
422 if (*p == '-')
423 {
424 negate = true;
425 ++p;
426 }
427 else
428 negate = false;
429
430 do
431 {
432 val *= 10;
433 val += *p++ - '0';
434 }
435 while (*p);
436
437 return negate ? -val : val;
438 }
439
440 sint64
441 object_thawer::get_sint64 () const
442 {
443 return last_value ? atoll (last_value) : 0;
444 }
445
446 double
447 object_thawer::get_double () const
448 {
449 return last_value ? atof (last_value) : 0;
450 }
451