webperimental: killstack decides stack protects.
[freeciv.git] / server / console.c
blob8f366714a926da0a1460f7d52d5daf48af9e3b31
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <string.h>
22 #ifdef FREECIV_HAVE_LIBREADLINE
23 #include <readline/readline.h>
24 #endif
26 /* utility */
27 #include "deprecations.h"
28 #include "fcbacktrace.h"
29 #include "fciconv.h"
30 #include "fcintl.h"
31 #include "log.h"
32 #include "support.h"
34 /* common */
35 #include "game.h"
37 /* server */
38 #include "notify.h"
39 #include "srv_main.h"
41 #include "console.h"
43 static bool console_show_prompt = FALSE;
44 static bool console_prompt_is_showing = FALSE;
45 static bool console_rfcstyle = FALSE;
46 #ifdef FREECIV_HAVE_LIBREADLINE
47 static bool readline_received_enter = TRUE;
48 #else
49 static int con_dump(enum rfc_status rfc_status, const char *message, ...);
50 #endif
52 /************************************************************************
53 Function to handle log messages.
54 This must match the log_callback_fn typedef signature.
55 ************************************************************************/
56 static void con_handle_log(enum log_level level, const char *message,
57 bool file_too)
59 if (LOG_ERROR == level) {
60 notify_conn(NULL, NULL, E_LOG_ERROR, ftc_warning, "%s", message);
61 } else if (LOG_FATAL >= level) {
62 /* Make sure that message is not left to buffers when server dies */
63 conn_list_iterate(game.est_connections, pconn) {
64 pconn->send_buffer->do_buffer_sends = 0;
65 #ifdef USE_COMPRESSION
66 pconn->compression.frozen_level = 0;
67 #endif
68 } conn_list_iterate_end;
70 notify_conn(NULL, NULL, E_LOG_FATAL, ftc_warning, "%s", message);
71 notify_conn(NULL, NULL, E_LOG_FATAL, ftc_warning,
72 _("Please report this message at %s"),
73 BUG_URL);
76 /* Write debug/verbose message to console only when not written to file. */
77 if (!file_too || level <= LOG_NORMAL) {
78 if (console_rfcstyle) {
79 con_write(C_LOG_BASE + level, "%s", message);
80 } else {
81 con_write(C_LOG_BASE + level, "%d: %s", level, message);
86 /************************************************************************
87 Print the prompt if it is not the last thing printed.
88 ************************************************************************/
89 static void con_update_prompt(void)
91 if (console_prompt_is_showing || !console_show_prompt) {
92 return;
95 #ifdef FREECIV_HAVE_LIBREADLINE
96 if (readline_received_enter) {
97 readline_received_enter = FALSE;
98 } else {
99 rl_forced_update_display();
101 #else /* FREECIV_HAVE_LIBREADLINE */
102 con_dump(C_READY,"> ");
103 con_flush();
104 #endif /* FREECIV_HAVE_LIBREADLINE */
106 console_prompt_is_showing = TRUE;
109 #ifdef FREECIV_DEBUG
110 /************************************************************************
111 Prefix for log messages saved to file. At the moment the turn and the
112 current date and time are used.
113 ************************************************************************/
114 static const char *log_prefix(void)
116 static char buf[128];
118 #ifdef LOG_TIMERS
119 char timestr[32];
120 time_t timestamp;
122 time(&timestamp);
123 strftime(timestr, sizeof(timestr), "%Y/%m/%d %H:%M:%S",
124 localtime(&timestamp));
126 fc_snprintf(buf, sizeof(buf), "T%03d - %s", game.info.turn, timestr);
128 #else /* LOG_TIMERS */
129 fc_snprintf(buf, sizeof(buf), "T%03d", game.info.turn);
130 #endif /* LOG_TIMERS */
132 return buf;
134 #endif /* FREECIV_DEBUG */
136 /************************************************************************
137 Deprecation warning callback to send event to clients.
138 ************************************************************************/
139 static void depr_warn_callback(const char *msg)
141 notify_conn(NULL, NULL, E_DEPRECATION_WARNING, ftc_warning, "%s", msg);
144 /************************************************************************
145 Initialize logging via console.
146 ************************************************************************/
147 void con_log_init(const char *log_filename, enum log_level level,
148 int fatal_assertions)
150 #ifdef FREECIV_DEBUG
151 log_init(log_filename, level, con_handle_log, log_prefix,
152 fatal_assertions);
153 #else
154 log_init(log_filename, level, con_handle_log, NULL,
155 fatal_assertions);
156 #endif /* FREECIV_DEBUG */
157 backtrace_init();
158 deprecation_warn_cb_set(depr_warn_callback);
161 /************************************************************************
162 Deinitialize logging
163 ************************************************************************/
164 void con_log_close(void)
166 backtrace_deinit();
168 log_close();
171 #ifndef FREECIV_HAVE_LIBREADLINE
172 /************************************************************************
173 Write to console without line-break, don't print prompt.
174 ************************************************************************/
175 static int con_dump(enum rfc_status rfc_status, const char *message, ...)
177 static char buf[MAX_LEN_CONSOLE_LINE];
178 va_list args;
180 va_start(args, message);
181 fc_vsnprintf(buf, sizeof(buf), message, args);
182 va_end(args);
184 if (console_prompt_is_showing) {
185 fc_printf("\n");
187 if ((console_rfcstyle) && (rfc_status >= 0)) {
188 fc_printf("%.3d %s", rfc_status, buf);
189 } else {
190 fc_printf("%s", buf);
192 console_prompt_is_showing = FALSE;
193 return (int) strlen(buf);
195 #endif /* FREECIV_HAVE_LIBREADLINE */
197 /************************************************************************
198 Write to console and add line-break, and show prompt if required.
199 ************************************************************************/
200 void con_write(enum rfc_status rfc_status, const char *message, ...)
202 /* First buffer contains featured text tags */
203 static char buf1[(MAX_LEN_CONSOLE_LINE * 3) / 2];
204 static char buf2[MAX_LEN_CONSOLE_LINE];
205 va_list args;
207 va_start(args, message);
208 fc_vsnprintf(buf1, sizeof(buf1), message, args);
209 va_end(args);
211 /* remove all format tags */
212 featured_text_to_plain_text(buf1, buf2, sizeof(buf2), NULL, FALSE);
213 con_puts(rfc_status, buf2);
216 /************************************************************************
217 Write to console and add line-break, and show prompt if required.
218 Same as con_write, but without the format string stuff.
219 The real reason for this is because __attribute__ complained
220 with con_write(C_COMMENT,"") of "warning: zero-length format string";
221 this allows con_puts(C_COMMENT,"");
222 ************************************************************************/
223 void con_puts(enum rfc_status rfc_status, const char *str)
225 if (console_prompt_is_showing) {
226 fc_printf("\n");
228 if ((console_rfcstyle) && (rfc_status >= 0)) {
229 fc_printf("%.3d %s\n", rfc_status, str);
230 } else {
231 fc_printf("%s\n", str);
233 console_prompt_is_showing = FALSE;
234 con_update_prompt();
237 /************************************************************************
238 Ensure timely update.
239 ************************************************************************/
240 void con_flush(void)
242 fflush(stdout);
245 /************************************************************************
246 Set style.
247 ************************************************************************/
248 void con_set_style(bool i)
250 console_rfcstyle = i;
251 if (console_rfcstyle)
252 con_puts(C_OK, _("Ok. RFC-style set."));
253 else
254 con_puts(C_OK, _("Ok. Standard style set."));
257 /************************************************************************
258 Returns rfc-style.
259 ************************************************************************/
260 bool con_get_style(void)
262 return console_rfcstyle;
265 /************************************************************************
266 Initialize prompt; display initial message.
267 ************************************************************************/
268 void con_prompt_init(void)
270 static bool first = TRUE;
272 if (first) {
273 con_puts(C_COMMENT, "");
274 con_puts(C_COMMENT, _("For introductory help, type 'help'."));
275 first = FALSE;
279 /************************************************************************
280 Make sure a prompt is printed, and re-printed after every message.
281 ************************************************************************/
282 void con_prompt_on(void)
284 console_show_prompt = TRUE;
285 con_update_prompt();
288 /************************************************************************
289 Do not print a prompt after log messages.
290 ************************************************************************/
291 void con_prompt_off(void)
293 console_show_prompt = FALSE;
296 /************************************************************************
297 User pressed enter: will need a new prompt
298 ************************************************************************/
299 void con_prompt_enter(void)
301 console_prompt_is_showing = FALSE;
302 #ifdef FREECIV_HAVE_LIBREADLINE
303 readline_received_enter = TRUE;
304 #endif
307 /************************************************************************
308 Clear "user pressed enter" state (used in special cases).
309 ************************************************************************/
310 void con_prompt_enter_clear(void)
312 console_prompt_is_showing = TRUE;
313 #ifdef FREECIV_HAVE_LIBREADLINE
314 readline_received_enter = FALSE;
315 #endif