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 
12 #ifndef WIN32	// Goober5000
13 
14 #ifndef NDEBUG
15 
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <string.h>
19 
20 #include "globalincs/pstypes.h"
21 #include "osapi/outwnd.h"
22 #include "osapi/osapi.h"
23 #include "osapi/osregistry.h"
24 #include "cfile/cfilesystem.h"
25 #include "globalincs/systemvars.h"
26 #include "globalincs/globals.h"
27 #include "parse/parselo.h"
28 
29 
30 
31 void outwnd_print(const char *id = NULL, const char *temp = NULL);
32 
33 #define MAX_LINE_WIDTH	128
34 
35 bool outwnd_inited = false;
36 ubyte Outwnd_no_filter_file = 0;		// 0 = .cfg file found, 1 = not found and warning not printed yet, 2 = not found and warning printed
37 
38 struct outwnd_filter_struct {
39 	char name[NAME_LENGTH];
40 	bool enabled;
41 
outwnd_filter_structoutwnd_filter_struct42 	outwnd_filter_struct()
43 		: enabled( false )
44 	{
45 		name[ 0 ] = 0;
46 	}
47 };
48 
49 SCP_vector<outwnd_filter_struct> OutwndFilter;
50 
51 int outwnd_filter_loaded = 0;
52 
53 // used for file logging
54 int Log_debug_output_to_file = 1;
55 FILE *Log_fp = NULL;
56 char *FreeSpace_logfilename = "fs2_open.log";
57 
58 SCP_string safe_string;
59 
60 
load_filter_info(void)61 void load_filter_info(void)
62 {
63 	FILE *fp = NULL;
64 	char pathname[MAX_PATH_LEN];
65 	char inbuf[NAME_LENGTH+4];
66 	outwnd_filter_struct new_filter;
67 	int z;
68 
69 	outwnd_filter_loaded = 1;
70 
71 	snprintf( pathname, MAX_PATH_LEN, "%s/%s/%s/%s", detect_home(), Osreg_user_dir, Pathtypes[CF_TYPE_DATA].path, NOX("debug_filter.cfg") );
72 
73 	fp = fopen(pathname, "rt");
74 
75 	if (!fp) {
76 		Outwnd_no_filter_file = 1;
77 
78 		memset( &new_filter, 0, sizeof(outwnd_filter_struct) );
79 		strcpy_s( new_filter.name, "error" );
80 		new_filter.enabled = true;
81 
82 		OutwndFilter.push_back( new_filter );
83 
84 		memset( &new_filter, 0, sizeof(outwnd_filter_struct) );
85 		strcpy_s( new_filter.name, "general" );
86 		new_filter.enabled = true;
87 
88 		OutwndFilter.push_back( new_filter );
89 
90 		memset( &new_filter, 0, sizeof(outwnd_filter_struct) );
91 		strcpy_s( new_filter.name, "warning" );
92 		new_filter.enabled = true;
93 
94 		OutwndFilter.push_back( new_filter );
95 
96 		return;
97 	}
98 
99 	Outwnd_no_filter_file = 0;
100 
101 	while ( fgets(inbuf, NAME_LENGTH+3, fp) ) {
102 		memset( &new_filter, 0, sizeof(outwnd_filter_struct) );
103 
104 		if (*inbuf == '+')
105 			new_filter.enabled = true;
106 		else if (*inbuf == '-')
107 			new_filter.enabled = false;
108 		else
109 			continue;	// skip everything else
110 
111 		z = strlen(inbuf) - 1;
112 		if (inbuf[z] == '\n')
113 			inbuf[z] = 0;
114 
115 		Assert( strlen(inbuf+1) < NAME_LENGTH );
116 		strcpy_s(new_filter.name, inbuf + 1);
117 
118 		if ( !stricmp(new_filter.name, "error") ) {
119 			new_filter.enabled = true;
120 		} else if ( !stricmp(new_filter.name, "general") ) {
121 			new_filter.enabled = true;
122 		} else if ( !stricmp(new_filter.name, "warning") ) {
123 			new_filter.enabled = true;
124 		}
125 
126 		OutwndFilter.push_back( new_filter );
127 	}
128 
129 	if ( ferror(fp) && !feof(fp) )
130 		nprintf(("Error", "Error reading \"%s\"\n", pathname));
131 
132 	fclose(fp);
133 }
134 
save_filter_info(void)135 void save_filter_info(void)
136 {
137 	FILE *fp = NULL;
138 	char pathname[MAX_PATH_LEN];
139 
140 	if ( !outwnd_filter_loaded )
141 		return;
142 
143 	if (Outwnd_no_filter_file)
144 		return;	// No file, don't save
145 
146 
147 	snprintf( pathname, MAX_PATH_LEN, "%s/%s/%s/%s", detect_home(), Osreg_user_dir, Pathtypes[CF_TYPE_DATA].path, NOX("debug_filter.cfg") );
148 
149 	fp = fopen(pathname, "wt");
150 
151 	if (fp) {
152 		for (uint i = 0; i < OutwndFilter.size(); i++)
153 			fprintf(fp, "%c%s\n", OutwndFilter[i].enabled ? '+' : '-', OutwndFilter[i].name);
154 
155 		fclose(fp);
156 	}
157 }
158 
outwnd_printf2(const char * format,...)159 void outwnd_printf2(const char *format, ...)
160 {
161 	SCP_string temp;
162 	va_list args;
163 
164 	if (format == NULL)
165 		return;
166 
167 	va_start(args, format);
168 	vsprintf(temp, format, args);
169 	va_end(args);
170 
171 	outwnd_print("General", temp.c_str());
172 }
173 
outwnd_printf(const char * id,const char * format,...)174 void outwnd_printf(const char *id, const char *format, ...)
175 {
176 	SCP_string temp;
177 	va_list args;
178 
179 	if ( (id == NULL) || (format == NULL) )
180 		return;
181 
182 	va_start(args, format);
183 	vsprintf(temp, format, args);
184 	va_end(args);
185 
186 	outwnd_print(id, temp.c_str());
187 }
188 
outwnd_print(const char * id,const char * tmp)189 void outwnd_print(const char *id, const char *tmp)
190 {
191 	uint i;
192 
193 	if ( (id == NULL) || (tmp == NULL) )
194 		return;
195 
196   	if ( !outwnd_inited ) {
197   		fputs("outwnd not initialized yet...  \n", stdout);
198 		fputs(tmp, stdout);
199 		fflush(stdout);
200 
201   		return;
202 	}
203 
204 	if (Outwnd_no_filter_file == 1) {
205 		Outwnd_no_filter_file = 2;
206 
207 		outwnd_print( "general", "==========================================================================\n" );
208 		outwnd_print( "general", "DEBUG SPEW: No debug_filter.cfg found, so only general, error, and warning\n" );
209 		outwnd_print( "general", "categories can be shown and no debug_filter.cfg info will be saved.\n" );
210 		outwnd_print( "general", "==========================================================================\n" );
211 	}
212 
213 	if ( !id )
214 		id = "General";
215 
216 	for (i = 0; i < OutwndFilter.size(); i++) {
217 		if ( !stricmp(id, OutwndFilter[i].name) )
218 			break;
219 	}
220 
221 	// id found that isn't in the filter list yet
222 	if ( i == OutwndFilter.size() ) {
223 		// Only create new filters if there was a filter file
224 		if (Outwnd_no_filter_file)
225 			return;
226 
227 		Assert( strlen(id)+1 < NAME_LENGTH );
228 		outwnd_filter_struct new_filter;
229 
230 		strcpy_s(new_filter.name, id);
231 		new_filter.enabled = true;
232 
233 		OutwndFilter.push_back( new_filter );
234 		save_filter_info();
235 	}
236 
237 	if ( !OutwndFilter[i].enabled )
238 		return;
239 
240 	if (Log_debug_output_to_file) {
241 		if (Log_fp != NULL) {
242 			fputs(tmp, Log_fp);
243 			fflush(Log_fp);
244 		}
245 	} else {
246 		fputs(tmp, stdout);
247 		fflush(stdout);
248 	}
249 }
250 
251 
outwnd_init(int display_under_freespace_window)252 void outwnd_init(int display_under_freespace_window)
253 {
254 	outwnd_inited = true;
255 
256 	char pathname[MAX_PATH_LEN];
257 
258     /* Set where the log file is going to go */
259     // Zacam: Set various conditions based on what type of log to generate.
260     if (Fred_running) {
261         FreeSpace_logfilename = "fred2_open.log";
262     } else if (Is_standalone) {
263         FreeSpace_logfilename = "fs2_standalone.log";
264     } else {
265         FreeSpace_logfilename = "fs2_open.log";
266     }
267 
268 	snprintf(pathname, MAX_PATH_LEN, "%s/%s/%s/%s", detect_home(), Osreg_user_dir, Pathtypes[CF_TYPE_DATA].path, FreeSpace_logfilename);
269 
270 	if (Log_fp == NULL) {
271 		Log_fp = fopen(pathname, "wb");
272 
273 		if (Log_fp == NULL) {
274 			outwnd_printf("Error", "Error opening %s\n", pathname);
275 		} else {
276 			time_t timedate = time(NULL);
277 			char datestr[50];
278 
279 			memset( datestr, 0, sizeof(datestr) );
280 			strftime( datestr, sizeof(datestr)-1, "%a %b %d %H:%M:%S %Y", localtime(&timedate) );
281 
282 			printf("Future debug output directed to: %s\n", pathname);
283 			outwnd_printf("General", "Opened log '%s', %s ...\n", pathname, datestr);
284 		}
285 	}
286 }
287 
outwnd_close()288 void outwnd_close()
289 {
290 	if (Log_fp != NULL) {
291 		time_t timedate = time(NULL);
292 		char datestr[50];
293 
294 		memset( datestr, 0, sizeof(datestr) );
295 		strftime( datestr, sizeof(datestr)-1, "%a %b %d %H:%M:%S %Y", localtime(&timedate) );
296 
297 		outwnd_printf("General", "... Log closed, %s\n", datestr);
298 
299 		fclose(Log_fp);
300 		Log_fp = NULL;
301 	}
302 
303 	outwnd_inited = false;
304 }
305 
safe_point_print(const char * format,...)306 void safe_point_print(const char *format, ...)
307 {
308 	SCP_string temp;
309 	va_list args;
310 
311 	va_start(args, format);
312 	vsprintf(temp, format, args);
313 	va_end(args);
314 
315 	safe_string = temp;
316 }
317 
safe_point(const char * file,int line,const char * format,...)318 void safe_point(const char *file, int line, const char *format, ...)
319 {
320 	safe_point_print("last safepoint: %s, %d; [%s]", file, line, format);
321 }
322 
323 #endif // NDEBUG
324 
325 #endif		// Goober5000 - #ifndef WIN32
326