// REN-FILE.VDM - Extended File Renaming Utility using regular expressions // Implements {Misc, More macros, Rename-Files} // // Written by: Christian Ziemski 10.08.2004 // Last change: 25.03.2006 // // Requires: VEDIT 6.15 or later. // // Note: Don't retab this macro! That would destroy the dialog construction! // //------------------------------------------------------------------ // // Register usage: // // 89 Locked in macro // 90 old filename // 91 new filename // 92 Search() function // 93 Replace() function // 94 directory // 95 old filename (regular expression) // 96 new filename (regular expression) // 97 for DI1(): initial input box // 98 for DI1(): initial input box // 99 optional error message // // 103-104 temp. usage // // #89 saved value of Visual_Macro // #90 answer from DI1() => main action // #91 Cursor position // #92 answer from DI1() => file overwrite // #93 longest line length // #94 option in DI_1 [] Select files case-sensitive // #95 option in DI_1 [] Force the renaming to // #96 option in DI_1 () lower or () UPPER case // #97 buffer number // #98 for File_Check() // #99 flag // //------------------------------------------------------------------ Reg_Push(89,99) // save used registers Num_Push(89,99) Reg_Set(97, ".i") // initial input focus on "Select files:" Reg_Empty(98) Reg_Empty(99) // no error message Reg_Set(94, CUR_DIR) // initial directory // Set some defaults if needed if (#94>1) { #94=0 } // [] Select files case-sensitive if (#95>1) { #95=0 } // [] Force the renaming to if ((#96<1) || (#96>2)) { #96=1 } // (o) lower or () UPPER case if (#95==0) { #96=0 } // if no case-forcing: clear "() lower or () UPPER case" #93=0 // longest line length Call("CREATE_FILES") // create helper files if needed // Set up the locked-in macro to catch errors // e.g. due to syntax error in user's Regexp Reg_Set(89, ' #98=File_Check("|(VEDIT_TEMP)\ren-file.tmp") if (#98 != -1) { Buf_Switch(#98) Buf_Quit(OK) Update } Chain(') Num_Str(Macro_Num, 89, LEFT+NOCR+APPEND) Reg_Set(89, ',"START")', APPEND) #89=Visual_Macro Visual_Macro(CLEAR) Reg_Lock_Macro(89) :START: repeat (ALL) { #90=Dialog_Input_1(94,"`Extended File Renaming Utility`, ` Renaming files using sophisticated search+replace expressions.`, ` Note: You can't use DOS/Windows wildcards here, only 'Regular Expressions'. If you aren't familiar with RegExp, please use the [Help] below. `, ` [Examples] opens an user-editable file with some example expressions.`, ` [Test] only lists the directory showing the planned renamings and reopens this dialog. `, `|@(99)`, `??&Directory: `, ` `,`.h[] Select files case-&sensitive`, `|@(97)??Select &files: `, `|@(98)??Re&name to: `, ` `,`.h[] F&orce the renaming to`, `.h() &lower or`, `.h() &UPPER case`, ` `, `[&Rename]`,`.b[&Test]`,`[&Cancel]`,`[&Help]`,`[&Examples]`", SET+SCREEN+CENTER,0,0) if ((#90==3) || (#90==0)) { // Cancel or ESC Goto END } if (#95==0) { // if no case-forcing: #96=0 // clear "() lower or () UPPER case" } else { if ((#96<1) || (#96>2)) { // if needed: #96=1 // set default as "(o) lower or () UPPER case" } } if (#90==4) { Help("Regular expressions") Continue } if (#90==5) { File_Open("|(USER_MACRO)\ren-file.txt") Goto END } Reg_Set(97, ".i") // initial input focus on "Select files:" Reg_Empty(98) Reg_Empty(99) // no error message if ( ! File_Exist("|@(94)\nul", NOERR) ) { Reg_Empty(97) // initial input focus on "Directory" Reg_Set(99, " >>>>> Error: Directory doesn't exist! <<<<< ") Continue } if (Reg_Size(95)==0) { Reg_Set(99, " >>>>> Error: Filename(s) missing in 'Select files:' <<<<< ") Win_Clear Continue } if ((Reg_Size(96)==0) && (#95==0)) { Reg_Set(98, ".i") // initial input focus on "Rename to:" Reg_Set(99, " >>>>> Error: Filename(s) missing in 'Rename to:' -or- 'Force .. to .. case' not set. <<<<< ") Win_Clear Continue } // check for empty target name (as good as possible) #99=0 #97=Buf_Num Buf_Switch(Buf_Free) Reg_Ins(96, BEGIN) if (Match("|W|>")==0) { #99=1 } Buf_Quit(OK) Buf_Switch(#97) if (#99==1) { Reg_Set(98, ".i") // initial input focus on "Rename to:" Reg_Set(99, " >>>>> Error: Invalid filename (only whitespace) in 'Rename to:' <<<<< ") Win_Clear Continue } // check for invalid characters in target name #99=0 #97=Buf_Num Buf_Switch(Buf_Free) Reg_Ins(96, BEGIN) Search('|{/,:,*,?,",<,>,||,\|>,\\}', NOERR) Buf_Quit(OK) Buf_Switch(#97) if (! ERROR_MATCH) { Reg_Set(98, ".i") // initial input focus on "Rename to:" Reg_Set(99, " >>>>> Error: Invalid filename in 'Rename to:' <<<<< ") Win_Clear Continue } Break // if none of the above buttons or problems: leave loop and do the work } // Prepare the search and replace commands Reg_Set(92,`Search_Block("^`) Reg_Set(92, @95, APPEND) Reg_Set(92, `$", Cur_Pos, EoL_Pos, REGEXP+NOERR`, APPEND) if (#94==0) { Reg_Set(92, `)`, APPEND) } else { Reg_Set(92, `+CASE)`, APPEND) } Reg_Set(93, `Replace_Block("`) Reg_Set(93, @95, APPEND) Reg_Set(93, `","`, APPEND) Reg_Set(93, @96, APPEND) Reg_Set(93, `", Cur_Pos, EoL_Pos, REGEXP+NOERR)`, APPEND) ChDir("|@(94)") // change to choosen data directory // Open a temporary working file and empty it if needed File_Open("|(VEDIT_TEMP)\ren-file.tmp", NOMSG+NOEVENT) Del_Block(0, File_Size) Config(PG_E_SYNTAX, "Enable syntax highlighting (*)", 1, LOCAL) Syntax_Load("ren-file.syn") // do a directory listing and redirect it into the current file Out_Ins() Dir("*.*", NOMSG+SUPPRESS+NOERR) Out_Ins(CLEAR) // get longest line Begin_Of_File while ( ! At_EoF ) { End_Of_Line #93=Max(#93, Cur_Col) Line(1) } // process the directory listing Begin_Of_File while ( ! At_EoF ) { Reg_Set(97,".i") // in case of an error: set focus on "Select files" input box Reg_Empty(98) Begin_Of_Line Call(92) // search within line if ( ! Error_Match) { // if found Reg_Copy_Block(90, BoL_Pos, EoL_Pos) // remember original filename if ((Reg_Size(96)>0) || (#95==1)) { End_Of_Line Ins_Indent(#93+4) Ins_Text("-> ") Reg_Ins(90, BEGIN) #91=Cur_Pos if (Reg_Size(96)>0) { Reg_Empty(97) Reg_Set(98,".i") // in case of an error: set focus on "Rename to" input box Call(93) // replace old name by new name Goto_Pos(#91) } if (#95==1) { if (#96==1) { Case_Lower_Block(Cur_Pos, EoL_Pos) } else { Case_Upper_Block(Cur_Pos, EoL_Pos) } } } Reg_Copy_Block(91, Cur_Pos, EoL_Pos) if (#90==1) { // if I really should do it, the rename ... #92=2 if (Reg_Size(96)>0) { // if there is a real renaming (and not only case switching): Reg_Set(103, @91) // check for existing target file while (File_Exist("|@(103)", NOERR)) { #92=Dialog_Input_1(103,"`Extended File Renaming Utility`, `Problem: The file |@(90) should be renamed to the already `, `??existing file`, `You can change the target name in the input field.`, `[&Try again]`, `[&Force]`,`[Do&n't touch]`", SET+SCREEN+CENTER,0,0) if (((#92==1) || (#92==2)) && (Reg_Size(103)==0)) { Continue } Reg_Set(91, @103) if (#92!=1) { break } #92=2 } // this check may no longer be needed, but to be sure I'll let it activated if (Error_Flag == 3) { Reg_Empty(97) Reg_Set(98, ".i") Reg_Set(99, " >>>>> Error: Target directory doesn't exist! <<<<< ") Break_Out } } if (#92==2) { if (Reg_Compare(90, @(91))==0) { // workaround for File_Rename bug (if only the case differs) File_Rename("|@(90)", "ren-file|(PID)", OK+NOERR) File_Rename("ren-file|(PID)", "|@(91)", OK+NOERR) } else { File_Rename("|@(90)", "|@(91)", OK+NOERR) } if (Error_Flag || ! File_Exist("|@(91)")) { // if rename was unsuccessful #92=Dialog_Input_1(103,"`Extended File Renaming Utility`, `Problem: The file |@(90) couldn't be renamed! `, `[&Ok]`,`[&Cancel]`", SET+SCREEN+CENTER,0,0) if (#92!=1) { break } } } } } Line(1) // next line in listing } File_Save(NOMSG+BEGIN) Update if (#90==2) { // if in "test" mode Search("-> ", NOERR) if (Error_Match) { Reg_Set(99, " >>>>> Info: No matching files found. <<<<< ") } else { if (Cur_Line > Win_Lines) { Set_Visual_Line(3) } } Update goto START } :END: Reg_Lock_Macro(CLEAR) Visual_Macro(#89) #98=File_Check("|(VEDIT_TEMP)\ren-file.tmp") if (#98 != -1) { Buf_Switch(#98) Buf_Quit(OK) } Num_Pop(89,99) // restore used registers Reg_Pop(89,99) File_Delete("|(VEDIT_TEMP)\ren-file.tmp", NOERR+OK) //File_Delete("|(USER_MACRO)\ren-file.syn", NOERR+OK) return //============================================================================= :CREATE_FILES: // Create Syntax-Highlighting file in USER_MACRO if it doesn't already exist if (! (File_Exist("|(USER_MACRO)\ren-file.syn") || File_Exist("|(HOME)\ren-file.syn"))) { #97=Buf_Num Buf_Switch(Buf_Free) Ins_Text(`// VEDIT syntax highlighting definition for REN-FILE.VDM Reserved2 = "->|*" `) File_Save_As("|(USER_MACRO)\ren-file.syn", OK+NOMSG) Buf_Quit(OK) Buf_Switch(#97) } // Create Example file in USER_MACRO if it doesn't already exist. // If it exists but seems to be for a too old VEDIT version // offer an update dialog. // if (File_Exist("|(USER_MACRO)\ren-file.txt")) { #97=Buf_Num File_Open("|(USER_MACRO)\ren-file.txt") Update Search("Old name:|W|H7B", BEGIN+NOERR) if (! Error_Match) { #90=Dialog_Input_1(103,"`Extended File Renaming Utility`, `The examples file seems to be too old.`, `Should it be reset by the macro now?`, `[&Yes]`,`[&No]`", SET+SCREEN+CENTER,0,0) } Buf_Quit(OK) Buf_Switch(#97) Update if (#90==1) { File_Delete("|(USER_MACRO)\ren-file.txt", OK) } } if (! File_Exist("|(USER_MACRO)\ren-file.txt")) { #97=Buf_Num Buf_Switch(Buf_Free) Ins_Text(`## Examples for REN-FILE.VDM Since Regular Expressions may be a bit complicated it may help to have some examples for usage with REN-FILE.VDM. 1) Renaming all .txt files to .doc files Old name: (.*)\.txt New name: \1.doc 2) Renaming test*.txt files to .doc files with additional name modification. The leading string "test" should be renamed to "prod" Old name: test(.*)\.txt New name: prod\1.doc 3) Files named like abc567.txt or Z9123.txt should be renamed to DATA-567.abc DATA-9123.Z Old name: ([a-z]+)([0-9]+)\.txt New name: DATA-\2.\1 4) Insert an additional digit at certain position to numbered files Old name: (.* )([0-9][0-9])([we]_)(.*)\.jpg New name: \10\2\3\4.jpg Example: "IL03 016s 10w_001.jpg" --> "IL03 016s 010w_001.jpg" "IL03 025n 015e_001.jpg" (untouched because of the already 3 digits in font of the 'e') 5) Force all .doc files to UPPER-case with no further renaming Old name: (.*)\.doc New name: [x] Force the renaming to ( ) lower or (o) UPPER case 6) to be continued ... `) File_Save_As("|(USER_MACRO)\ren-file.txt", OK+NOMSG) Buf_Quit(OK) Buf_Switch(#97) } return