ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.1
Committed: Sat Dec 30 10:16:11 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Log Message:
preliminary snapshot check-in, DO NOT USE IN PRODUCTION SYSTEMS
See the Changes file for details

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 "logger.h"
26 #include "cfperl.h"
27 #include "kw_hash.h"
28
29 object_freezer::object_freezer ()
30 : dynbuf (128 * 1024, 64 * 1024)
31 {
32 av = newAV ();
33 }
34
35 object_freezer::~object_freezer ()
36 {
37 SvREFCNT_dec (av);
38 }
39
40 void object_freezer::put (attachable *ext)
41 {
42 ext->optimise ();
43
44 if (ext->self)
45 {
46 int idx = AvFILLp ((AV *)av) + 1;
47 av_store (av, idx, newRV_inc ((SV *)ext->self));
48
49 add ((void *)"oid ", 4);
50 add ((sint32)idx);
51 add ('\n');
52 }
53 }
54
55 bool object_freezer::save (const char *filename)
56 {
57 CALL_BEGIN (3);
58 CALL_ARG_SV (newSVpv (filename, 0));
59 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
60 CALL_ARG_SV (newRV_inc ((SV *)av));
61 CALL_CALL ("cf::object_freezer_save", G_VOID | G_DISCARD);
62 CALL_END;
63 }
64
65 char *object_freezer::as_string ()
66 {
67 CALL_BEGIN (2);
68 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
69 CALL_ARG_SV (newRV_inc ((SV *)av));
70 CALL_CALL ("cf::object_freezer_as_string", G_SCALAR);
71
72 char *res = count > 0
73 ? strdup (SvPVbyte_nolen (POPs))
74 : strdup ("[fatal error]");
75
76 CALL_END;
77
78 return res;
79 }
80
81 int fprintf (object_freezer &freezer, const char *format, ...)
82 {
83 va_list ap;
84
85 va_start (ap, format);
86
87 int len = vsnprintf ((char *)freezer.force (1024), 1024, format, ap);
88
89 if (len >= 0)
90 freezer.alloc (len);
91
92 va_end (ap);
93 }
94
95 int fputs (const char *s, object_freezer &freezer)
96 {
97 freezer.add (s);
98 }
99
100 static const char thawer_eof[] = "\n\n\n\0\0\0";
101
102 object_thawer::object_thawer (const char *filename)
103 {
104 static const char eof[] = "\n\n\n\0\0\0";
105
106 av = 0;
107 text = 0;
108 line = 0;
109
110 if (filename)
111 {
112 CALL_BEGIN (1);
113 CALL_ARG_SV (newSVpv (filename, 0));
114 CALL_CALL ("cf::object_thawer_load", G_ARRAY);
115
116 if (count == 2)
117 {
118 // second value - perl objects
119 {
120 SV *sv = POPs;
121 if (SvROK (sv))
122 av = (AV *)SvREFCNT_inc (SvRV (sv));
123 }
124
125 // first value - text part, pad with 3 zeroes
126 {
127 SV *sv = POPs;
128 STRLEN len;
129 char *sv_ = SvPVbyte (sv, len);
130 text = newSV (len + sizeof (eof));
131 SvCUR_set (text, len);
132 memcpy (SvPVX (text), sv_, len);
133 memcpy (SvEND (text), eof, sizeof (eof)); // just to be sure
134
135 line = SvPVX (text);
136 }
137 }
138
139 CALL_END;
140 }
141 }
142
143 object_thawer::object_thawer (const char *data, AV *perlav)
144 {
145 av = perlav;
146 text = newSVpv (data, 0);
147 sv_catpv (text, thawer_eof);
148 line = SvPVbyte_nolen (text);
149 }
150
151 void object_thawer::get (attachable *obj, int oid)
152 {
153 if (!av || oid < 0) // this is actually an error of sorts
154 return;
155
156 SV **svp = av_fetch ((AV *)av, oid, 0);
157
158 if (!svp || !SvROK (*svp))
159 {
160 printf ("trying to thaw duplicate or never-issued oid %d, ignoring.\n", oid);
161 return;
162 }
163
164 if (!SvROK (*svp))
165 {
166 LOG (llevError, "deserialised perl object is not an RV");
167 return;
168 }
169
170 HV *hv = (HV *)SvRV (*svp);
171
172 if (SvTYPE (hv) != SVt_PVHV)
173 {
174 LOG (llevError, "deserialised perl object is not a PVHV");
175 return;
176 }
177
178 if (obj->self)
179 {
180 // the hard way(?)
181
182 // the dirty blues: "just" swap the XPVHV's
183 swap (SvANY (obj->self), SvANY (hv));
184
185 // do not swap magic, though
186 swap (SvMAGIC (obj->self), SvMAGIC (hv));
187 }
188 else
189 {
190 // the easy way(?)
191
192 obj->self = hv;
193 SvRV_set (*svp, &PL_sv_undef);
194
195 sv_magicext ((SV *)obj->self, 0, PERL_MAGIC_ext, &attachable::vtbl, (char *)obj, 0);
196
197 // borrow a refcount for the perl object
198 obj->flags |= attachable::F_BORROWED;
199 obj->refcnt_dec ();
200 }
201
202 obj->reattach ();
203 }
204
205 object_thawer::~object_thawer ()
206 {
207 if (text) SvREFCNT_dec (text);
208 if (av) SvREFCNT_dec (av);
209 }
210
211 char *fgets (char *s, int n, object_thawer &thawer)
212 {
213 char *p = thawer.line;
214 char *q = s;
215
216 if (!p)
217 return 0;
218
219 while (--n)
220 {
221 if (!*p)
222 break;
223
224 *q++ = *p;
225
226 if (*p++ == '\n')
227 break;
228 }
229
230 *q = 0;
231 thawer.line = p;
232
233 return s == q ? 0 : s;
234 }
235
236 keyword object_thawer::get_kv ()
237 {
238 if (!line)
239 return KW_EOF;
240
241 for (;;)
242 {
243 char *p = line;
244
245 if (!*p)
246 return KW_EOF;
247
248 // parse keyword
249 while (*p > ' ')
250 p++;
251
252 int klen = p - line;
253
254 if (*p++ != '\n')
255 {
256 // parse value
257 while (*(unsigned char *)p <= ' ' && *p != '\n') // skip 0x01 .. 0x20
258 ++p;
259
260 last_value = p;
261
262 while (*p != '\n')
263 p++;
264
265 *p++ = 0;
266 }
267 else
268 last_value = 0;
269
270 line [klen] = 0;
271 keyword_idx *kw = kw_lex::match (line, klen);
272
273 //printf ("KV %d<%s,%s>\n", kw ? kw->index : 0, line, last_value);//D
274
275 last_keyword = line;
276 line = p;
277
278 if (kw)
279 return kw->index;
280 else if (!*last_keyword || *last_keyword == '#')
281 ; // empty/comment line
282 else
283 return KW_ERROR;
284 }
285 }
286
287 void object_thawer::skip_kv (keyword kw)
288 {
289 shstr ml;
290
291 switch (kw)
292 {
293 case KW_msg: get_ml (KW_endmsg , ml); break;
294 case KW_lore: get_ml (KW_endlore , ml); break;
295 case KW_maplore: get_ml (KW_endmaplore, ml); break;
296 }
297 }
298
299 void object_thawer::get (shstr &sh) const
300 {
301 if (last_value)
302 sh = last_value;
303 else
304 {
305 sh = "<value missing>";
306 LOG (llevError, "keyword requires value: <%.320s>\n", line);//TODO: add filename
307 }
308 }
309
310 void object_thawer::get_ml (keyword kend, shstr &sh)
311 {
312 char kw[128];
313
314 int klen = keyword_len [kend];
315
316 kw [0] = '\n';
317 memcpy (kw + 1, keyword_str [kend], klen);
318 kw [klen + 1] = '\n';
319 kw [klen + 2] = 0;
320
321 // first test for completely empty msg... "endXXX\n"
322 if (!strncmp (line, kw + 1, klen + 1))
323 {
324 sh = 0;
325
326 line += klen + 1;
327
328 return;
329 }
330 else
331 {
332 // multi-line strings are delimited by "\nendXXX\n" or "endXXX\n" (NULL)
333
334 char *end = strstr (line, kw);
335
336 if (!end)
337 {
338 sh = 0;
339 return;
340 }
341
342 *end = 0;
343 sh = line;
344
345 line = end + keyword_len [kend] + 1;
346
347 while (*line++ != '\n')
348 ;
349 }
350 }
351
352 sint32 object_thawer::get_sint32 () const
353 {
354 char *p = last_value;
355
356 if (!p)
357 return 0;
358
359 sint32 val = 0;
360 bool negate;
361
362 if (*p == '-')
363 {
364 negate = true;
365 ++p;
366 }
367 else
368 negate = false;
369
370 do
371 {
372 val *= 10;
373 val += *p++ - '0';
374 }
375 while (*p);
376
377 return negate ? -val : val;
378 }
379
380 sint64 object_thawer::get_sint64 () const
381 {
382 return last_value ? atoll (last_value) : 0;
383 }
384
385 double object_thawer::get_double () const
386 {
387 return last_value ? atof (last_value) : 0;
388 }
389