naev 0.11.5
log.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <stdarg.h>
11#include <stdio.h>
12#include <time.h> /* strftime */
13#include "physfs.h"
14
15#include "naev.h"
18#include "log.h"
19
20#include "conf.h"
21#include "ndata.h"
22#include "nstring.h"
23
25static char *outcopy = NULL;
26static char *errcopy = NULL;
27
28static size_t moutcopy; /* Allocated size of outcopy. */
29static size_t merrcopy; /* Allocated size of errcopy. */
30
31static int noutcopy = 0; /* Number of bytes written to outcopy. */
32static int nerrcopy = 0; /* Number of bytes written to errcopy. */
33
35static char *outfiledouble = NULL;
36static char *errfiledouble = NULL;
37
38/* Whether to copy stdout and stderr to temporary buffers. */
39static int copying = 0;
40
41/* File descriptors */
42static PHYSFS_File *logout_file = NULL;
43static PHYSFS_File *logerr_file = NULL;
44
45/*
46 * Prototypes
47 */
48static void log_copy( int enable );
49static void log_append( FILE *stream, char *str );
50static void log_cleanStream( PHYSFS_File **file, const char *fname, const char *filedouble );
51static void log_purge (void);
52
56int logprintf( FILE *stream, int newline, const char *fmt, ... )
57{
58 va_list ap;
59 char *buf;
60 size_t n;
61
62 /* Offset to add error colour header as necessary. */
63 va_start( ap, fmt );
64 n = vsnprintf( NULL, 0, fmt, ap );
65 va_end( ap );
66 buf = malloc( 2+n+2 );
67 va_start( ap, fmt );
68 n = vsnprintf( &buf[2], n + 1, fmt, ap );
69 va_end( ap );
70
71 /* Finally add newline if necessary. */
72 if (newline) {
73 buf[2+n] = '\n';
74 buf[2+n+1] = '\0';
75 }
76 else
77 buf[2+n] = '\0';
78
79 /* Append to buffer. */
80 if (copying)
81 log_append(stream, &buf[2]);
82
83 if (stream == stdout && logout_file != NULL) {
84 PHYSFS_writeBytes( logout_file, &buf[2], newline ? n+1 : n );
85 if (newline)
86 PHYSFS_flush( logout_file );
87 }
88
89 if (stream == stderr && logerr_file != NULL) {
90 PHYSFS_writeBytes( logerr_file, &buf[2], newline ? n+1 : n );
91 if ( newline )
92 PHYSFS_flush( logerr_file );
93 }
94
95 /* Also print to the stream. */
96 n = fprintf( stream, "%s", &buf[ 2 ] );
97 if (newline)
98 fflush( stream );
99
100 free( buf );
101 return n;
102}
103
108void log_redirect (void)
109{
110 time_t cur;
111 struct tm *ts;
112 char timestr[20];
113
114 if (!conf.redirect_file)
115 return;
116
117 time(&cur);
118 ts = localtime(&cur);
119 strftime( timestr, sizeof(timestr), "%Y-%m-%d_%H-%M-%S", ts );
120
121 PHYSFS_mkdir( "logs" );
122 logout_file = PHYSFS_openWrite( "logs/stdout.txt" );
123 if ( logout_file == NULL )
124 WARN(_("Unable to redirect stdout to file"));
125
126 logerr_file = PHYSFS_openWrite( "logs/stderr.txt" );
127 if ( logerr_file == NULL )
128 WARN(_("Unable to redirect stderr to file"));
129
130 SDL_asprintf( &outfiledouble, "logs/%s_stdout.txt", timestr );
131 SDL_asprintf( &errfiledouble, "logs/%s_stderr.txt", timestr );
132
133 log_copy(0);
134}
135
142void log_init (void)
143{
144 log_copy( conf.redirect_file );
145}
146
156void log_copy( int enable )
157{
158 /* Nothing to do. */
159 if (copying == enable)
160 return;
161
162 if (enable) {
163 copying = 1;
164
165 moutcopy = 1;
166 noutcopy = 0;
167 outcopy = calloc(moutcopy, BUFSIZ);
168
169 merrcopy = 1;
170 nerrcopy = 0;
171 errcopy = calloc(merrcopy, BUFSIZ);
172
173 return;
174 }
175
176 if (noutcopy && logout_file != NULL)
177 PHYSFS_writeBytes( logout_file, outcopy, strlen(outcopy) );
178
179 if (nerrcopy && logerr_file != NULL)
180 PHYSFS_writeBytes( logerr_file, errcopy, strlen(errcopy) );
181
182 log_purge();
183}
184
188static void log_purge (void)
189{
190 if (!copying)
191 return;
192
193 free(outcopy);
194 free(errcopy);
195
196 outcopy = NULL;
197 errcopy = NULL;
198
199 copying = 0;
200}
201
205void log_clean (void)
206{
207 log_cleanStream( &logout_file, "logs/stdout.txt", outfiledouble );
208 log_cleanStream( &logerr_file, "logs/stderr.txt", errfiledouble );
209}
210
214static void log_cleanStream( PHYSFS_File **file, const char *fname, const char *filedouble )
215{
216 PHYSFS_Stat stat;
217
218 if (*file == NULL)
219 return;
220
221 PHYSFS_close( *file );
222 *file = NULL;
223
224 if (PHYSFS_stat( fname, &stat ) == 0)
225 return;
226
227 if (stat.filesize == 0)
228 PHYSFS_delete( fname );
229 else
230 ndata_copyIfExists( fname, filedouble );
231}
232
239static void log_append( FILE *stream, char *str )
240{
241 int len = strlen(str);
242 if (stream == stdout) {
243 while ((len + noutcopy) >= (int)moutcopy) {
244 moutcopy *= 2;
245 outcopy = realloc( outcopy, moutcopy );
246 if (outcopy == NULL) goto copy_err;
247 }
248
249 strncpy( &outcopy[noutcopy], str, len+1 );
250 noutcopy += len;
251 }
252 else if (stream == stderr) {
253 while ((len + nerrcopy) >= (int)merrcopy) {
254 merrcopy *= 2;
255 errcopy = realloc( errcopy, merrcopy );
256 if (errcopy == NULL) goto copy_err;
257 }
258
259 strncpy( &errcopy[nerrcopy], str, len+1 );
260 nerrcopy += len;
261 }
262
263 return;
264
265copy_err:
266 log_purge();
267 WARN(_("An error occurred while buffering %s!"),
268 stream == stdout ? "stdout" : "stderr");
269}
void log_clean(void)
Deletes useless (empty) log files from the current session.
Definition log.c:205
int logprintf(FILE *stream, int newline, const char *fmt,...)
Like fprintf, but automatically teed to log files (and line-terminated if newline is true).
Definition log.c:56
void log_init(void)
Sets up the logging subsystem. (Calling this ensures logging output is preserved until we have a plac...
Definition log.c:142
static void log_copy(int enable)
Sets up or terminates copying of standard streams into memory.
Definition log.c:156
void log_redirect(void)
Sets up redirection of stdout and stderr to files. PhysicsFS must be initialized for this to work.
Definition log.c:108
static void log_cleanStream(PHYSFS_File **file, const char *fname, const char *filedouble)
Definition log.c:214
static void log_purge(void)
Deletes copied output without printing the contents.
Definition log.c:188
static char * outfiledouble
Definition log.c:35
static void log_append(FILE *stream, char *str)
Appends a message to a stream's in-memory buffer.
Definition log.c:239
static char * outcopy
Definition log.c:25
Header file with generic functions and naev-specifics.
int ndata_copyIfExists(const char *file1, const char *file2)
Copy a file, if it exists.
Definition ndata.c:303
int redirect_file
Definition conf.h:148