// FRMT_C.VDM - Format C programs for improved readability // 8 Feb 1996 (Requires 4.2) // 21 November 2003: Force BOF, disable WordWrap, change to blanks before blocks // 25 November 2003: Nested switch blocks // 8 December 2003: Exclude "blocks" in comment lines, User Options // // Author:- // Ian Binnie // 8 Berripa Close // East Ryde 2113 // Australia // ian_binnie at optusnet dot com dot au ( replace "at" "dot" by the normal characters.) // // The first part of this program may be used to format // any block structured program e.g. VEDIT Macros // // Numeric codes are use to search for (,),{,} // Numeric registers 40 - 46 are used // NOTE Uses Do_Visual("\ID\") to Indent Block // this is not documented since Vedit 5.0, but still works // // Use default indent increment of 4 if not set // // Indenting styles vary. The following is an example of my style // //function (...) // { // statement; // if(...) // { // ... // } // else // statement; // // switch(...) // { // case ...: // statement; // } // // } // // User Style Options // // If you prefer to include whitespace after if, for, while or switch // delete or comment the 4 lines identified by // option 1 // this will not insert space, but will prevent it from being removed. // If you wish to ensure spaces are present, modify the replace string. // if(Config(PG_IND_INC)==0) { Config(PG_IND_INC, 4) } #40=Config(PG_IND_INC) Config( W_WORD_WRAP, 0) // // First some general tidy up (remove formatting) // // strip leading whitespace from outer program blocks // lines outside blocks are not affected // a program block is all contained between {...} Begin_Of_File() REPEAT(ALL) { Search("|123",ERRBREAK) Block_Begin(Cur_Pos) Match_Paren() Block_End(Cur_Pos+1) Goto_Pos(Block_Begin) Search("|<|W",REVERSE|NOERR) Replace_Block("|<|W","",Cur_Pos,Block_End,ALL|NOERR) Goto_Pos(Block_End) } Block_Begin(CLEAR) Replace("|L|X|123","|N|123",BEGIN|ALL|NOERR) // no blank before blocks; mod IB 21/11/2003 // now ensure that all blocks start on a new line // unless the block is on a single line Begin_Of_File() REPEAT(ALL) { Search("|123",ERRBREAK) if(Cur_Col==1) { Char(1) Continue } // OK - at start of line #45=Cur_Pos #43=Cur_Line if(Search("//",REVERSE|NOERR)) // exclude block start in comment IB 8/12/2003 { if(#43==Cur_Line) { Goto_Pos(#45+1) Continue } // Appears to be Comment found on same line } Goto_Pos(#45) // restore position Match_Paren() #44=Cur_Line Goto_Pos(#45) // restore position if(#44>#43) { Ins_Newline(1) } // not on same line Char(1) } // strip trailing whitespace Replace("|W|>","",BEGIN|ALL|NOERR) // now ensure that all blocks end on a clear line // unless the block is followed by a comment // or the block is an initialiser Begin_Of_File() REPEAT(ALL) { Search("|125",ERRBREAK) #45=Cur_Pos #43=Cur_Col End_Of_Line() if(Cur_Col-#43==1) { Continue } // OK - at end of line Goto_Pos(#45+1) // position after end of block // check if followed by comment or ; if(Match("|[|W]|{//,/*,;}")==0) { Continue } // OK Ins_Newline(1) Replace("|<|W","",NOERR) } // // Now the real task begins Begin_Of_File() // locate & mark outer program block REPEAT(ALL) { Search("|123",ERRBREAK) Call("indnt_blk") } // // Main task finished // Now follows C specific formatting Replace("if|W|40","if|40",BEGIN|ALL|NOERR) // option 1 Replace("for|W|40","for|40",BEGIN|ALL|NOERR) // option 1 Replace("while|W|40","while|40",BEGIN|ALL|NOERR) // option 1 Replace("switch|W|40","switch|40",BEGIN|ALL|NOERR) // option 1 // now ensure that case blocks are indented // test lines following switch( //) // now handles nested switches Begin_Of_File() REPEAT(ALL) { Search("switch|[|W]|40",ERRBREAK|ADVANCE) // switch found Search("|123",ERRBREAK) #45=Cur_Pos Match_Paren() #44=Cur_Line // end of switch Goto_Pos(#45+1) // point past beginning of block while(#44>Cur_Line+1) // test each line in switch { Line Search("|!|B",NOERR) // find first displayable character #41=Cur_Col // current indent if (!Match("|{case|Y:,default}") == 0) { if (Match("switch|[|W]|40") == 0) // nested switch found { Block_Begin(Cur_Pos) Search("|123",ERRBREAK) #45=Cur_Pos Match_Paren() // position at end of block line(0) Block_End(Cur_Pos-1) // { mark switch EXCEPT for '}' Goto_Pos(#45) // back to '{' following switch // } Do_Visual("\ID\") // need to be inside block Block_Begin(CLEAR) } else { // indent for non CASE statements Ins_Indent(#41+#40) } } } } Begin_Of_File() // now ensure that all blocks without {} are indented // test lines following if(, for(, while(, else, do //))) // ignore comments REPEAT(ALL) { Search("|{if|W|40,if|40,for|W|40,for|40,while|W|40,while|40,|!#else,do|W,//,/*}",ERRBREAK|ADVANCE) #43=Cur_Line if(Match_Item<7) { Char(-1) Match_Paren() // end of (...) } if(Match_Item==9) { // single line comment End_Of_Line() Continue } if(Match_Item==10) { // C style /* comment Search("*/",ERRBREAK|ADVANCE) Continue } #44=Cur_Line Search("|{|123,;}",ERRBREAK) // find next block or command if(Cur_Line==#44) { Continue } // statement on same line if(Match_Item==1) { // explicit block Match_Paren() // end of block if(Cur_Line-#44>1) { // multi line block Match_Paren() Continue } } if(Cur_Line-#44==1) { // statement on next line #44=Cur_Line Goto_Line(#43) Match("|<|W",ADVANCE) #41=Cur_Col Goto_Line(#44) Replace("|<|W","",NOERR) Ins_Indent(#41+#40) } else { // this is a multi line statement Block_Begin(Cur_Pos) Goto_Line(#44+1) Block_End(Cur_Pos) Do_Visual("\ID\") Block_Begin(CLEAR) } } // now ensure that multi line lists (...) are indented // these are usually argument lists, printf etc // ignore comments Begin_Of_File() REPEAT(ALL) { Search("|{|40,//,/*}",ERRBREAK) if(Match_Item==2) { // single line comment End_Of_Line() Continue } if(Match_Item==3) { // C style /* comment Search("*/",ERRBREAK|ADVANCE) Continue } #43=Cur_Line Match_Paren() // end of (...) if(Cur_Line==#43) { Continue } // single line if(Cur_Line-#43==1) { // lists extends over 2 lines #44=Cur_Line Goto_Line(#43) Match("|<|W",ADVANCE) #41=Cur_Col // starting column Goto_Line(#44) Replace("|<|[|W]"," ",NOERR) Ins_Indent(#41+#40) } else { // this is a multi line list Block_Begin(Cur_Pos) Goto_Line(#43+1) Block_End(Cur_Pos) Do_Visual("\ID\") Block_Begin(CLEAR) } } Replace("|<|W#","#",BEGIN|ALL|NOERR) // restore preprocessor directives // tidy up & finish // strip trailing whitespace Replace("|W|>","",BEGIN|ALL|NOERR) Return() // routine to indent block // on entry current position is start of block // on exit current position is end of block :indnt_blk: #43=Cur_Line Block_Begin(Cur_Pos) Match_Paren() #46=Cur_Pos #44=Cur_Line Block_End(Cur_Pos+1) Goto_Pos(Block_End) if(#43==#44) { Return() } // block on one line Do_Visual("\ID\") //relocate beginning & end of block as it may have moved Goto_Line(#43) Search("|123",ERRBREAK) #45=Cur_Pos Match_Paren() #46=Cur_Pos Block_Begin(CLEAR) Goto_Pos(#45+1) // point past beginning of block // search for inner block REPEAT(ALL) { Search("|123",ERRBREAK) if(Cur_Line>#44) { // outside block:- so no inner block found Goto_Pos(#45) Match_Paren() // position at end of block Return() } Num_Push(44,45) //save regs Call("indnt_blk") // recursively call subroutine to indent inner block Num_Pop(44,45) } Goto_Pos(#45) Match_Paren() // position at end of block Return()