ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/compat.C
Revision: 1.4
Committed: Sat Nov 7 18:30:05 2009 UTC (14 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_92, rel-2_93
Changes since 1.3: +5 -5 lines
Log Message:
lots of cleanups

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 * The authors can be reached via e-mail to <support@deliantra.net>
23 */
24
25 /*
26 * compatibility functions for older (GPL) source code parts
27 */
28
29 #include <cstring>
30 #include <assert.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <limits.h>
34
35 #include <global.h>
36 #include "define.h"
37 #include "path.h"
38
39
40 /* buf_overflow() - we don't want to exceed the buffer size of
41 * buf1 by adding on buf2! Returns true if overflow will occur.
42 */
43 int
44 buf_overflow (const char *buf1, const char *buf2, int bufsize)
45 {
46 int len1 = 0, len2 = 0;
47
48 if (buf1)
49 len1 = strlen (buf1);
50
51 if (buf2)
52 len2 = strlen (buf2);
53
54 if ((len1 + len2) >= bufsize)
55 return 1;
56
57 return 0;
58 }
59
60 /////////////////////////////////////////////////////////////////////////////
61
62 static const char *const fatalmsgs[80] = {
63 "Failed to allocate memory",
64 "Failed repeatedly to load maps",
65 "Hashtable for archetypes is too small",
66 "Too many errors"
67 };
68
69 /*
70 * fatal() is meant to be called whenever a fatal signal is intercepted.
71 * It will call the emergency_save and the clean_tmp_files functions.
72 */
73 void
74 fatal (int err)
75 {
76 LOG (llevError, "Fatal: %s\n", fatalmsgs [err]);
77 cleanup (fatalmsgs[err], 1);
78 }
79
80 /////////////////////////////////////////////////////////////////////////////
81
82 /*
83 * The random functions here take luck into account when rolling random
84 * dice or numbers. This function has less of an impact the larger the
85 * difference becomes in the random numbers. IE, the effect is lessened
86 * on a 1-1000 roll, vs a 1-6 roll. This can be used by crafty programmers,
87 * to specifically disable luck in certain rolls, simply by making the
88 * numbers larger (ie, 1d1000 > 500 vs 1d6 > 3)
89 */
90
91 /*
92 * Roll a random number between min and max. Uses op to determine luck,
93 * and if goodbad is non-zero, luck increases the roll, if zero, it decreases.
94 * Generally, op should be the player/caster/hitter requesting the roll,
95 * not the recipient (ie, the poor slob getting hit). [garbled 20010916]
96 */
97 int
98 random_roll (int r_min, int r_max, const object *op, int goodbad)
99 {
100 r_max = max (r_min, r_max);
101
102 int base = r_max - r_min > 1 ? 20 : 50; /* d2 and d3 are corner cases */
103
104 if (op->type == PLAYER)
105 {
106 int luck = op->stats.luck;
107
108 if (rndm (base) < min (10, abs (luck)))
109 {
110 //TODO: take luck into account
111 }
112 }
113
114 return rndm (r_min, r_max);
115 }
116
117 /*
118 * This is a 64 bit version of random_roll above. This is needed
119 * for exp loss calculations for players changing religions.
120 */
121 sint64
122 random_roll64 (sint64 r_min, sint64 r_max, const object *op, int goodbad)
123 {
124 sint64 omin = r_min;
125 sint64 range = max (0, r_max - r_min + 1);
126 int base = range > 2 ? 20 : 50; /* d2 and d3 are corner cases */
127
128 /*
129 * Make a call to get two 32 bit unsigned random numbers, and just to
130 * a little bitshifting.
131 */
132 sint64 ran = (sint64) rndm.next () ^ ((sint64) rndm.next () << 31);
133
134 if (op->type != PLAYER)
135 return ((ran % range) + r_min);
136
137 int luck = op->stats.luck;
138
139 if (rndm (base) < min (10, abs (luck)))
140 {
141 /* we have a winner */
142 ((luck > 0) ? (luck = 1) : (luck = -1));
143 range -= luck;
144 if (range < 1)
145 return (omin); /*check again */
146
147 ((goodbad) ? (r_min += luck) : (range));
148
149 return (max (omin, min (r_max, (ran % range) + r_min)));
150 }
151
152 return ran % range + r_min;
153 }
154
155 /*
156 * Roll a number of dice (2d3, 4d6). Uses op to determine luck,
157 * If goodbad is non-zero, luck increases the roll, if zero, it decreases.
158 * Generally, op should be the player/caster/hitter requesting the roll,
159 * not the recipient (ie, the poor slob getting hit).
160 * The args are num D size (ie 4d6) [garbled 20010916]
161 */
162 int
163 die_roll (int num, int size, const object *op, int goodbad)
164 {
165 int min_roll, luck, total, i, gotlucky;
166
167 int diff = size;
168 min_roll = 1;
169 luck = total = gotlucky = 0;
170 int base = diff > 2 ? 20 : 50; /* d2 and d3 are corner cases */
171
172 if (size < 2 || diff < 1)
173 {
174 LOG (llevError, "Calling die_roll with num=%d size=%d\n", num, size);
175 return num; /* avoids a float exception */
176 }
177
178 if (op->type == PLAYER)
179 luck = op->stats.luck;
180
181 for (i = 0; i < num; i++)
182 {
183 if (rndm (base) < min (10, abs (luck)) && !gotlucky)
184 {
185 /* we have a winner */
186 gotlucky++;
187 ((luck > 0) ? (luck = 1) : (luck = -1));
188 diff -= luck;
189 if (diff < 1)
190 return (num); /*check again */
191 ((goodbad) ? (min_roll += luck) : (diff));
192 total += max (1, min (size, rndm (diff) + min_roll));
193 }
194 else
195 total += rndm (size) + 1;
196 }
197
198 return total;
199 }
200
201 /////////////////////////////////////////////////////////////////////////////
202
203 #ifndef PATH_MAX
204 # define PATH_MAX 8192
205 #endif
206
207 char *
208 path_combine (const char *src, const char *dst)
209 {
210 char *p;
211 static char path[PATH_MAX];
212
213 if (*dst == '/')
214 {
215 /* absolute destination path => ignore source path */
216 strcpy (path, dst);
217 }
218 else
219 {
220 /* relative destination path => add after last '/' of source */
221 strcpy (path, src);
222 p = strrchr (path, '/');
223 if (p)
224 p++;
225 else
226 {
227 p = path;
228 if (*src == '/')
229 *p++ = '/';
230 }
231
232 strcpy (p, dst);
233 }
234
235 return path;
236 }
237
238 static void
239 path_normalize (char *path)
240 {
241 char *p; /* points to the beginning of the path not yet processed; this is
242 either a path component or a path separator character */
243 char *q; /* points to the end of the path component p points to */
244 char *w; /* points to the end of the already normalized path; w <= p is
245 maintained */
246 size_t len; /* length of current component (which p points to) */
247
248 p = path;
249 w = p;
250 while (*p != '\0')
251 {
252 if (*p == '/')
253 {
254 if ((w == path && *path == '/') || (w > path && w[-1] != '/'))
255 *w++ = '/';
256
257 p++;
258 continue;
259 }
260
261 q = strchr (p, '/');
262 if (q == NULL)
263 q = p + strlen (p);
264 len = q - p;
265 assert (len > 0);
266
267 if (len == 1 && *p == '.')
268 {
269 /* remove current component */
270 }
271 else if (len == 2 && memcmp (p, "..", 2) == 0)
272 {
273 if (w == path || (w == path + 3 && memcmp (path, "../", 3) == 0))
274 {
275 /* keep ".." at beginning of relative path ("../x" => "../x") */
276 memmove (w, p, len);
277 w += len;
278 }
279 else if (w == path + 1 && *path == '/')
280 {
281 /* remove ".." at beginning of absolute path ("/../x" => "/x") */
282 }
283 else
284 {
285 /* remove both current component ".." and preceding one */
286 if (w > path && w[-1] == '/')
287 w--;
288 while (w > path && w[-1] != '/')
289 w--;
290 }
291 }
292 else
293 {
294 /* normal component ==> add it */
295 memmove (w, p, len);
296 w += len;
297 }
298
299 p = q;
300 }
301
302 /* remove trailing slashes, but keep the one at the start of the path */
303 while (w > path + 1 && w[-1] == '/')
304 w--;
305
306 *w = '\0';
307 }
308
309 char *
310 path_combine_and_normalize (const char *src, const char *dst)
311 {
312 char *path;
313
314 path = path_combine (src, dst);
315 path_normalize (path);
316 return (path);
317 }
318
319 /**
320 * open_and_uncompress() first searches for the original filename. If it exist,
321 * then it opens it and returns the file-pointer.
322 */
323 FILE *
324 open_and_uncompress (const char *name, int flag, int *compressed)
325 {
326 *compressed = 0;
327 return fopen (name, "r");
328 }
329
330 /*
331 * See open_and_uncompress().
332 */
333
334 void
335 close_and_delete (FILE * fp, int compressed)
336 {
337 fclose (fp);
338 }
339
340 /*
341 * Strip out the media tags from a String.
342 * Warning the input string will contain the result string
343 */
344 void
345 strip_media_tag (char *message)
346 {
347 int in_tag = 0;
348 char *dest;
349 char *src;
350
351 src = dest = message;
352 while (*src != '\0')
353 {
354 if (*src == '[')
355 {
356 in_tag = 1;
357 }
358 else if (in_tag && (*src == ']'))
359 in_tag = 0;
360 else if (!in_tag)
361 {
362 *dest = *src;
363 dest++;
364 }
365 src++;
366 }
367 *dest = '\0';
368 }
369
370 #define EOL_SIZE (sizeof("\n")-1)
371 void
372 strip_endline (char *buf)
373 {
374 if (strlen (buf) < sizeof ("\n"))
375 {
376 return;
377 }
378 if (!strcmp (buf + strlen (buf) - EOL_SIZE, "\n"))
379 buf[strlen (buf) - EOL_SIZE] = '\0';
380 }
381
382 /**
383 * Replace in string src all occurrences of key by replacement. The resulting
384 * string is put into result; at most resultsize characters (including the
385 * terminating null character) will be written to result.
386 */
387 void
388 replace (const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
389 {
390 size_t resultlen;
391 size_t keylen;
392
393 /* special case to prevent infinite loop if key==replacement=="" */
394 if (strcmp (key, replacement) == 0)
395 {
396 snprintf (result, resultsize, "%s", src);
397 return;
398 }
399
400 keylen = strlen (key);
401
402 resultlen = 0;
403 while (*src != '\0' && resultlen + 1 < resultsize)
404 {
405 if (strncmp (src, key, keylen) == 0)
406 {
407 snprintf (result + resultlen, resultsize - resultlen, "%s", replacement);
408 resultlen += strlen (result + resultlen);
409 src += keylen;
410 }
411 else
412 {
413 result[resultlen++] = *src++;
414 }
415 }
416 result[resultlen] = '\0';
417 }
418