ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.7
Committed: Tue Jan 23 03:56:45 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +0 -4 lines
Log Message:
I knew there was an explanation

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