home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c031 / 4.ddi / SAMPLES / PWBEXTEN / ISEARCH.C$ / ISEARCH
Encoding:
Text File  |  1992-01-22  |  10.5 KB  |  400 lines

  1. /* ISEARCH.C - Emacs-style incremental search
  2.  *
  3.  * Copyright (C) 1988-1992, Microsoft Corporation
  4.  * All rights reserved.
  5.  *
  6.  * Demonstrates the following extension functions and features:
  7.  *
  8.  * Callback functions:
  9.  *  DoMessage, GetCursor, GetEditorObject, MoveCur, ReadChar, search
  10.  *
  11.  * Types:
  12.  *  SearchInfo, fl
  13.  *
  14.  * Switches: none
  15.  *
  16.  * Functions:
  17.  *  ISearch:Ctrl+I
  18.  *
  19.  */
  20.  
  21. /*  Turn off common warnings for benign extension constructs */
  22. #pragma warning( disable:4001 )  //Allow single-line comments
  23. #pragma warning( disable:4100 )  //Allow unused arguments
  24.  
  25. #include <stdlib.h>
  26. #include <ext.h>
  27. #include <readchar.h>
  28.  
  29. //  Exported functions
  30. //
  31. void _cdecl EXTERNAL WhenLoaded( void );
  32. PWBFUNC ISearch( unsigned int, ARG far *, flagType );
  33.  
  34. //  Private functions
  35. //
  36. void GetKey( WORD *shift, WORD *vk, WORD*code );
  37. void Adjust_fl( fl *Loc, flagType fDir );
  38.  
  39. //
  40. //  Stack of locations
  41. //
  42. #define LOC_MAX 50
  43. #define LOC_TOP LOC_MAX-1
  44. #define LOC_EMPTY -1
  45. #define LOC_END -2
  46. static fl  flStack[LOC_MAX];
  47. static int iTop = LOC_EMPTY;
  48.  
  49. void     PushLoc( void );
  50. flagType PopLoc( void  );
  51. void     ClearLoc( void );
  52.  
  53. static char szISearch[]    = "ISearch";
  54. static char szISearchKey[] = "Ctrl+I";
  55.  
  56.  
  57. void PushLoc( void )
  58. {
  59.     if( iTop == LOC_EMPTY )
  60.         iTop = 0;
  61.  
  62.     GetCursor( &flStack[iTop].col, &flStack[iTop].lin );
  63.     if( ++iTop > LOC_TOP )
  64.         iTop = 0;
  65.     flStack[iTop].col = LOC_END;  //set sentinel
  66.  
  67. }
  68.  
  69. flagType PopLoc( void )
  70. {
  71.     if( iTop == LOC_EMPTY )
  72.         return FALSE;
  73.  
  74.     if( --iTop < 0 )
  75.         iTop = LOC_TOP;
  76.  
  77.     if( flStack[iTop].col == LOC_END )
  78.     {
  79.         iTop = LOC_EMPTY;
  80.         return FALSE;
  81.     }
  82.  
  83.     MoveCur( flStack[iTop].col, flStack[iTop].lin );
  84.  
  85. }
  86.  
  87. void ClearLoc( void )
  88. {
  89.     iTop = LOC_EMPTY;
  90.     flStack[0].col = LOC_END;
  91.     flStack[LOC_TOP].col = LOC_END;
  92.  
  93. }
  94.  
  95.  
  96. //  GetKey
  97. //  Read a keystroke and extract its component fields.
  98. //
  99. void GetKey( WORD *shift, WORD *vk, WORD*code )
  100. {
  101.     long Key = ReadChar();
  102.  
  103.     *shift = HIWORD(Key) & ~KK_VK;  //shift state
  104.     *vk    = HIWORD(Key) & KK_VK;   //virtual key code
  105.     *code  = LOWORD(Key) & KK_VK;   //ASCII/virtual key code
  106. }
  107.  
  108. //  Adjust_fl
  109. //  Adjust a file location such that search() does not match the current
  110. //  location.
  111. //
  112. void Adjust_fl( fl *Loc, flagType fDir )
  113. {
  114.     if( fDir )
  115.     {
  116.         Loc->col++;
  117.         if( Loc->col >= BUFLEN )
  118.         {
  119.             Loc->lin++;
  120.             Loc->col = 0;
  121.         }
  122.     }
  123.     else
  124.     {
  125.         if( Loc->col > 0 )
  126.             Loc->col--;
  127.         else
  128.         {
  129.             Loc->lin--;
  130.             Loc->col = BUFLEN-1;
  131.         }
  132.     }
  133.  
  134. }
  135.  
  136. // ISearch - Incremental search function
  137. //
  138. // Input:
  139. //
  140. //  nullarg     - Default entry state
  141. //  textarg     - Initial search string
  142. //  arg arg...  - Reverse search
  143. //  meta...     - Case-insensitive
  144. //
  145. // Output:
  146. //  TRUE : cursor moved
  147. //  FALSE: cursor not moved: ISearch cancelled
  148. //
  149. // Description:
  150. //
  151. //  On entry:
  152. //      The status bar shows "+ │ISearch:" and waits for keystrokes.
  153. //      If reverse search,   "- │ISearch:"
  154. //
  155. //  Status Bar:
  156. //      After each search, if found: "+■│ISearch:<pattern>"
  157. //                         else:     "+ │ISearch:<pattern>"
  158. //
  159. //  CTRL+I(entry) - Display the last search string and go to the next
  160. //                  occurrence.
  161. //
  162. //  CTRL+I, F3    - Move to the next occurrence
  163. //
  164. //  F4            - Move to the previous occurrence
  165. //
  166. //  Any character - Append to the search string, display it on the message
  167. //                  line, and go to the first occurrence.
  168. //
  169. //  BKSP          - If last action was find, return to each previous
  170. //                  occurrence in order.
  171. //
  172. //                  If a character was typed, remove the character from the
  173. //                  string and show the cursor before that character was
  174. //                  added.
  175. //
  176. //  ENTER:          Exit and leave the cursor at the last location.
  177. //
  178. //  ESC, CTRL+G   - Exit and return the cursor to the position on entry to
  179. //                  ISearch.
  180. //
  181.  
  182. PWBFUNC ISearch( unsigned int argData, ARG far *pArg, flagType fMeta )
  183. {
  184.     SearchInfo *si;                     //previous search information
  185.     flagType fForward;                  //direction
  186.     flagType fCase = (flagType)!fMeta;  //case
  187.     fl       flStart;                   //starting location
  188.     fl       flCur;                     //current location
  189.     WORD vk;                            //keycode
  190.     WORD shift;                         //shift state
  191.     WORD code;                          //ASCII or virtual key code
  192.     PFILE pfile;                        //current file
  193.                                         //incremental search state
  194.     enum { ssERROR, ssENTRY, ssFIND, ssCHAR } iss;
  195.     static buffer Pattern;              //search pattern
  196.     char far *pchPatEnd;                //end of pattern
  197.     #define PROMPT "  │ISearch:"        //prompt string
  198.     static buffer Prompt;               //prompt buffer
  199.     char far *pchPatPrompt = Prompt+11; //position of pattern in buffer
  200.  
  201.     if( (pfile = FileNameToHandle( "", "" )) == PNULL ) //no file
  202.         return FALSE;
  203.  
  204.     GetEditorObject( RQ_SEARCHINFO, 0, &si ); //get current search state
  205.  
  206.     GetCursor( &flStart.col, &flStart.lin );  //get starting location
  207.     flCur.col = flStart.col;
  208.     flCur.lin = flStart.lin;
  209.     ClearLoc();                               //clear location stack
  210.     PushLoc();                                //push starting position
  211.  
  212.     iss = ssENTRY;
  213.     switch( pArg->argType )
  214.     {
  215.     case NOARG:
  216.         fForward = TRUE;
  217.         Pattern[0] = 0;
  218.         break;
  219.  
  220.     case NULLARG:
  221.         fForward = (flagType)(pArg->arg.nullarg.cArg <= 1);
  222.         Pattern[0] = 0;
  223.         break;
  224.  
  225.     case TEXTARG:
  226.         fForward = (flagType)(pArg->arg.textarg.cArg <= 1);
  227.         farstrcpy( Pattern, pArg->arg.textarg.pText );
  228.         if( search( pfile, fForward, FALSE, fCase, si->swit.fSrchWrap,
  229.                     Pattern, &flCur ) == -1 )
  230.             Prompt[1] = ' ';
  231.         else
  232.         {
  233.             Prompt[1] = '■';
  234.             MoveCur( flCur.col, flCur.lin );
  235.             PushLoc();
  236.         }
  237.         iss = ssFIND;
  238.         break;
  239.  
  240.     default:
  241.         return BadArg();
  242.     }
  243.  
  244.     farstrcpy( Prompt, PROMPT );
  245.     Prompt[0] = (char)(fForward ? '+' : '-');
  246.     pchPatEnd = Pattern + farstrlen( Pattern );
  247.  
  248.     for(;;)
  249.     {
  250.         farstrcpy( pchPatPrompt, Pattern );
  251.         DoMessage( Prompt );
  252.         GetKey( &shift, &vk, &code );
  253.  
  254.         //  ENTER: done
  255.         if( vk == VK_RETURN )
  256.         {
  257.             DoMessage( NULL );
  258.             return TRUE;
  259.         }
  260.  
  261.         //  ESC, CTRL+G : return to starting position and stop
  262.         if( (vk == VK_ESCAPE) || (shift & KK_CONTROL && vk == VK_G) )
  263.         {
  264.             MoveCur( flStart.col, flStart.lin );
  265.             DoMessage( NULL );
  266.  
  267.             //  Set global SearchInfo
  268.             farstrcpy( si->prev.szSrch, Pattern );
  269.             si->prev.fSrchDir  = fForward;
  270.             si->prev.fSrchCase = fCase;
  271.             si->prev.fSrchRe   = FALSE;
  272.  
  273.             return FALSE;
  274.         }
  275.  
  276.         //  CTRL+I, F3 : repeat search
  277.         if( (vk == VK_F3) || (shift & KK_CONTROL && vk == VK_I) )
  278.         {
  279.             if( iss == ssENTRY ) //Search for previous search string
  280.             {
  281.                 //get current search state
  282.                 GetEditorObject( RQ_SEARCHINFO, 0, &si );
  283.                 farstrcpy( Pattern, si->prev.szSrch );
  284.                 pchPatEnd = Pattern + farstrlen( Pattern );
  285.                 farstrcpy( pchPatPrompt, Pattern );
  286.                 DoMessage( Prompt );
  287.             }
  288.  
  289.             PushLoc();
  290.             Adjust_fl( &flCur, (flagType)fForward );
  291.             if( search( pfile, fForward, FALSE, fCase, si->swit.fSrchWrap,
  292.                         Pattern, &flCur ) == -1 )
  293.             {
  294.                 Prompt[1] = ' ';
  295.                 // restore unadjusted location
  296.                 GetCursor( &flCur.col, &flCur.lin );
  297.             }
  298.             else
  299.             {
  300.                 Prompt[1] = '■';
  301.                 MoveCur( flCur.col, flCur.lin );
  302.             }
  303.             iss = ssFIND;
  304.             continue;
  305.         }
  306.  
  307.         if( vk == VK_F4 )   //reverse search
  308.         {
  309.             PushLoc();
  310.             Adjust_fl( &flCur, (flagType)!fForward );
  311.             if( search( pfile, (flagType)!fForward, FALSE, fCase,
  312.                         si->swit.fSrchWrap, Pattern, &flCur ) == -1 )
  313.             {
  314.                 Prompt[1] = ' ';
  315.                 // restore unadjusted location
  316.                 GetCursor( &flCur.col, &flCur.lin );
  317.             }
  318.             else
  319.             {
  320.                 Prompt[1] = '■';
  321.                 MoveCur( flCur.col, flCur.lin );
  322.             }
  323.             iss = ssFIND;
  324.             continue;
  325.         }
  326.  
  327.         if( vk == VK_BACK ) //BKSP: back up
  328.         {
  329.             if( iss == ssCHAR )
  330.                 if( pchPatEnd > Pattern )
  331.                 {
  332.                     *--pchPatEnd = '\0';
  333.                     farstrcpy( pchPatPrompt, Pattern );
  334.                 }
  335.                 else
  336.                     bell();
  337.             if( PopLoc() )
  338.                 GetCursor( &flCur.col, &flCur.lin );
  339.             continue;
  340.         }
  341.  
  342.         if( (code < VK_MIN) || (code >= VK_A && code <= VK_Z) )
  343.         {
  344.             *pchPatEnd++ = (char)code;
  345.             *pchPatEnd = '\0';
  346.             farstrcpy( pchPatPrompt, Pattern );
  347.             DoMessage( Prompt );
  348.  
  349.             PushLoc();
  350.             if( search( pfile, fForward, FALSE, fCase, si->swit.fSrchWrap,
  351.                 Pattern, &flCur ) == -1 )
  352.             {
  353.                 Prompt[1] = ' ';
  354.             }
  355.             else
  356.             {
  357.                 Prompt[1] = '■';
  358.                 MoveCur( flCur.col, flCur.lin );
  359.             }
  360.             iss = ssCHAR;
  361.             continue;
  362.         }
  363.  
  364.         // Illegal key
  365.         bell();
  366.  
  367.     }
  368.  
  369. }
  370.  
  371.  
  372. //-------------------< Standard Extension Information >--------------------
  373.  
  374. //  WhenLoaded - Extension initialization
  375. void _cdecl EXTERNAL WhenLoaded( void )
  376. {
  377.     DoStatusBox( "Incremental Search Extension", NULL );
  378.  
  379.     SetKey( szISearch, szISearchKey );
  380.  
  381.     DoStatusBox( NULL, NULL );
  382. }
  383.  
  384. //
  385. // Command description table.
  386. //
  387. struct cmdDesc cmdTable[] =
  388. {
  389.     {szISearch, ISearch, 0, NOARG|NULLARG|TEXTARG },
  390.     {NULL, NULL, 0, 0 }
  391. };
  392.  
  393. //
  394. // Switch description table.
  395. //
  396. struct swiDesc swiTable[] =
  397. {
  398.     { NULL, NULL, 0 }
  399. };
  400.