1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
|
/*
* PARSEC - Command Completion
*
* $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:40 $
*
* Orginally written by:
* Copyright (c) Andreas Varga <sid@parsec.org> 1998-1999
* Copyright (c) Clemens Beer <cbx@parsec.org> 2002
* Copyright (c) Markus Hadwiger <msh@parsec.org> 1998-1999
*
* 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 the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// C library
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// compilation flags/debug support
#include "config.h"
#include "debug.h"
// general definitions
#include "general.h"
#include "objstruc.h"
// global externals
#include "globals.h"
// subsystem headers
#ifdef PARSEC_CLIENT
#include "aud_defs.h"
#endif // PARSEC_CLIENT
// local module header
#include "con_tab.h"
// proprietary module headers
#ifdef PARSEC_SERVER
#include "con_act_sv.h"
#include "con_aux_sv.h"
#include "con_com_sv.h"
#include "con_ext_sv.h"
#include "con_int_sv.h"
#include "con_main_sv.h"
#include "con_std_sv.h"
#else // !PARSEC_SERVER
#include "con_act.h"
#include "con_aux.h"
#include "con_com.h"
#include "con_conf.h"
#include "con_ext.h"
#include "con_int.h"
#include "con_main.h"
#include "con_std.h"
#endif // PARSEC_SERVER
// generic string paste area --------------------------------------------------
//
#define PASTE_STR_LEN 255
static char paste_str[ PASTE_STR_LEN + 1 ];
#if ( PASTE_STR_LEN < MAX_CONSOLE_LINE_LENGTH )
#error "CON_TAB::paste_str too short!"
#endif
// maximum number of possible completions that will be shown ------------------
//
#define MAX_COMPLETIONS 64
// list of possible completions found -----------------------------------------
//
static const char* found_names[ MAX_COMPLETIONS ];
static int found_param[ MAX_COMPLETIONS ];
// commands to check in current run -------------------------------------------
//
enum {
CHECK_STDCOMMS,
CHECK_USRCOMMS,
CHECK_INTCOMMS,
CHECK_EXTCOMMS,
CHECK_ACTCOMMS,
#ifdef PARSEC_CLIENT
CHECK_COLCOMMS,
#endif // PARSEC_CLIENT
// must be last!!
CHECK_NUM_COMMS
};
static int num_commands[ CHECK_NUM_COMMS ];
// <tab> key pressed in console -----------------------------------------------
//
void CompleteCommand()
{
// skip prompt
char* curinput = &con_lines[ con_bottom ][ PROMPT_SIZE ];
int skiplen = PROMPT_SIZE;
// only complete commands starting in first column
if ( ( curinput[ 0 ] == ' ' ) || ( curinput[ 0 ] == 0 ) )
return;
#ifdef PARSEC_CLIENT
// handle talkmode
if ( con_in_talk_mode ) {
// only complete commands
if ( curinput[ 0 ] != talk_escape_char ) {
if ( !AUX_DISABLE_TALK_ESCAPE_ON_TAB ) {
int maxlen = MAX_CONSOLE_LINE_LENGTH - PROMPT_SIZE - 1;
strncpy( paste_str, curinput, maxlen );
paste_str[ maxlen ] = 0;
curinput[ 0 ] = talk_escape_char;
strcpy( curinput + 1, paste_str );
} else {
return;
}
}
// skip command escape
curinput++;
skiplen++;
}
#endif // PARSEC_CLIENT
int inputlen = (int)strlen( curinput );
// fetch current numbers for all types
num_commands[ CHECK_STDCOMMS ] = num_std_commands;
num_commands[ CHECK_USRCOMMS ] = num_user_commands;
num_commands[ CHECK_INTCOMMS ] = num_int_commands;
num_commands[ CHECK_EXTCOMMS ] = num_external_commands;
num_commands[ CHECK_ACTCOMMS ] = ACM_NUM_COMMANDS;
#ifdef PARSEC_CLIENT
num_commands[ CHECK_COLCOMMS ] = num_col_commands;
#endif // PARSEC_CLIENT
// check all command types
int numfound = 0;
for ( int cmdtyp = 0; cmdtyp < CHECK_NUM_COMMS; cmdtyp++ ) {
// check all commands of current type
for ( int curcmd = 0; curcmd < num_commands[ cmdtyp ]; curcmd++ ) {
if ( ( cmdtyp == CHECK_ACTCOMMS ) && !ACMCALLABLE( curcmd ) )
continue;
const char* name;
int para;
switch ( cmdtyp ) {
case CHECK_STDCOMMS:
name = CMSTR( curcmd );
para = CMARG( curcmd );
break;
case CHECK_USRCOMMS:
name = USRSTR( curcmd );
para = USRARG( curcmd );
break;
case CHECK_INTCOMMS:
name = ICMSTR( curcmd );
para = 1;
break;
case CHECK_EXTCOMMS:
name = ECMSTR( curcmd );
para = 0;
break;
case CHECK_ACTCOMMS:
name = ACMSTR( curcmd );
para = 0;
break;
#ifdef PARSEC_CLIENT
case CHECK_COLCOMMS:
name = col_comms[ curcmd ].cmd;
para = -1;
break;
#endif // PARSEC_CLIENT
}
// count number of equal chars
int cpos = 0;
for ( cpos = 0; cpos < inputlen; cpos++ )
if ( curinput[ cpos ] != name[ cpos ] )
break;
if ( cpos == inputlen ) {
// we either found a valid command or at least
// a partially complete one
if ( numfound >= MAX_COMPLETIONS )
break;
found_names[ numfound ] = name;
found_param[ numfound ] = para;
numfound++;
}
}
}
if ( numfound == 1 ) {
// we've found just a single valid completion, so let's take it
strcpy( curinput, found_names[ 0 ] );
// special case for color commands
if ( found_param[ 0 ] == -1 ) {
int len = (int)strlen( curinput );
curinput[ len - 2 ] = 0;
curinput[ len - 1 ] = 0;
found_param[ 0 ] = 0;
}
// if command has parameters automatically append space
if ( found_param[ 0 ] > 0 ) {
strcat( curinput, " " );
}
} else {
#ifdef PARSEC_CLIENT
// we beep if we have found multiple possible
// completions or none at all
AUD_Select2();
#endif // PARSEC_CLIENT
// list possible completions and print common prefix
if ( numfound > 1 ) {
// save the original input line
strcpy( paste_str, con_lines[ con_bottom ] );
// overwrite old line in talkmode
if ( con_in_talk_mode ) {
con_bottom = con_talk_line;
CON_DisableLineFeed();
}
const char *common = found_names[ 0 ];
int comlen = (int)strlen( common );
// print the list of completions
for ( int cnum = 0; cnum < numfound; cnum++ ) {
const char *curname = found_names[ cnum ];
// maintain common prefix length
int cpos = 0;
for ( cpos = 0; cpos < comlen; cpos++ )
if ( curname[ cpos ] != common[ cpos ] )
break;
if ( cpos < comlen )
comlen = cpos;
CON_AddLine( curname );
}
#ifdef PARSEC_CLIENT
// print the common prefix
strncpy( paste_str + skiplen, common, comlen );
paste_str[ skiplen + comlen ] = 0;
CON_AddLine( paste_str );
#elif PARSEC_SERVER
extern void EraseConLine( int line );
// output supplied line
EraseConLine( con_bottom );
strcpy( con_lines[ con_bottom ], paste_str );
#endif // PARSEC_CLIENT
}
}
// set cursor position to end of line
cursor_x = (int)strlen( con_lines[ con_bottom ] + PROMPT_SIZE );
}
|