ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.6
Committed: Sun Jan 14 02:00:37 2007 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +7 -5 lines
Log Message:
- introduce cf::attachable::thawer_merge, allowing classes
  to overwrite what happens when two objects get merged.
- protect some extension data with it
- make unlink_save blocking, so we do not get needless reset loops
  because of slow disk response.

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 // borrow a refcount for the perl object
209 obj->flags |= attachable::F_BORROWED;
210 obj->refcnt_dec ();
211 }
212
213 obj->reattach ();
214 }
215
216 object_thawer::~object_thawer ()
217 {
218 if (text) SvREFCNT_dec (text);
219 if (av) SvREFCNT_dec (av);
220
221 free ((void *)name);
222 }
223
224 char *
225 fgets (char *s, int n, object_thawer &thawer)
226 {
227 char *p = thawer.line;
228 char *q = s;
229
230 if (!p)
231 return 0;
232
233 while (--n)
234 {
235 if (!*p)
236 break;
237
238 *q++ = *p;
239
240 if (*p++ == '\n')
241 break;
242 }
243
244 *q = 0;
245 thawer.line = p;
246
247 return s == q ? 0 : s;
248 }
249
250 keyword
251 object_thawer::get_kv ()
252 {
253 if (!line)
254 return KW_EOF;
255
256 for (;;)
257 {
258 char *p = line;
259
260 if (!*p)
261 return KW_EOF;
262
263 // parse keyword
264 while (*p > ' ')
265 p++;
266
267 int klen = p - line;
268
269 if (*p++ != '\n')
270 {
271 // parse value
272 while (*(unsigned char *)p <= ' ' && *p != '\n') // skip 0x01 .. 0x20
273 ++p;
274
275 last_value = p;
276
277 while (*p != '\n')
278 p++;
279
280 *p++ = 0;
281 }
282 else
283 last_value = 0;
284
285 line [klen] = 0;
286 keyword_idx *kw = kw_lex::match (line, klen);
287
288 //printf ("KV %d<%s,%s>\n", kw ? kw->index : 0, line, last_value);//D
289
290 last_keyword = line;
291 line = p;
292
293 if (kw)
294 return kw->index;
295 else if (!*last_keyword || *last_keyword == '#')
296 ; // empty/comment line
297 else
298 return KW_ERROR;
299 }
300 }
301
302 void
303 object_thawer::skip_kv (keyword kw)
304 {
305 shstr ml;
306
307 switch (kw)
308 {
309 case KW_msg: get_ml (KW_endmsg , ml); break;
310 case KW_lore: get_ml (KW_endlore , ml); break;
311 case KW_maplore: get_ml (KW_endmaplore, ml); break;
312 }
313 }
314
315 void
316 object_thawer::get (shstr &sh) const
317 {
318 if (last_value)
319 sh = last_value;
320 else
321 {
322 sh = "<value missing>";
323 LOG (llevError, "keyword \"%s\" requires value, substituting with <value missing>\n", last_keyword);//TODO: add filename
324 }
325 }
326
327 void
328 object_thawer::get_ml (keyword kend, shstr &sh)
329 {
330 char kw[128];
331
332 int klen = keyword_len [kend];
333
334 kw [0] = '\n';
335 memcpy (kw + 1, keyword_str [kend], klen);
336 kw [klen + 1] = '\n';
337 kw [klen + 2] = 0;
338
339 // first test for completely empty msg... "endXXX\n"
340 if (!strncmp (line, kw + 1, klen + 1))
341 {
342 sh = 0;
343
344 line += klen + 1;
345
346 return;
347 }
348 else
349 {
350 // multi-line strings are delimited by "\nendXXX\n" or "endXXX\n" (NULL)
351
352 char *end = strstr (line, kw);
353
354 if (!end)
355 {
356 sh = 0;
357 return;
358 }
359
360 *end = 0;
361 sh = line;
362
363 line = end + keyword_len [kend] + 1;
364
365 while (*line++ != '\n')
366 ;
367 }
368 }
369
370 sint32
371 object_thawer::get_sint32 () const
372 {
373 char *p = last_value;
374
375 if (!p)
376 return 0;
377
378 sint32 val = 0;
379 bool negate;
380
381 if (*p == '-')
382 {
383 negate = true;
384 ++p;
385 }
386 else
387 negate = false;
388
389 do
390 {
391 val *= 10;
392 val += *p++ - '0';
393 }
394 while (*p);
395
396 return negate ? -val : val;
397 }
398
399 sint64
400 object_thawer::get_sint64 () const
401 {
402 return last_value ? atoll (last_value) : 0;
403 }
404
405 double
406 object_thawer::get_double () const
407 {
408 return last_value ? atof (last_value) : 0;
409 }
410