home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cenvi23.zip
/
SHELLCHR.CMM
< prev
next >
Wrap
Text File
|
1996-02-16
|
13KB
|
379 lines
//****************************************************************************
//****** BEGIN SECTION TO HANDLE HISTORY AND EDITING FOR THE CLI SHELL *******
//****************************************************************************
//
// This script is to be #included from the AUTOLOAD.CMM. It is operating
// system independant, assuming that constants such as EXT_KEY_HOME are
// correctly set already. This script adds the following user interface
// features to the CEnvi commandline interface:
// <HOME> Pressing the home key brings the cursor to the start of the line.
// <END> Pressing the end key brings the cursor to the end of the line.
// <UP> Pressing the up key scrolls back through the command history.
// <DOWN> Pressing the down key scrolls forward through the command history.
// <ENTER> Pressing enter adds the line to the command history, before executing it.
// <ESC> Pressing escape clears the line.
// <TAB> Pressing tab activates filename completion. If the cursor is situated at
// the end of a partially completed filename, TAB will complete the filename
// if there is only one file that matches the partial name. If more than
// one file is present, it will list all those that do match (within reason)
if( !defined(_SHELL_) || !defined(shellchr_alright) )
{
printf("This file is part of the shell; it is not a standalone program.\n");
exit(0);
}
#include <filename.lib>
#define HISTORY_MAX_MEMORY 20 // maximum values to hold in history
gHistoryList;
gHistoryCount = 0;
gReviewLine = 0; // when scrolling through buffer, this is line being reviewed
// set up filter to handle every special character input
ShellFilterCharacter("AutoloadFilterCharacter",True);
// The 'true' passed to it indicates that ALL characters should be passed through
// filter, rather than just the non-printing ones. This means we are able to play
// with characters that are perfectly normal, such as 'w'. */
AutoloadFilterCharacter(pCommand,pPosition,pKey,pIsExtended,pIsAlnum)
{
lReturnCode = False; //Usually we don't need to redraw the line.
// Delete, Backspace, Left and Right arrows are handled in the binary executable, and
// need not be dealt with here. Isn't that convenient?
if ( pIsExtended ) { // All the keys that don't have nice normal ASCII values
switch( pKey ) {
case ext_key_home: // Jump cursor to beginning of line.
pPosition = 0;
break;
case ext_key_end: // Jump cursor to end of line.
pPosition = strlen(pCommand);
break;
case ext_key_up: // Scroll up one through the command history.
if ( gHistoryCount ) {
if ( gHistoryCount+1 <= ++gReviewLine )
gReviewLine = 0;
if( gReviewLine==0 )
strcpy(pCommand,"");
else
strcpy(pCommand,gHistoryList[gReviewLine-1]);
pPosition = strlen(pCommand);
pKey = 0; // We don't want the key to get added to the buffer..
return True;
}
break;
case ext_key_down: // Scroll down one through the command history.
if ( gHistoryCount ) {
if ( --gReviewLine < 0 )
gReviewLine = gHistoryCount;
if( gReviewLine==0 )
strcpy(pCommand,"");
else
strcpy(pCommand,gHistoryList[gReviewLine-1]);
pPosition = strlen(pCommand);
pKey = 0;
return True;
}
break;
}
} else {
switch (pKey) // These keys all have one byte ASCII values.
{
case '\r': // When <ENTER> is hit, the whole line is added into the command history.
pPosition = strlen(pCommand);
AddToHistory(pCommand);
break;
case 0x03: // Also clear the line if Control-C pressed.
case 0x1B: // Escape clears the line.
pCommand[0] = 0;
pPosition = 0;
pKey = 0;
return True;
case '\t': // Tab activates filename completion.
FileNameCompletion(pCommand, pPosition);
pKey = 0;
return True;
}
}
return lReturnCode;
}
/*
* Complete a filename. If this is the first part of the line, we do command
* completion by searching the current dir, CMMPATH, and PATH (or the
* appropriate versions for each system). If this is not the first part of
* the line, we just search the directory spec he has already built.
*/
FileNameCompletion(cl,pos)
{
loc = cl + pos;
in_quote = 0;
while( loc>cl )
{
if( loc[0]=='"' ) in_quote = 1-in_quote;
if( !in_quote && isspace(loc[-1]) ) break;
loc--;
}
length = 0;
in_quote = 0;
while( loc[length]!='\0' )
{
if( loc[length]=='"' ) in_quote = 1-in_quote;
if( isspace(loc[length]) && !in_quote ) break;
length++;
}
// A word is a program word if it is the first line on the page or it
// follows a pipe.
match_program = (loc==cl);
if( !match_program )
{
temp = loc;
while( temp>cl )
{
temp--;
if( !isspace(temp[0]) ) break;
}
if( temp[0]=='|' ) match_program = 1;
}
strncpy(complete,loc,length+1);
complete[length] = '\0';
quote_it = 0;
if( complete[0]=='"' )
{
quote_it = 1;
complete++;
s = strlen(complete);
if( complete[s-1]=='"' ) complete[s-1] = '\0';
}
// Complete the directory 'complete'
strcpy(name,complete);
if( (defined(_DOS16_) || defined(_DOS32_) || defined(_WIN16_)) &&
strchr(name,'.')==NULL )
strcat(name,"*.*");
else
strcat(name,"*");
// Find all matches
choices = Directory(name);
it = SplitFileName(name);
// Assuming we are looking for a program, we also do some other looks
// If it looks like he is typing in a pathname, do a completion on it
if( match_program && strpbrk(complete,path_chars)==NULL &&
complete[0]!='\0' )
{
// First, add the aliases and internal commands.
for( i=0;i<=GetArraySpan(__Autoload_Alias_List);i++ )
{
if( strnicmp(__Autoload_Alias_List[i][0],complete,strlen(complete)) )
continue;
if( choices==NULL )
{
undefine(choices);
strcpy(choices[0].name,__Autoload_Alias_List[i][0]);
choices[0].attrib = 0;
} else {
add_it = 1;
for( k=0;k<=GetArraySpan(choices);k++ )
{
if( !stricmp(choices[k].name,__Autoload_Alias_List[i][0]) )
{
add_it = 0;
break;
}
}
if( add_it )
{
index = GetArraySpan(choices)+1;
strcpy(choices[index].name,__Autoload_Alias_List[i][0]);
choices[index].attrib = 0;
}
}
}
for( i=0;i<=GetArraySpan(__Autoload_Internal_Commands);i++ )
{
if( strnicmp(__Autoload_Internal_Commands[i],complete,
strlen(complete)) )
continue;
if( choices==NULL )
{
undefine(choices);
strcpy(choices[0].name,__Autoload_Internal_Commands[i]);
choices[0].attrib = 0;
} else {
add_it = 1;
for( k=0;k<=GetArraySpan(choices);k++ )
{
if( !stricmp(choices[k].name,
__Autoload_Internal_Commands[i]) )
{
add_it = 0;
break;
}
}
if( add_it )
{
index = GetArraySpan(choices)+1;
strcpy(choices[index].name,__Autoload_Internal_Commands[i]);
choices[index].attrib = 0;
}
}
}
// Add all the possible executables he could be referring to.
places = build_path_list();
// Search each of the directories, adding the entries to choices.
for( i=0;places!=NULL && i<=GetArraySpan(places);i++ )
{
sprintf(name2,"%s%s%s",places[i],it.name,it.ext);
choices2 = Directory(name2,FALSE,~FATTR_SUBDIR);
for( j=0;choices2!=NULL && j<=GetArraySpan(choices2);j++ )
{
it2 = SplitFileName(choices2[j].name);
sprintf(choices2[j].name,"%s%s",it2.name,it2.ext);
// if it has an extension, only consider those we know about.
if( strlen(it2.ext) )
{
allow_it = 0;
for( x=0;x<=GetArraySpan(executable_extensions);x++ )
{
if( !stricmp(executable_extensions[x],it2.ext) )
{
allow_it = 1;
break;
}
}
if( !allow_it ) continue;
}
if( choices==NULL )
{
undefine(choices);
choices[0] = choices2[j];
} else {
add_it = 1;
for( k=0;k<=GetArraySpan(choices);k++ )
{
if( !stricmp(choices[k].name,choices2[j].name) )
{
add_it = 0;
break;
}
}
if( add_it )
{
choices[GetArraySpan(choices)+1] = choices2[j];
}
}
}
}
}
beeped = 0;
if( choices!=NULL )
{
strcpy(biggest,choices[0].name);
biggest = choices[0].name;
for( i=1;i<=GetArraySpan(choices);i++ )
{
newname = choices[i].name;
for( j=0;newname[j] && biggest[j] &&
toupper(newname[j])==toupper(biggest[j]);j++ );
if( (biggest[j] || newname[j]) && beeped==0 )
{
beeped = 1;
printf("\a");
}
biggest[j] = '\0';
}
if( strchr(biggest,' ') ) quote_it = 1;
late_space = 0;
if( !beeped )
{
if( GetArraySpan(choices)==0 && (choices[0].attrib & FATTR_SUBDIR) )
strcat(biggest,filename_separator);
else
{
if( quote_it )
late_space = 1;
else
strcat(biggest," ");
}
}
if( quote_it ) sprintf(biggest,"\"%s\"",biggest);
// if completed totally, put a space after it and set quote_it to 0 so
// the cursor position will be correct
if( late_space ) { strcat(biggest," "); quote_it = 0; }
// It may be that nothing matches what he gives, so don't erase what
// he typed...
if( strlen(biggest)>strlen(complete) )
{
big = strlen(biggest);
memmove(loc+big,loc+length,strlen(loc+length)+1);
memmove(loc,biggest,big);
pos = (loc-cl)+big-quote_it;
}
} else {
printf("\a");
}
}
AddToHistory(pCommand)
{
// skip all spaces at beginning of command
strcpy(lCommand,pCommand);
lCommand += strspn(lCommand," ");
// remove any spaces at end of command
while ( (lLastSpace = strrchr(lCommand,' ')) && !lLastSpace[1] )
lLastSpace[0] = '\0';
// if no command remains then do not save
if ( !lCommand[0] )
return;
// if this entry is already in the history then remove that entry so this
// one can replace as most recent. Otherwise remove oldest entry if there
// are up to max in the buffer
bool lNewEntry = True;
for ( lOldEntry = 0; lOldEntry < gHistoryCount; lOldEntry++ ) {
if ( !stricmp(lCommand,gHistoryList[lOldEntry]) ) {
lNewEntry = False;
break;
}
}
// move all entries down one to fill in the old gap
while ( lOldEntry-- )
gHistoryList[lOldEntry+1] = gHistoryList[lOldEntry];
// new command goes to top of list
gHistoryList[0] = lCommand;
if ( gHistoryCount < HISTORY_MAX_MEMORY && lNewEntry )
gHistoryCount++;
gReviewLine = 0;
}
//**************************************************************************
//****** END SECTION TO HANDLE HISTORY AND EDITING FOR THE CLI SHELL *******
//**************************************************************************