2 * Code for controlling the console
3 * Based on an early version of SDL_Console
5 * Written By: Garrett Banuk <mongoose@mongeese.org>
6 * Code Cleanup and heavily extended by: Clemens Wacha <reflex-2000@gmx.net>
7 * Ported to use native Descent interfaces by: Bradley Bell <btb@icculus.org>
9 * This is free, just be sure to give us credit when using it
10 * in any of your programs.
27 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
29 #define CLI_NUM_LINES 128
30 // Cut the buffer line if it becomes longer than this
31 #define CLI_CHARS_PER_LINE 128
32 // Cursor blink frequency in ms
33 #define CLI_BLINK_RATE 500
34 // Border in pixels from the most left to the first letter
35 #define CLI_CHAR_BORDER 4
36 // Default prompt used at the commandline
37 #define CLI_DEFAULT_PROMPT "]"
38 // Cursor shown if we are in insert mode
39 #define CLI_INS_CURSOR "_"
40 // Cursor shown if we are in overwrite mode
41 #define CLI_OVR_CURSOR "|"
43 int CLI_insert_mode; // Insert or Overwrite characters?
45 static char **CommandLines; // List of all the past commands
46 static int TotalCommands; // Number of commands in the Back Commands
47 static int LineBuffer; // The number of visible lines in the console (autocalculated)
48 static char *Prompt; // Prompt displayed in command line
49 static char Command[CLI_CHARS_PER_LINE]; // current command in command line = lcommand + rcommand
50 static char LCommand[CLI_CHARS_PER_LINE]; // right hand side of cursor
51 static char RCommand[CLI_CHARS_PER_LINE]; // left hand side of cursor
52 static char VCommand[CLI_CHARS_PER_LINE]; // current visible command line
53 static int CursorPos; // Current cursor position in CurrentCommand
54 static int Offset; // CommandOffset (first visible char of command) - if command is too long to fit into console
55 static int CommandScrollBack; // How much the users scrolled back in the command lines
58 /* Frees all the memory loaded by the cli */
59 static void cli_free(void);
60 /* shift command history (the one you can switch with the up/down keys) */
61 static void cli_newline(void);
64 /* Initializes the cli */
73 CommandScrollBack = 0;
74 Prompt = d_strdup(CLI_DEFAULT_PROMPT);
75 LineBuffer = CLI_NUM_LINES;
77 CommandLines = (char **)d_malloc(sizeof(char *) * LineBuffer);
78 for (loop = 0; loop <= LineBuffer - 1; loop++) {
79 CommandLines[loop] = (char *)d_calloc(CLI_CHARS_PER_LINE, sizeof(char));
81 memset(Command, 0, CLI_CHARS_PER_LINE);
82 memset(LCommand, 0, CLI_CHARS_PER_LINE);
83 memset(RCommand, 0, CLI_CHARS_PER_LINE);
84 memset(VCommand, 0, CLI_CHARS_PER_LINE);
90 /* Frees all the memory loaded by the console */
91 static void cli_free(void)
95 for (i = 0; i <= LineBuffer - 1; i++) {
96 d_free(CommandLines[i]);
106 /* Increments the command lines */
107 static void cli_newline(void)
112 temp = CommandLines[LineBuffer - 1];
114 for (loop = LineBuffer - 1; loop > 0; loop--)
115 CommandLines[loop] = CommandLines[loop - 1];
117 CommandLines[0] = temp;
119 memset(CommandLines[0], 0, CLI_CHARS_PER_LINE);
120 if (TotalCommands < LineBuffer - 1)
125 /* Draws the command line the user is typing in to the screen */
126 /* completely rewritten by C.Wacha */
132 static unsigned int LastBlinkTime = 0; // Last time the consoles cursor blinked
133 static int LastCursorPos = 0; // Last Cursor Position
134 static int Blink = 0; // Is the cursor currently blinking
136 // Concatenate the left and right side to command
137 strcpy(Command, LCommand);
138 strncat(Command, RCommand, strlen(RCommand));
140 gr_get_string_size(Command, &w, &h, &aw);
141 if (w > 0 && strlen(Command))
142 real_aw = (float)w/(float)strlen(Command);
145 commandbuffer = (GWIDTH - 2*CLI_CHAR_BORDER)/real_aw - (int)strlen(Prompt) - 1; // -1 to make cursor visible
147 //calculate display offset from current cursor position
148 if (Offset < CursorPos - commandbuffer)
149 Offset = CursorPos - commandbuffer;
150 if(Offset > CursorPos)
153 // first add prompt to visible part
154 strcpy(VCommand, Prompt);
156 // then add the visible part of the command
157 strncat(VCommand, &Command[Offset], strlen(&Command[Offset]));
159 // now display the result
160 gr_string(CLI_CHAR_BORDER, y-h, VCommand);
162 // at last add the cursor
163 // check if the blink period is over
164 if (get_msecs() > LastBlinkTime) {
165 LastBlinkTime = get_msecs() + CLI_BLINK_RATE;
172 // check if cursor has moved - if yes display cursor anyway
173 if (CursorPos != LastCursorPos) {
174 LastCursorPos = CursorPos;
175 LastBlinkTime = get_msecs() + CLI_BLINK_RATE;
180 int prompt_width, cmd_width, h, w;
182 gr_get_string_size(Prompt, &prompt_width, &h, &w);
183 gr_get_string_size(LCommand + Offset, &cmd_width, &h, &w);
184 x = CLI_CHAR_BORDER + prompt_width + cmd_width;
186 gr_string(x, y-h, CLI_INS_CURSOR);
188 gr_string(x, y-h, CLI_OVR_CURSOR);
193 /* Executes the command entered */
194 void cli_execute(void)
196 if(strlen(Command) > 0) {
199 // copy the input into the past commands strings
200 strcpy(CommandLines[0], Command);
202 // display the command including the prompt
203 con_out("%s%s\n", Prompt, Command);
208 CommandScrollBack = -1;
213 void cli_autocomplete(void)
218 command = cmd_complete(LCommand);
221 return; // no tab completion took place so return silently
223 j = (int)strlen(command);
224 if (j > CLI_CHARS_PER_LINE - 2)
225 j = CLI_CHARS_PER_LINE-1;
227 memset(LCommand, 0, CLI_CHARS_PER_LINE);
230 for (i = 0; i < j; i++) {
232 LCommand[i] = command[i];
234 // add a trailing space
237 LCommand[j+1] = '\0';
241 void cli_cursor_left(void)
243 char temp[CLI_CHARS_PER_LINE];
247 strcpy(temp, RCommand);
248 strcpy(RCommand, &LCommand[strlen(LCommand)-1]);
249 strcat(RCommand, temp);
250 LCommand[strlen(LCommand)-1] = '\0';
255 void cli_cursor_right(void)
257 char temp[CLI_CHARS_PER_LINE];
259 if(CursorPos < strlen(Command)) {
261 strncat(LCommand, RCommand, 1);
262 strcpy(temp, RCommand);
263 strcpy(RCommand, &temp[1]);
268 void cli_cursor_home(void)
270 char temp[CLI_CHARS_PER_LINE];
273 strcpy(temp, RCommand);
274 strcpy(RCommand, LCommand);
275 strncat(RCommand, temp, strlen(temp));
276 memset(LCommand, 0, CLI_CHARS_PER_LINE);
280 void cli_cursor_end(void)
282 CursorPos = (int)strlen(Command);
283 strncat(LCommand, RCommand, strlen(RCommand));
284 memset(RCommand, 0, CLI_CHARS_PER_LINE);
288 void cli_cursor_del(void)
290 char temp[CLI_CHARS_PER_LINE];
292 if (strlen(RCommand) > 0) {
293 strcpy(temp, RCommand);
294 strcpy(RCommand, &temp[1]);
298 void cli_cursor_backspace(void)
305 LCommand[strlen(LCommand)-1] = '\0';
310 void cli_add_character(char character)
312 if (strlen(Command) < CLI_CHARS_PER_LINE - 1)
315 LCommand[strlen(LCommand)] = character;
316 LCommand[strlen(LCommand)] = '\0';
324 memset( Command, 0, CLI_CHARS_PER_LINE);
325 memset(LCommand, 0, CLI_CHARS_PER_LINE);
326 memset(RCommand, 0, CLI_CHARS_PER_LINE);
327 memset(VCommand, 0, CLI_CHARS_PER_LINE);
331 void cli_history_prev(void)
333 if(CommandScrollBack < TotalCommands - 1) {
334 /* move back a line in the command strings and copy the command to the current input string */
336 memset(RCommand, 0, CLI_CHARS_PER_LINE);
338 strcpy(LCommand, CommandLines[CommandScrollBack]);
339 CursorPos = (int)strlen(CommandLines[CommandScrollBack]);
344 void cli_history_next(void)
346 if(CommandScrollBack > -1) {
347 /* move forward a line in the command strings and copy the command to the current input string */
349 memset(RCommand, 0, CLI_CHARS_PER_LINE);
350 memset(LCommand, 0, CLI_CHARS_PER_LINE);
352 if(CommandScrollBack > -1)
353 strcpy(LCommand, CommandLines[CommandScrollBack]);
354 CursorPos = (int)strlen(LCommand);