ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/freezethaw.C
Revision: 1.22
Committed: Sun Jul 1 05:00:20 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.21: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# Content
1 /*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 *
4 * Copyright (©) 2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5 *
6 * Crossfire TRT is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * The authors can be reached via e-mail to <crossfire@schmorp.de>
20 */
21
22 #include "global.h" // bug in cfperl.h, doesn't include interface_class stuff
23 #include "logger.h"
24 #include "cfperl.h"
25 #include "kw_hash.h"
26
27 object_freezer::object_freezer ()
28 : dynbuf_text (128 * 1024, 64 * 1024)
29 {
30 av = newAV ();
31 }
32
33 object_freezer::~object_freezer ()
34 {
35 SvREFCNT_dec (av);
36 }
37
38 void
39 object_freezer::put (attachable *ext)
40 {
41 ext->optimise ();
42
43 if (ext->self)
44 {
45 int idx = AvFILLp ((AV *)av) + 1;
46 av_store (av, idx, newRV_inc ((SV *)ext->self));
47
48 add ((void *)"oid ", 4);
49 add ((sint32)idx);
50 add ('\n');
51 }
52 }
53
54 bool
55 object_freezer::save (const char *path)
56 {
57 CALL_BEGIN (3);
58 CALL_ARG_SV (newSVpv (path, 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 return 1;
65 }
66
67 char *
68 object_freezer::as_string ()
69 {
70 CALL_BEGIN (2);
71 CALL_ARG_SV (newRV_noinc (newSVpvn ((char *)linearise (), size ())));
72 CALL_ARG_SV (newRV_inc ((SV *)av));
73 CALL_CALL ("cf::object_freezer_as_string", G_SCALAR);
74
75 char *res = count > 0
76 ? strdup (SvPVX (POPs))
77 : strdup ("[fatal error]");
78
79 CALL_END;
80
81 return res;
82 }
83
84 #if 0
85 void
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 // XXX: function not returning an int
101 void
102 fputs (const char *s, object_freezer &freezer)
103 {
104 freezer.add (s);
105 }
106 #endif
107
108 static const char thawer_eof[] = "\n\n\n\0\0\0";
109
110 object_thawer::object_thawer (const char *path)
111 : name (strdup (path))
112 {
113 static const char eof[] = "\n\n\n\0\0\0";
114
115 av = 0;
116 text = 0;
117 line = 0;
118 linenum = 0;
119
120 kw = KW_ERROR;
121 kw_str = 0;
122 value = 0;
123
124 if (path)
125 {
126 CALL_BEGIN (1);
127 CALL_ARG_SV (newSVpv (path, 0));
128 CALL_CALL ("cf::object_thawer_load", G_ARRAY);
129
130 if (count == 2)
131 {
132 // second value - perl objects
133 {
134 SV *sv = POPs;
135 if (SvROK (sv))
136 av = (AV *)SvREFCNT_inc (SvRV (sv));
137 }
138
139 // first value - text part, pad with 3 zeroes
140 {
141 SV *sv = POPs;
142 STRLEN len;
143 char *sv_ = SvPVbyte (sv, len);
144 text = newSV (len + sizeof (eof));
145 SvCUR_set (text, len);
146 memcpy (SvPVX (text), sv_, len);
147 memcpy (SvEND (text), eof, sizeof (eof)); // just to be sure
148
149 line = SvPVX (text);
150 }
151 }
152
153 CALL_END;
154 }
155 }
156
157 object_thawer::object_thawer (const char *data, AV *perlav)
158 : name (strdup ("(memory stream"))
159 {
160 av = perlav;
161 text = newSVpv (data, 0);
162 sv_catpv (text, thawer_eof);
163 line = SvPVbyte_nolen (text);
164 }
165
166 void
167 object_thawer::get (attachable *obj, int oid)
168 {
169 if (!av || oid < 0) // this is actually an error of sorts
170 return;
171
172 SV **svp = av_fetch ((AV *)av, oid, 0);
173
174 if (!svp || !SvROK (*svp))
175 {
176 LOG (llevError, "trying to thaw duplicate or never-issued oid %d, ignoring.\n", oid);
177 return;
178 }
179
180 if (!SvROK (*svp))
181 {
182 LOG (llevError, "deserialised perl object is not an RV\n");
183 return;
184 }
185
186 HV *hv = (HV *)SvRV (*svp);
187
188 if (SvTYPE (hv) != SVt_PVHV)
189 {
190 LOG (llevError, "deserialised perl object is not a PVHV\n");
191 return;
192 }
193
194 if (obj->self)
195 {
196 // the hard way(?)
197
198 CALL_BEGIN (2);
199 CALL_ARG_SV (newRV_inc ((SV *)obj->self));
200 CALL_ARG_SV (newRV_inc ((SV *)hv));
201 PUTBACK;
202 call_method ("thawer_merge", G_DISCARD | G_EVAL);
203 SPAGAIN;
204 CALL_END;
205 }
206 else
207 {
208 // the easy way(?)
209
210 obj->self = hv;
211 SvRV_set (*svp, &PL_sv_undef);
212
213 sv_magicext ((SV *)obj->self, 0, PERL_MAGIC_ext, &attachable::vtbl, (char *)obj, 0);
214 }
215
216 obj->reattach ();
217 }
218
219 object_thawer::~object_thawer ()
220 {
221 if (text) SvREFCNT_dec (text);
222 if (av) SvREFCNT_dec (av);
223
224 free ((void *)name);
225 }
226
227 //TODO: remove
228 char *
229 fgets (char *s, int n, object_thawer &thawer)
230 {
231 char *p = thawer.line;
232 char *q = s;
233
234 if (!p)
235 return 0;
236
237 while (--n)
238 {
239 if (!*p)
240 break;
241
242 *q++ = *p;
243
244 if (*p++ == '\n')
245 {
246 ++thawer.linenum;
247 break;
248 }
249 }
250
251 *q = 0;
252 thawer.line = p;
253
254 return s == q ? 0 : s;
255 }
256
257 bool
258 object_thawer::parse_error (const char *type, const char *name, bool skip)
259 {
260 if (!type) type = "file section";
261 if (!name) name = "generic";
262
263 switch (kw)
264 {
265 case KW_EOF:
266 LOG (llevError, "%s:%d end of file while reading %s '%s', aborting load.\n",
267 this->name, linenum, type, name);
268 return false;
269
270 case KW_ERROR:
271 LOG (llevError, "%s:%d error while reading %s '%s', at '%s', aborting load.\n",
272 this->name, linenum,
273 type, name,
274 kw_str ? kw_str : "<file load>");
275 return false;
276
277 default:
278 LOG (llevError, "%s:%d unexpected line (%s %s) while reading %s '%s', %s.\n",
279 this->name, linenum,
280 kw_str ? kw_str : "<null>",
281 value ? value : "<null>",
282 type, name,
283 skip ? "skipping line" : "aborting load");
284 return skip;
285 }
286 }
287
288 void
289 object_thawer::next ()
290 {
291 if (!line)
292 {
293 kw = KW_ERROR;
294 return;
295 }
296
297 for (;;)
298 {
299 char *p = line;
300
301 if (*p <= ' ')
302 {
303 // skip whitespace (only some files need this)
304 while (*p == ' ' || *p == '\t')
305 p++;
306
307 line = p;
308 }
309
310 if (!*p)
311 {
312 kw = KW_EOF;
313 break;
314 }
315
316 // parse keyword
317 while (*p > ' ')
318 p++;
319
320 int klen = p - line;
321
322 value_nn = "";
323 value = 0;
324
325 if (*p++ != '\n')
326 {
327 // parse value
328 while (*(unsigned char *)p <= ' ' && *p != '\n')
329 ++p;
330
331 value_nn = value = p;
332
333 while (*p != '\n')
334 p++;
335
336 *p++ = 0;
337 }
338
339 ++linenum;
340 line [klen] = 0;
341 keyword_idx *kw_idx = kw_lex::match (line, klen);
342
343 kw_str = line;
344 line = p;
345
346 if (kw_idx)
347 {
348 kw = kw_idx->index;
349 break;
350 }
351 else if (!*kw_str || *kw_str == '#')
352 ; // empty/comment line
353 else
354 {
355 kw = KW_ERROR;
356 break;
357 }
358 }
359 }
360
361 void
362 object_thawer::skip ()
363 {
364 shstr ml;
365
366 switch (kw)
367 {
368 case KW_msg: get_ml (KW_endmsg , ml); break;
369 case KW_lore: get_ml (KW_endlore , ml); break;
370 case KW_maplore: get_ml (KW_endmaplore, ml); break;
371 default: break;
372 }
373
374 next ();
375 }
376
377 void
378 object_thawer::get_ml (keyword kend, shstr &sh)
379 {
380 char kw[128];
381
382 int klen = keyword_len [kend];
383
384 kw [0] = '\n';
385 memcpy (kw + 1, keyword_str [kend], klen);
386 kw [klen + 1] = '\n';
387 kw [klen + 2] = 0;
388
389 ++linenum;
390
391 // first test for completely empty msg... "endXXX\n"
392 if (!strncmp (line, kw + 1, klen + 1))
393 {
394 sh = 0;
395
396 line += klen + 1;
397
398 return;
399 }
400 else
401 {
402 // multi-line strings are delimited by "\nendXXX\n" or "endXXX\n" (NULL)
403
404 char *end = strstr (line, kw);
405
406 if (!end)
407 {
408 sh = 0;
409 return;
410 }
411
412 *end = 0;
413 sh = line;
414
415 // count line numbers
416 while (line < end)
417 linenum += *line++ == '\n';
418
419 line += keyword_len [kend];
420
421 while (*line++ != '\n')
422 ;
423
424 ++linenum;
425 }
426 }
427
428 sint32
429 object_thawer::get_sint32 () const
430 {
431 char *p = value_nn;
432
433 sint32 val = 0;
434 bool negate;
435
436 if (*p == '-')
437 {
438 negate = true;
439 ++p;
440 }
441 else
442 negate = false;
443
444 do
445 {
446 val *= 10;
447 val += *p++ - '0';
448 }
449 while (*p);
450
451 return negate ? -val : val;
452 }
453