home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0010 - 0019 / ibm0010-0019 / ibm0010.tar / ibm0010 / ME494-3.ZIP / C.SRC < prev    next >
Encoding:
Text File  |  1990-03-29  |  20.1 KB  |  882 lines

  1. $MACRO_FILE C;
  2. {******************************************************************************
  3.                                                         MULTI-EDIT MACRO FILE
  4.  
  5. Name:        C
  6.  
  7. Description:  This macro file contains language support macros for C.
  8.  
  9. C_IND - Smart indent for C
  10. CMTCH - Construct/brace matching for C
  11. BUILDCMT - Builds a shell of a comment block for C
  12. CTEMP - Template editing for C
  13.  
  14.                              (C) Copyright 1989 by American Cybernetics, Inc.
  15. ******************************************************************************}
  16.  
  17. $MACRO C_IND;
  18. {******************************************************************************
  19.                                                                 MULTI-EDIT MACRO
  20.  
  21. Name: C_IND
  22.  
  23. Description: Performs a smart indent each time the Carriage Return or Enter
  24. key is pressed.  Is called by the macro CR.
  25.  
  26. Written by Todd M. Johnson and William M. Miller.
  27.  
  28. The algorithm used is to look at the line-ending characters (ignoring
  29. comments, including C++ '//' comments, labels, and white space) for the
  30. current and preceding lines, then decide whether and how much to change the
  31. indentation from that of the current line.  In addition, if the CR was done
  32. inside a (C-style, /* */) comment, the "line of asterisks" style of comment
  33. continuation is automatically supplied.
  34.  
  35.                              (C) Copyright 1989 by American Cybernetics, Inc.
  36. ******************************************************************************}
  37.  
  38.     def_int(outdent_flag,
  39.                     sig_char_found,
  40.                     in_comment,  {1 = /* comment, 2 = // comment}
  41.                     curr_ind,
  42.                     start_col,
  43.                     start_line,
  44.                     cur_char_line,
  45.                     curr_end_char,
  46.                     prev_end_char,
  47.                     in_struct,
  48.                     junk,
  49.                     match_brace, go_match_brace,
  50.                     jx);
  51.  
  52.     def_char( orig_char );
  53.  
  54.     {If you want an outdent after a right brace then change the following
  55.      Outdent_flag to True.}
  56.  
  57.     Outdent_flag := FALSE;
  58.  
  59.     {If you want your end brace to line up with the first word of the
  60.      line that the opening brace is on, then set Match_Brace to TRUE}
  61.     Match_Brace := TRUE;
  62.     go_match_brace := FALSE;
  63.  
  64.     Messages := False;
  65.     reg_exp_stat := true;
  66.     mark_pos;
  67.  
  68.     { If we are before or at the first character of the first word of the line
  69.         then leave the level the same for the line }
  70.     start_col := c_col;
  71.     start_line := c_line;
  72.     first_word;
  73.     if c_col >= start_col then
  74.         set_indent_level;
  75.         cr;
  76.         goto mac_exit;
  77.     end;
  78.     orig_char := cur_char;
  79.     goto_col(start_col);
  80.  
  81.     call skip_c_noise;
  82.  
  83. { If the cursor is inside a comment, skip_c_noise leaves it at the opening
  84.     '/'.  We move one character right, to align with the '*', set the indent
  85.     level, do the carriage return, and insert a '* ' to form the line of
  86.     asterisks continuation. }
  87.  
  88.     if (in_comment) then
  89.         right;
  90.         set_indent_level;
  91.         right;
  92.         while NOT(at_eol) and (xpos(cur_char,' |9|255',1) <> 0) do
  93.             right;
  94.         end;
  95.         start_col := c_col;
  96.         goto_mark;
  97.         cr;
  98.  
  99.         {If you don't want the * then comment out the next line}
  100.         if (in_comment = 1) then
  101.             text('* ');
  102.         end;
  103.     {    while c_col < start_col do
  104.             text(' ');
  105.         end; }
  106.  
  107.         set_indent_level;
  108.         goto mac_exit;
  109.     end;
  110.  
  111. { Here, we are at the top of the file, before any non-comment text.  We just
  112.     put everything in column 1 in that case. }
  113.  
  114.     if (not(sig_char_found)) then
  115.         goto_col(1);
  116.         set_indent_level;
  117.         goto_mark;
  118.         cr;
  119.         goto mac_exit;
  120.     end;
  121.  
  122. { Here we've found the nearest non-noise character.  There are four that
  123.     specifically influence indentation decisions, so instead of carrying around
  124.     a big string variable, we just save the index into a string of those four
  125.     characters.  In addition, we find the first non-blank character on the line
  126.     to determine its indentation.  Furthermore, we check if that first character
  127.     is a '}' (probably as a result of the '} name;' at the end of a structure,
  128.     union, or enum definition) so we can know how much to indent later. }
  129.  
  130.     cur_char_line := c_line;
  131.     curr_end_char := pos(cur_char, ';{},');
  132.  
  133.         {Special processing if we have a lone '{' on a line}
  134.     jx := c_col;                        { store the current column position }
  135.     first_word;
  136.     if (c_col = jx) and (curr_end_char = 2) then
  137.         curr_ind := 1;
  138.         set_indent_level;
  139.         goto do_curs;
  140.     end;
  141.  
  142.     set_indent_level;
  143.     curr_ind := 0;
  144.     start_col := c_col;
  145.     in_struct := (cur_char = '}');
  146.  
  147.  
  148. { Now we get the line ending for the preceding line. }
  149.     call skip_c_noisex;  {no need to check to see if we're in a comment}
  150.     if (sig_char_found) then
  151.         prev_end_char := pos(cur_char, ';{}');
  152.     else
  153.         prev_end_char := 1;    { treat like semicolon }
  154.     end;
  155.  
  156.  
  157. { This code is executed when the nearest line-ending character was a semicolon.
  158.     }
  159.  
  160.     if (curr_end_char = 1) then     { semicolon }
  161.         if (prev_end_char = 0) then   {if continuation line then undent twice}
  162.             curr_ind := curr_ind - 2;
  163.         end;
  164.         if (outdent_flag and in_struct) then
  165.             curr_ind := curr_ind - 1;
  166.         end;
  167.     else
  168.  
  169.  
  170. { This code is executed if the nearest line-ending character was a left
  171.     brace.
  172.     }
  173.         if (curr_end_char = 2) then         { left brace }
  174.             curr_ind := curr_ind + 1;
  175.             if (prev_end_char = 0) then
  176.                 curr_ind := curr_ind - 2;       {if continuation line then undent twice}
  177.             end;
  178.         else
  179.             if (curr_end_char = 3) then       { right brace }
  180.                 if (outdent_flag) then
  181.                     curr_ind := curr_ind - 1;
  182.                 else
  183.                     IF (Match_Brace) THEN
  184.                         IF cur_char_line = start_line THEN
  185.                             go_match_brace := TRUE;
  186.                         END;
  187.                     END;
  188.                 END;
  189.             else
  190.  
  191. { Commas cause no indentation (to support enum declarations).  If the line-
  192.     ending character was none of the above, the new line will be a continuation
  193.     line, indented twice.  However, if the preceding line-ending character was not
  194.     ';{}', we assume that the current line was already a continuation line and no
  195.     further indentation is necessary. }
  196.  
  197.                 if ((curr_end_char <> 4) and (prev_end_char <> 0)) then
  198.                     curr_ind := curr_ind + 2;
  199.                 end;
  200.  
  201.             end;
  202.         end;
  203.     end;
  204.  
  205. do_curs:
  206. { Here we put the cursor at the correct column position, we set the indent
  207.     level, return to the original position, and perform the carriage return. }
  208.  
  209.     jx := 0;
  210.  
  211.     goto_mark;
  212.     cr;
  213.     If curr_ind > 0 THEN
  214.         While jx < curr_ind do
  215.             ++jx;
  216.             indent;
  217.         END;
  218.     else
  219.         While jx > curr_ind do
  220.             --jx;
  221.             undent;
  222.         END;
  223.     end;
  224.  
  225.     set_indent_level;
  226.  
  227.     IF (go_match_brace) AND (orig_char = '}') THEN
  228.         refresh := false;
  229.         UP;
  230.         First_Word;
  231.         mark_pos;
  232.         RM( 'CMTCH' );
  233.         FIRST_WORD;
  234.         set_indent_level;
  235.         goto_mark;
  236.         first_word;
  237.         while (c_col > indent_level) DO
  238.             back_space;
  239.         END;
  240.         down;
  241.         make_message('} undenting occurred.');
  242.     END;
  243.  
  244.     goto mac_exit;
  245.  
  246.  
  247. skip_c_noisex:
  248.     Refresh := false;
  249.     IF (c_line = 1) AND (c_col = 1) THEN
  250.         sig_char_found := FALSE;
  251.         goto exit_skip_c;
  252.     END;
  253.     left;
  254.     goto skip_c_noise1;
  255.  
  256. { This subroutine moves the cursor to the nearest preceding non-whitespace
  257.     character.  If there is no such character (the cursor is at the top of the
  258.     file), the variable sig_char_found will be FALSE; otherwise, it will be
  259.     true.  The macro also sets the variable in_comment appropriately. }
  260.  
  261. skip_c_noise:
  262.     Refresh := false;
  263.  
  264.     left;
  265.     mark_pos;
  266.  
  267. { First check if we are inside a comment.  We look for the nearest of '/*' or
  268.     '*/'; if we find the former, we are inside a comment.  In this case, we
  269.     leave the cursor at the beginning of the comment to establish the correct
  270.     indentation margin and return. }
  271.  
  272. comment_again:
  273.     if (search_bwd('/',50)) THEN
  274.         right;
  275.         if (cur_char = '*') or (cur_char = '/') then
  276.             pop_mark;
  277.             if (cur_char = '/') then
  278.                 in_comment := 2;
  279.             ELSE
  280.                 in_comment := 1;
  281.             END;
  282.             left;
  283.             goto exit_skip_c;
  284.         end;
  285.         left;
  286.         left;
  287.         if (cur_char <> '*') then
  288.             goto comment_again;
  289.         end;
  290.     end;
  291.     goto_mark;
  292.     in_comment := FALSE;
  293.  
  294. { The following code is a loop which skips over comments (including C++ '//'
  295.     comments) and labels, leaving the cursor on the nearest preceding non-noise
  296.     character, if any. }
  297.  
  298.  
  299.  
  300. skip_c_noise1:
  301.  
  302.     IF (c_line = 1) AND (c_col = 1) THEN
  303.         sig_char_found := FALSE;
  304.         goto exit_skip_c;
  305.     END;
  306. { If there is a '//' on the line, we move the cursor before it and
  307.     look some more. }
  308.  
  309.     if (search_bwd('//', 1)) then
  310.         if ((c_col = 1) and (c_line = 1)) then
  311.             sig_char_found := FALSE;
  312.             goto exit_skip_c;
  313.         end;
  314.         left;
  315.         goto skip_c_noise1;
  316.     end;
  317.  
  318.  
  319.  
  320. { Here we look for the nearest preceding nonblank character.  If it is a '/',
  321.     we check if the preceding character was an asterisk; if so, we search for
  322.     the corresponding '/*' and try again.  If the character before the '/' was
  323.     not '*', we have found a significant character and are done. }
  324.  
  325.     if (search_bwd('[~|9 ]', 1)) then
  326.         if (cur_char = '/') then
  327.             left;
  328.             if (cur_char = '*') then
  329.                 junk := search_bwd('/@*', 0);
  330.                 left;
  331.                 goto skip_c_noise1;
  332.             end;
  333.             right;
  334.             sig_char_found := TRUE;
  335.             goto exit_skip_c;
  336.         end;
  337.  
  338. { If the character we found was a colon, we have found a label.  We assume
  339.     that the label was the first thing on the line and proceed to the end of
  340.     the preceding line.  Any other character is significant. }
  341.  
  342.         if (cur_char = ':') then
  343.             IF (C_Line = 1) THEN
  344.                 Eol;
  345.                 cr;
  346.                 Goto_Col(1);
  347.                 Indent;
  348.                 Set_Indent_Level;
  349.                 goto mac_exit;
  350.             END;
  351.             up;
  352.             eol;
  353.             goto skip_c_noise1;
  354.         end;
  355.         sig_char_found := TRUE;
  356.         goto exit_skip_c;
  357.     end;
  358.  
  359. { If we failed to find a nonblank character on the current line, and the
  360.     cursor is on line 1, we failed to find a significant character; otherwise,
  361.     we back up a line and try again. }
  362.  
  363.     if (c_line = 1) then
  364.         sig_char_found := FALSE;
  365.         goto exit_skip_c;
  366.     end;
  367.     up;
  368.     eol;
  369.     goto skip_c_noise1;
  370.  
  371. exit_skip_c:
  372.     refresh := true;
  373.     ret;
  374.  
  375. mac_exit:
  376.     Messages := True;
  377. END_MACRO;
  378.  
  379. $MACRO CMTCH TRANS;
  380. {******************************************************************************
  381.                                                                 MULTI-EDIT MACRO
  382.  
  383. Name: CMTCH
  384.  
  385. Description: Match occurances of {} or () and handles problems with
  386.     characters embedded in comments or quotes.
  387.      11/01/88 11:15am  Modified for greater speed.  Also, handles screen
  388.                                         updates much better.
  389.  
  390.                              (C) Copyright 1989 by American Cybernetics, Inc.
  391. ******************************************************************************}
  392.     DEF_STR( Str1,Str2,  Search_Str );  {Strings to match}
  393.  
  394.     DEF_INT( Direction,    {1 = Search forward, 0 = backward}
  395.                      B_Count,      {Brace count.  0 = match found}
  396.                      S_Res,        {Result of last search}
  397.                      T_Row, T_Col, T_Line, {Holds the original position}
  398.                      JX,           {General purpos}
  399.                      F_Line, F_Col ); {Found position}
  400.  
  401.     Refresh := False;      {Turn screen display off}
  402.     T_Line := C_Line;      {Store the current position}
  403.     T_Col := C_Col;
  404.  
  405.     Push_Undo;
  406.     Mark_Pos;
  407.  
  408. Find_Match_Str:
  409.  
  410.     IF (Cur_Char = '(') THEN    {If current char is a '(' then setup}
  411.         Str1 := '(';
  412.         Str2 := ')';
  413.         Direction := 1;
  414.         Goto Start_Match;
  415.     END;
  416.     IF (Cur_Char = ')') THEN    {If current char is a ')' then setup}
  417.         Str1 := ')';
  418.         Str2 := '(';
  419.         Direction := 0;
  420.         Goto Start_Match;
  421.     END;
  422.     IF (Cur_Char = '{') THEN    {If current char is a '{' then setup}
  423.         Str1 := '{';
  424.         Str2 := '}';
  425.         Direction := 1;
  426.         Goto Start_Match;
  427.     END;
  428.     IF (Cur_Char = '}') THEN    {If current char is a ')' then setup}
  429.         Str1 := '}';
  430.         Str2 := '{';
  431.         Direction := 0;
  432.         Goto Start_Match;
  433.     END;
  434.                                                             {If nothing matched then }
  435.                                                             {  Return to original position}
  436.     Goto_Line(T_Line);
  437.     Goto_Col(T_Col);
  438.     Goto_Mark;
  439.     Make_Message('NOTHING to Match');
  440.     Goto Macro_Exit;            {Go exit}
  441.  
  442. Start_Match:
  443.  
  444.  { Search_Str := '{\["'']}||[''"]||{/@*}||{@*/}||[' + Str1 + Str2+']'; }
  445.  
  446.     Search_Str := '["''/' + Str1 + Str2 + ']';
  447.  
  448.     Reg_Exp_Stat := True;
  449.     Ignore_Case := True;        {Ignore the search case}
  450.     B_Count := 1;               {Brace count starts at 1}
  451.     S_Res := 1;                 {Init search result to true}
  452.                                                             {Tell the user what we're matching}
  453.     Make_Message('Matching "'+Str1+'"...');
  454.  
  455.  
  456. MATCH_LOOP:     {Main loop}
  457.  
  458.     If S_Res = 0 THEN           {If the last search was a failure then exit}
  459.         RM('MEERROR^Beeps /C=1');
  460.         Goto Error_Exit;
  461.     END;
  462.  
  463.     If B_Count = 0 THEN         {If brace count is zero then success}
  464.         Goto Found_Exit;
  465.     END;
  466.  
  467.             {Execute search based on direction}
  468.             {  We are going to search not only for the match brace or paren, but
  469.                  also for comments and double and single quotes}
  470.     If Direction = 1 THEN
  471.         Right;
  472.         While (NOT (At_EOL)) and ((Cur_Char = '|255') or
  473.                     (Cur_Char = '|9')) Do
  474.             RIGHT;
  475.         END;
  476.         S_Res := Search_Fwd( Search_Str, 0);
  477.     ELSE
  478.         Left;
  479.         While (Cur_Char = '|255') or
  480.                     (Cur_Char = '|9') Do
  481.             Left;
  482.         END;
  483.         S_Res := Search_Bwd( Search_Str , 0);
  484.     END;
  485.  
  486.                                         {If the search result was a failure then exit}
  487.     If S_Res = 0 THEN
  488.         Goto Error_Exit;
  489.     END;
  490.  
  491.  
  492.                                         {If we found the original string then up the count}
  493.     IF Found_Str = STR1 THEN
  494.         B_Count := B_Count + 1;
  495.         Goto Match_Loop;
  496.     END;
  497.                                         {If we found the matching string then decrement the count}
  498.     IF Found_Str = STR2 THEN
  499.         B_Count := B_Count - 1;
  500.         Goto Match_Loop;
  501.     END;
  502.  
  503.                                         {If we found a single quote the match it }
  504.     IF Found_Str = '''' THEN
  505.         Quote_Loop:
  506.             If Direction = 1 THEN
  507.                 RIGHT;
  508.             else
  509.                 LEFT;
  510.             END;
  511.             IF Direction = 1 THEN
  512.                 S_Res := Search_Fwd('{\''}||{''}',0);
  513.             else
  514.                 S_Res := Search_Bwd('{\''}||{''}',0);
  515.             END;
  516.             If S_Res = 0 THEN
  517.                 Goto Error_Exit;
  518.             END;
  519.             If Found_Str = '\''' THEN
  520.                 Goto Quote_Loop;
  521.             END;
  522.             Goto Match_Loop;
  523.     END;
  524.  
  525.                                             {If we found a double quote then match it}
  526.     IF Found_Str = '"' THEN
  527.         Quote_Loop2:
  528.             If Direction = 1 THEN
  529.                 RIGHT;
  530.             else
  531.                 LEFT;
  532.             END;
  533.             IF Direction = 1 THEN
  534.                 S_Res := Search_Fwd('{\"}||"',0);
  535.             else
  536.                 S_Res := Search_Bwd('{\"}||"',0);
  537.             END;
  538.             If S_Res = 0 THEN
  539.                 Goto Error_Exit;
  540.             END;
  541.             If Found_Str = '\"' THEN
  542.                 Goto Quote_Loop2;
  543.             END;
  544.             Goto Match_Loop;
  545.     END;
  546.  
  547.                                             {If we found a opening comment then match it}
  548.     If (Found_Str = '/') then
  549.         If (Direction = 1) then
  550.             Right;
  551.             IF (Cur_Char = '*') THEN
  552.                 S_Res := Search_Fwd('@*/',0);
  553.                 right; right;
  554.             END;
  555.             Goto Match_Loop;
  556.         else
  557.             if c_col > 1 then
  558.                 Left;
  559.                                                         {If we found a closing comment then match it}
  560.                 IF (Cur_Char = '*') THEN
  561.                         S_Res := Search_Bwd('/@*',0);
  562.                         left;
  563.                 end;
  564.             end;
  565.             Goto Match_Loop;
  566.         END;
  567.     end;
  568.  
  569.  
  570.  
  571. Error_Exit:       {We go here if no match was found}
  572.     Goto_Mark;
  573.     Make_Message('Match NOT Found.');
  574.     Goto Macro_Exit;
  575.  
  576. Found_Exit:       {We go here if a match was found}
  577.     F_Line := C_Line;  F_Col := C_Col;
  578.  
  579.  
  580.     If C_Line > T_Line THEN
  581.         JX := C_Line - T_Line;
  582.     ELSE
  583.         JX := T_Line - C_Line;
  584.     END;
  585.  
  586.     If jx < Screen_Length then
  587.         goto_mark;
  588.         while  jx > 0 do
  589.             --jx;
  590.             if f_line > t_line then
  591.                 down;
  592.             else
  593.                 up;
  594.             end;
  595.         end;
  596.     else
  597.         pop_mark;
  598.     end;
  599.     goto_line( f_line );
  600.     goto_col( f_col );
  601.     Make_Message('Match Found.');
  602.  
  603. Macro_Exit:
  604.     Refresh := True;
  605.     Redraw;
  606.     Pop_Undo;
  607. END_MACRO;
  608.  
  609. $MACRO BUILDCMT;
  610. {******************************************************************************
  611.                                                                 MULTI-EDIT MACRO
  612.  
  613. Name:    BUILDCMT
  614.  
  615. Description:    Builds a C comment block.
  616.  
  617.                              (C) Copyright 1989 by American Cybernetics, Inc.
  618. ******************************************************************************}
  619.  
  620.     def_int( ic,        { the indent column }
  621.                      jx,        { general purpose }
  622.                      jk,    { general purpose }
  623.                      ti            { temp insert mode }
  624.                  );
  625.  
  626.     def_str( tstr        { general purpose }
  627.                  );
  628.  
  629.     push_undo;
  630.  
  631.     ti := insert_mode;
  632.     insert_mode := true;
  633.     mark_pos;
  634.     while (get_line = '') and Not(At_EOF) do
  635.         down;
  636.         First_Word;
  637.     end;
  638.     if At_EOF then
  639.         Goto_Mark;
  640.         Text('/*  */');
  641.         Left;
  642.         Left;
  643.         Left;
  644.         Goto Exit;
  645.     end;
  646.     Set_Indent_Level;
  647.     ic := C_Col;
  648.  
  649.     if (ic = 1) then
  650.         if (search_fwd('(',1)) then
  651.             mark_pos;
  652.             if (search_fwd(')',0)) then
  653.                 right;
  654.                 if (cur_char <> ';') then
  655.                     goto_mark;
  656.                     goto build_header;
  657.                 end;
  658.             end;
  659.             goto_mark;
  660.         end;
  661.     end;
  662.  
  663.     Goto_Mark;
  664.     Goto_Col( ic );
  665.  
  666. {If you don't like the fancy comment construct with the time and date, simply
  667. remove the comments off the following 5 lines, and a very simple comment will
  668. be created.
  669.     Text('/*  */');
  670.     Left;
  671.     Left;
  672.     Left;
  673.     Goto Exit;
  674. }
  675.     text('/*');
  676.     jx := 0;
  677.     while (c_col < 79) and (jx < 50) do
  678.         text('-');
  679.         ++jx;
  680.     end;
  681.     jk := ic + (jx / 2) - 8;
  682.     if jk < (ic + 2) then
  683.         jk := ic + 2;
  684.     end;
  685.     goto_col( jk );
  686.     insert_mode := false;
  687.     text( date + ' ' + str_del( time, 6, 3) );
  688.     insert_mode := true;
  689.     eol;
  690.  
  691.     Cr;
  692.     Cr;
  693.     right;
  694.     jk := 0;
  695.     while (jk < jx) do
  696.         text('-');
  697.         ++jk;
  698.     end;
  699.     text('*/');
  700.     up;
  701.     home;
  702.     text(' *');
  703.     right;
  704.     set_indent_level;
  705.  
  706.     goto exit;
  707.  
  708. build_header:
  709.     first_word;
  710.     tstr := get_word('(');
  711.     goto_mark;
  712.     Goto_Col( 1 );
  713.     set_indent_level;
  714.     text('/************************************************');
  715.     cr;
  716.     text(' *');
  717.     jk := 24 - ((Length(tstr) + 8) / 2);
  718.     if jk < 3 then
  719.         jk := 3;
  720.     end;
  721.     goto_col(jk);
  722.     text('--- ' + tstr + ' ---');
  723.     cr;
  724.     text(' *');
  725.     cr;
  726.     text(' ************************************************/');
  727.     up;
  728.     eol;
  729.     indent;
  730. Exit:
  731.     insert_mode := ti;
  732.     pop_undo;
  733.  
  734. end_macro;
  735.  
  736.  
  737. $MACRO CTEMP;
  738. {******************************************************************************
  739.                                                                 MULTI-EDIT MACRO
  740.  
  741. Name: CTEMP
  742.  
  743. Description: Creates C language constructs based on a single character to the
  744. left of the current cursor position.
  745.  
  746.                              (C) Copyright 1989 by American Cybernetics, Inc.
  747. ******************************************************************************}
  748.     DEF_INT(Temp_Col,     {Stores the old column position}
  749.                     Temp_Insert   {Stores the old insert mode}
  750.                  );
  751.  
  752.     Def_Str(Key_Word);  {The key word to indent from}
  753.  
  754.     Push_Undo;
  755.  
  756.     Temp_Insert := Insert_Mode;   {Store insert mode}
  757.     If (At_EOL = False) Then
  758.         GOTO END_OF_MAC;
  759.     End;
  760.  
  761.     Insert_Mode := True;          {Set insert mode to on}
  762.     Temp_Col := C_COL;            {Store the current column pos}
  763.  
  764.     if (c_col = 1) then                        {ignore if at beginning of line}
  765.         goto end_of_mac;
  766.     end;
  767.  
  768.     Left;                         {Move one char to the left}
  769.  
  770.     If (Cur_Char = '*') Then      {Check for 'do' template}
  771.         left;
  772.         if (cur_char = '/') then
  773.             goto make_comment;
  774.         end;
  775.         goto abandon;
  776.     End;
  777.  
  778.     if (c_col > 1) then
  779.         left;
  780.         if xpos(cur_char,' |9|255*+-=!\/{}()[]<>,;',1) = 0 then
  781.             goto abandon;
  782.         end;
  783.         right;
  784.     end;
  785.  
  786.     If (Cur_Char = 'i') Then      {Check for 'if' template}
  787.         Key_Word := 'f';
  788.         GOTO MAKE_CONSTRUCT;
  789.     End;
  790.  
  791.         If (Cur_Char = '{') Then    {Check for '{' template}
  792.             GOTO MAKE_BRACE;
  793.         End;
  794.  
  795.     If (Cur_Char = 'w') Then      {Check for 'while' template}
  796.         Key_Word := 'hile';
  797.         GOTO MAKE_CONSTRUCT;
  798.     End;
  799.  
  800.     If (Cur_Char = 'f') Then      {Check for 'for' template}
  801.         Key_Word := 'or';
  802.         GOTO MAKE_CONSTRUCT;
  803.     End;
  804.  
  805.     If (Cur_Char = 's') Then      {Check for 'switch' template}
  806.         GOTO MAKE_SWITCH;
  807.     End;
  808.  
  809.     If (Cur_Char = 'd') Then      {Check for 'do' template}
  810.         GOTO MAKE_DO_WHILE;
  811.     End;
  812.  
  813. abandon:
  814.     Goto_Col(Temp_Col);           {Else return to original pos and exit}
  815.     GOTO END_OF_MAC;
  816.  
  817. MAKE_CONSTRUCT:                 {Creates a general C construct}
  818.     Goto_Col(Temp_Col);
  819.     Text(Key_Word + ' () {');
  820.     Cr;
  821.     Cr;
  822.     Goto_Col(Temp_Col - 1);
  823.     Text('}');
  824.     Up;
  825.     Goto_Col(Temp_Col);
  826.     Indent;
  827.     Up;
  828.     Goto_Col(Temp_Col + Length(Key_Word) + 2);
  829.     GOTO END_OF_MAC;
  830.  
  831. MAKE_SWITCH:                {Creates a 'switch' construct}
  832.     Goto_Col(Temp_Col);
  833.     Text('witch () {');
  834.     Cr;
  835.     Goto_Col(Temp_Col);
  836.     Indent;
  837.     Text('case  :');
  838.     Cr;
  839.     Goto_Col(Temp_Col);
  840.     Text('}');
  841.     Up;
  842.     Up;
  843.     Goto_Col(Temp_Col + 7);
  844.     GOTO END_OF_MAC;
  845.  
  846. MAKE_DO_WHILE:                {Creates a 'do while' construct}
  847.     Goto_Col(Temp_Col);
  848.     Text('o {');
  849.     Cr;
  850.     Goto_Col(Temp_Col);
  851.     Indent;
  852.     Cr;
  853.     Goto_Col(Temp_Col - 1);
  854.     Text('} while ();');
  855.     Up;
  856.     Home;
  857.     GOTO END_OF_MAC;
  858.  
  859. MAKE_BRACE:                   {Creates a matching brace}
  860.     First_Word;
  861.     Temp_Col := C_Col;
  862.     Eol;
  863.     CR;
  864.     CR;
  865.     Goto_Col(Temp_Col);
  866.     Text('}');
  867.     Up;
  868.     left;
  869.     Indent;
  870.     GOTO End_OF_MAC;
  871.  
  872. MAKE_COMMENT:                            {build a comment block}
  873.     del_chars(2);
  874.     RM('buildcmt');
  875.     goto end_of_mac;
  876.  
  877. END_OF_MAC:
  878.                                             {Return insert_mode to original state}
  879.     Insert_Mode := Temp_Insert;
  880.     Pop_Undo;
  881.  
  882. END_MACRO;