]> icculus.org git repositories - taylor/freespace2.git/blob - src/osapi/outwnd.cpp
get rid of NOX() here
[taylor/freespace2.git] / src / osapi / outwnd.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on the 
6  * source.
7  *
8 */
9
10 /*
11  * $Logfile: /Freespace2/code/OsApi/OutWnd.cpp $
12  * $Revision$
13  * $Date$
14  * $Author$
15  *
16  * Routines for debugging output
17  *
18  * $Log$
19  * Revision 1.1  2004/12/15 04:10:45  taylor
20  * outwnd_unix.cpp from fs2_open for logging to file in debug mode
21  * fixes for default function values
22  * always use vm_* functions for sanity sake
23  * make cfilearchiver 64-bit compatible
24  * fix crash on exit from double free()
25  * fix crash on startup from extra long GL extension string in debug
26  *
27  * Revision 2.4  2004/07/26 17:50:02  Goober5000
28  * last bit of Unix fixorage
29  * --Goober5000
30  *
31  * Revision 2.3  2003/03/18 10:07:05  unknownplayer
32  * The big DX/main line merge. This has been uploaded to the main CVS since I can't manage to get it to upload to the DX branch. Apologies to all who may be affected adversely, but I'll work to debug it as fast as I can.
33  *
34  * Revision 2.2.2.1  2002/11/04 21:25:00  randomtiger
35  *
36  * When running in D3D all ani's are memory mapped for speed, this takes up more memory but stops gametime locking of textures which D3D8 hates.
37  * Added new command line tag Cmdline_d3dlowmem for people who dont want to make use of this because they have no memory.
38  * Cleaned up some more texture stuff enabled console debug for D3D.
39  *
40  * Revision 2.2  2002/08/01 01:41:09  penguin
41  * The big include file move
42  *
43  * Revision 2.1  2002/07/29 20:12:02  penguin
44  * removed bogus #include windows.h
45  *
46  * Revision 2.0  2002/06/03 04:10:40  penguin
47  * Warpcore CVS sync
48  *
49  * Revision 1.3  2002/05/21 15:46:27  mharris
50  * Turned on debug logging to file
51  *
52  * Revision 1.2  2002/05/17 23:41:41  mharris
53  * We can print even if not inited... also flush after print
54  *
55  * Revision 1.1  2002/05/16 00:47:21  mharris
56  * New version of OsApi files for Unix variants.
57  *
58  * Revision 1.2  2002/05/09 13:52:26  mharris
59  * Removed dead test code
60  *
61  * Revision 1.1  2002/05/02 18:03:12  mharris
62  * Initial checkin - converted filenames and includes to lower case
63  *
64  * 
65  * 6     6/03/99 6:37p Dave
66  * More TNT fun. Made perspective bitmaps more flexible.
67  * 
68  * 5     6/02/99 6:18p Dave
69  * Fixed TNT lockup problems! Wheeeee!
70  * 
71  * 4     12/14/98 12:13p Dave
72  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
73  * Need to test now.
74  * 
75  * 3     10/08/98 2:38p Dave
76  * Cleanup up OsAPI code significantly. Removed old functions, centralized
77  * registry functions.
78  * 
79  * 2     10/07/98 10:53a Dave
80  * Initial checkin.
81  * 
82  * 1     10/07/98 10:50a Dave
83  * 
84  * 49    5/15/98 3:36p John
85  * Fixed bug with new graphics window code and standalone server.  Made
86  * hwndApp not be a global anymore.
87  * 
88  * 48    5/14/98 5:42p John
89  * Revamped the whole window position/mouse code for the graphics windows.
90  * 
91  * 47    5/14/98 11:24a Allender
92  * throw mprints to outtext regardless of gr mode
93  * 
94  * 46    4/30/98 4:53p John
95  * Restructured and cleaned up cfile code.  Added capability to read off
96  * of CD-ROM drive and out of multiple pack files.
97  * 
98  * 45    4/16/98 6:31p Dave
99  * Doubled MAX_FILTERS to 48
100  * 
101  * 44    3/31/98 5:18p John
102  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
103  * bunch of debug stuff out of player file.  Made model code be able to
104  * unload models and malloc out only however many models are needed.
105  *  
106  * 
107  * 43    3/11/98 12:06p John
108  * Made it so output window never gets focus upon startup
109  * 
110  * 42    2/16/98 9:47a John
111  * Made so only error, general, and warning are shown if no
112  * debug_filter.cfg and  .cfg file isn't saved if so.
113  * 
114  * 41    2/05/98 9:21p John
115  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
116  * game.
117  * 
118  * 40    1/15/98 9:14p John
119  * Made it so general, error and warning can't be turned off.
120  * 
121  * 39    9/13/97 10:44a Lawrance
122  * allow logging of nprintf output to file
123  * 
124  * 38    8/23/97 11:32a Dave
125  * Made debug window size correctly in standalone mode.
126  * 
127  * 37    8/22/97 3:42p Hoffoss
128  * Lowered the filter limit to 24, and added support for filter recycling,
129  * instead of the rather nasty SDL_assert if we should happen to exceed this
130  * limit.
131  * 
132  * 36    8/05/97 4:29p Dave
133  * Futzed with window sizes/placements for standalone mode.
134  * 
135  * 35    8/04/97 3:15p Dave
136  * Added an include for systemvars.h
137  * 
138  * 34    5/20/97 1:13p Allender
139  * fixes to make outwnd work better under Win95
140  * 
141  * 33    5/14/97 11:08a John
142  * fixed bug under 95 that occasionally hung program.
143  * 
144  * 32    5/07/97 3:01p Lawrance
145  * check for NT in mono_init
146  * 
147  * 31    5/07/97 3:06p John
148  * disabled new mono direct stuff under NT.
149  * 
150  * 30    5/07/97 2:59p John
151  * Made so mono driver works under '95.
152  * 
153  * 29    4/22/97 10:56a John
154  * fixed some resource leaks.
155  *
156  * $NoKeywords: $
157  */
158
159 #ifndef NDEBUG
160
161 #include <stdio.h>
162 #include <stdarg.h>
163 #include <string.h>
164
165 #include "pstypes.h"
166 #include "outwnd.h"
167 #include "osapi.h"
168 #include "osregistry.h"
169 #include "cfile.h"
170 #include "cfilesystem.h"
171
172
173 void outwnd_print(const char *id, const char *tmp);
174
175 #define MAX_FILTERS 48
176 #define MAX_LINE_WIDTH  128
177
178 bool outwnd_inited = false;
179 bool outwnd_disabled = true;
180 bool OutputActive = false;
181 int Outwnd_no_filter_file = 0;          // 0 = .cfg file found, 1 = not found and warning not printed yet, 2 = not found and warning printed
182
183 struct outwnd_filter_struct {
184         char name[FILTER_NAME_LENGTH];
185         int state;
186 } *outwnd_filter[MAX_FILTERS], real_outwnd_filter[MAX_FILTERS];
187
188
189 int outwnd_filter_count = 0;
190 int outwnd_filter_loaded = 0;
191
192 // used for file logging
193 int Log_debug_output_to_file = 1;
194 FILE *Log_fp;
195 const char *Freespace_logfilename = "fs_debug.log";
196
197 void load_filter_info(void)
198 {
199         FILE *fp;
200         char pathname[512];
201         char inbuf[FILTER_NAME_LENGTH+4];
202         int z;
203
204         outwnd_filter_loaded = 1;
205         outwnd_filter_count = 0;
206
207         if ( cfile_init_paths() ) {
208                 return;
209         }
210
211         SDL_snprintf(pathname, sizeof(pathname), "%s%s%sdebug_filter.cfg", Cfile_user_dir, Pathtypes[CF_TYPE_DATA].path, DIR_SEPARATOR_STR);
212
213         fp = fopen(pathname, "rt");
214         if (!fp)        {
215                 Outwnd_no_filter_file = 1;
216
217                 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
218                 SDL_strlcpy( outwnd_filter[outwnd_filter_count]->name, "error", FILTER_NAME_LENGTH );
219                 outwnd_filter[outwnd_filter_count]->state = 1;
220                 outwnd_filter_count++;
221
222                 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
223                 SDL_strlcpy( outwnd_filter[outwnd_filter_count]->name, "general", FILTER_NAME_LENGTH );
224                 outwnd_filter[outwnd_filter_count]->state = 1;
225                 outwnd_filter_count++;
226
227                 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
228                 SDL_strlcpy( outwnd_filter[outwnd_filter_count]->name, "warning", FILTER_NAME_LENGTH );
229                 outwnd_filter[outwnd_filter_count]->state = 1;
230                 outwnd_filter_count++;
231
232                 return;
233         }
234
235         Outwnd_no_filter_file = 0;
236
237         while (fgets(inbuf, FILTER_NAME_LENGTH+3, fp))
238         {
239                 if (outwnd_filter_count == MAX_FILTERS)
240                         break;
241
242                 outwnd_filter[outwnd_filter_count] = &real_outwnd_filter[outwnd_filter_count];
243                 if (*inbuf == '+')
244                         outwnd_filter[outwnd_filter_count]->state = 1;
245                 else if (*inbuf == '-')
246                         outwnd_filter[outwnd_filter_count]->state = 0;
247                 else continue;  // skip everything else
248
249                 z = strlen(inbuf) - 1;
250                 if (inbuf[z] == '\n')
251                         inbuf[z] = 0;
252
253                 SDL_assert(strlen(inbuf+1) < FILTER_NAME_LENGTH);
254                 SDL_strlcpy(outwnd_filter[outwnd_filter_count]->name, inbuf + 1, FILTER_NAME_LENGTH);
255
256                 if ( !SDL_strcasecmp( outwnd_filter[outwnd_filter_count]->name, "error" ) )     {
257                         outwnd_filter[outwnd_filter_count]->state = 1;
258                 } else if ( !SDL_strcasecmp( outwnd_filter[outwnd_filter_count]->name, "general" ) )    {
259                         outwnd_filter[outwnd_filter_count]->state = 1;
260                 } else if ( !SDL_strcasecmp( outwnd_filter[outwnd_filter_count]->name, "warning" ) )    {
261                         outwnd_filter[outwnd_filter_count]->state = 1;
262                 }
263
264                 outwnd_filter_count++;
265         }
266
267         if (ferror(fp) && !feof(fp))
268                 nprintf(("Error", "Error reading \"%s\"\n", pathname));
269
270         fclose(fp);
271 }
272
273 void save_filter_info(void)
274 {
275         FILE *fp;
276         int i;
277         char pathname[512];
278
279         if (!outwnd_filter_loaded)
280                 return;
281
282         if ( Outwnd_no_filter_file )    {
283                 return; // No file, don't save
284         }
285
286         if ( cfile_init_paths() ) {
287                 return;
288         }
289
290         SDL_snprintf(pathname, sizeof(pathname), "%s%s%sdebug_filter.cfg", Cfile_user_dir, Pathtypes[CF_TYPE_DATA].path, DIR_SEPARATOR_STR);
291
292         fp = fopen(pathname, "wt");
293         if (fp)
294         {
295                 for (i=0; i<outwnd_filter_count; i++)
296                         fprintf(fp, "%c%s\n", outwnd_filter[i]->state ? '+' : '-', outwnd_filter[i]->name);
297
298                 fclose(fp);
299         }
300 }
301
302 void outwnd_printf2(const char *format, ...)
303 {
304         char tmp[MAX_LINE_WIDTH*4];
305         va_list args;
306         
307         va_start(args, format);
308         SDL_vsnprintf(tmp, sizeof(tmp), format, args);
309         va_end(args);
310         outwnd_print("General", tmp);
311 }
312
313 void outwnd_printf(const char *id, const char *format, ...)
314 {
315         char tmp[MAX_LINE_WIDTH*4];
316         va_list args;
317         
318         va_start(args, format);
319         SDL_vsnprintf(tmp, sizeof(tmp), format, args);
320         va_end(args);
321         outwnd_print(id, tmp);
322 }
323
324 void outwnd_print(const char *id, const char *tmp)
325 {
326         int i;
327         outwnd_filter_struct *temp;
328
329         if (!outwnd_inited) {
330                 fputs("outwnd not initialized yet...  ", stdout);
331                 fputs(tmp, stdout);
332                 fflush(stdout);
333                 return;
334         }
335
336         if ( Outwnd_no_filter_file == 1 )       {
337                 Outwnd_no_filter_file = 2;
338
339                 outwnd_print( "general", "==========================================================================\n" );
340                 outwnd_print( "general", "DEBUG SPEW: No debug_filter.cfg found, so only general, error, and warning\n" );
341                 outwnd_print( "general", "categories can be shown and no debug_filter.cfg info will be saved.\n" );
342                 outwnd_print( "general", "==========================================================================\n" );
343         }
344
345         if (!id)
346                 id = "General";
347
348         for (i=0; i<outwnd_filter_count; i++)
349                 if (!SDL_strcasecmp(id, outwnd_filter[i]->name))
350                         break;
351
352
353         if (i == outwnd_filter_count)  // new id found that's not yet in filter list
354         {
355                 // Only create new filters if there was a filter file
356                 if ( Outwnd_no_filter_file )    {
357                         return;
358                 }
359
360                 if (outwnd_filter_count >= MAX_FILTERS) {
361                         SDL_assert(outwnd_filter_count == MAX_FILTERS);  // how did it get over the max?  Very bad..
362                         outwnd_printf("General", "Outwnd filter limit reached.  Recycling \"%s\" to add \"%s\"",
363                                 outwnd_filter[MAX_FILTERS - 1]->name, id);
364
365                         i--;  // overwrite the last element (oldest used filter in the list)
366                 }
367
368                 SDL_assert(strlen(id) < FILTER_NAME_LENGTH);
369                 outwnd_filter[i] = &real_outwnd_filter[i];  // note: this assumes the list doesn't have gaps (from deleting an element for example)
370                 SDL_strlcpy(outwnd_filter[i]->name, id, FILTER_NAME_LENGTH);
371                 outwnd_filter[i]->state = 1;
372                 outwnd_filter_count = i + 1;
373                 save_filter_info();
374         }
375
376         // sort the filters from most recently used to oldest, so oldest ones will get recycled first
377         temp = outwnd_filter[i];
378         while (i--)
379                 outwnd_filter[i + 1] = outwnd_filter[i];
380
381         i++;
382         outwnd_filter[i] = temp;
383
384         if (!outwnd_filter[i]->state)
385                 return;
386
387         if ( Log_debug_output_to_file ) {
388                 if ( Log_fp != NULL ) {
389                         fputs(tmp, Log_fp);     
390                         fflush(Log_fp);
391                 }
392         } else {
393                 fputs(tmp, stdout);
394                 fflush(stdout);
395         }
396 }
397
398
399 void outwnd_init(int display_under_freespace_window)
400 {
401         if ( cfile_init_paths() ) {
402                 return;
403         }
404
405         outwnd_inited = TRUE;
406
407         char pathname[512];
408
409         SDL_snprintf(pathname, sizeof(pathname), "%s%s%s%s", Cfile_user_dir, Pathtypes[CF_TYPE_DATA].path, DIR_SEPARATOR_STR, Freespace_logfilename);
410         cf_create_directory(CF_TYPE_DATA);
411
412         if ( Log_fp == NULL ) {
413                 Log_fp = fopen(pathname, "wb");
414                 if ( Log_fp == NULL ) {
415                         SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Warning!", "Unable to open debug log file. Debug output will not be saved.", NULL);
416                 }
417         }
418 }
419
420 void outwnd_close()
421 {
422         if ( Log_fp != NULL ) {
423                 fclose(Log_fp);
424                 Log_fp = NULL;
425         }
426 }
427
428 #endif // NDEBUG