/* UPath - More than unix like accessing files and folders Revision: 0.4 Status: EXPERIMENTAL BETA Date: Sun, 26 November 2006 12:26:21 GMT Author: Tuncay Homepage: http://tuncay.uttx.net/autohotkey/upath/ License: GNU GPL, Version 2 Type: Library Standalone: Yes Polymorph: No Tested AHK Version: 1.0.45.04 Tested WIN Version: XP Pro SP2 Please send any bug report to tuncay.d@gmx.net. See at UPath.man.txt for description and usage about UPath function. Public Functions: (Any parameter enclosed in '[' and ']' are optional.) UPath(Path, [Options], [RegExFilter]) - The main function returning absolute windows path. RunUPath([Path], [With], [WorkingDir], [RegExFilter]) - Built-in for easily running an UPath. */ #NoEnv SendMode Input /* Public Function UPath 2006 by Tuncay */ UPath(Path, Options = "", RegExFilter = "") { Global ErrorLevel@UPath ErrorLevel@UPath := 0 Argument?Path := Path ; Unchanged backup of the argument string Path. CurrentScriptBatchLines := A_BatchLines SplitPath, A_ScriptFullPath,,,,, RootDir RootDir := RootDir . "\" HomeDir := AddDirectoryTail@UPath(A_MyDocuments) GoSub, SetOptions@UPath PathIsAbsolute := IsAbsolute@UPath(Path) StringLeft, FirstChar, Path, 1 If (FirstChar = "/") { StringTrimLeft, Path, Path, 1 StringLeft, FirstChar, Path, 1 ; "//" Relative to current ScriptDir where UPath was called from. ; (Absolute, doesn't affect from WorkingDir.) If (FirstChar = "/") { StringTrimLeft, Path, Path, 1 FullPath := AddDirectoryTail@UPath(A_ScriptDir) . SubDirectoryTail@UPath(Path) } ; Relative to Root. (Absolute, doesn't affect from WorkingDir.) Else FullPath := RootDir . SubDirectoryTail@UPath(Path) } ; Relative to MyDocuments of current user. (Absolute, doesn't affect from ; WorkingDir.) Else If (FirstChar = "~") { StringTrimLeft, Path, Path, 1 Path := SubFirstChar@UPath(Path, "/") ; Access like in Unix with an "~user" is not supported, only current ; user profile with "~" or optionally with an ending slash "~/". FullPath := HomeDir . SubDirectoryTail@UPath(Path) } ; Windows absolute full path. Don't change it. Else If PathIsAbsolute FullPath := SubDirectoryTail@UPath(Path) ; Relative to current WorkingDir. Else FullPath := AddDirectoryTail@UPath(A_WorkingDir) . SubDirectoryTail@UPath(Path) StringReplace, FullPath, FullPath, /, \, All If (Option?SearchInEnvPath) { EnvGet, EnvPath, Path If (Option?SearchInEnvPath = 1) EnvPath := A_WorkingDir . ";" . EnvPath Loop, Parse, EnvPath, `; { CurrentLoopPath := AddDirectoryTail@UPath(A_LoopField) . Path If ((Option?IncludeFolders = 1) OR (Option?IncludeFolders = 2 AND InStr(FileExist(CurrentLoopPath), "D")) OR (Option?IncludeFolders = 0 AND NOT InStr(FileExist(CurrentLoopPath), "D"))) { If FileExist(CurrentLoopPath) { If (Option?RetrieveAll = 1) { CurrentLoopPath := GetPathFromLoop@UPath(CurrentLoopPath, Option?IncludeFolders, Option?SearchInSubfolders, Option?RetrieveAll, Option?IncludeSystemFiles, Option?RegExFilter, RegExFilter, RegExStartPosition) If (CurrentLoopPath) CurrentFullPath := CurrentFullPath . ";" . SubFirstChar@UPath(CurrentLoopPath, ";") Continue } Else If (Option?RetrieveAll = 0) { CurrentFullPath := GetPathFromLoop@UPath(CurrentLoopPath, Option?IncludeFolders, Option?SearchInSubfolders, Option?RetrieveAll, Option?IncludeSystemFiles, Option?RegExFilter, RegExFilter, RegExStartPosition) Break } } } } FullPath := SubFirstChar@UPath(CurrentFullPath, ";") } Else If NOT (Argument?Path = "/") FullPath := GetPathFromLoop@UPath(SubDirectoryTail@UPath(FullPath), Option?IncludeFolders, Option?SearchInSubfolders, Option?RetrieveAll, Option?IncludeSystemFiles, Option?RegExFilter, RegExFilter, RegExStartPosition) FullPath := AddDirectoryTail@UPath(FullPath) If Option?AddQuotes FullPath := AddQuotes@UPath(FullPath) If Options Contains -h { SetBatchLines, %CurrentScriptBatchLines% Process, Priority,, Normal } Return FullPath SetOptions@UPath: ; Default settings SetBatchLines, 10ms ; Standard priority. Option?SearchInSubfolders := 0 ; No search in subdirectories. Option?SearchInEnvPath := 0 ; No search in environment PATH. Option?IncludeFolders := 1 ; Files AND folders are included. Option?IncludeSystemFiles := 0 ; No including system files. Option?RetrieveAll := 0 ; Retrieve only one file. Option?RegExFilter := 0 ; No filtering with RegEx. Option?AddQuotes := 0 ; No quotes in path. GoSub, SetRegEx@UPath CurrentStringCaseSense := A_StringCaseSense StringCaseSense On If Options Contains -- { StringReplace, Options, Options,--quot,-q StringReplace, Options, Options,--file,-f StringReplace, Options, Options,--dir,-d StringReplace, Options, Options,--system,-S StringReplace, Options, Options,--all,-a StringReplace, Options, Options,--subdirs,-s StringReplace, Options, Options,--envonly,-E ; Parse before --env. StringReplace, Options, Options,--env,-e StringReplace, Options, Options,--high,-H } StringReplace, Options, Options,/,-, All ; Overwriting default settings. OptionsFoundList := "" ; For performance, not to loop if already founded ; and avoid dublicates. Loop, Parse, Options,-,%A_SPACE% { If A_LoopField In ,%A_SPACE% Continue ; Inner Loop for enabling the short style for grouping of options. Loop, Parse, A_LoopField { IfInString, OptionsFoundList, %A_LoopField% Continue ; High Priority, BatchLines ; * normal and recommended (default) ; * high speed If InStr(A_LoopField, "H", 1) { SetBatchLines, -1 Process, Priority,, High OptionsFoundList := OptionsFoundList . A_LoopField Continue } ; Option?AddQuotes ; 0=do not enclose path between double quotes (default) ; 1=enclose every path between double quotes If InStr(A_LoopField, "q", 1) { Option?AddQuotes := 1 OptionsFoundList := OptionsFoundList . A_LoopField Continue } ; Option?RetrieveAll ; 0=get only first match (default) ; 1=all matches will be retrieved as a semicolon separated list If InStr(A_LoopField, "a", 1) { Option?RetrieveAll := 1 OptionsFoundList := OptionsFoundList . A_LoopField Continue } ; Option?IncludeFolders ; 1=files and folders (default) ; 0=files only ; 2=folders only If (InStr(A_LoopField, "f", 1) AND Option?IncludeFolders = 2) { Option?IncludeFolders := 1 OptionsFoundList := OptionsFoundList . A_LoopField Continue } Else If (InStr(A_LoopField, "d", 1) AND Option?IncludeFolders = 0) { Option?IncludeFolders := 1 OptionsFoundList := OptionsFoundList . A_LoopField Continue } Else If InStr(A_LoopField, "f", 1) { Option?IncludeFolders := 0 OptionsFoundList := OptionsFoundList . A_LoopField Continue } Else If InStr(A_LoopField, "d", 1) { Option?IncludeFolders := 2 OptionsFoundList := OptionsFoundList . A_LoopField Continue } ; Option?SearchInSubfolders ; 0=don't recurse subfolders (default) ; 1=include subfolders If InStr(A_LoopField, "s", 1) { Option?SearchInSubfolders := 1 OptionsFoundList := OptionsFoundList . A_LoopField Continue } ; Option?SearchInEnvPath ; -E overwrites -e. ; 0=don't search in system environment path (default) ; 1=search in path (like the windows cmd does it, also the ; workingdir will be searched) ; 2=search in path only (no including workingdir) If InStr(A_LoopField, "E", 1) { Option?SearchInEnvPath := 2 OptionsFoundList := OptionsFoundList . A_LoopField Continue } Else If (InStr(A_LoopField, "e", 1) AND Option?SearchInEnvPath != 2) { Option?SearchInEnvPath := 1 OptionsFoundList := OptionsFoundList . A_LoopField Continue } ; Option?IncludeSystemFiles ; 0=don't get files with attribute 'system' (default) ; 1=get files/folders with 'system' attribute also If InStr(A_LoopField, "S", 1) { Option?IncludeSystemFiles := 1 OptionsFoundList := OptionsFoundList . A_LoopField Continue } } } StringCaseSense %CurrentStringCaseSense% Return SetRegEx@UPath: RegExStartPosition := 1 RegExInPathPosition := GetRegExInPathPosition@UPath(Path) If (RegExInPathPosition) { StringMid, RegExFilter, Path, RegExInPathPosition + 4 StringMid, Path, Path, RegExInPathPosition,, L } If (RegExFilter) Option?RegExFilter := 1 Return } ; PRIVATE /* Private Function GetPathFromLoop Extend wildcards and get FullPath and (if needed) all files and folders as a list, filtered with regular expression. 2006 by Tuncay */ GetPathFromLoop@UPath(Path, Option?IncludeFolders = 1, Option?SearchInSubfolders = 0, Option?RetrieveAll = 0, Option?IncludeSystemFiles = 0, Option?RegExFilter = 0, RegExFilter = "", RegExStartPosition = 1) { Global ErrorLevel@UPath CurrentLoopPath := Path Loop, %Path%, %Option?IncludeFolders%, %Option?SearchInSubfolders% { If (Option?IncludeSystemFiles = 0 AND InStr(FileExist(A_LoopFileLongPath), "S")) Continue Else If (A_Index > 1 AND Option?RetrieveAll = 1 AND ErrorLevel@UPath > 0) { If ((Option?RegExFilter = 0) OR Option?RegExFilter = 1 AND RegExMatch(AddDirectoryTail@UPath(A_LoopFileLongPath), "iS)" . RegExFilter, "", RegExStartPosition)) { CurrentLoopPath := CurrentLoopPath . ";" . AddDirectoryTail@UPath(A_LoopFileLongPath) ErrorLevel@UPath += 1 } Continue } Else If ((A_Index = 1 AND Option?RetrieveAll = 1) OR (ErrorLevel@UPath = 0 AND Option?RetrieveAll = 1)) { ; outcommended, not needed any more???? ; If FileExist(A_LoopFileLongPath) ;{ If ((Option?RegExFilter = 0) OR Option?RegExFilter = 1 AND RegExMatch(AddDirectoryTail@UPath(A_LoopFileLongPath), "iS)" . RegExFilter, "", RegExStartPosition)) { CurrentLoopPath := AddDirectoryTail@UPath(A_LoopFileLongPath) ErrorLevel@UPath += 1 } Else If (Option?RegExFilter = 1) CurrentLoopPath := "" ; RegEx does not match. ;} ;Else ; CurrentLoopPath := "" Continue } Else { If ((Option?RegExFilter = 0) OR Option?RegExFilter = 1 AND RegExMatch(AddDirectoryTail@UPath(A_LoopFileLongPath), "iS)" . RegExFilter, "", RegExStartPosition)) { CurrentLoopPath := AddDirectoryTail@UPath(A_LoopFileLongPath) ErrorLevel@UPath += 1 Break } Else Continue } } Return CurrentLoopPath } /* Private Function AddDirectoryTail Add a backslash as last char to a path if its an existing directory. 2006 by Tuncay */ AddDirectoryTail@UPath(Path) { FileGetAttrib, Attributes, %Path% If (InStr(Attributes, "D")) { StringRight, LastChar, Path, 1 If (LastChar != "\") Path := Path . "\" } Return Path } /* Private Function SubDirctoryTail Deletes the last backslash of a path if its an existing directory. 2006 by Tuncay */ SubDirectoryTail@UPath(Path) { If InStr(FileExist(Path), "D") { StringRight, LastChar, Path, 1 If (LastChar = "\" OR LastChar = "/") StringTrimRight, Path, Path, 1 } Return Path } /* Private Function SubFirstChar Removes character at first position, if any existing. If Char is given, each character in Char is treated as a separate substring. 2006 by Tuncay */ SubFirstChar@UPath(Path, Char = "") { StringLeft, FirstChar, Path, 1 If (FirstChar = Char OR Char = "") StringTrimLeft, Path, Path, 1 Else { Loop, Parse { If (FirstChar = A_LoopField) { StringTrimLeft, Path, Path, 1 Break } } } Return Path } /* Private Function AddQuotes Encloses every path (semicolon separated also) between double quotes. 2006 by Tuncay */ AddQuotes@UPath(Path) { QuotedPath := "" If InStr(Path, ";") { Loop, Parse, Path, `; QuotedPath = %QuotedPath%`;"%A_LoopField%" QuotedPath := SubFirstChar@UPath(QuotedPath, ";") } Else QuotedPath = "%Path%" Return QuotedPath } /* Private Function IsAbsolute Checks if the string is an absolute path address. 2006 by Tuncay */ IsAbsolute@UPath(Path) { PathContainsDoubleColon := InStr(Path, ":") If (PathContainsDoubleColon = 2) { StringLeft, FirstChar, Path, 1 If FirstChar Is Alpha IsAbsolute := "Yes" } Return IsAbsolute } /* Private Function GetRegExInPathPosition Gets the position of the regular expression separator from an UPath string. */ GetRegExInPathPosition@UPath(Path) { RegExSeparator := A_SPACE . "||" . A_SPACE Return InStr(Path, RegExSeparator) } ; PUBLIC /* Public Function RunUPath Runs an UPath. All matches of path will be executed, even if wildcards or regular expressions are used. The second parameter 'With' defines an another application to run the founded file or folder, prior to that one the standard registered application of that filetype is. On default, the matched files or folders own directory will be used as the WorkingDir. Giving a WorkingDir to RunUPath will execute every founded item with that one. Requires UPath.ahk 2006 by Tuncay */ RunUPath(Path = "", With = "", Argument = "", WorkingDir = "", Wait = "", RegExFilter = "") { Global ErrorLevel@UPath RegExInPathPosition := GetRegExInPathPosition@UPath(Path) If (RegExInPathPosition) StringMid, PathOnly, Path, RegExInPathPosition,, L If ((RegExInPathPosition > 0 AND (InStr(PathOnly, "*") OR InStr(PathOnly, "?"))) OR (RegExInPathPosition = 0 AND (InStr(Path, "*") OR InStr(Path, "?")))) { Options := Options . "--all" } Path := UPath(Path, Options, RegExFilter) If (ErrorLevel@UPath > 0) { BackupErrorLevel@UPath := ErrorLevel@UPath If (Argument) Argument := A_SPACE . Argument Loop, Parse, Path, `; { If (WorkingDir = "") SplitPath, A_LoopField,, WorkingDir If (With = "") { If (Wait = "yes") RunWait, "%A_LoopField%", %WorkingDir%%Argument%, UseErrorLevel Else Run, "%A_LoopField%", %WorkingDir%%Argument%, UseErrorLevel } Else If FileExist(With) { If (Wait = "yes") RunWait, "%With%" "%A_LoopField%"%Argument%, %WorkingDir%, UseErrorLevel Else Run, "%With%" "%A_LoopField%"%Argument%, %WorkingDir%, UseErrorLevel } Else { If (RunWith = "") RunWith := UPath(With, "--file --env") If (Wait = "yes") RunWait, "%RunWith%" "%A_LoopField%"%Argument%, %WorkingDir%, UseErrorLevel Else Run, "%RunWith%" "%A_LoopField%"%Argument%, %WorkingDir%, UseErrorLevel } } ErrorLevel@UPath := BackupErrorLevel@UPath } Return Path }