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