1 //------------------------------------------------------------------------
2 // SYSTEM : System specific code
3 //------------------------------------------------------------------------
4 //
5 // DEH_EDGE Copyright (C) 2004-2005 The EDGE Team
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License (in COPYING.txt) for more details.
16 //
17 //------------------------------------------------------------------------
18 //
19 // DEH_EDGE is based on:
20 //
21 // + DeHackEd source code, by Greg Lewis.
22 // - DOOM source code (C) 1993-1996 id Software, Inc.
23 // - Linux DOOM Hack Editor, by Sam Lantinga.
24 // - PrBoom's DEH/BEX code, by Ty Halderman, TeamTNT.
25 //
26 //------------------------------------------------------------------------
27
28 #include "i_defs.h"
29
30 #include "dh_plugin.h"
31 #include "system.h"
32
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 namespace Deh_Edge
40 {
41
42 #define FATAL_COREDUMP 0
43
44 #define DEBUG_ENABLED 0
45 #define DEBUG_ENDIAN 0
46 #define DEBUG_PROGRESS 0
47
48 #define DEBUGGING_FILE "deh_debug.log"
49
50
51 int cpu_big_endian = 0;
52 bool disable_progress = false;
53
54 char message_buf[1024];
55
56 char global_error_buf[1024];
57 bool has_error_msg = false;
58
59 #if (DEBUG_ENABLED)
60 FILE *debug_fp = NULL;
61 #endif
62
63
64 typedef struct
65 {
66 public:
67 // current major range
68 int low_perc;
69 int high_perc;
70
71 // current percentage
72 int cur_perc;
73
ResetDeh_Edge::__anon192f930d010874 void Reset(void)
75 {
76 low_perc = high_perc = 0;
77 cur_perc = 0;
78 }
79
MajorDeh_Edge::__anon192f930d010880 void Major(int low, int high)
81 {
82 low_perc = cur_perc = low;
83 high_perc = high;
84 }
85
MinorDeh_Edge::__anon192f930d010886 bool Minor(int count, int limit)
87 {
88 int new_perc = low_perc + (high_perc - low_perc) * count / limit;
89
90 if (new_perc > cur_perc)
91 {
92 cur_perc = new_perc;
93 return true;
94 }
95
96 return false;
97 }
98 }
99 progress_info_t;
100
101 progress_info_t progress;
102
103
104 // forward decls
105 void Debug_Startup(void);
106 void Debug_Shutdown(void);
107 void Endian_Startup(void);
108
109
110 //
111 // System_Startup
112 //
System_Startup(void)113 void System_Startup(void)
114 {
115 has_error_msg = false;
116
117 if (! cur_funcs)
118 {
119 setbuf(stdout, NULL);
120
121 #if defined(LINUX) || defined(UNIX)
122 // no whirling baton if stderr is redirected
123 if (! isatty(2))
124 disable_progress = true;
125 #endif
126 }
127
128 progress.Reset();
129
130 Debug_Startup();
131 Endian_Startup();
132 }
133
134 //
135 // System_Shutdown
136 //
System_Shutdown(void)137 void System_Shutdown(void)
138 {
139 // if (! cur_funcs) ClearProgress();
140
141 Debug_Shutdown();
142 }
143
144
145 /* -------- text output code ----------------------------- */
146
147 //
148 // PrintMsg
149 //
PrintMsg(const char * str,...)150 void PrintMsg(const char *str, ...)
151 {
152 va_list args;
153
154 va_start(args, str);
155 vsprintf(message_buf, str, args);
156 va_end(args);
157
158 if (cur_funcs)
159 cur_funcs->print_msg("%s", message_buf);
160 else
161 {
162 printf("%s", message_buf);
163 fflush(stdout);
164 }
165
166 #if (DEBUG_ENABLED)
167 Debug_PrintMsg("> %s", message_buf);
168 #endif
169 }
170
171 //
172 // PrintWarn
173 //
PrintWarn(const char * str,...)174 void PrintWarn(const char *str, ...)
175 {
176 va_list args;
177
178 va_start(args, str);
179 vsprintf(message_buf, str, args);
180 va_end(args);
181
182 if (! quiet_mode)
183 {
184 if (cur_funcs)
185 cur_funcs->print_msg("- Warning: %s", message_buf);
186 else
187 {
188 printf("- Warning: %s", message_buf);
189 fflush(stdout);
190 }
191 }
192
193 #if (DEBUG_ENABLED)
194 Debug_PrintMsg("> Warning: %s", message_buf);
195 #endif
196 }
197
198 //
199 // FatalError
200 //
FatalError(const char * str,...)201 void FatalError(const char *str, ...)
202 {
203 va_list args;
204
205 va_start(args, str);
206 vsprintf(message_buf, str, args);
207 va_end(args);
208
209 if (cur_funcs)
210 {
211 cur_funcs->fatal_error("Error: %s\n", message_buf);
212 /* NOT REACHED */
213 }
214 else
215 {
216 printf("\nError: %s\n", message_buf);
217 fflush(stdout);
218 }
219
220 System_Shutdown();
221
222 #if (FATAL_COREDUMP && defined(UNIX))
223 raise(SIGSEGV);
224 #endif
225
226 exit(5);
227 }
228
229 //
230 // InternalError
231 //
InternalError(const char * str,...)232 void InternalError(const char *str, ...)
233 {
234 va_list args;
235
236 va_start(args, str);
237 vsprintf(message_buf, str, args);
238 va_end(args);
239
240 if (cur_funcs)
241 {
242 cur_funcs->fatal_error("INTERNAL ERROR: %s\n", message_buf);
243 /* NOT REACHED */
244 }
245 else
246 {
247 printf("\nINTERNAL ERROR: %s\n", message_buf);
248 fflush(stdout);
249 }
250
251 System_Shutdown();
252
253 #if (FATAL_COREDUMP && defined(UNIX))
254 raise(SIGSEGV);
255 #endif
256
257 exit(5);
258 }
259
SetErrorMsg(const char * str,...)260 void SetErrorMsg(const char *str, ...)
261 {
262 va_list args;
263
264 va_start(args, str);
265 vsprintf(global_error_buf, str, args);
266 va_end(args);
267
268 has_error_msg = true;
269 }
270
GetErrorMsg(void)271 const char *GetErrorMsg(void)
272 {
273 if (! has_error_msg)
274 return "";
275
276 has_error_msg = false;
277
278 return global_error_buf;
279 }
280
281
282 /* --------- progress handling -------------------------------- */
283
284 //
285 // ProgressMajor
286 //
287 // Called for major elements, i.e. each patch file to process and
288 // also the final save.
289 //
ProgressMajor(int low_perc,int high_perc)290 void ProgressMajor(int low_perc, int high_perc)
291 {
292 progress.Major(low_perc, high_perc);
293
294 if (cur_funcs)
295 cur_funcs->progress_bar(progress.cur_perc);
296 #if (DEBUG_PROGRESS)
297 else
298 fprintf(stderr, "PROGRESS %d%% (to %d%%)\n", progress.low_perc,
299 progress.high_perc);
300 #endif
301 }
302
303 //
304 // ProgressMinor
305 //
306 // Called for the progress of a single element (patch file loading,
307 // hwa file saving). The count value should range from 0 to limit-1.
308 //
ProgressMinor(int count,int limit)309 void ProgressMinor(int count, int limit)
310 {
311 if (progress.Minor(count, limit))
312 {
313 if (cur_funcs)
314 cur_funcs->progress_bar(progress.cur_perc);
315 #if (DEBUG_PROGRESS)
316 else
317 fprintf(stderr, " Progress Minor %d%%\n", progress.cur_perc);
318 #endif
319 }
320 }
321
322 //
323 // ProgressText
324 //
ProgressText(const char * str)325 void ProgressText(const char *str)
326 {
327 if (cur_funcs)
328 cur_funcs->progress_text(str);
329 #if (DEBUG_PROGRESS)
330 else
331 fprintf(stderr, "------ %s ------\n", str);
332 #endif
333 }
334
335 #if 0
336 //
337 // ClearProgress
338 //
339 void ClearProgress(void)
340 {
341 fprintf(stderr, " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
342
343 progress_shown = -1;
344 }
345
346 //
347 // ShowProgress
348 //
349 void ShowProgress(int count, int limit)
350 {
351 if (disable_progress)
352 return;
353
354 int perc = count * 100 / limit;
355
356 if (perc == progress_shown)
357 return;
358
359 fprintf(stderr, "--%3d%%--\b\b\b\b\b\b\b\b", perc);
360
361 progress_shown = perc;
362 }
363 #endif
364
365
366 /* -------- debugging code ----------------------------- */
367
Debug_Startup(void)368 void Debug_Startup(void)
369 {
370 #if (DEBUG_ENABLED)
371 debug_fp = fopen(DEBUGGING_FILE, "w");
372
373 if (! debug_fp)
374 PrintMsg("Unable to open DEBUG FILE: %s\n", DEBUGGING_FILE);
375
376 Debug_PrintMsg("=== START OF DEBUG FILE ===\n");
377 #endif
378 }
379
Debug_Shutdown(void)380 void Debug_Shutdown(void)
381 {
382 #if (DEBUG_ENABLED)
383 if (debug_fp)
384 {
385 Debug_PrintMsg("=== END OF DEBUG FILE ===\n");
386
387 fclose(debug_fp);
388 debug_fp = NULL;
389 }
390 #endif
391 }
392
393 //
394 // Debug_PrintMsg
395 //
Debug_PrintMsg(const char * str,...)396 void Debug_PrintMsg(const char *str, ...)
397 {
398 #if (DEBUG_ENABLED)
399 if (debug_fp)
400 {
401 va_list args;
402
403 va_start(args, str);
404 vfprintf(debug_fp, str, args);
405 va_end(args);
406
407 fflush(debug_fp);
408 }
409 #else
410 (void) str;
411 #endif
412 }
413
414
415 /* -------- endian code ----------------------------- */
416
417 //
418 // Endian_Startup
419 //
420 // Parts inspired by the Yadex endian.cc code.
421 //
Endian_Startup(void)422 void Endian_Startup(void)
423 {
424 volatile union
425 {
426 unsigned char mem[32];
427 unsigned int val;
428 }
429 u_test;
430
431 /* sanity-check type sizes */
432
433 int size_8 = sizeof(unsigned char);
434 int size_16 = sizeof(unsigned short);
435 int size_32 = sizeof(unsigned int);
436
437 if (size_8 != 1)
438 FatalError("Sanity check failed: sizeof(uint8) = %d\n", size_8);
439
440 if (size_16 != 2)
441 FatalError("Sanity check failed: sizeof(uint16) = %d\n", size_16);
442
443 if (size_32 != 4)
444 FatalError("Sanity check failed: sizeof(uint32) = %d\n", size_32);
445
446 /* check endianness */
447
448 memset((unsigned int *) u_test.mem, 0, sizeof(u_test.mem));
449
450 u_test.mem[0] = 0x70; u_test.mem[1] = 0x71;
451 u_test.mem[2] = 0x72; u_test.mem[3] = 0x73;
452
453 #if (DEBUG_ENDIAN)
454 Debug_PrintMsg("Endianness magic value: 0x%08x\n", u_test.val);
455 #endif
456
457 if (u_test.val == 0x70717273)
458 cpu_big_endian = 1;
459 else if (u_test.val == 0x73727170)
460 cpu_big_endian = 0;
461 else
462 FatalError("Sanity check failed: weird endianness (0x%08x)\n", u_test.val);
463
464 #if (DEBUG_ENDIAN)
465 Debug_PrintMsg("Endianness = %s\n", cpu_big_endian ? "BIG" : "LITTLE");
466
467 Debug_PrintMsg("Endianness check: 0x1234 --> 0x%04x\n",
468 (int) Endian_U16(0x1234));
469
470 Debug_PrintMsg("Endianness check: 0x11223344 --> 0x%08x\n",
471 Endian_U32(0x11223344));
472 #endif
473 }
474
475 //
476 // Endian_U16
477 //
Endian_U16(unsigned short x)478 unsigned short Endian_U16(unsigned short x)
479 {
480 if (cpu_big_endian)
481 return (x >> 8) | (x << 8);
482 else
483 return x;
484 }
485
486 //
487 // Endian_U32
488 //
Endian_U32(unsigned int x)489 unsigned int Endian_U32(unsigned int x)
490 {
491 if (cpu_big_endian)
492 return (x >> 24) | ((x >> 8) & 0xff00) |
493 ((x << 8) & 0xff0000) | (x << 24);
494 else
495 return x;
496 }
497
498 } // Deh_Edge
499