[Solved] How can I get the parent of a directory

Just starting out? Need help? Post your questions and find answers here.
User avatar
helpy
Enthusiast
Enthusiast
Posts: 552
Joined: Sat Jun 28, 2003 12:01 am

Re: [Solved] How can I get the parent of a directory

Post by helpy »

There are some open issues:

Example 1: GetParentDirecotry of an absolute path like "C:\" or "/".
Should the procedure really return an empty string?
Or would it more accurate to return the root "C:\" or "/", because there is no parent of the root.

Example 2:
How should relative paths be handled?
Should'nt GetParentDirectory("relativePath") return ".\"?
Should'nt GetParentDirectory(".\") return "..\"?
Should'nt GetParentDirectory("..\") return "..\..\"?
Windows 10 / Windows 7
PB Last Final / Last Beta Testing
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [Solved] How can I get the parent of a directory

Post by Little John »

helpy wrote:There are some open issues:

Example 1: GetParentDirecotry of an absolute path like "C:\" or "/".
Should the procedure really return an empty string?
Or would it more accurate to return the root "C:\" or "/", because there is no parent of the root.
IMHO trying to get the parent of a root directory should result in an error.
So for me the main question is, what is the best way to indicate an error in this context (without writing an extra GetError() function or something). I think returning an empty string is a good error indicator here, which can be checked easily by the code that calls the ParentDirectory() function.
helpy wrote:Example 2:
How should relative paths be handled?
Should'nt GetParentDirectory("relativePath") return ".\"?
Should'nt GetParentDirectory(".\") return "..\"?
Should'nt GetParentDirectory("..\") return "..\..\"?
Now the situation becomes more complex. :-)
Here is my attempt to handle absolute and relative paths:

Code: Select all

EnableExplicit

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
   #DirSep$ = "\"
   #DirSepChars$ = #DirSep$ + "/"
   Macro PathIsRelative (_path_)
      (Asc(_path_) <> '\' And FindString(_path_, ":") = 0)
   EndMacro
CompilerElse
   #DirSep$ = "/"
   #DirSepChars$ = #DirSep$
   Macro PathIsRelative (_path_)
      (Asc(_path_) <> '/' And Left(_path_, 2) <> "\\")
   EndMacro
CompilerEndIf


Procedure.s ParentDirectory (path$)
   ; in : path$: absolute or relative path, with or without trailing (back)slash;
   ;             If path$ = "", then it is set to the current directory.
   ; out: return value: path to parent directory, with trailing (back)slash;
   ;                    or "" if 'path$' is a root directory
   Protected posn.i, ret$
   
   If path$ = ""
      path$ = GetCurrentDirectory()
   EndIf
   
   posn = Len(path$) - 1
   While posn > 0 And FindString(#DirSepChars$, Mid(path$, posn, 1)) = 0
      posn - 1
   Wend
   
   If Mid(path$, posn+1, 1) <> "."
      ret$ = Left(path$, posn)
      If (ret$ = "") And PathIsRelative(path$)
         ret$ = ".\"
      EndIf   
      ProcedureReturn ret$
   Else
      If FindString(#DirSepChars$, Right(path$, 1)) = 0
         path$ + #DirSep$
      EndIf
      ProcedureReturn path$ + ".." + #DirSep$
   EndIf
EndProcedure


; -- Demo (for Windows)
; absolute paths
Debug "'" + ParentDirectory("F:\Users\LJ\") + "'"
Debug "'" + ParentDirectory("C:\") + "'"
Debug "'" + ParentDirectory("\") + "'"
Debug ""

; relative paths
Debug "'" + ParentDirectory("ab\cd\") + "'"
Debug "'" + ParentDirectory("ab\") + "'"
Debug "'" + ParentDirectory(".\") + "'"
Debug "'" + ParentDirectory("..\") + "'"
User avatar
Sicro
Enthusiast
Enthusiast
Posts: 538
Joined: Wed Jun 25, 2014 5:25 pm
Location: Germany
Contact:

Re: [Solved] How can I get the parent of a directory

Post by Sicro »

Little John wrote:
Sicro wrote:Good trick, davido! If this is safe to use, it would save a lot of code.
But it's undocumented behavior, so currently it's not safe to use, in my opinion.
What exactly is undocumented in this context?
Davidos code uses in its code the undocumented behavior of GetPathPart, that in case of a missing trailing slash the last directory is cut off from the path.

In this case, it is also an incorrect use of GetPathPart because the command parameter requires a file path and not a directory path.
Little John wrote:
Sicro wrote:[CodeArchiv-Code]
IMHO it never makes sense to do unnecessary work, neither for humans nor for computers. :-)
Here, it's not necessary to re-build Path$ in each iteration of the loop. The purpose of the loop "only" is, to find the position of the regarding slash. Then the wanted path can be built afterwards outside of the loop.
Yes, you're right, of course. I didn't think enough about programming the code. :(
At the next update of the master branch of the CodeArchive I will release an improved version of the code.
Little John wrote:Using pointers will probably yield even faster code.
Yes, sure. While programming the code, I wanted to make it easy for everyone to understand.


Many thanks to everyone for their codes 8)
Image
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [Solved] How can I get the parent of a directory

Post by Little John »

Sicro wrote:
Little John wrote:
Sicro wrote:Good trick, davido! If this is safe to use, it would save a lot of code.
But it's undocumented behavior, so currently it's not safe to use, in my opinion.
What exactly is undocumented in this context?
Davidos code uses in its code the undocumented behavior of GetPathPart, that in case of a missing trailing slash the last directory is cut off from the path.
This behaviour isn't undocumented ... doing so is the purpose of GetPathPart(). :-)
Sicro wrote:In this case, it is also an incorrect use of GetPathPart because the command parameter requires a file path and not a directory path.
This function does not check the file system on the drive, it just parses a string. And if the path passed to it doesn't have a trailing (back)slash, then GetPathPart() cannot distinguish between a file path and a directory path -- and this distinction doesn't matter in this context at all.
User avatar
Sicro
Enthusiast
Enthusiast
Posts: 538
Joined: Wed Jun 25, 2014 5:25 pm
Location: Germany
Contact:

Re: [Solved] How can I get the parent of a directory

Post by Sicro »

Thank you, Little John.
I was too focused on the file system, so I didn't think that the function would only process the path as a string. Until now I have only used this function with existing paths.
Now I also think that Davido's code and the other codes here using the same technique are safe to use :D
Image
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: [Solved] How can I get the parent of a directory

Post by davido »

Thank you all for your help with my little problem.:D
It is very much appreciated.
DE AA EB
User avatar
Sicro
Enthusiast
Enthusiast
Posts: 538
Joined: Wed Jun 25, 2014 5:25 pm
Location: Germany
Contact:

Re: [Solved] How can I get the parent of a directory

Post by Sicro »

I rewrote the code in the CodeArchive. It now uses GetPathPart() and supports relative paths.

Checking for a relative path is a simpler version than the one from Little John. I hope that this method is still enough.

Currently, the code is still in a development branch and will remain there for a while until I am sure that it is error-free and no more functions are required.

https://github.com/SicroAtGit/PureBasic ... ectory.pbi
Code snippet:

Code: Select all

Procedure$ GetParentDirectory(Path$)
  
  Select Right(Path$, 2)
    Case "./" : ProcedureReturn Path$ + "../"
    Case ".\" : ProcedureReturn Path$ + "..\"
  EndSelect
  
  Select Right(Path$, 3)
    Case "../" : ProcedureReturn Path$ + "../"
    Case "..\" : ProcedureReturn Path$ + "..\"
  EndSelect
  
  Path$ = GetPathPart(Left(Path$, Len(Path$) - 1))
  
  ProcedureReturn Path$
  
EndProcedure
Image
Why OpenSource should have a license :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (syntax color scheme) :: RegEx-Engine (compiles RegExes to NFA/DFA)
Manjaro Xfce x64 (Main system) :: Windows 10 Home (VirtualBox) :: Newest PureBasic version
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6161
Joined: Sat May 17, 2003 11:31 am
Contact:

Re: [Solved] How can I get the parent of a directory

Post by blueznl »

Mine... just one of the many :-)

Code: Select all

Procedure.s x_chop(string.s,left.i,right.i)                          ; chop a bit of the left and right side of a string
  Protected l.i
  ;
  ; *** chop 'n' characters from the left or right of a string
  ;
  l = Len(string)
  If left+right >= l
    string = ""
  Else
    If right > 0
      string = Left(string,l-right)
    EndIf
    If left > 0
      string = Mid(string,left+1,l)
    EndIf
  EndIf
  ;
  ProcedureReturn string
  ;
EndProcedure

Procedure.s x_getparentpathpart(s.s)                                   ; returns parent folder part of a given path
  Protected q.s, p.i
  ;
  ; *** get the 'parent' folder from the given string, ie. c:\windows\system32\ would return c:\windows\
  ;
  ; notes:
  ;
  ; - assume that given string is a path, regardless if it ended on a backslash or not
  ; - if it cannot find a parent path it returns an empty string
  ; - might :-/ hancle unc paths
  ;
  If Mid(s,2,1) = ":"                 ; local root
    q = Left(s,2)
    s = Mid(s,3,#MAX_PATH)
  ElseIf Left(s,2) = "\\"             ; unc path
    p = FindString(s,"\",3)
    If p > 0                          ; valid unc path
      q = Left(s,p)
      s = Mid(s,p+1,#MAX_PATH)
    Else                              ; invalid unc path
      q = ""
      s = ""
    EndIf
  EndIf
  ;
  If s > ""                           ; if there is something to find the parent of...
    If Right(s,1) = "\"               ; strip the trailing backslash to getpathpart() returns one level higher
      s = x_chop(s,0,1)
    EndIf
    If s > ""                         ; there must be something left, in which case we'll put the leading drive / unc path in front of it
      s = q+GetPathPart(s)
    EndIf
  EndIf
  ProcedureReturn s
  ;
EndProcedure
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Post Reply