]> git.pond.sub.org Git - empserver/blob - src/lib/subs/journal.c
Update copyright notice
[empserver] / src / lib / subs / journal.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2012, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  journal.c: Log a journal of events to a file
28  *
29  *  Known contributors to this file:
30  *     Markus Armbruster, 2004-2011
31  *     Ron Koenderink, 2008
32  */
33
34 /*
35  * Journal file format: each line logs an event, and looks like this:
36  *
37  *     TIME THREAD EVENT DATA
38  *
39  * Events and their data are:
40  *
41  *     startup
42  *     shutdown
43  *     prng NAME SEED
44  *     login CNUM HOSTADDR USER
45  *     logout CNUM
46  *     command NAME
47  *     input INPUT
48  *     output THREAD ID OUTPUT
49  *     update ETU
50  */
51
52 #include <config.h>
53
54 #include <ctype.h>
55 #include <errno.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <time.h>
59 #include "misc.h"
60 #include "empthread.h"
61 #include "journal.h"
62 #include "optlist.h"
63 #include "player.h"
64 #include "prototypes.h"
65
66 static char journal_fname[] = "journal.log";
67 static FILE *journal;
68
69 static void journal_entry_start(char *fmt, ...)
70     ATTRIBUTE((format (printf, 1, 2)));
71 static void journal_entry(char *fmt, ...)
72     ATTRIBUTE((format (printf, 1, 2)));
73 static void journal_output_start(struct player *, int);
74
75 static FILE *
76 journal_open(void)
77 {
78     return fopen(journal_fname, "a");
79 }
80
81 static void
82 journal_entry_vstart(char *fmt, va_list ap)
83 {
84     time_t now;
85
86     if (!journal)
87         return;
88     time(&now);
89     fprintf(journal, "%.24s %10.10s ",
90             ctime(&now), empth_name(empth_self()));
91     vfprintf(journal, fmt, ap);
92 }
93
94 static void
95 journal_entry_start(char *fmt, ...)
96 {
97     va_list ap;
98
99     va_start(ap, fmt);
100     journal_entry_vstart(fmt, ap);
101     va_end(ap);
102 }
103
104 static void
105 journal_entry_write(char *s, size_t n)
106 {
107     char *p;
108
109     if (!journal)
110         return;
111     for (p = s; p < s + n; p++) {
112         if (*p == '\\')
113             fprintf(journal, "\\\\");
114         else if (isprint(*(unsigned char *)p) || *p == '\t')
115             putc(*p, journal);
116         else
117             fprintf(journal, "\\%03o", *p);
118     }
119 }
120
121 static void
122 journal_entry_end(int newline, int flush)
123 {
124     if (!journal)
125         return;
126     if (!newline)
127         fputc('\\', journal);
128     fputc('\n', journal);
129     fflush(journal);
130     if (ferror(journal)) {
131         logerror("Error writing journal (%s)", strerror(errno));
132         clearerr(journal);
133     }
134 }
135
136 static void
137 journal_entry(char *fmt, ...)
138 {
139     va_list ap;
140
141     va_start(ap, fmt);
142     journal_entry_vstart(fmt, ap);
143     va_end(ap);
144     journal_entry_end(1, 1);
145 }
146
147 int
148 journal_startup(void)
149 {
150     if (!keep_journal)
151         return 0;
152     journal = journal_open();
153     if (!journal) {
154         logerror("Can't open %s (%s)", journal_fname, strerror(errno));
155         return -1;
156     }
157     journal_entry("startup");
158     return 0;
159 }
160
161 void
162 journal_shutdown(void)
163 {
164     journal_entry("shutdown");
165     if (journal) {
166         fclose(journal);
167         journal = NULL;
168     }
169 }
170
171 int
172 journal_reopen(void)
173 {
174     FILE *j;
175
176     if (!keep_journal)
177         return 0;
178     j = journal_open();
179     if (!j) {
180         logerror("Can't open %s (%s)", journal_fname, strerror(errno));
181         return -1;
182     }
183     if (journal)
184         fclose(journal);
185     journal = j;
186     return 0;
187 }
188
189 void
190 journal_prng(unsigned seed)
191 {
192     journal_entry("prng BSD %d", seed);
193 }
194
195 void
196 journal_login(void)
197 {
198     journal_entry("login %d %s %s",
199                   player->cnum, player->hostaddr, player->userid);
200 }
201
202 void
203 journal_logout(void)
204 {
205     journal_entry("logout %d", player->cnum);
206 }
207
208 void
209 journal_output(struct player *pl, int id, char *output)
210 {
211     static char buf[1024];
212     static char *bp = buf;
213     static struct player *bpl;
214     static int bid;
215     char *s, *e;
216
217     if (keep_journal < 2)
218         return;
219
220     if (bp != buf && (pl != bpl || id != bid)) {
221         journal_output_start(bpl, bid);
222         journal_entry_write(buf, bp - buf);
223         journal_entry_end(0, 0);
224         bp = buf;
225     }
226
227     for (s = output; (e = strchr(s, '\n')); s = e + 1) {
228         journal_output_start(pl, id);
229         journal_entry_write(buf, bp - buf);
230         journal_entry_write(s, e - s);
231         journal_entry_end(1, 0);
232         bp = buf;
233     }
234     e = strchr(s, 0);
235     if (bp + (e - s) <= buf + sizeof(buf)) {
236         memcpy(bp, s, e - s);
237         bp += e - s;
238         bpl = pl;
239         bid = id;
240     } else {
241         journal_output_start(pl, id);
242         journal_entry_write(buf, bp - buf);
243         journal_entry_write(s, e - s);
244         journal_entry_end(0, 0);
245         bp = buf;
246     }
247 }
248
249 static void
250 journal_output_start(struct player *pl, int id)
251 {
252     journal_entry_start("output %s %d ", empth_name(pl->proc), id);
253 }
254
255 void
256 journal_input(char *input)
257 {
258     journal_entry_start("input ");
259     journal_entry_write(input, strlen(input));
260     journal_entry_end(1, 1);
261 }
262
263 void
264 journal_command(char *cmd)
265 {
266     char *eptr = strchr(cmd, ' ');
267     journal_entry("command %.*s", eptr ? (int)(eptr - cmd) : -1, cmd);
268 }
269
270 void
271 journal_update(int etu)
272 {
273     journal_entry("update %d", etu);
274 }