aboutsummaryrefslogtreecommitdiff
path: root/src/libparsec/con_tab.cpp
blob: bb9309a83d518babefa82e29acf0736fd675f1ee (plain)
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 );
}