// // FILEGREP.VDM Ch. Ziemski 18.11.2003 // 11.12.2003 // // Imagine this macro as a "grep in a file". // // It searches in a structured text with specially marked title or // divider lines for a second string. // Every divided block containing the second string is then listed // with title/divider line and optionally the found lines or complete division. // // The search can work on the whole file or at a highlighted block. // It begins at cursor position or at BoF/BlockBegin and can // use pattern matching or regular expressions. // // Since the macro uses Dialog_Input_1() it requires VEDIT for Windows. // // //----------------------------------------------------------------------- // // Example: // // #=<>=# block/paragraph 1 // some text // more text on mondays // and so on // // #=<>=# message 2 // another pile of characters // dito // // #=<>=# part 3 // monday // tuesday // // #=<>=# text 4 // january // february // //--- // // In the above example file the string "#=<>=#" can be used as divider. // We are searching for blocks containing the string "monday". // // Resulting list: // // #=<>=# block/paragraph 1 // more text on mondays // // #=<>=# part 3 // monday // //----------------------------------------------------------------------- // // Used registers (restored at return) // // #82 flag: something found // #83 flag: something found // #84 flag: TReg-space exhausted => tmp file used // #85 counter for tmp-filename // #86 flag for output: 1=additional empty line between found divider lines // #87 flag for output: 0=complete divider line; 1=complete matched divider search string // #88 current buffer number // #89 working buffer / results // #90 temp. for DI1 etc. // #91 flag for DI1: title or divider search string // #92 flag for DI1: pattern/regexp for divider search // #93 flag for DI1: pattern/regexp for contents search // #94 flag for DI1: Case sensitive // #95 flag for DI1: begin search at CurPos or at BoF // #96 flag for DI1: search in marked block only // #97 flag for DI1: list found divider lines only // #98 flag for DI1: list whole division // #99 // // #103 Cur_Pos begin of whole search // #104 Cur_Pos end of whole search // #105 Cur_Pos begin of search within one division // #106 Cur_Pos end of search within one division // // $90 temp.: text of found divison // $91 search string: divider // $92 search string: contents // $93 found divider // $94 found contents // $95 temp. for divider line // $96 for focus setting for DI1 // $97 for focus setting for DI1 // $98 filepath/name for tempfile // $99 filepath/name for tempfile // // $103 parameter for call of subroutine // $104 built Search() command for divider // $105 built Search_Block() command for contents // $106 temp. for error messages // //----------------------------------------------------------------------- if ( ! Is_Windows) { Message("\n\n Sorry, this macro requires VEDIT for Windows. \n\n ") return } Reg_Push(90,99) // save used registers Num_Push(80,99) //============================================================================= // // Configuration // #86 = 1 // flag for output (has to be set manually here) // 1=additional empty line between found divider lines #87 = 0 // flag for output (has to be set manually here) // 0=complete divider line // 1=complete matched divider search string // default settings for DI_1(): Reg_Set(91,"") // search divider, default //Reg_Set(91,"| 0) { Reg_Set(106, ">>> ERROR: ", INSERT) Reg_Set(106, " <<<", APPEND) } #90=Dialog_Input_1(91,"`FILEGREP - Search in a file of ...`, `|@(106)`, `Let me try a description: You can search in a file structured by special divider lines/strings. Every division in which the contents search string is found is listed with it's divider/title line and (optional) the found strings/lines or the complete divison. (You can use full pattern matching or regular expression search.) `, `The following string is `, `.h()a title line or `, `.h()a divider `, `|@(96)??&Title/div. search string: `, ` using`, `.h()pattern matching or`, `.h()regular expressions`, ` `, `|@(97)??Contents search s&tring:`, ` using`, `.h()pattern matching or`, `.h()regular expressions`, ` `, `.g[]Case sensitive`, `[]Search &from beginning of file (or block); else from cursor`, `[]Only within the highlighted &block`, `[]List divider lines and found contents; else only divider lines`, `[]List the whole found divison (not only the matching lines)`, ` `, `[&Search]`, `[&Cancel]`", @91,SET+WORKAREA+CENTER,0,0) if ( #90 != 1 ) { Buf_Switch(#89) // necessary? Buf_Quit(OK) Buf_Switch(#88) Num_Pop(80,99) Reg_Pop(90,99) return } if (Reg_Size(91)==0) { Reg_Set(106, "Search strings must not be empty!") Reg_Set(96, ".i") Reg_Empty(97) Goto START } if (Reg_Size(92)==0) { Reg_Set(106, "Search strings must not be empty!") Reg_Empty(96) Reg_Set(97, ".i") Goto START } // set the search range if (#96 == 1) { // only in Block if (BB != -1 || BE != -1) { // if at least one blockmarker is set #90=Cur_Pos if (BB == -1) { Block_Begin(Cur_Pos) } if (BE == -1) { Block_End(Cur_Pos) } #103=Min(Block_Begin, Block_End) #104=Max(Block_Begin, Block_End) if (#95 == 0) { // from cursor position on if ((#90 >= #103) && (#90 <= #104)) { // if cursor within block #103=#90 } } } else { #96=0 // reset search_in_block flag } } if (#96 == 0) { // up to EoF (not in block) if (#95 == 0) { // from cursor position on #103=Cur_Pos } else { // or from BoF #103=0 } #104=File_Size } #105=0 #106=0 Reg_Empty(106) //call("SHOWDEBUG") // prepare the search strings Reg_Set(103, @91) Call("Set_Delim") if (Reg_Size(103) == 0) { Reg_Set(106, "No string delimiters left in string 1") Reg_Set(96, ".i") Reg_Empty(97) Goto START } Reg_Set(104, "Search_Block(") Reg_Set(104, @103, APPEND) Reg_Set(104, ", #103", APPEND) Reg_Set(104, ", #104", APPEND) Reg_Set(104, ", NOERR", APPEND) if (#94==1) { Reg_Set(104, "+CASE", APPEND) } if (#92==2) { Reg_Set(104, "+REGEXP", APPEND) } Reg_Set(104, ")", APPEND) Reg_Set(103, @92) Call("Set_Delim") if (Reg_Size(103) == 0) { Reg_Set(106, "No string delimiters left in string 2") Reg_Empty(96) Reg_Set(97, ".i") Goto START } Reg_Set(105, "Search_Block(") Reg_Set(105, @103, APPEND) Reg_Set(105, ", #105", APPEND) Reg_Set(105, ", #106", APPEND) Reg_Set(105, ", NOERR", APPEND) if (#93==2) { Reg_Set(105, "+REGEXP", APPEND) } if (#94==1) { Reg_Set(105, "+CASE", APPEND) } Reg_Set(105, ")", APPEND) // save the resulting buffer (esp. for huge results!) Reg_Set(99, @98) // tmp filename #85=1 repeat(ALL){ #90=File_Check("|@(99).tmp") if (#90 == -1) { // if tmp file not opened in any edit buffer break } // if (#85==1) { // built next version of filename Reg_Set(99, @98) Reg_Set(99, "-", APPEND) // } Num_Str(#85, 99, LEFT+APPEND) #85++ } Buf_Switch(#89) // to be sure ... Buf_Empty(OK) File_Save_As("|@(99).tmp", OK+NOMSG) Update // and now start the real work Buf_Switch(#88) // original buffer Goto_Pos(#103) Call(104) // search title/divider if (EM) { Reg_Set(106, "No divider matching string 1 found.") Reg_Set(96, ".i") Reg_Empty(97) Buf_Switch(#88) Update GOTO START } if (#91==2) { // if divider: we have to take first part too // (it has no "title" then) Goto_Pos(#103) } else { if (#87 == 0) { // save complete title/divider line BoL Reg_Copy(93, 1) } else { // or matched characters Reg_Copy_Block(93, Cur_Pos, Cur_Pos+Chars_Matched) Out_Reg(93, APPEND) Type_Newline(1) Out_Reg(CLEAR) } Line(1, NOERR) // on the 1st line of contents in this divison } #105 = Cur_Pos #83=0 // flag: nothing found yet at all #84=0 // flag: no tmp file for divisons needed yet File_Delete("|@(98)-dv.tmp", OK+NOERR) // room for big divisons while (! AT_EoF) { //call("SHOWDEBUG") Buf_Switch(#88) // original buffer Goto_Pos(#105) Call(104) // search next title/divider in block(#103,#104) but from cursor if (EM) { Reg_Empty(95) Goto_Pos(#104) // end of search range } else { if ((#96 == 1) && (Cur_Pos > #104)){ break } if (#87 == 0) { // save complete title/divider line BoL Reg_Copy(95, 1) } else { // or matched characters Reg_Copy_Block(95, Cur_Pos, Cur_Pos+Chars_Matched) Out_Reg(95, APPEND) Type_Newline(1) Out_Reg(CLEAR) } } #106 = Cur_Pos // just before next divider ==> block(#105,#106) is area to search for contents Line(1, NOERR) if ((#96 == 1) && ( #106 > #104)){ // search max to block end #106=#104 } Reg_Empty(94) // for found contents #82=0 // flag for: found something in current division Goto_Pos(#105) Call(105) // search string in block(#105,#106) while ( ! EM ) { BoL if (Tfree < (EoL_Pos-Cur_Pos+1000)) { // if TReg-memory exhausted #84=1 // set flag File_Open("|@(98)-dv.tmp", NOMSG) // open/switch to temp file End_Of_File Reg_Ins(94) // and insert already collected data there File_Save(NOMSG) Reg_Empty(94) Buf_Switch(#88) // back to original buffer } Reg_Copy(94,1, APPEND) // save that contents (whole line) #82=1 // flag: at least one string found in current divison #83=1 // flag: at least one string found in whole search area Line(1,NOERR+ERRBREAK) Call(105) // search string in block #105-#106 } if ( #82 != 0 ) { // if at least one found string Buf_Switch(#89) // append found data to result buffer Update Reg_Ins(93) // divider line ("title") if (#97 == 1){ // only if contents are wanted to be listed if (#98 == 1){ // if whole divison Buf_Switch(#88) if ( Tfree > (#106-#105+1000)) { // handle big divisons Reg_Copy_Block(90, #105, #106) Buf_Switch(#89) Reg_Ins(90) } else { Block_Save_As("|(VEDIT_TEMP)\filegrep.tmp",#105,#106,OK) Buf_Switch(#89) Ins_File("|(VEDIT_TEMP)\filegrep.tmp",1,ALL) File_Delete("|(VEDIT_TEMP)\filegrep.tmp",OK) } } else { if ( #84==1) { // if (File_Exist("|@(98)-dv.tmp")) Ins_File("|@(98)-dv.tmp",1,ALL) File_Delete("|@(98)-dv.tmp", OK+NOERR) #84=0 // flag: no tmp file for divisons } Reg_Ins(94) } if (#86==1) { Ins_Newline(1) // optical divider } } } Buf_Switch(#88) Goto_Pos(#106) Line(1, NOERR) #105 = Cur_Pos Reg_Set(93,@95) if (Cur_Pos >= #104) { break } } if (#83 == 0) { // nothing found Buf_Switch(#88) Update Reg_Set(106, "No contents matching string 2 found.") Reg_Empty(96) Reg_Set(97, ".i") GOTO START } Buf_Switch(#89) // show results BoF File_Save(NOMSG) SR_Set(@91) // set {Search, Next} to divider search string Search_Options((#92-1)*REGEXP + #94*CASE) Num_Pop(80,99) // restore used registers Reg_Pop(90,99) return //--------------------------------------------------------------------------- // try to find a string delimiter not included in the user's search strings :SET_DELIM: Buf_Switch(#89) // working buffer Buf_Empty(OK) Reg_Ins(103) // the original search string BoF Ins_Text(.`'´"%&*:;/~^=,.)// and all possible delimiters Ins_Text(".") for (#90=0; #90<15 ; #90++) { // loop through all the possible delimiters Goto_Pos(#90) Reg_Copy_Block(103, Cur_Pos, CP+1) // get this possible delimiter Char(1) // advance past it Search(.|@(103)., NOERR) // search for it in the rest of the string if (EM) { // if not found: good Goto_Pos(#90+1) // delete the rest of the possible ones Del_Char(15-#90-1) Del_Block(0, #90) EoF Reg_Ins(103) // and add the found delimiter at end too break // leave the loop } } Reg_Copy_Block(103, 0, File_Size) if (#90 == 15) { // if no delimiter found Dialog_Input_1(99 ,"`Error`, `There are no more string delimiters possible for internal use.\nAll of them are used in your string.`, `Please change your search string a bit!`", WORKAREA+CENTER,0,0) Reg_Empty(103) } Buf_Empty(OK) Buf_Switch(#88) // original buffer return //----------------------------------------------------------------------------------- :SHOWDEBUG: ItoA(#95, 11) ItoA(#96, 11, APPEND) ItoA(Cur_Pos, 12) ItoA(#103, 13) ItoA(#104, 13, APPEND) ItoA(File_Size, 14) ItoA(#105, 15) ItoA(#106, 15, APPEND) #11=Dialog_Input_1(1,"`Debug Infos...`, `|@(11)`, `|@(12)`, `|@(13)`, `|@(14)`, `|@(15)`, `[&OK]`", SET+WORKAREA+BOTTOM+RIGHT,0,0) if (#11 == 0) { break_out(EXTRA) } return //-----------------------------------------------------------------------------------