Create a branch for header work.
[reactos.git] / base / applications / network / telnet / src / tnmain.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998 Paul Brannan
4 //Copyright (C) 1998 I.Ioannou
5 //Copyright (C) 1997 Brad Johnson
6 //
7 //This program is free software; you can redistribute it and/or
8 //modify it under the terms of the GNU General Public License
9 //as published by the Free Software Foundation; either version 2
10 //of the License, or (at your option) any later version.
11 //
12 //This program is distributed in the hope that it will be useful,
13 //but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 //GNU General Public License for more details.
16 //
17 //You should have received a copy of the GNU General Public License
18 //along with this program; if not, write to the Free Software
19 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 //I.Ioannou
22 //roryt@hol.gr
23 //
24 ///////////////////////////////////////////////////////////////////////////
25
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 // Module: tnmain.cpp
29 //
30 // Contents: telnet main program
31 //
32 // Product: telnet
33 //
34 // Revisions: August 11, 1998 Thomas Briggs <tbriggs@qmetric.com>
35 // May 14, 1998 Paul Brannan <pbranna@clemson.edu>
36 // 5.April.1997 jbj@nounname.com
37 // 5.Dec.1996 jbj@nounname.com
38 // Version 2.0
39 //
40 // 02.Apr.1995 igor.milavec@uni-lj.si
41 // Original code
42 //
43 ///////////////////////////////////////////////////////////////////////////////
44
45 #include <string.h>
46 #include <locale.h>
47 #include "tnmain.h"
48 #include "tnmisc.h"
49
50 int telCommandLine (Telnet &MyConnection);
51
52 void waitforkey() {
53 HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
54 INPUT_RECORD InputRecord;
55 DWORD dwInput;
56 BOOL done = FALSE;
57 while (!done){
58 WaitForSingleObject( hConsole, INFINITE );
59 if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){
60 done = TRUE;
61 continue;
62 }
63 if (InputRecord.EventType == KEY_EVENT &&
64 InputRecord.Event.KeyEvent.bKeyDown )
65 done = TRUE;
66 }
67 }
68
69 //char * cfgets ( char * buf, unsigned int length, char pszHistory[][80], int iHistLength){
70 struct cmdHistory * cfgets (char *buf, unsigned int length, struct cmdHistory *cmdhist) {
71
72 HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
73 unsigned int current=0, cursor =0, iEraseLength=0, i;
74 char chr;
75 char temp[2];
76 char temp1[80];
77
78 INPUT_RECORD InputRecord;
79 BOOL done = FALSE;
80
81 temp[1] = 0;
82 buf[0] = '\0';
83
84 if(!ini.get_input_redir()) {
85 while (!done) {
86 DWORD dwInput;
87 int MustRefresh = 0;
88 WaitForSingleObject( hConsole, INFINITE );
89 if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){
90 done = TRUE;
91 continue;
92 }
93 MustRefresh = 0;
94 if (InputRecord.EventType == KEY_EVENT &&
95 InputRecord.Event.KeyEvent.bKeyDown ) {
96
97 if(InputRecord.Event.KeyEvent.dwControlKeyState &
98 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
99
100 switch(InputRecord.Event.KeyEvent.wVirtualKeyCode) {
101 case 'D': // Thomas Briggs 8/11/98
102 buf[0] = '\04';
103 buf[1] = '\0';
104 current = 1;
105 done = true;
106 continue;
107 case 'U': // Paul Brannan 8/11/98
108 buf[0] = '\0';
109 current = 0;
110 cursor = 0;
111 MustRefresh = 1;
112 break;
113 }
114 }
115
116 switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
117 case VK_UP:
118 // crn@ozemail.com.au
119 if (cmdhist != NULL) {
120 if (!strcmp(buf, ""))
121 strncpy(buf, cmdhist->cmd, 79);
122 else if (cmdhist->prev != NULL) {
123 cmdhist = cmdhist->prev;
124 strncpy(buf, cmdhist->cmd, 79);
125 }
126 current = strlen(buf);
127 }
128 ///
129 MustRefresh = 1;
130 break;
131 case VK_DOWN:
132 // crn@ozemail.com.au
133 if (cmdhist != NULL) {
134 if (cmdhist->next != NULL) {
135 cmdhist = cmdhist->next;
136 strncpy(buf, cmdhist->cmd, 79);
137 } else {
138 strncpy(buf, "", 79);
139 }
140 current = strlen(buf);
141 }
142 ///
143 MustRefresh = 1;
144 break;
145 case VK_RIGHT: //crn@ozemail.com.au (added ctrl+arrow)
146 if (cursor < current) {
147 if (InputRecord.Event.KeyEvent.dwControlKeyState &
148 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
149 unsigned int j, k;
150 for (j = cursor; j <= current; j++)
151 if (buf[j+1] == ' ' || (j+1)==current)
152 break;
153 for (k = ++j; k <= current; k++)
154 if (buf[k] != ' ' || k == current) {
155 cursor = k == current ? --k : k;
156 break;
157 }
158 } else
159 cursor++;
160 MustRefresh = 1;
161 break;
162 }
163 case VK_LEFT: //crn@ozemail.com.au (added ctrl+arrow)
164 if (cursor > 0) {
165 if(InputRecord.Event.KeyEvent.dwControlKeyState &
166 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
167 int j, k;
168 for (j = cursor; j >= 0; j--)
169 if (buf[j-1] != ' ')
170 break;
171 for (k = --j; k >= 0; k--)
172 if (buf[k] == ' ' || k == 0) {
173 cursor = !k ? k : ++k;
174 break;
175 }
176 } else
177 cursor--;
178 MustRefresh = 1;
179 break;
180 }
181 case VK_HOME:
182 if (cursor>0) cursor = 0;
183 MustRefresh = 1;
184 break;
185 case VK_END:
186 if (cursor<current) cursor = current;
187 MustRefresh = 1;
188 break;
189 case VK_DELETE:
190 if (current > 0 && current > cursor) {
191 strcpy(&buf[cursor],&buf[cursor+1]);
192 current--;
193 buf[current] = 0;
194 printit("\r");
195 for (i = 0; i < current+strlen("telnet>")+1 ;i++)
196 printit(" ");
197 }
198 MustRefresh = 1;
199 break;
200 case VK_BACK:
201 if (cursor > 0 ) {
202 strcpy(&buf[cursor-1],&buf[cursor]);
203 current--;
204 cursor--;
205 buf[current] = 0;
206 printit("\r");
207 for (i = 0; i < current+strlen("telnet>")+1 ;i++)
208 printit(" ");
209 }
210 MustRefresh = 1;
211 break;
212
213 default:
214 chr = InputRecord.Event.KeyEvent.uChar.AsciiChar;
215 if (chr == '\r') {
216 done = TRUE;
217 continue;
218 }
219 if (current >= length-1){
220 done = TRUE;
221 continue;
222 }
223 if ( isprint (chr) ){
224 strncpy(temp1,&buf[cursor],79);
225 strncpy(&buf[cursor+1],temp1,79-(cursor+1));
226 buf[cursor++]=chr;
227 current++;
228 buf[current] = 0;
229 MustRefresh = 1;
230 }
231 break;
232 }
233 if (MustRefresh == 1)
234 {
235 printit("\rtelnet");
236 for (i = 0; i <= iEraseLength ;i++)
237 printit(" ");
238 printit("\rtelnet>");
239 printit(buf);
240 iEraseLength = strlen(buf);
241 for (i = 0; i < current-cursor; i++)
242 printit("\b");
243 }
244 }
245 }
246 buf[current] = 0;
247 if (strcmp(buf, "")) {
248 if (cmdhist == NULL) {
249 cmdhist = new struct cmdHistory;
250 if (cmdhist == NULL) {
251 printit ("\nUnable to allocate memory for history buffer -- use the \"flush\" command to clear the buffer.\n");
252 return cmdhist;
253 }
254 strncpy(cmdhist->cmd, buf, 79);
255 cmdhist->next = NULL;
256 cmdhist->prev = NULL;
257 } else {
258 while (cmdhist->next != NULL) // move to the end of the list
259 cmdhist = cmdhist->next;
260 cmdhist->next = new struct cmdHistory;
261 if (cmdhist->next == NULL) {
262 printit ("\nUnable to allocate memory for history buffer -- use the \"flush\" command to clear the buffer.\n");
263 return cmdhist;
264 }
265 cmdhist->next->prev = cmdhist; // previous is where we are now
266 cmdhist = cmdhist->next;
267 strncpy(cmdhist->cmd, buf, 79);
268 cmdhist->next = NULL;
269 }
270 while (cmdhist->next)
271 cmdhist = cmdhist->next;
272 }
273 return cmdhist;
274 ///
275 } else {
276 WaitForSingleObject( hConsole, INFINITE );
277 DWORD dwInput;
278 DWORD OldMode;
279 GetConsoleMode(hConsole, &OldMode);
280 SetConsoleMode(hConsole,
281 OldMode &~ (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT) );
282 while (ReadFile(hConsole, &chr, 1, &dwInput, NULL)) {
283 if (chr == '\r') {
284 temp[0] = chr;
285 printit(&temp[0]);
286 break;
287 }
288 if (chr == '\b' && current > 0) {
289 current--;
290 printit("\b \b");
291 }
292 if (current >= length-1){
293 break;
294 }
295 if ( isprint (chr) ){
296 temp[0] = chr;
297 printit(&temp[0]);
298 buf[current++]=chr;
299 }
300 }
301 buf[current] = 0;
302 SetConsoleMode(hConsole, OldMode);
303 return NULL;
304 }
305 }
306
307 // AVS ** for fix bug in command 'keys load keymapname' without file
308 // static char keyfile[MAX_PATH*2];
309
310 int main(int ArgC, char* ArgV[]) {
311
312 CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
313 GetConsoleScreenBufferInfo(
314 GetStdHandle(STD_OUTPUT_HANDLE),
315 &ConsoleScreenBufferInfo
316 );
317
318 char *k;
319 char startdir[MAX_PATH*2];
320 char exename[MAX_PATH];
321
322 // strncpy(startdir, ArgV[0],MAX_PATH);
323 // This should be more accurate than using argv[0] (Paul Brannan 9/16/98)
324 GetModuleFileName(NULL, startdir, sizeof(startdir));
325
326 // Get the current console title so it can be set later
327 // ("Pedro A. Aranda GutiƩrrez" <paag@coppi.tid.es>)
328 TCHAR ConsoleTitle[255];
329 GetConsoleTitle(ConsoleTitle, sizeof(ConsoleTitle));
330
331 k = strrchr(startdir, '\\');
332 if (k == NULL){ // if the \ character is not found...
333 strcpy(exename, startdir);
334 strcpy(startdir,""); // set the path to nothing
335 } else {
336 // end the string after the last '\' to get rid of the file name
337 strcpy(exename, k+1);
338 k[1] = 0;
339 }
340
341 printm(0, FALSE, MSG_COPYRIGHT);
342 printm(0, FALSE, MSG_COPYRIGHT_1);
343
344 // set up the ini class
345 ini.init(startdir, exename);
346
347 // Process the command line arguments and connect to a host if necessary
348 if(ini.Process_Params(ArgC, ArgV)) {
349 const char *szHost = ini.get_host();
350 const char *strPort = ini.get_port();
351 if(!*szHost) {
352 Telnet MyConnection;
353 while(telCommandLine(MyConnection));
354 } else {
355 Telnet MyConnection;
356 if(MyConnection.Open(szHost, strPort) == TNPROMPT) {
357 // still connected
358 printit("\n");
359 telCommandLine(MyConnection);
360 }
361 }
362 }
363 //// (Paul Brannan 5/14/98)
364
365 if(ini.get_term_width() != -1 || ini.get_term_height() != -1) {
366 SetConsoleScreenBufferSize(
367 GetStdHandle(STD_OUTPUT_HANDLE), // handle of console screen buffer
368 ConsoleScreenBufferInfo.dwSize // new size in character rows and cols.
369 );
370 SetConsoleWindowInfo(
371 GetStdHandle(STD_OUTPUT_HANDLE), // handle of console screen buffer
372 TRUE, // coordinate type flag
373 &ConsoleScreenBufferInfo.srWindow // address of new window rectangle
374 );
375 }
376 SetConsoleTextAttribute(
377 GetStdHandle(STD_OUTPUT_HANDLE), // handle of console screen buffer
378 ConsoleScreenBufferInfo.wAttributes // text and background colors
379 );
380
381 // Restore the original console title
382 // ("Pedro A. Aranda GutiƩrrez" <paag@coppi.tid.es>)
383 SetConsoleTitle(ConsoleTitle);
384
385 return 0;
386 }
387
388 // AVS
389 enum {
390 BAD_USAGE = -3,
391 EMPTY_LINE = -2,
392 INVALID_CMD = -1,
393 __FIRST_COMMAND = 0,
394
395 OPEN = __FIRST_COMMAND,
396 CLOSE,
397 KEYS,
398 QUIT,
399 HELP,
400 HELP2, // there is way for synonims
401 K_LOAD, // subcommand of 'keys'
402 K_SWITCH, // subcommand of 'keys'
403 K_DISPLAY, // subcommand of 'keys'
404
405 SET, // Paul Brannan 5/30/98
406
407 SUSPEND,
408 FASTQUIT, // Thomas Briggs 8/11/98
409 CMD_HISTORY, // crn@ozemail.com.au
410 CLEAR_HISTORY, // crn@ozemail.com.au
411
412 ALIASES, // Paul Brannan 1/1/99
413
414 __COMMAND_LIST_SIZE // must be last
415 };
416
417
418 struct command {
419 const char* cmd; // command
420 int minLen, // minimal length for match
421 minParms, // minimal count of parms
422 maxParms; // maximal -/- (negative disables)
423 int isSubCmd, // is a subcommand - number of wich command
424 haveSubCmd; // have subcommands? 0 or 1
425 const char* usage; // text of usage
426 };
427
428 command cmdList[__COMMAND_LIST_SIZE] = {
429 {"open", 1, 1, 2, -1, 0, "o[pen] host [port]\n"},
430 {"close", 2, 0, 0, -1, 0, NULL},
431 {"keys", 2, 1, 3, -1, 1, "ke[ys] l[oad] keymapname [file]\n"
432 "ke[ys] d[isplay]\n"
433 "ke[ys] s[witch] number\n"},
434 // Ioannou : i change it to q, to be more compatible with unix telnet
435 {"quit", 1, 0, 0, -1, 0, NULL}, // must type it exactly
436 {"?", 1, 0, 0, -1, 0, NULL},
437 {"help", 1, 0, 0, -1, 0, NULL},
438 {"load", 1, 1, 2, KEYS, 0, NULL},
439 {"switch", 1, 1, 1, KEYS, 0, NULL},
440 {"display", 1, 0, 0, KEYS, 0, NULL},
441 // Paul Brannan 5/30/98
442 {"set", 3, 0, 2, -1, 0, "set will display available groups.\n"
443 "set groupname will display all variables/values in a group.\n"
444 "set [variable [value]] will set variable to value.\n"},
445 // Thomas Briggs 8/11/98
446 {"z", 1, 0, 0, -1, 0, "suspend telnet\n"},
447 {"\04", 1, 0, 0, -1, 0, NULL},
448 // crn@ozemail.com.au
449 {"history", 2, 0, 0, -1, 0, "show command history"},
450 {"flush", 2, 0, 0, -1, 0, "flush history buffer"},
451 // Paul Brannan 1/1/99
452 {"aliases", 5, 0, 0, -1, 0, NULL}
453 };
454
455 // a maximal count of parms
456 #define MAX_PARM_COUNT 3
457 #define MAX_TOKEN_COUNT (MAX_PARM_COUNT+2)
458
459 static int cmdMatch(const char* cmd, const char* token, int tokenLen, int minM) {
460 if ( tokenLen < minM ) return 0;
461 // The (unsigned) gets rid of a compiler warning (Paul Brannan 5/25/98)
462 if ( (unsigned)tokenLen > strlen(cmd) ) return 0;
463 if ( strcmp(cmd,token) == 0 ) return 1;
464
465 int i;
466 for ( i = 0; i < minM; i++ ) if ( cmd[i] != token[i] ) return 0;
467
468 for ( i = minM; i < tokenLen; i++ ) if ( cmd[i] != token[i] ) return 0;
469
470 return 1;
471 };
472
473 static void printUsage(int cmd) {
474 if ( cmdList[cmd].usage != NULL ) {
475 printit(cmdList[cmd].usage);
476 return;
477 };
478 if ( cmdList[cmd].isSubCmd >= 0 ) {
479 printUsage(cmdList[cmd].isSubCmd);
480 return;
481 }
482 printm(0, FALSE, MSG_BADUSAGE);
483 };
484
485 int tokenizeCommand(char* szCommand, int& argc, char** argv) {
486 char* tokens[MAX_TOKEN_COUNT];
487 char* p;
488 int args = 0;
489
490 if(!szCommand || !*szCommand) return EMPTY_LINE;
491
492 // Removed strtok to handle tokens with spaces; this is handled with
493 // quotes. (Paul Brannan 3/18/99)
494 char *token_start = szCommand;
495 for(p = szCommand;; p++) {
496 if(*p == '\"') {
497 char *tmp = p;
498 for(p++; *p != '\"' && *p != 0; p++); // Find the next quote
499 if(*p != 0) strcpy(p, p + 1); // Remove quote#2
500 strcpy(tmp, tmp + 1); // Remove quote#1
501 }
502 if(*p == 0 || *p == ' ' || *p == '\t') {
503 tokens[args] = token_start;
504 args++;
505 if(args >= MAX_TOKEN_COUNT) break; // Break if too many args
506 token_start = p + 1;
507 if(*p == 0) break;
508 *p = 0;
509 }
510 }
511 // while ( (p = strtok((args?NULL:szCommand), " \t")) != NULL && args < MAX_TOKEN_COUNT ) {
512 // tokens[args] = p;
513 // args++;
514 // };
515
516 if ( !args ) return EMPTY_LINE;
517 argc = args - 1;
518 args = 0;
519 int curCmd = -1;
520 int ok = -1;
521 while ( ok < 0 ) {
522 int tokenLen = strlen(tokens[args]);
523 int match = 0;
524 for ( int i = 0; i<__COMMAND_LIST_SIZE; i++ ) {
525 if ( cmdMatch(cmdList[i].cmd, tokens[args], tokenLen, cmdList[i].minLen) ) {
526 if (argc < cmdList[i].minParms || argc > cmdList[i].maxParms) {
527 printUsage(i);
528 return BAD_USAGE;
529 };
530 if ( cmdList[i].haveSubCmd && curCmd == cmdList[i].isSubCmd) {
531 curCmd = i;
532 args++;
533 argc--;
534 match = 1;
535 break;
536 };
537 if ( curCmd == cmdList[i].isSubCmd ) {
538 ok = i;
539 match = 1;
540 break;
541 };
542 printUsage(i);
543 return BAD_USAGE;
544 };
545 };
546 if ( !match ) {
547 if ( curCmd < 0 ) return INVALID_CMD;
548 printUsage(curCmd);
549 return -3;
550 };
551 };
552
553 for ( int i = 0; i<argc; i++ ) {
554 argv[i] = tokens[i+args+1];
555 };
556 return ok;
557
558 };
559
560 int telCommandLine (Telnet &MyConnection){
561 #define HISTLENGTH 25
562 int i, retval;
563 char* Parms[MAX_PARM_COUNT];
564 char szCommand[80];
565 int bDone = 0;
566 char *extitle, *newtitle;
567 struct cmdHistory *cmdhist;
568 cmdhist = NULL;
569
570 // printit("\n"); // crn@ozemail.com.au 14/12/98
571 while (!bDone){
572 // printit("\n"); // Paul Brannan 5/25/98
573 printit( "telnet>");
574 cmdhist = cfgets (szCommand, 79, cmdhist);
575 printit( "\n");
576
577 strlwr(szCommand); // convert command line to lower
578 // i = sscanf(szCommand,"%80s %80s %80s %80s", szCmd, szArg1, szArg2, szArg3);
579 switch ( tokenizeCommand(szCommand, i, Parms) ) {
580 case BAD_USAGE: break;
581 case EMPTY_LINE:
582 if(MyConnection.Resume() == TNPROMPT) {
583 printit("\n");
584 break;
585 }
586 else
587 return 1;
588 case INVALID_CMD:
589 printm(0, FALSE, MSG_INVCMD);
590 break;
591 case OPEN:
592 if (i == 1)
593 retval = MyConnection.Open(Parms[0], "23");
594 else
595 retval = MyConnection.Open(Parms[0], Parms[1]);
596 if(retval != TNNOCON && retval != TNPROMPT) return 1;
597 if(retval == TNPROMPT) printit("\n");
598 break;
599 case CLOSE:
600 MyConnection.Close();
601 break;
602 case FASTQUIT: // Thomas Briggs 8/11/98
603 case QUIT:
604 MyConnection.Close();
605 bDone = 1;
606 break;
607 case HELP:
608 case HELP2:
609 printm(0, FALSE, MSG_HELP);
610 printm(0, FALSE, MSG_HELP_1);
611 break;
612 // case KEYS: we should never get it
613 case K_LOAD:
614 if ( i == 1 ) {
615 // Ioannou : changed to ini.get_keyfile()
616 if(MyConnection.LoadKeyMap( ini.get_keyfile(), Parms[0]) != 1)
617 printit("Error loading keymap.\n");
618 break;
619 };
620 if(MyConnection.LoadKeyMap( Parms[1], Parms[0]) != 1)
621 printit("Error loading keymap.\n");
622 break;
623 case K_DISPLAY:
624 MyConnection.DisplayKeyMap();
625 break;
626 case K_SWITCH:
627 MyConnection.SwitchKeyMap(atoi(Parms[0]));
628 break;
629
630 // Paul Brannan 5/30/98
631 case SET:
632 if(i == 0) {
633 printit("Available groups:\n"); // Print out groups
634 ini.print_groups(); // (Paul Brannan 9/3/98)
635 } else if(i == 1) {
636 ini.print_vars(Parms[0]);
637 } else if(i >= 2) {
638 ini.set_value(Parms[0], Parms[1]);
639 // FIX ME !!! Ioannou: here we must call the parser routine for
640 // wrap line, not the ini.set_value
641 // something like Parser.ConLineWrap(Wrap_Line);
642 }
643 break;
644
645 case SUSPEND: // Thomas Briggs 8/11/98
646
647 // remind the user we're suspended -crn@ozemail.com.au 15/12/98
648 extitle = new char[128];
649 GetConsoleTitle (extitle, 128);
650
651 newtitle = new char[128+sizeof("[suspended]")];
652 strcpy(newtitle, extitle);
653 strncat(newtitle, "[suspended]", 128+sizeof("[suspended]"));
654 if(ini.get_set_title()) SetConsoleTitle (newtitle);
655 delete[] newtitle;
656
657 if (getenv("comspec") == NULL) {
658 switch (GetWin32Version()) {
659 case 2: // 'cmd' is faster than 'command' in NT -crn@ozemail.com.au
660 system ("cmd");
661 break;
662 default:
663 system ("command");
664 break;
665 }
666 } else {
667 system(getenv("comspec"));
668 }
669
670 if(ini.get_set_title()) SetConsoleTitle (extitle);
671 delete[] extitle;
672 ///
673
674 break;
675
676 case CMD_HISTORY: //crn@ozemail.com.au
677 if (cmdhist != NULL) {
678 while (cmdhist->prev != NULL)
679 cmdhist = cmdhist->prev; //rewind
680 printf ("Command history:\n");
681 while (1) {
682 printf ("\t%s\n", cmdhist->cmd);
683
684 if (cmdhist->next != NULL)
685 cmdhist = cmdhist->next;
686 else
687 break;
688 }
689 } else
690 printf ("No command history available.\n");
691
692 break;
693
694 case CLEAR_HISTORY: //crn@ozemail.com.au
695 if (cmdhist != NULL) {
696 while (cmdhist->next != NULL)
697 cmdhist = cmdhist->next; //fast forward
698 while (cmdhist->prev != NULL) {
699 cmdhist = cmdhist->prev;
700 delete cmdhist->next;
701 }
702 delete cmdhist;
703 cmdhist = NULL;
704 printf ("Command history cleared.\n");
705 } else
706 printf ("No command history available.\n");
707
708 case ALIASES: // Paul Brannan 1/1/99
709 ini.print_aliases();
710 break;
711
712 default: // paranoik
713 printm(0, FALSE, MSG_INVCMD);
714 break;
715 }
716
717 }
718
719 return 0;
720 }