]> icculus.org git repositories - btb/d2x.git/blob - main/cli.c
more unused stuff
[btb/d2x.git] / main / cli.c
1 /*
2  *  Code for controlling the console
3  *  Based on an early version of SDL_Console
4  *
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>
8  *
9  *  This is free, just be sure to give us credit when using it
10  *  in any of your programs.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 #include <conf.h>
15 #endif
16
17 #include <string.h>
18
19 #include "inferno.h"
20 #include "maths.h"
21 #include "gr.h"
22 #include "timer.h"
23 #include "u_mem.h"
24 #include "strutil.h"
25
26
27 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
28
29 #define CON_NUM_LINES           128
30 // Cut the buffer line if it becomes longer than this
31 #define CON_CHARS_PER_LINE      128
32 // Cursor blink frequency in ms
33 #define CON_BLINK_RATE          500
34 // Border in pixels from the most left to the first letter
35 #define CON_CHAR_BORDER         4
36 // Default prompt used at the commandline
37 #define CON_DEFAULT_PROMPT      "]"
38 // Cursor shown if we are in insert mode
39 #define CON_INS_CURSOR          "_"
40 // Cursor shown if we are in overwrite mode
41 #define CON_OVR_CURSOR          "|"
42
43
44 /* The console's data */
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 int VChars;              // The number of visible characters in one console line (autocalculated)
49 static char *Prompt;            // Prompt displayed in command line
50 static char  Command[CON_CHARS_PER_LINE];   // current command in command line = lcommand + rcommand
51 static char LCommand[CON_CHARS_PER_LINE];   // right hand side of cursor
52 static char RCommand[CON_CHARS_PER_LINE];   // left hand side of cursor
53 static char VCommand[CON_CHARS_PER_LINE];   // current visible command line
54 static int CursorPos;           // Current cursor position in CurrentCommand
55 static int Offset;              // CommandOffset (first visible char of command) - if command is too long to fit into console
56 int InsMode;                    // Insert or Overwrite characters?
57 static int CommandScrollBack;   // How much the users scrolled back in the command lines
58
59
60 /* Frees all the memory loaded by the console */
61 static void CON_Free(void);
62 /* shift command history (the one you can switch with the up/down keys) */
63 static void CON_NewLineCommand(void);
64
65
66 /* Initializes the console */
67 void cli_init()
68 {
69         int loop;
70
71         CommandLines = NULL;
72         TotalCommands = 0;
73         InsMode = 1;
74         CursorPos = 0;
75         CommandScrollBack = 0;
76         Prompt = d_strdup(CON_DEFAULT_PROMPT);
77
78         VChars = CON_CHARS_PER_LINE - 1;
79         LineBuffer = CON_NUM_LINES;
80
81         CommandLines = (char **)d_malloc(sizeof(char *) * LineBuffer);
82         for (loop = 0; loop <= LineBuffer - 1; loop++) {
83                 CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
84         }
85         memset(Command, 0, CON_CHARS_PER_LINE);
86         memset(LCommand, 0, CON_CHARS_PER_LINE);
87         memset(RCommand, 0, CON_CHARS_PER_LINE);
88         memset(VCommand, 0, CON_CHARS_PER_LINE);
89
90         atexit(CON_Free);
91 }
92
93
94 /* Frees all the memory loaded by the console */
95 static void CON_Free(void)
96 {
97         int i;
98
99         for (i = 0; i <= LineBuffer - 1; i++) {
100                 d_free(CommandLines[i]);
101         }
102         d_free(CommandLines);
103
104         CommandLines = NULL;
105
106         d_free(Prompt);
107 }
108
109
110 /* Increments the command lines */
111 static void CON_NewLineCommand(void)
112 {
113         int loop;
114         char *temp;
115
116         temp  = CommandLines[LineBuffer - 1];
117
118         for (loop = LineBuffer - 1; loop > 0; loop--)
119                 CommandLines[loop] = CommandLines[loop - 1];
120
121         CommandLines[0] = temp;
122
123         memset(CommandLines[0], 0, CON_CHARS_PER_LINE);
124         if (TotalCommands < LineBuffer - 1)
125                 TotalCommands++;
126 }
127
128
129 /* Draws the command line the user is typing in to the screen */
130 /* completely rewritten by C.Wacha */
131 void DrawCommandLine(int y)
132 {
133         int x;
134         int commandbuffer;
135         static unsigned int LastBlinkTime = 0;  // Last time the consoles cursor blinked
136         static int LastCursorPos = 0;           // Last Cursor Position
137         static int Blink = 0;                   // Is the cursor currently blinking
138
139         commandbuffer = VChars - (int)strlen(Prompt) - 1; // -1 to make cursor visible
140
141         // Concatenate the left and right side to command
142         strcpy(Command, LCommand);
143         strncat(Command, RCommand, strlen(RCommand));
144
145         //calculate display offset from current cursor position
146         if (Offset < CursorPos - commandbuffer)
147                 Offset = CursorPos - commandbuffer;
148         if(Offset > CursorPos)
149                 Offset = CursorPos;
150
151         // first add prompt to visible part
152         strcpy(VCommand, Prompt);
153
154         // then add the visible part of the command
155         strncat(VCommand, &Command[Offset], strlen(&Command[Offset]));
156
157         // now display the result
158         gr_string(CON_CHAR_BORDER, y - grd_curfont->ft_h, VCommand);
159
160         // at last add the cursor
161         // check if the blink period is over
162         if (get_msecs() > LastBlinkTime) {
163                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
164                 if(Blink)
165                         Blink = 0;
166                 else
167                         Blink = 1;
168         }
169
170         // check if cursor has moved - if yes display cursor anyway
171         if (CursorPos != LastCursorPos) {
172                 LastCursorPos = CursorPos;
173                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
174                 Blink = 1;
175         }
176
177         if (Blink) {
178                 int prompt_width, cmd_width, h, w;
179
180                 gr_get_string_size(Prompt, &prompt_width, &h, &w);
181                 gr_get_string_size(LCommand + Offset, &cmd_width, &h, &w);
182                 x = CON_CHAR_BORDER + prompt_width + cmd_width;
183                 if (InsMode)
184                         gr_string(x, y - grd_curfont->ft_h, CON_INS_CURSOR);
185                 else
186                         gr_string(x, y - grd_curfont->ft_h, CON_OVR_CURSOR);
187         }
188 }
189
190
191 /* Sets the Prompt for console */
192 void CON_SetPrompt(char* newprompt) {
193         // check length so we can still see at least 1 char :-)
194         if (strlen(newprompt) < VChars) {
195                 d_free(Prompt);
196                 Prompt = d_strdup(newprompt);
197         } else
198                 CON_Out("prompt too long. (max. %i chars)\n", VChars - 1);
199 }
200
201
202 /* Executes the command entered */
203 void CON_Execute(void)
204 {
205         if(strlen(Command) > 0) {
206                 CON_NewLineCommand();
207
208                 // copy the input into the past commands strings
209                 strcpy(CommandLines[0], Command);
210
211                 // display the command including the prompt
212                 CON_Out("%s%s\n", Prompt, Command);
213
214                 cmd_append(Command);
215
216                 Clear_Command();
217                 CommandScrollBack = -1;
218         }
219 }
220
221
222 void CON_TabCompletion(void)
223 {
224         int i, j;
225         char *command;
226
227         command = cmd_complete(LCommand);
228
229         if (!command)
230                 return; // no tab completion took place so return silently
231
232         j = (int)strlen(command);
233         if (j > CON_CHARS_PER_LINE - 2)
234                 j = CON_CHARS_PER_LINE-1;
235
236         memset(LCommand, 0, CON_CHARS_PER_LINE);
237         CursorPos = 0;
238
239         for (i = 0; i < j; i++) {
240                 CursorPos++;
241                 LCommand[i] = command[i];
242         }
243         // add a trailing space
244         CursorPos++;
245         LCommand[j] = ' ';
246         LCommand[j+1] = '\0';
247 }
248
249
250 void Cursor_Left(void)
251 {
252         char temp[CON_CHARS_PER_LINE];
253
254         if (CursorPos > 0) {
255                 CursorPos--;
256                 strcpy(temp, RCommand);
257                 strcpy(RCommand, &LCommand[strlen(LCommand)-1]);
258                 strcat(RCommand, temp);
259                 LCommand[strlen(LCommand)-1] = '\0';
260         }
261 }
262
263
264 void Cursor_Right(void)
265 {
266         char temp[CON_CHARS_PER_LINE];
267
268         if(CursorPos < strlen(Command)) {
269                 CursorPos++;
270                 strncat(LCommand, RCommand, 1);
271                 strcpy(temp, RCommand);
272                 strcpy(RCommand, &temp[1]);
273         }
274 }
275
276
277 void Cursor_Home(void)
278 {
279         char temp[CON_CHARS_PER_LINE];
280
281         CursorPos = 0;
282         strcpy(temp, RCommand);
283         strcpy(RCommand, LCommand);
284         strncat(RCommand, temp, strlen(temp));
285         memset(LCommand, 0, CON_CHARS_PER_LINE);
286 }
287
288
289 void Cursor_End(void)
290 {
291         CursorPos = (int)strlen(Command);
292         strncat(LCommand, RCommand, strlen(RCommand));
293         memset(RCommand, 0, CON_CHARS_PER_LINE);
294 }
295
296
297 void Cursor_Del(void)
298 {
299         char temp[CON_CHARS_PER_LINE];
300
301         if (strlen(RCommand) > 0) {
302                 strcpy(temp, RCommand);
303                 strcpy(RCommand, &temp[1]);
304         }
305 }
306
307 void Cursor_BSpace(void)
308 {
309         if (CursorPos > 0) {
310                 CursorPos--;
311                 Offset--;
312                 if (Offset < 0)
313                         Offset = 0;
314                 LCommand[strlen(LCommand)-1] = '\0';
315         }
316 }
317
318
319 void Cursor_Add(char character)
320 {
321         if (strlen(Command) < CON_CHARS_PER_LINE - 1)
322         {
323                 CursorPos++;
324                 LCommand[strlen(LCommand)] = character;
325                 LCommand[strlen(LCommand)] = '\0';
326         }
327 }
328
329
330 void Clear_Command(void)
331 {
332         CursorPos = 0;
333         memset( Command, 0, CON_CHARS_PER_LINE);
334         memset(LCommand, 0, CON_CHARS_PER_LINE);
335         memset(RCommand, 0, CON_CHARS_PER_LINE);
336         memset(VCommand, 0, CON_CHARS_PER_LINE);
337 }
338
339
340 void Command_Up(void)
341 {
342         if(CommandScrollBack < TotalCommands - 1) {
343                 /* move back a line in the command strings and copy the command to the current input string */
344                 CommandScrollBack++;
345                 memset(RCommand, 0, CON_CHARS_PER_LINE);
346                 Offset = 0;
347                 strcpy(LCommand, CommandLines[CommandScrollBack]);
348                 CursorPos = (int)strlen(CommandLines[CommandScrollBack]);
349         }
350 }
351
352
353 void Command_Down(void)
354 {
355         if(CommandScrollBack > -1) {
356                 /* move forward a line in the command strings and copy the command to the current input string */
357                 CommandScrollBack--;
358                 memset(RCommand, 0, CON_CHARS_PER_LINE);
359                 memset(LCommand, 0, CON_CHARS_PER_LINE);
360                 Offset = 0;
361                 if(CommandScrollBack > -1)
362                         strcpy(LCommand, CommandLines[CommandScrollBack]);
363                 CursorPos = (int)strlen(LCommand);
364         }
365 }