home *** CD-ROM | disk | FTP | other *** search
- $MACRO_FILE C;
- {******************************************************************************
- MULTI-EDIT MACRO FILE
-
- Name: C
-
- Description: This macro file contains language support macros for C.
-
- C_IND - Smart indent for C
- CMTCH - Construct/brace matching for C
- BUILDCMT - Builds a shell of a comment block for C
- CTEMP - Template editing for C
-
- (C) Copyright 1989 by American Cybernetics, Inc.
- ******************************************************************************}
-
- $MACRO C_IND;
- {******************************************************************************
- MULTI-EDIT MACRO
-
- Name: C_IND
-
- Description: Performs a smart indent each time the Carriage Return or Enter
- key is pressed. Is called by the macro CR.
-
- Written by Todd M. Johnson and William M. Miller.
-
- The algorithm used is to look at the line-ending characters (ignoring
- comments, including C++ '//' comments, labels, and white space) for the
- current and preceding lines, then decide whether and how much to change the
- indentation from that of the current line. In addition, if the CR was done
- inside a (C-style, /* */) comment, the "line of asterisks" style of comment
- continuation is automatically supplied.
-
- (C) Copyright 1989 by American Cybernetics, Inc.
- ******************************************************************************}
-
- def_int(outdent_flag,
- sig_char_found,
- in_comment, {1 = /* comment, 2 = // comment}
- curr_ind,
- start_col,
- start_line,
- cur_char_line,
- curr_end_char,
- prev_end_char,
- in_struct,
- junk,
- match_brace, go_match_brace,
- jx);
-
- def_char( orig_char );
-
- {If you want an outdent after a right brace then change the following
- Outdent_flag to True.}
-
- Outdent_flag := FALSE;
-
- {If you want your end brace to line up with the first word of the
- line that the opening brace is on, then set Match_Brace to TRUE}
- Match_Brace := TRUE;
- go_match_brace := FALSE;
-
- Messages := False;
- reg_exp_stat := true;
- mark_pos;
-
- { If we are before or at the first character of the first word of the line
- then leave the level the same for the line }
- start_col := c_col;
- start_line := c_line;
- first_word;
- if c_col >= start_col then
- set_indent_level;
- cr;
- goto mac_exit;
- end;
- orig_char := cur_char;
- goto_col(start_col);
-
- call skip_c_noise;
-
- { If the cursor is inside a comment, skip_c_noise leaves it at the opening
- '/'. We move one character right, to align with the '*', set the indent
- level, do the carriage return, and insert a '* ' to form the line of
- asterisks continuation. }
-
- if (in_comment) then
- right;
- set_indent_level;
- right;
- while NOT(at_eol) and (xpos(cur_char,' |9|255',1) <> 0) do
- right;
- end;
- start_col := c_col;
- goto_mark;
- cr;
-
- {If you don't want the * then comment out the next line}
- if (in_comment = 1) then
- text('* ');
- end;
- { while c_col < start_col do
- text(' ');
- end; }
-
- set_indent_level;
- goto mac_exit;
- end;
-
- { Here, we are at the top of the file, before any non-comment text. We just
- put everything in column 1 in that case. }
-
- if (not(sig_char_found)) then
- goto_col(1);
- set_indent_level;
- goto_mark;
- cr;
- goto mac_exit;
- end;
-
- { Here we've found the nearest non-noise character. There are four that
- specifically influence indentation decisions, so instead of carrying around
- a big string variable, we just save the index into a string of those four
- characters. In addition, we find the first non-blank character on the line
- to determine its indentation. Furthermore, we check if that first character
- is a '}' (probably as a result of the '} name;' at the end of a structure,
- union, or enum definition) so we can know how much to indent later. }
-
- cur_char_line := c_line;
- curr_end_char := pos(cur_char, ';{},');
-
- {Special processing if we have a lone '{' on a line}
- jx := c_col; { store the current column position }
- first_word;
- if (c_col = jx) and (curr_end_char = 2) then
- curr_ind := 1;
- set_indent_level;
- goto do_curs;
- end;
-
- set_indent_level;
- curr_ind := 0;
- start_col := c_col;
- in_struct := (cur_char = '}');
-
-
- { Now we get the line ending for the preceding line. }
- call skip_c_noisex; {no need to check to see if we're in a comment}
- if (sig_char_found) then
- prev_end_char := pos(cur_char, ';{}');
- else
- prev_end_char := 1; { treat like semicolon }
- end;
-
-
- { This code is executed when the nearest line-ending character was a semicolon.
- }
-
- if (curr_end_char = 1) then { semicolon }
- if (prev_end_char = 0) then {if continuation line then undent twice}
- curr_ind := curr_ind - 2;
- end;
- if (outdent_flag and in_struct) then
- curr_ind := curr_ind - 1;
- end;
- else
-
-
- { This code is executed if the nearest line-ending character was a left
- brace.
- }
- if (curr_end_char = 2) then { left brace }
- curr_ind := curr_ind + 1;
- if (prev_end_char = 0) then
- curr_ind := curr_ind - 2; {if continuation line then undent twice}
- end;
- else
- if (curr_end_char = 3) then { right brace }
- if (outdent_flag) then
- curr_ind := curr_ind - 1;
- else
- IF (Match_Brace) THEN
- IF cur_char_line = start_line THEN
- go_match_brace := TRUE;
- END;
- END;
- END;
- else
-
- { Commas cause no indentation (to support enum declarations). If the line-
- ending character was none of the above, the new line will be a continuation
- line, indented twice. However, if the preceding line-ending character was not
- ';{}', we assume that the current line was already a continuation line and no
- further indentation is necessary. }
-
- if ((curr_end_char <> 4) and (prev_end_char <> 0)) then
- curr_ind := curr_ind + 2;
- end;
-
- end;
- end;
- end;
-
- do_curs:
- { Here we put the cursor at the correct column position, we set the indent
- level, return to the original position, and perform the carriage return. }
-
- jx := 0;
-
- goto_mark;
- cr;
- If curr_ind > 0 THEN
- While jx < curr_ind do
- ++jx;
- indent;
- END;
- else
- While jx > curr_ind do
- --jx;
- undent;
- END;
- end;
-
- set_indent_level;
-
- IF (go_match_brace) AND (orig_char = '}') THEN
- refresh := false;
- UP;
- First_Word;
- mark_pos;
- RM( 'CMTCH' );
- FIRST_WORD;
- set_indent_level;
- goto_mark;
- first_word;
- while (c_col > indent_level) DO
- back_space;
- END;
- down;
- make_message('} undenting occurred.');
- END;
-
- goto mac_exit;
-
-
- skip_c_noisex:
- Refresh := false;
- IF (c_line = 1) AND (c_col = 1) THEN
- sig_char_found := FALSE;
- goto exit_skip_c;
- END;
- left;
- goto skip_c_noise1;
-
- { This subroutine moves the cursor to the nearest preceding non-whitespace
- character. If there is no such character (the cursor is at the top of the
- file), the variable sig_char_found will be FALSE; otherwise, it will be
- true. The macro also sets the variable in_comment appropriately. }
-
- skip_c_noise:
- Refresh := false;
-
- left;
- mark_pos;
-
- { First check if we are inside a comment. We look for the nearest of '/*' or
- '*/'; if we find the former, we are inside a comment. In this case, we
- leave the cursor at the beginning of the comment to establish the correct
- indentation margin and return. }
-
- comment_again:
- if (search_bwd('/',50)) THEN
- right;
- if (cur_char = '*') or (cur_char = '/') then
- pop_mark;
- if (cur_char = '/') then
- in_comment := 2;
- ELSE
- in_comment := 1;
- END;
- left;
- goto exit_skip_c;
- end;
- left;
- left;
- if (cur_char <> '*') then
- goto comment_again;
- end;
- end;
- goto_mark;
- in_comment := FALSE;
-
- { The following code is a loop which skips over comments (including C++ '//'
- comments) and labels, leaving the cursor on the nearest preceding non-noise
- character, if any. }
-
-
-
- skip_c_noise1:
-
- IF (c_line = 1) AND (c_col = 1) THEN
- sig_char_found := FALSE;
- goto exit_skip_c;
- END;
- { If there is a '//' on the line, we move the cursor before it and
- look some more. }
-
- if (search_bwd('//', 1)) then
- if ((c_col = 1) and (c_line = 1)) then
- sig_char_found := FALSE;
- goto exit_skip_c;
- end;
- left;
- goto skip_c_noise1;
- end;
-
-
-
- { Here we look for the nearest preceding nonblank character. If it is a '/',
- we check if the preceding character was an asterisk; if so, we search for
- the corresponding '/*' and try again. If the character before the '/' was
- not '*', we have found a significant character and are done. }
-
- if (search_bwd('[~|9 ]', 1)) then
- if (cur_char = '/') then
- left;
- if (cur_char = '*') then
- junk := search_bwd('/@*', 0);
- left;
- goto skip_c_noise1;
- end;
- right;
- sig_char_found := TRUE;
- goto exit_skip_c;
- end;
-
- { If the character we found was a colon, we have found a label. We assume
- that the label was the first thing on the line and proceed to the end of
- the preceding line. Any other character is significant. }
-
- if (cur_char = ':') then
- IF (C_Line = 1) THEN
- Eol;
- cr;
- Goto_Col(1);
- Indent;
- Set_Indent_Level;
- goto mac_exit;
- END;
- up;
- eol;
- goto skip_c_noise1;
- end;
- sig_char_found := TRUE;
- goto exit_skip_c;
- end;
-
- { If we failed to find a nonblank character on the current line, and the
- cursor is on line 1, we failed to find a significant character; otherwise,
- we back up a line and try again. }
-
- if (c_line = 1) then
- sig_char_found := FALSE;
- goto exit_skip_c;
- end;
- up;
- eol;
- goto skip_c_noise1;
-
- exit_skip_c:
- refresh := true;
- ret;
-
- mac_exit:
- Messages := True;
- END_MACRO;
-
- $MACRO CMTCH TRANS;
- {******************************************************************************
- MULTI-EDIT MACRO
-
- Name: CMTCH
-
- Description: Match occurances of {} or () and handles problems with
- characters embedded in comments or quotes.
- 11/01/88 11:15am Modified for greater speed. Also, handles screen
- updates much better.
-
- (C) Copyright 1989 by American Cybernetics, Inc.
- ******************************************************************************}
- DEF_STR( Str1,Str2, Search_Str ); {Strings to match}
-
- DEF_INT( Direction, {1 = Search forward, 0 = backward}
- B_Count, {Brace count. 0 = match found}
- S_Res, {Result of last search}
- T_Row, T_Col, T_Line, {Holds the original position}
- JX, {General purpos}
- F_Line, F_Col ); {Found position}
-
- Refresh := False; {Turn screen display off}
- T_Line := C_Line; {Store the current position}
- T_Col := C_Col;
-
- Push_Undo;
- Mark_Pos;
-
- Find_Match_Str:
-
- IF (Cur_Char = '(') THEN {If current char is a '(' then setup}
- Str1 := '(';
- Str2 := ')';
- Direction := 1;
- Goto Start_Match;
- END;
- IF (Cur_Char = ')') THEN {If current char is a ')' then setup}
- Str1 := ')';
- Str2 := '(';
- Direction := 0;
- Goto Start_Match;
- END;
- IF (Cur_Char = '{') THEN {If current char is a '{' then setup}
- Str1 := '{';
- Str2 := '}';
- Direction := 1;
- Goto Start_Match;
- END;
- IF (Cur_Char = '}') THEN {If current char is a ')' then setup}
- Str1 := '}';
- Str2 := '{';
- Direction := 0;
- Goto Start_Match;
- END;
- {If nothing matched then }
- { Return to original position}
- Goto_Line(T_Line);
- Goto_Col(T_Col);
- Goto_Mark;
- Make_Message('NOTHING to Match');
- Goto Macro_Exit; {Go exit}
-
- Start_Match:
-
- { Search_Str := '{\["'']}||[''"]||{/@*}||{@*/}||[' + Str1 + Str2+']'; }
-
- Search_Str := '["''/' + Str1 + Str2 + ']';
-
- Reg_Exp_Stat := True;
- Ignore_Case := True; {Ignore the search case}
- B_Count := 1; {Brace count starts at 1}
- S_Res := 1; {Init search result to true}
- {Tell the user what we're matching}
- Make_Message('Matching "'+Str1+'"...');
-
-
- MATCH_LOOP: {Main loop}
-
- If S_Res = 0 THEN {If the last search was a failure then exit}
- RM('MEERROR^Beeps /C=1');
- Goto Error_Exit;
- END;
-
- If B_Count = 0 THEN {If brace count is zero then success}
- Goto Found_Exit;
- END;
-
- {Execute search based on direction}
- { We are going to search not only for the match brace or paren, but
- also for comments and double and single quotes}
- If Direction = 1 THEN
- Right;
- While (NOT (At_EOL)) and ((Cur_Char = '|255') or
- (Cur_Char = '|9')) Do
- RIGHT;
- END;
- S_Res := Search_Fwd( Search_Str, 0);
- ELSE
- Left;
- While (Cur_Char = '|255') or
- (Cur_Char = '|9') Do
- Left;
- END;
- S_Res := Search_Bwd( Search_Str , 0);
- END;
-
- {If the search result was a failure then exit}
- If S_Res = 0 THEN
- Goto Error_Exit;
- END;
-
-
- {If we found the original string then up the count}
- IF Found_Str = STR1 THEN
- B_Count := B_Count + 1;
- Goto Match_Loop;
- END;
- {If we found the matching string then decrement the count}
- IF Found_Str = STR2 THEN
- B_Count := B_Count - 1;
- Goto Match_Loop;
- END;
-
- {If we found a single quote the match it }
- IF Found_Str = '''' THEN
- Quote_Loop:
- If Direction = 1 THEN
- RIGHT;
- else
- LEFT;
- END;
- IF Direction = 1 THEN
- S_Res := Search_Fwd('{\''}||{''}',0);
- else
- S_Res := Search_Bwd('{\''}||{''}',0);
- END;
- If S_Res = 0 THEN
- Goto Error_Exit;
- END;
- If Found_Str = '\''' THEN
- Goto Quote_Loop;
- END;
- Goto Match_Loop;
- END;
-
- {If we found a double quote then match it}
- IF Found_Str = '"' THEN
- Quote_Loop2:
- If Direction = 1 THEN
- RIGHT;
- else
- LEFT;
- END;
- IF Direction = 1 THEN
- S_Res := Search_Fwd('{\"}||"',0);
- else
- S_Res := Search_Bwd('{\"}||"',0);
- END;
- If S_Res = 0 THEN
- Goto Error_Exit;
- END;
- If Found_Str = '\"' THEN
- Goto Quote_Loop2;
- END;
- Goto Match_Loop;
- END;
-
- {If we found a opening comment then match it}
- If (Found_Str = '/') then
- If (Direction = 1) then
- Right;
- IF (Cur_Char = '*') THEN
- S_Res := Search_Fwd('@*/',0);
- right; right;
- END;
- Goto Match_Loop;
- else
- if c_col > 1 then
- Left;
- {If we found a closing comment then match it}
- IF (Cur_Char = '*') THEN
- S_Res := Search_Bwd('/@*',0);
- left;
- end;
- end;
- Goto Match_Loop;
- END;
- end;
-
-
-
- Error_Exit: {We go here if no match was found}
- Goto_Mark;
- Make_Message('Match NOT Found.');
- Goto Macro_Exit;
-
- Found_Exit: {We go here if a match was found}
- F_Line := C_Line; F_Col := C_Col;
-
-
- If C_Line > T_Line THEN
- JX := C_Line - T_Line;
- ELSE
- JX := T_Line - C_Line;
- END;
-
- If jx < Screen_Length then
- goto_mark;
- while jx > 0 do
- --jx;
- if f_line > t_line then
- down;
- else
- up;
- end;
- end;
- else
- pop_mark;
- end;
- goto_line( f_line );
- goto_col( f_col );
- Make_Message('Match Found.');
-
- Macro_Exit:
- Refresh := True;
- Redraw;
- Pop_Undo;
- END_MACRO;
-
- $MACRO BUILDCMT;
- {******************************************************************************
- MULTI-EDIT MACRO
-
- Name: BUILDCMT
-
- Description: Builds a C comment block.
-
- (C) Copyright 1989 by American Cybernetics, Inc.
- ******************************************************************************}
-
- def_int( ic, { the indent column }
- jx, { general purpose }
- jk, { general purpose }
- ti { temp insert mode }
- );
-
- def_str( tstr { general purpose }
- );
-
- push_undo;
-
- ti := insert_mode;
- insert_mode := true;
- mark_pos;
- while (get_line = '') and Not(At_EOF) do
- down;
- First_Word;
- end;
- if At_EOF then
- Goto_Mark;
- Text('/* */');
- Left;
- Left;
- Left;
- Goto Exit;
- end;
- Set_Indent_Level;
- ic := C_Col;
-
- if (ic = 1) then
- if (search_fwd('(',1)) then
- mark_pos;
- if (search_fwd(')',0)) then
- right;
- if (cur_char <> ';') then
- goto_mark;
- goto build_header;
- end;
- end;
- goto_mark;
- end;
- end;
-
- Goto_Mark;
- Goto_Col( ic );
-
- {If you don't like the fancy comment construct with the time and date, simply
- remove the comments off the following 5 lines, and a very simple comment will
- be created.
- Text('/* */');
- Left;
- Left;
- Left;
- Goto Exit;
- }
- text('/*');
- jx := 0;
- while (c_col < 79) and (jx < 50) do
- text('-');
- ++jx;
- end;
- jk := ic + (jx / 2) - 8;
- if jk < (ic + 2) then
- jk := ic + 2;
- end;
- goto_col( jk );
- insert_mode := false;
- text( date + ' ' + str_del( time, 6, 3) );
- insert_mode := true;
- eol;
-
- Cr;
- Cr;
- right;
- jk := 0;
- while (jk < jx) do
- text('-');
- ++jk;
- end;
- text('*/');
- up;
- home;
- text(' *');
- right;
- set_indent_level;
-
- goto exit;
-
- build_header:
- first_word;
- tstr := get_word('(');
- goto_mark;
- Goto_Col( 1 );
- set_indent_level;
- text('/************************************************');
- cr;
- text(' *');
- jk := 24 - ((Length(tstr) + 8) / 2);
- if jk < 3 then
- jk := 3;
- end;
- goto_col(jk);
- text('--- ' + tstr + ' ---');
- cr;
- text(' *');
- cr;
- text(' ************************************************/');
- up;
- eol;
- indent;
- Exit:
- insert_mode := ti;
- pop_undo;
-
- end_macro;
-
-
- $MACRO CTEMP;
- {******************************************************************************
- MULTI-EDIT MACRO
-
- Name: CTEMP
-
- Description: Creates C language constructs based on a single character to the
- left of the current cursor position.
-
- (C) Copyright 1989 by American Cybernetics, Inc.
- ******************************************************************************}
- DEF_INT(Temp_Col, {Stores the old column position}
- Temp_Insert {Stores the old insert mode}
- );
-
- Def_Str(Key_Word); {The key word to indent from}
-
- Push_Undo;
-
- Temp_Insert := Insert_Mode; {Store insert mode}
- If (At_EOL = False) Then
- GOTO END_OF_MAC;
- End;
-
- Insert_Mode := True; {Set insert mode to on}
- Temp_Col := C_COL; {Store the current column pos}
-
- if (c_col = 1) then {ignore if at beginning of line}
- goto end_of_mac;
- end;
-
- Left; {Move one char to the left}
-
- If (Cur_Char = '*') Then {Check for 'do' template}
- left;
- if (cur_char = '/') then
- goto make_comment;
- end;
- goto abandon;
- End;
-
- if (c_col > 1) then
- left;
- if xpos(cur_char,' |9|255*+-=!\/{}()[]<>,;',1) = 0 then
- goto abandon;
- end;
- right;
- end;
-
- If (Cur_Char = 'i') Then {Check for 'if' template}
- Key_Word := 'f';
- GOTO MAKE_CONSTRUCT;
- End;
-
- If (Cur_Char = '{') Then {Check for '{' template}
- GOTO MAKE_BRACE;
- End;
-
- If (Cur_Char = 'w') Then {Check for 'while' template}
- Key_Word := 'hile';
- GOTO MAKE_CONSTRUCT;
- End;
-
- If (Cur_Char = 'f') Then {Check for 'for' template}
- Key_Word := 'or';
- GOTO MAKE_CONSTRUCT;
- End;
-
- If (Cur_Char = 's') Then {Check for 'switch' template}
- GOTO MAKE_SWITCH;
- End;
-
- If (Cur_Char = 'd') Then {Check for 'do' template}
- GOTO MAKE_DO_WHILE;
- End;
-
- abandon:
- Goto_Col(Temp_Col); {Else return to original pos and exit}
- GOTO END_OF_MAC;
-
- MAKE_CONSTRUCT: {Creates a general C construct}
- Goto_Col(Temp_Col);
- Text(Key_Word + ' () {');
- Cr;
- Cr;
- Goto_Col(Temp_Col - 1);
- Text('}');
- Up;
- Goto_Col(Temp_Col);
- Indent;
- Up;
- Goto_Col(Temp_Col + Length(Key_Word) + 2);
- GOTO END_OF_MAC;
-
- MAKE_SWITCH: {Creates a 'switch' construct}
- Goto_Col(Temp_Col);
- Text('witch () {');
- Cr;
- Goto_Col(Temp_Col);
- Indent;
- Text('case :');
- Cr;
- Goto_Col(Temp_Col);
- Text('}');
- Up;
- Up;
- Goto_Col(Temp_Col + 7);
- GOTO END_OF_MAC;
-
- MAKE_DO_WHILE: {Creates a 'do while' construct}
- Goto_Col(Temp_Col);
- Text('o {');
- Cr;
- Goto_Col(Temp_Col);
- Indent;
- Cr;
- Goto_Col(Temp_Col - 1);
- Text('} while ();');
- Up;
- Home;
- GOTO END_OF_MAC;
-
- MAKE_BRACE: {Creates a matching brace}
- First_Word;
- Temp_Col := C_Col;
- Eol;
- CR;
- CR;
- Goto_Col(Temp_Col);
- Text('}');
- Up;
- left;
- Indent;
- GOTO End_OF_MAC;
-
- MAKE_COMMENT: {build a comment block}
- del_chars(2);
- RM('buildcmt');
- goto end_of_mac;
-
- END_OF_MAC:
- {Return insert_mode to original state}
- Insert_Mode := Temp_Insert;
- Pop_Undo;
-
- END_MACRO;