2001-07-16 21:39:50 +00:00
|
|
|
/*
|
|
|
|
sv_console.c
|
|
|
|
|
|
|
|
ncurses console for the server
|
|
|
|
|
|
|
|
Copyright (C) 2001 Bill Currie <bill@taniwha.org>
|
|
|
|
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2001/7/10
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2021-03-29 08:54:39 +00:00
|
|
|
#ifdef HAVE_NCURSES
|
2001-07-16 21:39:50 +00:00
|
|
|
# include <curses.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
2001-09-10 12:56:23 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
2011-08-25 13:35:20 +00:00
|
|
|
#if defined(_WIN32) && defined(HAVE_MALLOC_H)
|
2007-04-09 00:10:10 +00:00
|
|
|
# include <malloc.h>
|
|
|
|
#endif
|
2001-09-10 12:56:23 +00:00
|
|
|
|
2001-09-28 16:03:45 +00:00
|
|
|
#ifdef HAVE_SYS_IOCTL_H
|
|
|
|
# include <sys/ioctl.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_TERMIOS_H
|
|
|
|
# include <termios.h>
|
|
|
|
#endif
|
2001-09-25 20:16:24 +00:00
|
|
|
#include <signal.h>
|
2001-09-10 12:56:23 +00:00
|
|
|
#include <stdlib.h>
|
2001-07-16 21:39:50 +00:00
|
|
|
|
2013-01-22 05:09:41 +00:00
|
|
|
#include "qfalloca.h"
|
|
|
|
|
2002-07-31 05:19:03 +00:00
|
|
|
#include "QF/cbuf.h"
|
2001-07-16 21:39:50 +00:00
|
|
|
#include "QF/cmd.h"
|
|
|
|
#include "QF/console.h"
|
|
|
|
#include "QF/cvar.h"
|
2002-03-18 16:47:04 +00:00
|
|
|
#include "QF/dstring.h"
|
2001-09-16 05:41:28 +00:00
|
|
|
#include "QF/keys.h"
|
2001-07-16 21:39:50 +00:00
|
|
|
#include "QF/qtypes.h"
|
2002-08-27 07:16:28 +00:00
|
|
|
#include "QF/quakefs.h"
|
2001-07-16 21:39:50 +00:00
|
|
|
#include "QF/sys.h"
|
2002-08-07 18:46:53 +00:00
|
|
|
#include "QF/va.h"
|
2001-07-16 21:39:50 +00:00
|
|
|
|
2012-02-13 12:58:34 +00:00
|
|
|
#include "QF/plugin/general.h"
|
|
|
|
#include "QF/plugin/console.h"
|
|
|
|
|
2021-06-12 13:50:51 +00:00
|
|
|
#include "QF/ui/view.h"
|
|
|
|
|
|
|
|
#include "QF/ui/inputline.h"
|
|
|
|
|
2001-08-02 23:00:39 +00:00
|
|
|
#include "compat.h"
|
2007-04-09 00:10:10 +00:00
|
|
|
#include "sv_console.h"
|
2001-08-02 23:00:39 +00:00
|
|
|
|
2005-06-08 10:07:48 +00:00
|
|
|
static console_data_t sv_con_data;
|
2001-09-16 05:41:28 +00:00
|
|
|
|
2002-08-27 07:16:28 +00:00
|
|
|
static QFile *log_file;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
static char *sv_logfile;
|
|
|
|
static cvar_t sv_logfile_cvar = {
|
|
|
|
.name = "sv_logfile",
|
|
|
|
.description =
|
|
|
|
"Control server console logging. \"none\" for off, or "
|
|
|
|
"\"filename:gzflags\"",
|
|
|
|
.default_value = "none",
|
|
|
|
.flags = CVAR_NONE,
|
2022-04-24 11:04:06 +00:00
|
|
|
.value = { .type = 0, .value = &sv_logfile },
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
};
|
|
|
|
static exprenum_t sv_conmode_enum;
|
|
|
|
static exprtype_t sv_conmode_type = {
|
|
|
|
.name = "sv_conmode",
|
2022-04-24 11:46:06 +00:00
|
|
|
.size = sizeof (sv_con_data.exec_line),
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
.data = &sv_conmode_enum,
|
|
|
|
.get_string = cexpr_enum_get_string,
|
|
|
|
};
|
|
|
|
static int sv_exec_line_command (void *data, const char *line);
|
|
|
|
static int sv_exec_line_chat (void *data, const char *line);
|
|
|
|
static int (*sv_conmode_values[])(void *, const char *) = {
|
|
|
|
sv_exec_line_command,
|
|
|
|
sv_exec_line_chat,
|
|
|
|
};
|
|
|
|
static exprsym_t sv_conmode_symbols[] = {
|
|
|
|
{"command", &sv_conmode_type, sv_conmode_values + 0},
|
|
|
|
{"chat", &sv_conmode_type, sv_conmode_values + 1},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
static exprtab_t sv_conmode_symtab = {
|
|
|
|
sv_conmode_symbols,
|
|
|
|
};
|
|
|
|
static exprenum_t sv_conmode_enum = {
|
|
|
|
&sv_conmode_type,
|
|
|
|
&sv_conmode_symtab,
|
|
|
|
};
|
|
|
|
static cvar_t sv_conmode_cvar = {
|
|
|
|
.name = "sv_conmode",
|
|
|
|
.description =
|
|
|
|
"Set the console input mode (command, chat)",
|
|
|
|
.default_value = "command",
|
|
|
|
.flags = CVAR_NONE,
|
2022-04-24 11:46:06 +00:00
|
|
|
.value = { .type = &sv_conmode_type, .value = &sv_con_data.exec_line },
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
};
|
|
|
|
static int sv_use_curses;
|
|
|
|
static cvar_t sv_use_curses_cvar = {
|
|
|
|
.name = "sv_use_curses",
|
|
|
|
.description =
|
|
|
|
"Set to 1 to enable curses server console.",
|
|
|
|
.default_value = "0",
|
|
|
|
.flags = CVAR_ROM,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_use_curses },
|
|
|
|
};
|
2002-08-07 18:46:53 +00:00
|
|
|
|
2021-03-29 08:54:39 +00:00
|
|
|
#ifdef HAVE_NCURSES
|
2005-06-14 11:30:33 +00:00
|
|
|
|
2021-07-06 02:55:29 +00:00
|
|
|
static void key_event (knum_t key, short unicode, qboolean down);
|
|
|
|
|
2005-06-14 11:30:33 +00:00
|
|
|
enum {
|
|
|
|
sv_resize_x = 1,
|
|
|
|
sv_resize_y = 2,
|
|
|
|
sv_scroll = 4,
|
|
|
|
sv_cursor = 8,
|
|
|
|
};
|
|
|
|
|
2001-07-16 23:15:27 +00:00
|
|
|
static int use_curses = 1;
|
2001-07-16 21:39:50 +00:00
|
|
|
|
2005-06-14 11:30:33 +00:00
|
|
|
static view_t *output;
|
|
|
|
static view_t *status;
|
|
|
|
static view_t *input;
|
2001-07-16 23:15:27 +00:00
|
|
|
static int screen_x, screen_y;
|
2020-03-23 07:16:50 +00:00
|
|
|
static volatile sig_atomic_t interrupted;
|
2010-01-13 06:47:48 +00:00
|
|
|
static int batch_print;
|
2001-07-16 23:15:27 +00:00
|
|
|
|
2001-09-16 05:41:28 +00:00
|
|
|
#define MAXCMDLINE 256
|
|
|
|
|
2001-09-30 05:59:33 +00:00
|
|
|
#define BUFFER_SIZE 32768
|
|
|
|
#define MAX_LINES 1024
|
2004-01-22 04:07:39 +00:00
|
|
|
static int view_offset;
|
2001-09-30 05:59:33 +00:00
|
|
|
|
2007-04-09 00:10:10 +00:00
|
|
|
#define CP_YELLOW_BLACK (1)
|
|
|
|
#define CP_GREEN_BLACK (2)
|
|
|
|
#define CP_RED_BLACK (3)
|
|
|
|
#define CP_CYAN_BLACK (4)
|
|
|
|
#define CP_MAGENTA_BLACK (5)
|
|
|
|
#define CP_YELLOW_BLUE (6)
|
|
|
|
#define CP_GREEN_BLUE (7)
|
|
|
|
#define CP_RED_BLUE (8)
|
|
|
|
#define CP_CYAN_BLUE (9)
|
|
|
|
#define CP_MAGENTA_BLUE (10)
|
2021-12-27 15:06:12 +00:00
|
|
|
#define CP_WHITE_BLUE (11)
|
2007-04-09 00:10:10 +00:00
|
|
|
|
|
|
|
static chtype attr_table[16] = {
|
|
|
|
A_NORMAL,
|
|
|
|
COLOR_PAIR (CP_GREEN_BLACK),
|
|
|
|
COLOR_PAIR (CP_RED_BLACK),
|
|
|
|
0,
|
|
|
|
COLOR_PAIR (CP_YELLOW_BLACK),
|
|
|
|
COLOR_PAIR (CP_CYAN_BLACK),
|
|
|
|
COLOR_PAIR (CP_MAGENTA_BLACK),
|
|
|
|
0,
|
2021-12-27 15:06:12 +00:00
|
|
|
COLOR_PAIR(CP_WHITE_BLUE),
|
|
|
|
A_BOLD | COLOR_PAIR (CP_GREEN_BLUE),
|
|
|
|
A_BOLD | COLOR_PAIR (CP_RED_BLUE),
|
2007-04-09 00:10:10 +00:00
|
|
|
0,
|
2021-12-27 15:06:12 +00:00
|
|
|
A_BOLD | COLOR_PAIR (CP_YELLOW_BLUE),
|
|
|
|
A_BOLD | COLOR_PAIR (CP_CYAN_BLUE),
|
|
|
|
A_BOLD | COLOR_PAIR (CP_MAGENTA_BLUE),
|
2007-04-09 00:10:10 +00:00
|
|
|
0,
|
2001-07-16 21:39:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const byte attr_map[256] = {
|
2007-04-09 00:10:10 +00:00
|
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2,
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
2001-07-16 21:39:50 +00:00
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
2007-04-09 00:10:10 +00:00
|
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 6, 6, 0, 6, 6,
|
|
|
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
2001-07-16 21:39:50 +00:00
|
|
|
};
|
|
|
|
|
2001-09-10 12:56:23 +00:00
|
|
|
|
2001-10-01 16:09:06 +00:00
|
|
|
static inline void
|
2007-04-09 00:10:10 +00:00
|
|
|
draw_fun_char (WINDOW *win, byte c, int blue)
|
2001-10-01 16:09:06 +00:00
|
|
|
{
|
|
|
|
chtype ch = c;
|
2007-04-09 00:10:10 +00:00
|
|
|
int offset = blue ? 8 : 0;
|
|
|
|
ch = sys_char_map[ch] | attr_table[attr_map[ch] + offset];
|
2001-10-01 16:09:06 +00:00
|
|
|
waddch (win, ch);
|
|
|
|
}
|
|
|
|
|
2005-06-14 11:30:33 +00:00
|
|
|
static inline void
|
|
|
|
sv_refresh (view_t *view)
|
|
|
|
{
|
|
|
|
sv_view_t *sv_view = view->data;
|
2010-01-13 06:52:42 +00:00
|
|
|
wnoutrefresh ((WINDOW *) sv_view->win);
|
2005-06-14 11:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
sv_getch (view_t *view)
|
|
|
|
{
|
|
|
|
sv_view_t *sv_view = view->data;
|
2010-01-13 06:52:42 +00:00
|
|
|
return wgetch ((WINDOW *) sv_view->win);
|
2005-06-14 11:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
sv_draw (view_t *view)
|
|
|
|
{
|
|
|
|
sv_view_t *sv_view = view->data;
|
|
|
|
if (sv_view->draw)
|
|
|
|
sv_view->draw (view);
|
2010-01-13 06:52:42 +00:00
|
|
|
wnoutrefresh ((WINDOW *) sv_view->win);
|
2005-06-14 11:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
sv_setgeometry (view_t *view)
|
|
|
|
{
|
|
|
|
sv_view_t *sv_view = view->data;
|
|
|
|
WINDOW *win = sv_view->win;
|
|
|
|
wresize (win, view->ylen, view->xlen);
|
|
|
|
mvwin (win, view->yabs, view->xabs);
|
|
|
|
if (sv_view->setgeometry)
|
|
|
|
sv_view->setgeometry (view);
|
|
|
|
}
|
|
|
|
|
2010-01-13 06:47:21 +00:00
|
|
|
static void
|
|
|
|
sv_complete (inputline_t *il)
|
|
|
|
{
|
2010-01-13 06:47:48 +00:00
|
|
|
batch_print = 1;
|
2010-01-13 06:47:21 +00:00
|
|
|
Con_BasicCompleteCommandLine (il);
|
2010-01-13 06:47:48 +00:00
|
|
|
batch_print = 0;
|
|
|
|
|
|
|
|
sv_refresh (output);
|
|
|
|
sv_refresh (input);
|
|
|
|
doupdate ();
|
2010-01-13 06:47:21 +00:00
|
|
|
}
|
|
|
|
|
2001-09-26 16:31:36 +00:00
|
|
|
static void
|
2005-06-14 11:30:33 +00:00
|
|
|
draw_output (view_t *view)
|
2001-09-28 23:10:15 +00:00
|
|
|
{
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_view_t *sv_view = view->data;
|
|
|
|
WINDOW *win = sv_view->win;
|
|
|
|
con_buffer_t *output_buffer = sv_view->obj;
|
2012-05-21 23:23:22 +00:00
|
|
|
|
2001-09-30 05:59:33 +00:00
|
|
|
// this is not the most efficient way to update the screen, but oh well
|
2005-06-14 11:30:33 +00:00
|
|
|
int lines = view->ylen - 1; // leave a blank line
|
|
|
|
int width = view->xlen;
|
2004-01-22 04:07:39 +00:00
|
|
|
int cur_line = output_buffer->cur_line + view_offset;
|
2001-10-01 06:49:59 +00:00
|
|
|
int i, y;
|
2001-09-30 05:59:33 +00:00
|
|
|
|
|
|
|
if (lines < 1)
|
|
|
|
return;
|
|
|
|
|
2001-10-01 06:49:59 +00:00
|
|
|
for (y = i = 0; y < lines; i++, y++) {
|
2001-09-30 05:59:33 +00:00
|
|
|
con_line_t *l = Con_BufferLine (output_buffer, cur_line - i);
|
|
|
|
if (!l->text) {
|
|
|
|
i--;
|
|
|
|
break;
|
|
|
|
}
|
2001-10-01 06:49:59 +00:00
|
|
|
y += l->len / width; // really dumb line wrap algo :)
|
2001-09-30 05:59:33 +00:00
|
|
|
}
|
2001-10-01 06:49:59 +00:00
|
|
|
cur_line -= i;
|
|
|
|
y -= lines;
|
2005-06-14 11:30:33 +00:00
|
|
|
wclear (win);
|
|
|
|
wmove (win, 0, 0);
|
2001-09-30 05:59:33 +00:00
|
|
|
do {
|
|
|
|
con_line_t *l = Con_BufferLine (output_buffer, cur_line++);
|
|
|
|
byte *text = l->text;
|
|
|
|
int len = l->len;
|
|
|
|
|
2001-10-01 06:49:59 +00:00
|
|
|
if (y > 0) {
|
|
|
|
text += y * width;
|
|
|
|
len -= y * width;
|
2012-05-21 23:23:22 +00:00
|
|
|
y = 0;
|
2001-10-01 06:49:59 +00:00
|
|
|
if (len < 1) {
|
|
|
|
len = 1;
|
|
|
|
text = l->text + l->len - 1;
|
|
|
|
}
|
2001-09-30 05:59:33 +00:00
|
|
|
}
|
2001-10-01 16:09:06 +00:00
|
|
|
while (len--)
|
2007-04-09 00:10:10 +00:00
|
|
|
draw_fun_char (win, *text++, 0);
|
2004-01-22 04:07:39 +00:00
|
|
|
} while (cur_line < output_buffer->cur_line + view_offset);
|
2001-09-28 23:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2005-06-14 11:30:33 +00:00
|
|
|
draw_status (view_t *view)
|
2001-09-28 23:10:15 +00:00
|
|
|
{
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_view_t *sv_view = view->data;
|
2007-04-09 00:10:10 +00:00
|
|
|
WINDOW *win = sv_view->win;
|
|
|
|
sv_sbar_t *sb = sv_view->obj;
|
|
|
|
int i;
|
|
|
|
char *old = alloca (sb->width);
|
|
|
|
|
|
|
|
memcpy (old, sb->text, sb->width);
|
|
|
|
memset (sb->text, ' ', sb->width);
|
|
|
|
view_draw (view);
|
|
|
|
if (memcmp (old, sb->text, sb->width)) {
|
2021-12-27 15:06:12 +00:00
|
|
|
wbkgdset (win, COLOR_PAIR (CP_WHITE_BLUE));
|
2007-04-09 00:10:10 +00:00
|
|
|
wmove (win, 0, 0);
|
|
|
|
for (i = 0; i < sb->width; i++)
|
|
|
|
draw_fun_char (win, sb->text[i], 1);
|
|
|
|
}
|
2001-09-28 23:10:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2005-06-14 11:30:33 +00:00
|
|
|
draw_input_line (inputline_t *il)
|
2001-09-26 16:31:36 +00:00
|
|
|
{
|
2005-06-14 11:30:33 +00:00
|
|
|
view_t *view = il->user_data;
|
|
|
|
sv_view_t *sv_view = view->data;
|
|
|
|
WINDOW *win = sv_view->win;
|
2003-04-17 00:01:48 +00:00
|
|
|
size_t i;
|
2001-09-26 16:31:36 +00:00
|
|
|
const char *text;
|
|
|
|
|
|
|
|
text = il->lines[il->edit_line] + il->scroll;
|
|
|
|
wmove (win, 0, 0);
|
|
|
|
if (il->scroll) {
|
2007-04-09 00:10:10 +00:00
|
|
|
waddch (win, '<' | COLOR_PAIR (CP_CYAN_BLACK));
|
2001-09-26 16:31:36 +00:00
|
|
|
text++;
|
|
|
|
} else {
|
|
|
|
waddch (win, *text++);
|
|
|
|
}
|
|
|
|
for (i = 0; i < il->width - 2 && *text; i++) {
|
|
|
|
chtype ch = (byte)*text++;
|
|
|
|
ch = sys_char_map[ch] | attr_table[attr_map[ch]];
|
|
|
|
waddch (win, ch);
|
|
|
|
}
|
|
|
|
while (i++ < il->width - 2) {
|
|
|
|
waddch (win, ' ');
|
|
|
|
}
|
|
|
|
if (*text) {
|
2007-04-09 00:10:10 +00:00
|
|
|
waddch (win, '>' | COLOR_PAIR (CP_CYAN_BLACK));
|
2001-09-26 16:31:36 +00:00
|
|
|
} else {
|
|
|
|
waddch (win, ' ');
|
|
|
|
}
|
|
|
|
wmove (win, 0, il->linepos - il->scroll);
|
2005-06-14 11:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_input (view_t *view)
|
|
|
|
{
|
|
|
|
sv_view_t *sv_view = view->data;
|
|
|
|
draw_input_line (sv_view->obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setgeometry_input (view_t *view)
|
|
|
|
{
|
|
|
|
sv_view_t *sv_view = view->data;
|
|
|
|
inputline_t *il = sv_view->obj;
|
|
|
|
il->width = view->xlen;
|
2001-09-26 16:31:36 +00:00
|
|
|
}
|
|
|
|
|
2007-04-09 00:10:10 +00:00
|
|
|
static void
|
|
|
|
setgeometry_status (view_t *view)
|
|
|
|
{
|
|
|
|
sv_view_t *sv_view = view->data;
|
|
|
|
sv_sbar_t *sb = sv_view->obj;
|
|
|
|
sb->width = view->xlen;
|
|
|
|
sb->text = realloc (sb->text, sb->width);
|
|
|
|
memset (sb->text, 0, sb->width); // force an update
|
|
|
|
}
|
2010-12-23 02:40:16 +00:00
|
|
|
#ifdef SIGWINCH
|
2001-09-25 20:16:24 +00:00
|
|
|
static void
|
|
|
|
sigwinch (int sig)
|
|
|
|
{
|
2001-09-25 20:35:37 +00:00
|
|
|
interrupted = 1;
|
2001-09-25 20:16:24 +00:00
|
|
|
}
|
2010-12-23 02:40:16 +00:00
|
|
|
#endif
|
2010-01-13 06:47:48 +00:00
|
|
|
static void
|
|
|
|
get_size (int *xlen, int *ylen)
|
|
|
|
{
|
2020-03-23 07:01:07 +00:00
|
|
|
#ifdef SIGWINCH
|
2010-01-13 06:47:48 +00:00
|
|
|
struct winsize size;
|
|
|
|
|
|
|
|
*xlen = *ylen = 0;
|
|
|
|
if (ioctl (fileno (stdout), TIOCGWINSZ, &size) != 0)
|
|
|
|
return;
|
|
|
|
*xlen = size.ws_col;
|
|
|
|
*ylen = size.ws_row;
|
2020-03-23 07:01:07 +00:00
|
|
|
#else
|
2010-12-23 02:40:16 +00:00
|
|
|
getmaxyx (stdscr, *ylen, *xlen);
|
2020-03-23 07:01:07 +00:00
|
|
|
#endif
|
2010-01-13 06:47:48 +00:00
|
|
|
}
|
|
|
|
|
2005-06-13 09:41:48 +00:00
|
|
|
static void
|
|
|
|
process_input (void)
|
|
|
|
{
|
|
|
|
int ch;
|
|
|
|
int escape = 0;
|
|
|
|
|
2020-03-23 07:01:07 +00:00
|
|
|
if (__builtin_expect (interrupted, 0)) {
|
2005-06-13 09:41:48 +00:00
|
|
|
interrupted = 0;
|
2020-03-23 07:01:07 +00:00
|
|
|
#ifdef SIGWINCH
|
2010-01-13 06:47:48 +00:00
|
|
|
get_size (&screen_x, &screen_y);
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_dev, "resizing to %d x %d\n", screen_x, screen_y);
|
2010-01-13 06:47:48 +00:00
|
|
|
resizeterm (screen_y, screen_x);
|
|
|
|
con_linewidth = screen_x;
|
|
|
|
view_resize (sv_con_data.view, screen_x, screen_y);
|
|
|
|
sv_con_data.view->draw (sv_con_data.view);
|
2010-12-23 02:40:16 +00:00
|
|
|
#endif
|
2005-06-13 09:41:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (ch = 1; ch; ) {
|
2005-06-14 11:30:33 +00:00
|
|
|
ch = sv_getch (input);
|
2005-06-13 09:41:48 +00:00
|
|
|
if (ch == ERR)
|
|
|
|
escape = 0;
|
|
|
|
if (escape) {
|
|
|
|
switch (escape) {
|
|
|
|
case 1:
|
|
|
|
if (ch == '[') {
|
|
|
|
escape = 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
switch (ch) {
|
|
|
|
case '1':
|
|
|
|
escape = 3;
|
|
|
|
continue;
|
|
|
|
case '4':
|
|
|
|
escape = 4;
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
escape = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (ch == '~')
|
|
|
|
ch = KEY_HOME;
|
|
|
|
escape = 0;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if (ch == '~')
|
|
|
|
ch = KEY_END;
|
|
|
|
escape = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (ch) {
|
|
|
|
case '\033':
|
|
|
|
escape = 1;
|
|
|
|
continue;
|
|
|
|
case KEY_ENTER:
|
|
|
|
case '\n':
|
|
|
|
case '\r':
|
|
|
|
ch = QFK_RETURN;
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
ch = QFK_TAB;
|
|
|
|
break;
|
|
|
|
case KEY_BACKSPACE:
|
|
|
|
case '\b':
|
|
|
|
ch = QFK_BACKSPACE;
|
|
|
|
break;
|
|
|
|
case KEY_DC:
|
|
|
|
ch = QFK_DELETE;
|
|
|
|
break;
|
|
|
|
case KEY_RIGHT:
|
|
|
|
ch = QFK_RIGHT;
|
|
|
|
break;
|
|
|
|
case KEY_LEFT:
|
|
|
|
ch = QFK_LEFT;
|
|
|
|
break;
|
|
|
|
case KEY_UP:
|
|
|
|
ch = QFK_UP;
|
|
|
|
break;
|
|
|
|
case KEY_DOWN:
|
|
|
|
ch = QFK_DOWN;
|
|
|
|
break;
|
|
|
|
case KEY_HOME:
|
|
|
|
ch = QFK_HOME;
|
|
|
|
break;
|
|
|
|
case KEY_END:
|
|
|
|
ch = QFK_END;
|
|
|
|
break;
|
|
|
|
case KEY_NPAGE:
|
|
|
|
ch = QFK_PAGEDOWN;
|
|
|
|
break;
|
|
|
|
case KEY_PPAGE:
|
|
|
|
ch = QFK_PAGEUP;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (ch < 0 || ch >= 256)
|
|
|
|
ch = 0;
|
|
|
|
}
|
2021-07-06 02:55:29 +00:00
|
|
|
key_event (ch, 0, 1);
|
2005-06-13 09:41:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
key_event (knum_t key, short unicode, qboolean down)
|
|
|
|
{
|
|
|
|
int ovf = view_offset;
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_view_t *sv_view;
|
|
|
|
con_buffer_t *buffer;
|
2005-06-13 09:41:48 +00:00
|
|
|
|
|
|
|
switch (key) {
|
|
|
|
case QFK_PAGEUP:
|
|
|
|
view_offset -= 10;
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_view = output->data;
|
|
|
|
buffer = sv_view->obj;
|
|
|
|
if (view_offset <= -(buffer->num_lines - (screen_y - 3)))
|
|
|
|
view_offset = -(buffer->num_lines - (screen_y - 3)) + 1;
|
2005-06-13 09:41:48 +00:00
|
|
|
if (ovf != view_offset)
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_draw (output);
|
2005-06-13 09:41:48 +00:00
|
|
|
break;
|
|
|
|
case QFK_PAGEDOWN:
|
|
|
|
view_offset += 10;
|
|
|
|
if (view_offset > 0)
|
|
|
|
view_offset = 0;
|
|
|
|
if (ovf != view_offset)
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_draw (output);
|
2005-06-13 09:41:48 +00:00
|
|
|
break;
|
|
|
|
case '\f':
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_draw (output);
|
2005-06-13 09:41:48 +00:00
|
|
|
break;
|
|
|
|
default:
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_view = input->data;
|
|
|
|
Con_ProcessInputLine (sv_view->obj, key);
|
2010-01-13 06:52:42 +00:00
|
|
|
sv_refresh (input);
|
2005-06-13 09:41:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-01-13 06:52:42 +00:00
|
|
|
doupdate ();
|
2005-06-13 09:41:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print (char *txt)
|
|
|
|
{
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_view_t *sv_view = output->data;
|
|
|
|
Con_BufferAddText (sv_view->obj, txt);
|
2005-06-13 09:41:48 +00:00
|
|
|
if (!view_offset) {
|
|
|
|
while (*txt)
|
2007-04-09 00:10:10 +00:00
|
|
|
draw_fun_char (sv_view->win, (byte) *txt++, 0);
|
2010-01-13 06:47:48 +00:00
|
|
|
if (!batch_print) {
|
|
|
|
sv_refresh (output);
|
|
|
|
doupdate ();
|
|
|
|
}
|
2005-06-13 09:41:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-14 11:30:33 +00:00
|
|
|
static view_t *
|
|
|
|
create_window (view_t *parent, int xpos, int ypos, int xlen, int ylen,
|
|
|
|
grav_t grav, void *obj, int opts, void (*draw) (view_t *),
|
|
|
|
void (*setgeometry) (view_t *))
|
|
|
|
{
|
|
|
|
view_t *view;
|
|
|
|
sv_view_t *sv_view;
|
|
|
|
|
|
|
|
sv_view = calloc (1, sizeof (sv_view_t));
|
|
|
|
sv_view->obj = obj;
|
|
|
|
sv_view->win = newwin (ylen, xlen, 0, 0); // will get moved when added
|
|
|
|
scrollok (sv_view->win, (opts & sv_scroll) ? TRUE : FALSE);
|
|
|
|
leaveok (sv_view->win, (opts & sv_cursor) ? FALSE : TRUE);
|
|
|
|
nodelay (sv_view->win, TRUE);
|
|
|
|
keypad (sv_view->win, TRUE);
|
|
|
|
sv_view->draw = draw;
|
|
|
|
sv_view->setgeometry = setgeometry;
|
|
|
|
|
|
|
|
view = view_new (xpos, ypos, xlen, ylen, grav);
|
|
|
|
view->data = sv_view;
|
|
|
|
view->draw = sv_draw;
|
|
|
|
view->setgeometry = sv_setgeometry;
|
|
|
|
view->resize_x = (opts & sv_resize_x) != 0;
|
|
|
|
view->resize_y = (opts & sv_resize_y) != 0;
|
|
|
|
view_add (parent, view);
|
|
|
|
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
2011-03-26 23:03:39 +00:00
|
|
|
static void
|
|
|
|
exec_line (inputline_t *il)
|
|
|
|
{
|
|
|
|
Con_ExecLine (il->line);
|
|
|
|
}
|
|
|
|
|
2005-06-14 11:30:33 +00:00
|
|
|
static inputline_t *
|
|
|
|
create_input_line (int width)
|
|
|
|
{
|
|
|
|
inputline_t *input_line;
|
|
|
|
|
|
|
|
input_line = Con_CreateInputLine (16, MAXCMDLINE, ']');
|
2010-01-13 06:47:21 +00:00
|
|
|
input_line->complete = sv_complete;
|
2011-03-26 23:03:39 +00:00
|
|
|
input_line->enter = exec_line;
|
2005-06-14 11:30:33 +00:00
|
|
|
input_line->user_data = input;
|
|
|
|
input_line->draw = draw_input_line;
|
|
|
|
input_line->width = width;
|
|
|
|
|
|
|
|
return input_line;
|
|
|
|
}
|
|
|
|
|
2005-06-13 09:41:48 +00:00
|
|
|
static void
|
|
|
|
init (void)
|
|
|
|
{
|
2010-12-23 02:40:16 +00:00
|
|
|
#ifdef SIGWINCH
|
2020-03-23 07:01:07 +00:00
|
|
|
struct sigaction action = {};
|
|
|
|
action.sa_handler = sigwinch;
|
|
|
|
sigaction (SIGWINCH, &action, 0);
|
2010-12-23 02:40:16 +00:00
|
|
|
#endif
|
2005-06-13 09:41:48 +00:00
|
|
|
|
|
|
|
initscr ();
|
|
|
|
start_color ();
|
|
|
|
cbreak ();
|
|
|
|
noecho ();
|
|
|
|
|
|
|
|
nonl ();
|
|
|
|
|
2010-01-13 06:47:48 +00:00
|
|
|
get_size (&screen_x, &screen_y);
|
2005-06-14 11:30:33 +00:00
|
|
|
sv_con_data.view = view_new (0, 0, screen_x, screen_y, grav_northwest);
|
|
|
|
|
|
|
|
output = create_window (sv_con_data.view,
|
|
|
|
0, 0, screen_x, screen_y - 2, grav_northwest,
|
|
|
|
Con_CreateBuffer (BUFFER_SIZE, MAX_LINES),
|
|
|
|
sv_resize_x | sv_resize_y | sv_scroll,
|
|
|
|
draw_output, 0);
|
|
|
|
|
|
|
|
status = create_window (sv_con_data.view,
|
|
|
|
0, 1, screen_x, 1, grav_southwest,
|
2007-04-09 00:10:10 +00:00
|
|
|
calloc (1, sizeof (sv_sbar_t)),
|
|
|
|
sv_resize_x,
|
|
|
|
draw_status, setgeometry_status);
|
|
|
|
sv_con_data.status_view = status;
|
2005-06-14 11:30:33 +00:00
|
|
|
|
|
|
|
input = create_window (sv_con_data.view,
|
|
|
|
0, 0, screen_x, 1, grav_southwest,
|
|
|
|
create_input_line (screen_x),
|
|
|
|
sv_resize_x | sv_cursor,
|
|
|
|
draw_input, setgeometry_input);
|
|
|
|
((inputline_t *) ((sv_view_t *) input->data)->obj)->user_data = input;
|
2005-06-13 09:41:48 +00:00
|
|
|
|
2007-04-09 00:10:10 +00:00
|
|
|
init_pair (CP_YELLOW_BLACK, COLOR_YELLOW, COLOR_BLACK);
|
|
|
|
init_pair (CP_GREEN_BLACK, COLOR_GREEN, COLOR_BLACK);
|
|
|
|
init_pair (CP_RED_BLACK, COLOR_RED, COLOR_BLACK);
|
|
|
|
init_pair (CP_CYAN_BLACK, COLOR_CYAN, COLOR_BLACK);
|
|
|
|
init_pair (CP_MAGENTA_BLACK, COLOR_MAGENTA, COLOR_BLACK);
|
|
|
|
|
|
|
|
init_pair (CP_YELLOW_BLUE, COLOR_YELLOW, COLOR_BLUE);
|
|
|
|
init_pair (CP_GREEN_BLUE, COLOR_GREEN, COLOR_BLUE);
|
|
|
|
init_pair (CP_RED_BLUE, COLOR_RED, COLOR_BLUE);
|
|
|
|
init_pair (CP_CYAN_BLUE, COLOR_CYAN, COLOR_BLUE);
|
|
|
|
init_pair (CP_MAGENTA_BLUE, COLOR_MAGENTA, COLOR_BLUE);
|
2021-12-27 15:06:12 +00:00
|
|
|
init_pair (CP_WHITE_BLUE, COLOR_WHITE, COLOR_BLUE);
|
2005-06-13 09:41:48 +00:00
|
|
|
|
|
|
|
con_linewidth = screen_x;
|
|
|
|
|
2007-04-09 00:22:17 +00:00
|
|
|
sv_con_data.view->draw (sv_con_data.view);
|
2010-01-13 06:47:48 +00:00
|
|
|
wrefresh (curscr);
|
2005-06-13 09:41:48 +00:00
|
|
|
}
|
2001-09-21 17:28:35 +00:00
|
|
|
#endif
|
2001-09-16 05:41:28 +00:00
|
|
|
|
2002-08-07 18:46:53 +00:00
|
|
|
static void
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
sv_logfile_f (void *data, const cvar_t *cvar)
|
2002-08-07 18:46:53 +00:00
|
|
|
{
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (!sv_logfile[0] || strequal (sv_logfile, "none")) {
|
2002-08-07 18:46:53 +00:00
|
|
|
if (log_file)
|
|
|
|
Qclose (log_file);
|
|
|
|
log_file = 0;
|
|
|
|
} else {
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
char *fname = strdup (sv_logfile);
|
2002-08-07 18:46:53 +00:00
|
|
|
char *flags = strrchr (fname, ':');
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
if (flags) {
|
2002-08-07 18:46:53 +00:00
|
|
|
*flags++ = 0;
|
2003-01-06 18:28:13 +00:00
|
|
|
flags = nva ("a%s", flags);
|
|
|
|
} else {
|
|
|
|
flags = nva ("a");
|
|
|
|
}
|
2003-05-23 17:17:01 +00:00
|
|
|
log_file = QFS_Open (fname, flags);
|
2002-08-07 18:46:53 +00:00
|
|
|
free (flags);
|
|
|
|
free (fname);
|
|
|
|
}
|
|
|
|
}
|
2001-09-16 05:41:28 +00:00
|
|
|
|
2007-04-07 05:50:29 +00:00
|
|
|
static int
|
|
|
|
sv_exec_line_command (void *data, const char *line)
|
|
|
|
{
|
|
|
|
Cbuf_AddText (sv_con_data.cbuf, line);
|
|
|
|
Cbuf_AddText (sv_con_data.cbuf, "\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sv_exec_line_chat (void *data, const char *line)
|
|
|
|
{
|
|
|
|
Cbuf_AddText (sv_con_data.cbuf, "say ");
|
|
|
|
Cbuf_AddText (sv_con_data.cbuf, line);
|
|
|
|
Cbuf_AddText (sv_con_data.cbuf, "\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-07-16 23:15:27 +00:00
|
|
|
static void
|
|
|
|
C_Init (void)
|
2001-07-16 21:39:50 +00:00
|
|
|
{
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
Cvar_Register (&sv_use_curses_cvar, 0, 0);
|
2021-03-29 08:54:39 +00:00
|
|
|
#ifdef HAVE_NCURSES
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
use_curses = sv_use_curses;
|
2001-07-16 23:15:27 +00:00
|
|
|
if (use_curses) {
|
2005-06-13 09:41:48 +00:00
|
|
|
init ();
|
2001-08-09 15:33:44 +00:00
|
|
|
} else
|
2001-07-16 23:15:27 +00:00
|
|
|
#endif
|
2001-08-09 15:33:44 +00:00
|
|
|
setvbuf (stdout, 0, _IOLBF, BUFSIZ);
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
Cvar_Register (&sv_logfile_cvar, sv_logfile_f, 0);
|
|
|
|
Cvar_Register (&sv_conmode_cvar, 0, 0);
|
2001-07-16 21:39:50 +00:00
|
|
|
}
|
|
|
|
|
2001-07-16 23:15:27 +00:00
|
|
|
static void
|
2019-07-12 14:15:26 +00:00
|
|
|
C_shutdown (void)
|
2001-07-16 21:39:50 +00:00
|
|
|
{
|
2002-08-07 18:46:53 +00:00
|
|
|
if (log_file) {
|
|
|
|
Qclose (log_file);
|
|
|
|
log_file = 0;
|
|
|
|
}
|
2021-03-29 08:54:39 +00:00
|
|
|
#ifdef HAVE_NCURSES
|
2001-07-16 23:15:27 +00:00
|
|
|
if (use_curses)
|
|
|
|
endwin ();
|
|
|
|
#endif
|
2001-07-16 21:39:50 +00:00
|
|
|
}
|
|
|
|
|
2021-03-27 10:52:59 +00:00
|
|
|
static __attribute__((format(PRINTF, 1, 0))) void
|
2001-07-16 23:15:27 +00:00
|
|
|
C_Print (const char *fmt, va_list args)
|
2001-07-16 21:39:50 +00:00
|
|
|
{
|
2002-03-08 23:11:42 +00:00
|
|
|
static dstring_t *buffer;
|
2001-09-25 16:19:26 +00:00
|
|
|
|
2002-03-08 23:11:42 +00:00
|
|
|
if (!buffer)
|
|
|
|
buffer = dstring_new ();
|
|
|
|
|
|
|
|
dvsprintf (buffer, fmt, args);
|
|
|
|
|
2003-10-22 09:04:18 +00:00
|
|
|
if (log_file) {
|
2002-08-07 18:46:53 +00:00
|
|
|
Qputs (log_file, buffer->str);
|
2003-10-22 09:04:18 +00:00
|
|
|
Qflush (log_file);
|
|
|
|
}
|
2021-03-29 08:54:39 +00:00
|
|
|
#ifdef HAVE_NCURSES
|
2001-07-16 23:15:27 +00:00
|
|
|
if (use_curses) {
|
2005-06-13 09:41:48 +00:00
|
|
|
print (buffer->str);
|
2001-07-16 23:15:27 +00:00
|
|
|
} else
|
|
|
|
#endif
|
2001-09-25 16:13:41 +00:00
|
|
|
{
|
2005-06-13 09:41:48 +00:00
|
|
|
unsigned char *txt = (unsigned char *) buffer->str;
|
2001-09-25 16:19:26 +00:00
|
|
|
while (*txt)
|
|
|
|
putc (sys_char_map[*txt++], stdout);
|
2001-09-25 16:13:41 +00:00
|
|
|
fflush (stdout);
|
|
|
|
}
|
2001-07-16 21:39:50 +00:00
|
|
|
}
|
|
|
|
|
2001-09-16 05:41:28 +00:00
|
|
|
static void
|
|
|
|
C_ProcessInput (void)
|
|
|
|
{
|
2021-03-29 08:54:39 +00:00
|
|
|
#ifdef HAVE_NCURSES
|
2001-09-16 05:41:28 +00:00
|
|
|
if (use_curses) {
|
2005-06-13 09:41:48 +00:00
|
|
|
process_input ();
|
2001-09-16 05:41:28 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
while (1) {
|
|
|
|
const char *cmd = Sys_ConsoleInput ();
|
|
|
|
if (!cmd)
|
2001-09-16 06:08:09 +00:00
|
|
|
break;
|
2007-04-07 05:50:29 +00:00
|
|
|
Con_ExecLine (cmd);
|
2001-09-16 05:41:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-07-25 22:21:47 +00:00
|
|
|
C_DrawConsole (void)
|
2002-01-19 04:37:47 +00:00
|
|
|
{
|
2007-04-09 00:10:10 +00:00
|
|
|
// only the status bar is drawn because the inputline and output views
|
|
|
|
// take care of themselves
|
|
|
|
if (sv_con_data.status_view)
|
|
|
|
sv_con_data.status_view->draw (sv_con_data.status_view);
|
2002-01-19 04:37:47 +00:00
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2002-01-19 04:37:47 +00:00
|
|
|
C_CheckResize (void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2002-01-19 04:37:47 +00:00
|
|
|
C_NewMap (void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2001-07-16 23:15:27 +00:00
|
|
|
static general_funcs_t plugin_info_general_funcs = {
|
2021-06-26 06:43:17 +00:00
|
|
|
.init = C_Init,
|
|
|
|
.shutdown = C_shutdown,
|
2001-07-16 23:15:27 +00:00
|
|
|
};
|
|
|
|
static general_data_t plugin_info_general_data;
|
2001-07-16 21:39:50 +00:00
|
|
|
|
2001-07-16 23:15:27 +00:00
|
|
|
static console_funcs_t plugin_info_console_funcs = {
|
2021-06-26 06:43:17 +00:00
|
|
|
.print = C_Print,
|
|
|
|
.process_input = C_ProcessInput,
|
|
|
|
.draw_console = C_DrawConsole,
|
|
|
|
.check_resize = C_CheckResize,
|
|
|
|
.new_map = C_NewMap,
|
2001-07-16 23:15:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static plugin_funcs_t plugin_info_funcs = {
|
2021-06-26 06:43:17 +00:00
|
|
|
.general = &plugin_info_general_funcs,
|
|
|
|
.console = &plugin_info_console_funcs,
|
2001-07-16 23:15:27 +00:00
|
|
|
};
|
2001-07-16 21:39:50 +00:00
|
|
|
|
2001-07-16 23:15:27 +00:00
|
|
|
static plugin_data_t plugin_info_data = {
|
2021-06-26 06:43:17 +00:00
|
|
|
.general = &plugin_info_general_data,
|
|
|
|
.console = &sv_con_data,
|
2001-07-16 23:15:27 +00:00
|
|
|
};
|
2001-07-16 21:39:50 +00:00
|
|
|
|
2001-07-16 23:15:27 +00:00
|
|
|
static plugin_t plugin_info = {
|
|
|
|
qfp_console,
|
|
|
|
0,
|
|
|
|
QFPLUGIN_VERSION,
|
|
|
|
"0.1",
|
|
|
|
"server console driver",
|
|
|
|
"Copyright (C) 1996-1997 id Software, Inc.\n"
|
|
|
|
"Copyright (C) 1999,2000,2001 contributors of the QuakeForge"
|
|
|
|
" project\n"
|
|
|
|
"Please see the file \"AUTHORS\" for a list of contributors",
|
|
|
|
&plugin_info_funcs,
|
|
|
|
&plugin_info_data,
|
|
|
|
};
|
|
|
|
|
2003-08-01 19:53:46 +00:00
|
|
|
PLUGIN_INFO(console, server)
|
2001-07-16 23:15:27 +00:00
|
|
|
{
|
|
|
|
return &plugin_info;
|
2001-07-16 21:39:50 +00:00
|
|
|
}
|