2 * Command-line interface for the console
4 * 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 CLI_HISTORY_MAX 128
28 // Cut the buffer line if it becomes longer than this
29 #define CLI_CHARS_PER_LINE 128
30 // Cursor blink interval
31 #define CLI_BLINK_RATE (F1_0/2)
32 // Border in pixels from the most left to the first letter
33 #define CLI_CHAR_BORDER 4
34 // Default prompt used at the commandline
35 #define CLI_DEFAULT_PROMPT "]"
36 // Cursor shown if we are in insert mode
37 #define CLI_INS_CURSOR "_"
38 // Cursor shown if we are in overwrite mode
39 #define CLI_OVR_CURSOR "|"
41 int CLI_insert_mode; // Insert or Overwrite characters?
43 static char *CommandLines[CLI_HISTORY_MAX]; // List of all the past commands
44 static int TotalCommands; // Number of commands in the Back Commands
45 static char *Prompt; // Prompt displayed in command line
46 static char Command[CLI_CHARS_PER_LINE]; // current command in command line = lcommand + rcommand
47 static char LCommand[CLI_CHARS_PER_LINE]; // right hand side of cursor
48 static char RCommand[CLI_CHARS_PER_LINE]; // left hand side of cursor
49 static char VCommand[CLI_CHARS_PER_LINE]; // current visible command line
50 static size_t CursorPos; // Current cursor position in CurrentCommand
51 static size_t Offset; // CommandOffset (first visible char of command) - if command is too long to fit into console
52 static int CommandScrollBack; // How much the users scrolled back in the command lines
55 /* Frees all the memory loaded by the cli */
56 static void cli_free(void)
60 for (i = 0; i <= CLI_HISTORY_MAX - 1; i++) {
62 d_free(CommandLines[i]);
69 /* Initializes the cli */
75 CommandScrollBack = 0;
76 Prompt = d_strdup(CLI_DEFAULT_PROMPT);
78 memset(CommandLines, 0, sizeof(CommandLines));
79 memset(Command, 0, sizeof(Command));
80 memset(LCommand, 0, sizeof(LCommand));
81 memset(RCommand, 0, sizeof(RCommand));
82 memset(VCommand, 0, sizeof(VCommand));
88 /* Increments the command lines */
89 static void cli_newline(void)
93 if (CommandLines[CLI_HISTORY_MAX - 1])
94 d_free(CommandLines[CLI_HISTORY_MAX - 1]);
96 for (loop = CLI_HISTORY_MAX - 1; loop > 0; loop--)
97 CommandLines[loop] = CommandLines[loop - 1];
99 CommandLines[0] = NULL;
101 if (TotalCommands < CLI_HISTORY_MAX - 1)
106 /* Draws the command line the user is typing in to the screen */
107 /* completely rewritten by C.Wacha */
112 size_t commandbuffer;
113 fix cur_time = timer_get_fixed_seconds();
114 static fix LastBlinkTime = 0; // Last time the cursor blinked
115 static size_t LastCursorPos = 0; // Last cursor position
116 static int Blink = 0; // Is the cursor currently blinking
118 // Concatenate the left and right side to command
119 strcpy(Command, LCommand);
120 strncat(Command, RCommand, sizeof(Command) - strlen(Command) - 1);
122 gr_get_string_size(Command, &w, &h, &aw);
123 if (w > 0 && *Command)
124 real_aw = (float)w/(float)strlen(Command);
127 commandbuffer = (GWIDTH - 2*CLI_CHAR_BORDER)/real_aw - strlen(Prompt) - 1; // -1 to make cursor visible
129 //calculate display offset from current cursor position
130 if (CursorPos > commandbuffer && Offset < CursorPos - commandbuffer)
131 Offset = CursorPos - commandbuffer;
132 if(Offset > CursorPos)
135 // first add prompt to visible part
136 strcpy(VCommand, Prompt);
138 // then add the visible part of the command
139 strncat(VCommand, &Command[Offset], sizeof(VCommand) - strlen(VCommand) - 1);
141 gr_set_fontcolor(CON_color, -1);
143 // now display the result
144 gr_string(CLI_CHAR_BORDER, y-h, VCommand);
146 // at last add the cursor
147 // check if the blink period is over
148 if (cur_time > LastBlinkTime) {
149 LastBlinkTime = cur_time + CLI_BLINK_RATE;
156 // check if cursor has moved - if yes display cursor anyway
157 if (CursorPos != LastCursorPos) {
158 LastCursorPos = CursorPos;
159 LastBlinkTime = cur_time + CLI_BLINK_RATE;
164 int prompt_width, cmd_width, h, w;
166 gr_get_string_size(Prompt, &prompt_width, &h, &w);
167 gr_get_string_size(LCommand + Offset, &cmd_width, &h, &w);
168 x = CLI_CHAR_BORDER + prompt_width + cmd_width;
170 gr_string(x, y-h, CLI_INS_CURSOR);
172 gr_string(x, y-h, CLI_OVR_CURSOR);
177 /* Executes the command entered */
178 void cli_execute(void)
180 if(strlen(Command) > 0) {
183 // copy the input into the past commands strings
184 CommandLines[0] = d_strdup(Command);
186 // display the command including the prompt
187 con_printf(CON_NORMAL, "%s%s\n", Prompt, Command);
192 CommandScrollBack = -1;
197 void cli_autocomplete(void)
202 command = cmd_complete(LCommand);
205 return; // no tab completion took place so return silently
208 if (j > CLI_CHARS_PER_LINE - 2)
209 j = CLI_CHARS_PER_LINE - 1;
211 memset(LCommand, 0, sizeof(LCommand));
214 for (i = 0; i < j; i++) {
216 LCommand[i] = command[i];
218 // add a trailing space
221 LCommand[j+1] = '\0';
225 void cli_cursor_left(void)
227 char temp[CLI_CHARS_PER_LINE];
231 strcpy(temp, RCommand);
232 strcpy(RCommand, &LCommand[strlen(LCommand)-1]);
233 strcat(RCommand, temp);
234 LCommand[strlen(LCommand)-1] = '\0';
239 void cli_cursor_right(void)
241 char temp[CLI_CHARS_PER_LINE];
243 if(CursorPos < strlen(Command)) {
245 strncat(LCommand, RCommand, 1);
246 strcpy(temp, RCommand);
247 strcpy(RCommand, &temp[1]);
252 void cli_cursor_home(void)
254 char temp[CLI_CHARS_PER_LINE];
257 strcpy(temp, RCommand);
258 strcpy(RCommand, LCommand);
259 strncat(RCommand, temp, sizeof(RCommand) - strlen(RCommand) - 1);
260 memset(LCommand, 0, sizeof(LCommand));
264 void cli_cursor_end(void)
266 CursorPos = strlen(Command);
267 strncat(LCommand, RCommand, sizeof(LCommand) - strlen(LCommand) - 1);
268 memset(RCommand, 0, sizeof(RCommand));
272 void cli_cursor_del(void)
274 char temp[CLI_CHARS_PER_LINE];
276 if (strlen(RCommand) > 0) {
277 strcpy(temp, RCommand);
278 strcpy(RCommand, &temp[1]);
283 void cli_cursor_backspace(void)
289 LCommand[strlen(LCommand)-1] = '\0';
294 void cli_add_character(char character)
296 if (strlen(Command) < CLI_CHARS_PER_LINE - 1)
299 LCommand[strlen(LCommand)] = character;
300 LCommand[strlen(LCommand)] = '\0';
302 if (!CLI_insert_mode)
310 memset(Command, 0, sizeof(Command));
311 memset(LCommand, 0, sizeof(LCommand));
312 memset(RCommand, 0, sizeof(RCommand));
313 memset(VCommand, 0, sizeof(VCommand));
317 void cli_history_prev(void)
319 if(CommandScrollBack < TotalCommands - 1) {
320 /* move back a line in the command strings and copy the command to the current input string */
322 memset(RCommand, 0, sizeof(RCommand));
324 strcpy(LCommand, CommandLines[CommandScrollBack]);
325 CursorPos = strlen(CommandLines[CommandScrollBack]);
330 void cli_history_next(void)
332 if(CommandScrollBack > -1) {
333 /* move forward a line in the command strings and copy the command to the current input string */
335 memset(RCommand, 0, sizeof(RCommand));
336 memset(LCommand, 0, sizeof(LCommand));
338 if(CommandScrollBack > -1)
339 strcpy(LCommand, CommandLines[CommandScrollBack]);
340 CursorPos = strlen(LCommand);