home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cenvi23.zip / SHELLCHR.CMM < prev    next >
Text File  |  1996-02-16  |  13KB  |  379 lines

  1. //****************************************************************************
  2. //****** BEGIN SECTION TO HANDLE HISTORY AND EDITING FOR THE CLI SHELL *******
  3. //****************************************************************************
  4. //
  5. //  This script is to be #included from the AUTOLOAD.CMM.  It is operating
  6. //  system independant, assuming that constants such as EXT_KEY_HOME are
  7. //  correctly set already.  This script adds the following user interface
  8. //  features to the CEnvi commandline interface:
  9.  
  10. //  <HOME>  Pressing the home key brings the cursor to the start of the line.
  11. //  <END>   Pressing the end key brings the cursor to the end of the line.
  12. //  <UP>    Pressing the up key scrolls back through the command history.
  13. //  <DOWN>  Pressing the down key scrolls forward through the command history.
  14. //  <ENTER> Pressing enter adds the line to the command history, before executing it.
  15. //  <ESC>   Pressing escape clears the line.
  16. //  <TAB>   Pressing tab activates filename completion.  If the cursor is situated at
  17. //            the end of a partially completed filename, TAB will complete the filename
  18. //            if there is only one file that matches the partial name.  If more than
  19. //            one file is present, it will list all those that do match (within reason)
  20.  
  21.  
  22.  
  23. if( !defined(_SHELL_) || !defined(shellchr_alright) )
  24. {
  25.   printf("This file is part of the shell; it is not a standalone program.\n");
  26.   exit(0);
  27. }
  28.  
  29.  
  30. #include <filename.lib>
  31.  
  32.  
  33. #define HISTORY_MAX_MEMORY     20   // maximum values to hold in history
  34. gHistoryList;
  35. gHistoryCount = 0;
  36. gReviewLine = 0;   // when scrolling through buffer, this is line being reviewed
  37.  
  38. // set up filter to handle every special character input
  39. ShellFilterCharacter("AutoloadFilterCharacter",True);
  40.  
  41. // The 'true' passed to it indicates that ALL characters should be passed through
  42. // filter, rather than just the non-printing ones.  This means we are able to play
  43. // with characters that are perfectly normal, such as 'w'.  */
  44.  
  45. AutoloadFilterCharacter(pCommand,pPosition,pKey,pIsExtended,pIsAlnum)
  46. {
  47.    lReturnCode = False; //Usually we don't need to redraw the line.
  48.  
  49.    // Delete, Backspace, Left and Right arrows are handled in the binary executable, and
  50.    // need not be dealt with here.  Isn't that convenient?
  51.  
  52.    if ( pIsExtended ) {  // All the keys that don't have nice normal ASCII values
  53.       switch( pKey ) {
  54.          case ext_key_home: // Jump cursor to beginning of line.
  55.             pPosition = 0;
  56.             break;
  57.          case ext_key_end: // Jump cursor to end of line.
  58.             pPosition = strlen(pCommand);
  59.             break;
  60.          case ext_key_up:  // Scroll up one through the command history.
  61.             if ( gHistoryCount ) {
  62.                if ( gHistoryCount+1 <= ++gReviewLine )
  63.                   gReviewLine = 0;
  64.                if( gReviewLine==0 )
  65.                  strcpy(pCommand,"");
  66.                else
  67.                  strcpy(pCommand,gHistoryList[gReviewLine-1]);
  68.                pPosition = strlen(pCommand);
  69.                pKey = 0;  // We don't want the key to get added to the buffer..
  70.                return True;
  71.             }
  72.             break;
  73.          case ext_key_down: // Scroll down one through the command history.
  74.             if ( gHistoryCount ) {
  75.                if ( --gReviewLine < 0 )
  76.                   gReviewLine = gHistoryCount;
  77.                if( gReviewLine==0 )
  78.                  strcpy(pCommand,"");
  79.                else
  80.                  strcpy(pCommand,gHistoryList[gReviewLine-1]);
  81.                pPosition = strlen(pCommand);
  82.                pKey = 0;
  83.                return True;
  84.             }
  85.             break;
  86.       }
  87.    } else {
  88.       switch (pKey)  // These keys all have one byte ASCII values.
  89.       {
  90.          case '\r':  // When <ENTER> is hit, the whole line is added into the command history.
  91.             pPosition = strlen(pCommand);
  92.             AddToHistory(pCommand);
  93.             break;
  94.          case 0x03:  // Also clear the line if Control-C pressed.
  95.          case 0x1B:  // Escape clears the line.
  96.             pCommand[0] = 0;
  97.             pPosition = 0;
  98.             pKey = 0;
  99.             return True;
  100.          case '\t':  // Tab activates filename completion.
  101.             FileNameCompletion(pCommand, pPosition);
  102.             pKey = 0;
  103.             return True;
  104.       }
  105.    }
  106.    return lReturnCode;
  107. }
  108.  
  109.  
  110. /*
  111.  * Complete a filename. If this is the first part of the line, we do command
  112.  * completion by searching the current dir, CMMPATH, and PATH (or the
  113.  * appropriate versions for each system). If this is not the first part of
  114.  * the line, we just search the directory spec he has already built.
  115.  */
  116. FileNameCompletion(cl,pos)
  117. {
  118.   loc = cl + pos;
  119.   in_quote = 0;
  120.   while( loc>cl )
  121.     {
  122.       if( loc[0]=='"' ) in_quote = 1-in_quote;
  123.       if( !in_quote && isspace(loc[-1]) ) break;
  124.       loc--;
  125.     }
  126.   length = 0;
  127.   in_quote = 0;
  128.   while( loc[length]!='\0' )
  129.     {
  130.       if( loc[length]=='"' ) in_quote = 1-in_quote;
  131.       if( isspace(loc[length]) && !in_quote ) break;
  132.       length++;
  133.     }
  134.  
  135. // A word is a program word if it is the first line on the page or it
  136. // follows a pipe.
  137.  
  138.   match_program = (loc==cl);
  139.   if( !match_program )
  140.     {
  141.       temp = loc;
  142.       while( temp>cl )
  143.         {
  144.           temp--;
  145.           if( !isspace(temp[0]) ) break;
  146.         }
  147.       if( temp[0]=='|' ) match_program = 1;
  148.     }
  149.  
  150.   strncpy(complete,loc,length+1);
  151.   complete[length] = '\0';
  152.   quote_it = 0;
  153.   if( complete[0]=='"' )
  154.     {
  155.       quote_it = 1;
  156.       complete++;
  157.       s = strlen(complete);
  158.       if( complete[s-1]=='"' ) complete[s-1] = '\0';
  159.     }
  160.  
  161. // Complete the directory 'complete'
  162.   strcpy(name,complete);
  163.   if( (defined(_DOS16_) || defined(_DOS32_) || defined(_WIN16_)) &&
  164.       strchr(name,'.')==NULL )
  165.     strcat(name,"*.*");
  166.   else
  167.     strcat(name,"*");
  168.  
  169. // Find all matches
  170.   choices = Directory(name);
  171.   it = SplitFileName(name);
  172.  
  173. // Assuming we are looking for a program, we also do some other looks
  174. // If it looks like he is typing in a pathname, do a completion on it
  175.   if( match_program && strpbrk(complete,path_chars)==NULL &&
  176.       complete[0]!='\0' )
  177.     {
  178. // First, add the aliases and internal commands.
  179.       for( i=0;i<=GetArraySpan(__Autoload_Alias_List);i++ )
  180.         {
  181.           if( strnicmp(__Autoload_Alias_List[i][0],complete,strlen(complete)) )
  182.             continue;
  183.           if( choices==NULL )
  184.             {
  185.               undefine(choices);
  186.               strcpy(choices[0].name,__Autoload_Alias_List[i][0]);
  187.               choices[0].attrib = 0;
  188.             } else {
  189.               add_it = 1;
  190.               for( k=0;k<=GetArraySpan(choices);k++ )
  191.                 {
  192.                   if( !stricmp(choices[k].name,__Autoload_Alias_List[i][0]) )
  193.                     {
  194.                       add_it = 0;
  195.                       break;
  196.                     }
  197.                 }
  198.               if( add_it )
  199.                 {
  200.                   index = GetArraySpan(choices)+1;
  201.                   strcpy(choices[index].name,__Autoload_Alias_List[i][0]);
  202.                   choices[index].attrib = 0;
  203.                 }
  204.             }
  205.         }
  206.       for( i=0;i<=GetArraySpan(__Autoload_Internal_Commands);i++ )
  207.         {
  208.           if( strnicmp(__Autoload_Internal_Commands[i],complete,
  209.                        strlen(complete)) )
  210.             continue;
  211.           if( choices==NULL )
  212.             {
  213.               undefine(choices);
  214.               strcpy(choices[0].name,__Autoload_Internal_Commands[i]);
  215.               choices[0].attrib = 0;
  216.             } else {
  217.               add_it = 1;
  218.               for( k=0;k<=GetArraySpan(choices);k++ )
  219.                 {
  220.                   if( !stricmp(choices[k].name,
  221.                                __Autoload_Internal_Commands[i]) )
  222.                     {
  223.                       add_it = 0;
  224.                       break;
  225.                     }
  226.                 }
  227.               if( add_it )
  228.                 {
  229.                   index = GetArraySpan(choices)+1;
  230.                   strcpy(choices[index].name,__Autoload_Internal_Commands[i]);
  231.                   choices[index].attrib = 0;
  232.                 }
  233.             }
  234.         }
  235.  
  236. // Add all the possible executables he could be referring to.
  237.       places = build_path_list();
  238.  
  239. // Search each of the directories, adding the entries to choices.
  240.       for( i=0;places!=NULL && i<=GetArraySpan(places);i++ )
  241.         {
  242.           sprintf(name2,"%s%s%s",places[i],it.name,it.ext);
  243.           choices2 = Directory(name2,FALSE,~FATTR_SUBDIR);
  244.           for( j=0;choices2!=NULL && j<=GetArraySpan(choices2);j++ )
  245.             {
  246.               it2 = SplitFileName(choices2[j].name);
  247.               sprintf(choices2[j].name,"%s%s",it2.name,it2.ext);
  248.  
  249. // if it has an extension, only consider those we know about.
  250.               if( strlen(it2.ext) )
  251.                 {
  252.                   allow_it = 0;
  253.                   for( x=0;x<=GetArraySpan(executable_extensions);x++ )
  254.                     {
  255.                       if( !stricmp(executable_extensions[x],it2.ext) )
  256.                         {
  257.                           allow_it = 1;
  258.                           break;
  259.                         }
  260.                     }
  261.                   if( !allow_it ) continue;
  262.                 }
  263.  
  264.               if( choices==NULL )
  265.                 {
  266.                   undefine(choices);
  267.                   choices[0] = choices2[j];
  268.                 } else {
  269.                   add_it = 1;
  270.                   for( k=0;k<=GetArraySpan(choices);k++ )
  271.                     {
  272.                       if( !stricmp(choices[k].name,choices2[j].name) )
  273.                         {
  274.                           add_it = 0;
  275.                           break;
  276.                         }
  277.                     }
  278.                   if( add_it )
  279.                     {
  280.                       choices[GetArraySpan(choices)+1] = choices2[j];
  281.                     }
  282.                 }
  283.             }
  284.         }
  285.     }
  286.  
  287.   beeped = 0;
  288.   if( choices!=NULL )
  289.     {
  290.       strcpy(biggest,choices[0].name);
  291.       biggest = choices[0].name;
  292.  
  293.       for( i=1;i<=GetArraySpan(choices);i++ )
  294.         {
  295.           newname = choices[i].name;
  296.           for( j=0;newname[j] && biggest[j] &&
  297.                toupper(newname[j])==toupper(biggest[j]);j++ );
  298.           if( (biggest[j] || newname[j]) && beeped==0 )
  299.             {
  300.               beeped = 1;
  301.               printf("\a");
  302.             }
  303.           biggest[j] = '\0';
  304.         }
  305.  
  306.       if( strchr(biggest,' ') ) quote_it = 1;
  307.       late_space = 0;
  308.       if( !beeped )
  309.         {
  310.           if( GetArraySpan(choices)==0 && (choices[0].attrib & FATTR_SUBDIR) )
  311.             strcat(biggest,filename_separator);
  312.           else
  313.             {
  314.               if( quote_it )
  315.                 late_space = 1;
  316.               else
  317.                 strcat(biggest," ");
  318.             }
  319.         }
  320.       if( quote_it ) sprintf(biggest,"\"%s\"",biggest);
  321.  
  322. // if completed totally, put a space after it and set quote_it to 0 so
  323. // the cursor position will be correct
  324.       if( late_space ) { strcat(biggest," "); quote_it = 0; }
  325.  
  326. // It may be that nothing matches what he gives, so don't erase what
  327. // he typed...
  328.  
  329.       if( strlen(biggest)>strlen(complete) )
  330.         {
  331.           big = strlen(biggest);
  332.           memmove(loc+big,loc+length,strlen(loc+length)+1);
  333.           memmove(loc,biggest,big);
  334.           pos = (loc-cl)+big-quote_it;
  335.         }
  336.     } else {
  337.       printf("\a");
  338.     }
  339. }
  340.  
  341. AddToHistory(pCommand)
  342. {
  343.    // skip all spaces at beginning of command
  344.    strcpy(lCommand,pCommand);
  345.    lCommand += strspn(lCommand," ");
  346.    // remove any spaces at end of command
  347.    while ( (lLastSpace = strrchr(lCommand,' '))  &&  !lLastSpace[1] )
  348.       lLastSpace[0] = '\0';
  349.  
  350.    // if no command remains then do not save
  351.    if ( !lCommand[0] )
  352.       return;
  353.  
  354.    // if this entry is already in the history then remove that entry so this
  355.    // one can replace as most recent.  Otherwise remove oldest entry if there
  356.    // are up to max in the buffer
  357.    bool lNewEntry = True;
  358.    for ( lOldEntry = 0; lOldEntry < gHistoryCount; lOldEntry++ ) {
  359.       if ( !stricmp(lCommand,gHistoryList[lOldEntry]) ) {
  360.          lNewEntry = False;
  361.          break;
  362.       }
  363.    }
  364.  
  365.    // move all entries down one to fill in the old gap
  366.    while ( lOldEntry-- )
  367.       gHistoryList[lOldEntry+1] = gHistoryList[lOldEntry];
  368.  
  369.    // new command goes to top of list
  370.    gHistoryList[0] = lCommand;
  371.    if ( gHistoryCount < HISTORY_MAX_MEMORY  &&  lNewEntry )
  372.       gHistoryCount++;
  373.    gReviewLine = 0;
  374. }
  375.  
  376. //**************************************************************************
  377. //****** END SECTION TO HANDLE HISTORY AND EDITING FOR THE CLI SHELL *******
  378. //**************************************************************************
  379.