home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK4 / SAMPLES / PWBEXTEN / INDENT.C$ / INDENT
Encoding:
Text File  |  1992-01-15  |  9.8 KB  |  344 lines

  1. /* INDENT.C -- Sample autoindentation handler
  2.  *
  3.  * Copyright (C) 1992, Microsoft Corporation, All rights reserved
  4.  *
  5.  * Demonstrates PWB 2.x autoindentation handling
  6.  *
  7.  *Switches:
  8.  *
  9.  *  i_suffixes:.c .h .cxx .hxx .cpp .hpp ;list of suffixes to handle
  10.  *  i_softcr:yes                         ;enable this handler
  11.  *  Simplecr:no                          ;perform only simple indent
  12.  *
  13.  *Functions:
  14.  *
  15.  *  None (all action is performed by an event handler)
  16.  *
  17.  *Remarks:
  18.  *
  19.  *  The i_suffixes switch lists the filename extensions for which
  20.  *  this extension should handle automatic indentation. If '.*' is
  21.  *  specified, handles all files. Note that the wildcard feature is
  22.  *  not supported by the standard language extensions.
  23.  *
  24.  *  The i_softcr switch turns this handler on and off.
  25.  *
  26.  *  When the Simplecr switch is turned on, this handler indents
  27.  *  to the same level as the current line. When turned off,
  28.  *  special indentation for C/C++ is performed.
  29.  *
  30.  */
  31. #pragma warning( disable:4001 )  //Allow single-line comments
  32. #pragma warning( disable:4100 )  //Allow unused arguments
  33. #include <ext.h>
  34.  
  35. void _cdecl EXPORT WhenLoaded( void );
  36.  
  37. //  Text switch handler
  38. char far * pascal EXTERNAL GetSetISuffixList( char far *pszISuffixList,
  39.                                               flagType fQuery );
  40.  
  41. //  Private utilities
  42. static int pascal CKeywordLookup( char far * s );
  43. static flagType pascal parseline( char far *pbuf,
  44.                                   char far * far *ppbegtok,
  45.                                   char far * far *ppendtok );
  46. static flagType pascal IsISuffix( char far *szSuffix );
  47.  
  48. //  Event handler
  49. flagType pascal EXPORT ISoftcr( EVTargs far *lpevtargs );
  50.  
  51.  
  52. //----------------------- Miscellaneous Data -----------------------//
  53.  
  54. // global common buffer.
  55. //
  56. linebuf lbTmp;
  57.  
  58. // C/C++ keyword table for ISoftcr routine
  59. // Future enhancement:
  60. //   Change CKeywordLookup and use a text switch for the table.
  61. static char * CKeywords[] =
  62. {
  63.     "if"        ,
  64.     "else"      ,
  65.     "for"       ,
  66.     "while"     ,
  67.     "do"        ,
  68.     "case"      ,
  69.     "default"   ,
  70.  
  71.     //  C++
  72.     "private"   ,
  73.     "protected" ,
  74.     "public"    ,
  75.  
  76.     NULL
  77. };
  78.  
  79. //  Switch names
  80. char SzISuffixes[]  = "i_suffixes";
  81. char SzISoftcr[]    = "i_softcr";
  82. char SzISimplecr[]  = "Simplecr";
  83.  
  84. // default list of suffixes associated with the <i_suffixes> switch
  85. //
  86. buffer SzISuffixList = ".c .h .cxx .hxx .cpp .hpp";
  87.  
  88. // storage for Boolean switches
  89. //
  90. flagType fISoftcr   = TRUE;     //handle autoindentation
  91. flagType fISimplecr = FALSE;    //do only simple autoindentation
  92.  
  93.  
  94. //------------------- Standard PWB extension data ------------------//
  95.  
  96. // Command description table. This extension defines no commands.
  97. //
  98. struct cmdDesc cmdTable[] = { { NULL, NULL, 0, 0 } };
  99.  
  100. // Switch description table.
  101. //
  102. struct swiDesc swiTable[] =
  103. {
  104.     { (char far *)SzISuffixes, GetSetISuffixList, SWI_EXTTEXT },
  105.     { (char far *)SzISoftcr,   toPIF(fISoftcr),   SWI_BOOLEAN },
  106.     { (char far *)SzISimplecr, toPIF(fISimplecr), SWI_BOOLEAN },
  107.     { NULL,                    NULL,              0 }
  108. };
  109.  
  110. // Event structure to register
  111. static  EVT EvtNewline = { 0, ISoftcr, 0, EVT_NEWLINE, 0 };
  112.  
  113. void _cdecl EXPORT WhenLoaded( void )
  114. {
  115.     RegisterEvent (&EvtNewline);
  116. }
  117.  
  118. //------------------------- GetSetISuffixList ---------------------//
  119. //
  120. // Set/get the current value of the <i_suffixes> switch.
  121. //
  122. // Input:
  123. //  pszISuffixList - pointer to suffix text
  124. //  fQuery         - boolean to indicate whether we are getting or setting
  125. //
  126. // Output:
  127. //  fQuery TRUE: return pointer to SzISuffixList
  128. //  fQuery FALSE: return NULL
  129. //
  130. //-----------------------------------------------------------------//
  131.  
  132. char far * pascal EXTERNAL GetSetISuffixList (
  133.         char far *pszISuffixList,
  134.         flagType fQuery
  135.         )
  136. {
  137.     if( fQuery )
  138.         return ((char far *)SzISuffixList);
  139.     farstrcpy (SzISuffixList, pszISuffixList);
  140.     return (NULL);
  141. }
  142.  
  143. //------------------------ CKeywordLookup -------------------------//
  144. //
  145. // Locate string in CKeywords table.
  146. //
  147. // Input:
  148. //  s           - pointer to string to search for in CKeyword table
  149. //
  150. // Output:
  151. //  Returns index+1 of first string s that is in table, or zero.
  152. //
  153. //-----------------------------------------------------------------//
  154.  
  155. static int pascal CKeywordLookup( char far *s )
  156. {
  157.     int i;
  158.  
  159.     for( i=0; CKeywords[i]; i++ )
  160.         if( !farstricmp( CKeywords[i], s ) )
  161.             return i+1;
  162.     return 0;
  163.  
  164. } // CKeywordLookup
  165.  
  166.  
  167. static flagType pascal parseline (
  168.         char far *pbuf,
  169.         char far * far *ppbegtok,
  170.         char far * far *ppendtok
  171.         )
  172. {
  173.     char far *p1, far *p2;
  174.  
  175.     p1 = pbuf;
  176.     while( *p1 == ' ' )
  177.         p1++;                           // skip whitespace
  178.  
  179.     if( !*p1 )
  180.         return FALSE;
  181.     if( (p2 = farstrchr( p1, ' ' )) != NULL ) // find blank
  182.     {
  183.         *p2++ = 0;
  184.         p2 += farstrlen( p2 ) - 1;
  185.         while( *p2 )
  186.             if( *p2 == ' ' )
  187.                 break;
  188.             else
  189.                 p2--;
  190.         if( !*++p2 )
  191.             p2 = p1;    //no other token on line, end same as begin
  192.     }
  193.     else
  194.         p2 = p1;
  195.     *ppbegtok = p1;
  196.     *ppendtok = p2;
  197.     return TRUE;
  198. }
  199.  
  200.  
  201. //----------------------------- IsISuffix -------------------------//
  202. //
  203. // Determine whether a file suffix occurs in the list of "known"
  204. // suffixes given by the <i_suffixes> switch.
  205. //
  206. // Input:
  207. //  szSuffix    - the suffix we are testing for.
  208. //
  209. // Output:
  210. //      TRUE:  file suffix recognized.
  211. //      FALSE: file suffix not recognized.
  212. //
  213. //-----------------------------------------------------------------//
  214.  
  215. static flagType pascal IsISuffix( char far *szSuffix )
  216. {
  217.     char far *pbeg, far *pend;
  218.  
  219.     // check suffix to determine whether szSuffix matches a suffix given
  220.     // by the <i_suffixes> switch.
  221.  
  222.     // if list contains .*, match all extensions
  223.     if( farstrstr( SzISuffixList, ".*" ) != NULL )
  224.         return TRUE;
  225.  
  226.     pend = SzISuffixList;
  227.     do {
  228.         if( (pbeg = farstrchr( pend, '.' )) != NULL )
  229.             return FALSE;
  230.         if( (pend = farstrchr( pbeg, ' ' )) != NULL )
  231.             pend = pbeg + farstrlen( pbeg );
  232.  
  233.     } while(    farstrlen( szSuffix ) != (pend - pbeg )
  234.              || farstrnicmp( pbeg, szSuffix, pend - pbeg ) );
  235.  
  236.     return TRUE;
  237.  
  238. } // IsISuffix
  239.  
  240. //----------------------------- ISoftcr ---------------------------//
  241. //
  242. // Perform C soft CR processing.
  243. //
  244. // Algorithm:
  245. //
  246. //  Given that you have just entered a newline at the end of a line:
  247. //      If file suffix is found in <i_suffixes> switch then:
  248. //      If Simple flag set, indent same as current
  249. //      else if the original line begins with "}", tab out
  250. //      else if the original line ends with "{" or begins with a keyword,
  251. //              tab in
  252. //      else if the line preceding the original line doen't end with "{"
  253. //           but does begin with a keyword, tab out
  254. //
  255. // Input:
  256. //  lpevtargs  FAR pointer to event arguments
  257. //
  258. // Output:
  259. //      TRUE:  File suffix recognized. Tab as indicated by tabmode.
  260. //      FALSE: File suffix not recognized. Let another extension or
  261. //             PWB handle the autoindent.
  262. //
  263. //------------------------------------------------------------------//
  264.  
  265. flagType pascal EXPORT ISoftcr( EVTargs far *lpevtargs )
  266. {
  267.  
  268.     char far *pbeg, far *pend, far *p;
  269.     flagType fEmpty = TRUE;
  270.  
  271.     // check suffix to determine whether we are interested in this file.
  272.     // if current file's suffix matches a suffix given by the
  273.     // <i_suffixes> switch, then process the EVT_NEWLINE.
  274.     //
  275.     if( fISoftcr && IsISuffix( lpevtargs->EvtNewline.lpszSuffix ) )
  276.     {
  277.  
  278.         GetLine( lpevtargs->EvtNewline.line, (char far *)lbTmp,
  279.                  lpevtargs->EvtNewline.pFile );
  280.  
  281.         // Skip whitespace.
  282.         // GetLine translates tabs to spaces...
  283.         //
  284.         p = lbTmp;
  285.         while( *p == ' ' )
  286.             p++;
  287.         if( !*p )
  288.         {
  289.             p = lbTmp;
  290.             fEmpty = TRUE;
  291.         }
  292.  
  293.         // calculate new column position based on current line.
  294.         //
  295.         lpevtargs->EvtNewline.newcol = p - (char far *)lbTmp;
  296.  
  297.         // determine whether to tab forward or backward from there based
  298.         // on a lookup of certain C keywords...
  299.         //
  300.         if( !fISimplecr && parseline( lbTmp, &pbeg, &pend ) )
  301.         {
  302.             if( *pbeg == '}' )
  303.             {
  304.                 lpevtargs->EvtNewline.tabmode = TM_BACKWARD;
  305.                 return TRUE;
  306.             }
  307.             else
  308.             if(  (pend && *pend == '{' ) || CKeywordLookup( pbeg ) )
  309.             {
  310.                 lpevtargs->EvtNewline.tabmode = TM_FORWARD;
  311.                 return TRUE;
  312.             }
  313.             else
  314.             if( lpevtargs->EvtNewline.line )
  315.             {
  316.                 GetLine( lpevtargs->EvtNewline.line-1, (char far *)lbTmp,
  317.                          lpevtargs->EvtNewline.pFile );
  318.                 if( parseline( lbTmp, &pbeg, &pend ) )
  319.                 {
  320.                     if(  !(pend && *pend == '{') && CKeywordLookup( pbeg ) )
  321.                     {
  322.                         lpevtargs->EvtNewline.tabmode = TM_BACKWARD;
  323.                         return TRUE;
  324.                     }
  325.                 }
  326.             }
  327.         }
  328.  
  329.         // Simple flag set or fell through special conditions: Indent to
  330.         // same level as previous line, or cursor column if blank
  331.         //
  332.         if( fEmpty )    // current line empty
  333.         {
  334.             COL x; LINE y;
  335.             GetCursor( (COL far *)&x, (LINE far *)&y );
  336.             lpevtargs->EvtNewline.newcol = x;
  337.         }
  338.         lpevtargs->EvtNewline.tabmode = TM_NONE;
  339.         return TRUE;
  340.     }
  341.     return FALSE;
  342.  
  343. }
  344.