Jump to content
Sign in to follow this  
Valik

Au3 Version Of _splitpath

Recommended Posts

Valik

Here's a version of _SplitPath in AU3 which seems to emulate the C library function _splitpath well. For those unfamiliar, it takes a path argument and splits it into drive, path, filename and file extension (Including .) components.

There's no return value and no errors. Any missing parts are set to a null string.

EDIT: This version of the code was old.  The newer version is posted somewhere below.

An example of usage and output would be:

Global $path
Global $drive
Global $dir
Global $file
Global $ext
$path = "C:\Program Files\test\moo.cow"
_SplitPath($path, $drive, $dir, $file, $ext)

MsgBox(4096, "_SplitPath", "Path= " & $path & @CRLF & _
    "Drive= " & $drive & @CRLF & _
    "Dir= " & $dir & @CRLF & _
    "File= " & $file & @CRLF & _
    "Ext= " & $ext)

The above should produce the output:

Path= C:\Program Files\test\moo.cow

Drive= C:

Dir= \Program Files\test\

File= moo

Ext= .cow

Edited by Valik

Share this post


Link to post
Share on other sites
CyberSlug

Nice :whistle:

Perhaps you could add UNC-style support, e.g. "$path = "\\127.0.0.1\SharedDocs\foo.txt"

might produce something like:

Drive= \\127.0.0.1

Dir= \SharedDocs\

File= foo

Ext= .txt

However, your script works fine as is.


Use Mozilla | Take a look at My Disorganized AutoIt stuff | Very very old: AutoBuilder 11 Jan 2005 prototype I need to update my sig!

Share this post


Link to post
Share on other sites
Valik

I thought about UNC paths, but I don't know if _splitpath supports them or not and I was attempting to emulate it's functionality. I'll take a look at it later, though and see if I want to add that or not (Should be easy to do, I just want to make sure there's no possible way to confuse it).

However, your script works fine as is.

Shooo. When I saw you, the best obscure bug detecter on the planet, had replied, I thought I'd done something wrong and had a bug. Good to know that you haven't found one... :whistle:

...Yet B)

Share this post


Link to post
Share on other sites
Valik

EDIT I changed this post because I changed my mind on what I'm going to do.

I'll modifying _SplitPath to work with UNC paths. I'm also going to write _MakePath and _FullPath which will go along with the C library versions, except I'll make sure they support UNC paths, too. When I finish, I'll post the code here and send it to Jon for inclusion in the standard library thingy.

Edited by Valik

Share this post


Link to post
Share on other sites
Valik

Here's a new version of _SplitPath which has the following changes:

New: Accepts UNC server names as the drive.

New: Returns an array with the elements in it (See code comment for details)

Fixed: Uses local variables during execution as opposed to the output variables (This was changed in order to prevent a possible bug where the same variable was passed multiple times, for example, $null could be passed for arguments the user didn't want/need).

Watch wordwrap...

; _SplitPath()
; $szPath - IN - The path to be split (Can contain a UNC server or drive letter)
; $szDrive - OUT - String to hold the drive
; $szDir - OUT - String to hold the directory
; $szFName - OUT - String to hold the file name
; $szExt - OUT - String to hold the file extension
; Return - Array with 5 elements where 0 = original path, 1 = drive, 2 = directory, 3 = filename, 4 = extension
; Errors - None.  An empty string denotes a missing component.
Func _SplitPath($szPath, ByRef $szDrive, ByRef $szDir, ByRef $szFName, ByRef $szExt)
  ; Set local strings to null (We use local strings in case one of the arguments is the same variable)
    $drive = ""
    $dir = ""
    $fname = ""
    $ext = ""
    
  ; Create an array which will be filled and returned later
    Dim $array[5]
    $array[0] = $szPath; $szPath can get destroyed, so it needs set now
    
  ; Get drive letter if present (Can be a UNC server)
    If StringMid($szPath, 2, 1) = ":" Then 
        $drive = StringLeft($szPath, 2)
        $szPath = StringTrimLeft($szPath, 2)
    ElseIf StringLeft($szPath, 2) = "\\" Then
        $szPath = StringTrimLeft($szPath, 2)  ; Trim the \\
        $pos = StringInStr($szPath, "\")
        If $pos = 0 Then $pos = StringInStr($szPath, "/")
        If $pos = 0 Then
            $drive = "\\" & $szPath; Prepend the \\ we stripped earlier
            $szPath = ""  ; Set to null because the whole path was just the UNC server name
        Else
            $drive = "\\" & StringLeft($szPath, $pos - 1)  ; Prepend the \\ we stripped earlier
            $szPath = StringTrimLeft($szPath, $pos - 1)
        EndIf
    EndIf
    
  ; Set the directory and file name if present
    For $i = StringLen($szPath) To 0 Step -1
        If StringMid($szPath, $i, 1) = "\" OR StringMid($szPath, $i, 1) = "/" Then
            $dir = StringLeft($szPath, $i)
            $fname = StringRight($szPath, StringLen($szPath) - $i)
            ExitLoop
        EndIf
    Next
    
  ; If $szDir wasn't set, then the whole path must just be a file, so set the filename
    If StringLen($dir) = 0 Then $fname = $szPath
    
  ; Check the filename for an extension and set it
    For $i = StringLen($fname) To 0 Step -1
        If StringMid($fname, $i, 1) = "." Then
            $ext = StringRight($fname, StringLen($fname) - ($i -1))
            $fname = StringLeft($fname, $i - 1)
            ExitLoop
        EndIf
    Next
    
  ; Set the strings and array to what we found
    $szDrive = $drive
    $szDir = $dir
    $szFName = $fname
    $szExt = $ext
    $array[1] = $drive
    $array[2] = $dir
    $array[3] = $fname
    $array[4] = $ext
    Return $array
EndFunc; _SplitPath()
Edited by Valik

Share this post


Link to post
Share on other sites
CyberSlug

(This was changed in order to prevent a possible bug where the same variable was passed multiple times, for example, $null could be passed for arguments the user didn't want/need).

Darn, missed that one!

Style suggestion: If you are a minimalist, you may want to consider this:

; Set the strings and array to what we found
Return StringSplit($szDrive & "|" & $szDir & "|" & $szFName & "|" & $szExt, "|")

Edit: Well, you'd need to change element 0 to what you want.

Edited by CyberSlug

Use Mozilla | Take a look at My Disorganized AutoIt stuff | Very very old: AutoBuilder 11 Jan 2005 prototype I need to update my sig!

Share this post


Link to post
Share on other sites
Valik

Darn, missed that one!

May not of even existed, I never tested for it, but it _looked_ like it might cause problems so I thought I'd head it off before it became an issue.

Style suggestion:  If you are a minimalist, you may want to consider this:

; Set the strings and array to what we found
Return StringSplit($szDrive & "|" & $szDir & "|" & $szFName & "|" & $szExt, "|")

Edit:  Well, you'd need to change element 0 to what you want.

Personally, I'm not a fan of using the StringSplit method, I'd rather assign by hand. To be honest, though, I never even thought about it. The only reason I added an array at all is simply because I figured somebody would request it at some point. I just use the variables I pass and even then, I don't always need all of those so I pass them a pseudo-null.

Share this post


Link to post
Share on other sites
Valik

Here's _MakePath. Watch wordwrap/see comments

; _MakePath()
; $szFullPath - OUT - The newly created full path
; $szDrive - IN - Drive (Can be UNC).  If it's a drive letter, a : is automatically appended
; $szDir - IN - Directory.  A trailing slash is provided if not found (No preceeding slash is added)
; $szFName - IN - The name of the file
; $szExt - IN - The file extension.  A period is supplied if not found in the extension
; Return - The string for the newly created path (Same as $szFullPath)
; Errors - None.  Missing components are ignored and the path is created without it.
; Notes - This doesn't check the validity of the path created, it could contain characters which
;   are invalid on your filesystem.
Func _MakePath(ByRef $szFullPath, $szDrive, $szDir, $szFName, $szExt)

   ; Format $szDrive, if it's not a UNC server name, then just get the drive letter and add a colon
    If StringLen($szDrive) Then 
        If Not(StringLeft($szDrive, 2) = "\\") Then $szDrive = StringLeft($szDrive, 1) & ":"
    EndIf

   ; Format the directory by adding any necessary slashes
    If StringLen($szDir) Then
        If Not(StringRight($szDir, 1) = "\") And Not (StringRight($szDir, 1) = "/") Then $szDir = $szDir & "\"
    EndIf

   ; Nothing to be done for the filename
    
   ; Add the period to the extension if necessary
    If StringLen($szExt) Then
        If Not(StringLeft($szExt, 1) = ".") Then $szExt = "." & $szExt
    EndIf
    
    $szFullPath = $szDrive & $szDir & $szFName & $szExt
    Return $szFullPath
EndFunc; _MakePath()

Share this post


Link to post
Share on other sites
Valik

Here's _FullPath. It would surprise me greatly if this function doesn't have bugs as it's a pain to implement. Here it is for your bug-testing pleasure. As always, beware word-wrap and check the comments for more information. Just an up front warning also, this function requires my versions of _SplitPath and _MakePath which are above.

; _FullPath()
; This function creates a path based on the relative path you provide.  For example, if you specify
; "C:\test\folder\..\file.txt", the output would be "C:\test\file.txt" because of the ..\.
; $szABSPath - OUT - The newly created absolute path
; $szRelPath - IN - The relative path
; Return - The newly created absolute path is returned
; Errors - None, if no relative path is specified, the current working directory will be returned
; Notes - This function requires _SplitPath and _MakePath (Which also means it supports UNC)
Func _FullPath(ByRef $szABSPath, $szRelPath)
    Local $drive
    Local $dir
    Local $file
    Local $ext
    Local $wDrive
    Local $wDir
    Local $NULL
    _SplitPath($szRelPath, $drive, $dir, $file, $ext)
    _SplitPath(@WorkingDir, $wDrive, $wDir, $NULL, $NULL)
    
   ; If no drive specified, then we use the working directory to set our path relative to
    If Not StringLen($drive) Then
        $drive = $wDrive
        $dir = $wDir & $dir
    EndIf
    
   ; If the only thing specified was the drive, then return the working directory for that drive
    If Not StringLen($dir) AND Not StringLen($file) And Not StringLen($ext) Then 
        If $drive = $wDrive Then Return _MakePath($szABSPath, $wDrive, $wDir, "", "")
        Return _MakePath($szABSPath, $drive, "\", "", "")
    EndIf

   ; Look for any .\ and ..\
    While StringInStr($dir, ".\") Or StringInStr($dir, "./")
        $nPos = StringInStr($dir, ".\")
        If $nPos = 0 Then $nPos = StringInStr($dir, "./")
        If $nPos = 0 Then ExitLoop
        If StringMid($dir, $npos - 1, 1) = "." Then; It's ..\
            For $i = ($nPos - 3) To 0 Step -1
                If StringMid($dir, $i, 1) = "\" Or StringMid($dir, $i, 1) = "/" Then ExitLoop
            Next
                If $i > 0 Then
                    $dir = StringLeft($dir, $i) & StringRight($dir, StringLen($dir) - ($npos + 1))
                Else
                    $dir = StringRight($dir, StringLen($dir) - ($npos + 1))
                EndIf
        Else   ; It's .\
            $dir = StringLeft($dir, $npos - 1) & StringRight($dir, StringLen($dir) - $npos - 1)
        EndIf
    If Not StringLen($dir) Then $dir = "\"
    WEnd
    Return _MakePath($szABSPath, $drive, $dir, $file, $ext)
EndFunc; _FullPath()

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.