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

Just starting out? Need help? Post your questions and find answers here.
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

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

Post by davido »

For example I have a path to a directory: /Volumes/PureBasic_MacOSX/PureBasic/PureBasic.app/Contents/

Is there a general way of getting the parent directory: /Volumes/PureBasic_MacOSX/PureBasic/PureBasic.app/

Currently I use the following method:

Code: Select all

A$ = GetCurrentDirectory()
A$ = Left(A$,Len(A$) - 1)
Debug GetPathPart(A$)
This is, I think, rather crude.
Can anyone suggest a more elegant way?
Last edited by davido on Fri Sep 15, 2017 7:51 pm, edited 2 times in total.
DE AA EB
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How can I get the parent of a directory

Post by mk-soft »

Nice Idee :D

Update

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  Macro GetParentDirectory(Path)
    GetPathPart(RTrim(Path, "\"))
  EndMacro
CompilerElse
  Macro GetParentDirectory(Path)
    GetPathPart(RTrim(Path, "/"))
  EndMacro
CompilerEndIf  
  
A$ = GetCurrentDirectory()
Debug a$
a$ = GetParentDirectory(A$)
Debug a$
a$ = GetParentDirectory(A$)
Debug a$
a$ = GetParentDirectory(A$)
Debug a$
a$ = GetParentDirectory(A$)
Debug a$
a$ = GetParentDirectory(A$)
Debug a$
a$ = GetParentDirectory(A$)
Debug a$
a$ = GetParentDirectory(A$)
Debug a$
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: How can I get the parent of a directory

Post by Little John »

Hi davido,

I've also used this method in the past. There's nothing wrong with it IMHO. :-)
User avatar
DK_PETER
Addict
Addict
Posts: 898
Joined: Sat Feb 19, 2011 10:06 am
Location: Denmark
Contact:

Re: How can I get the parent of a directory

Post by DK_PETER »

or you could traverse backwards using stringfield/countstring

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  #delimit = "\"
CompilerElse
  #delimit = "/"
CompilerEndIf

Declare.s ReturnParent(st.s, Delimit.s = #delimit)

Procedure.s ReturnParent(st.s, Delimit.s = #delimit)
  Protected count = CountString(st, Delimit)-1
  Protected retstring.s
  If count > 0
    For x = 1 To count
      retstring + StringField(st, x, Delimit) + Delimit
    Next x
  EndIf
  ProcedureReturn retstring
EndProcedure

st.s = GetPathPart(ProgramFilename())
co.i = CountString(st, #delimit)
For x = 1 To co
  st = ReturnParent(st, #delimit)
  Debug st
Next x

Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
User avatar
Sicro
Enthusiast
Enthusiast
Posts: 538
Joined: Wed Jun 25, 2014 5:25 pm
Location: Germany
Contact:

Re: How can I get the parent of a directory

Post by Sicro »

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.

The code 'GetPreviousDirectory' in the CodeArchive uses a more complicated method, but should be safe:
https://github.com/SicroAtGit/PureBasic ... ectory.pbi
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: How can I get the parent of a directory

Post by davido »

@Sicro,
Thank you for you comments and the link to your code.
A nicely engineered piece of code. Thank you for sharing.
DE AA EB
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

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

Post by RASHAD »

While it is solved,I like to introduce my 2c :)

Code: Select all

Global A$

Procedure.s getPDirectory()
  If SetCurrentDirectory(GetPathPart(A$))
    A$ = GetCurrentDirectory()
    A$ = Left(A$,Len(A$) - 1)
    Debug GetPathPart(A$)
  EndIf
EndProcedure
 
A$ = "e:\projects\stuff rashad\New folder\"

getPDirectory()
getPDirectory()
getPDirectory()
Egypt my love
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 »

Now we have different methods and everybody can choose the one he likes best :D

@RASHAD
Why do you use Get/SetCurrentDirectory? It doesn't make sense.
SetCurrentDirectory is dangerous and should be run only once at program startup, because it can quickly lead to incorrect code if relative paths are often used in the code.
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: How can I get the parent of a directory

Post by Little John »

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?
Sicro wrote:The code 'GetPreviousDirectory' in the CodeArchive uses a more complicated method, but should be safe:
https://github.com/SicroAtGit/PureBasic ... ectory.pbi
I'm copying the procedure here, so that it's easier to discuss about it:

Code: Select all

Procedure$ GetPreviousDirectory(Path$)
  
  Protected Slash$
  Protected StringLength
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    Slash$ = "\"
  CompilerElse ; Linux, Mac
    Slash$ = "/"
  CompilerEndIf
  
  Path$ = RTrim(Path$, Slash$)
  
  StringLength = Len(Path$)
  
  While Path$ <> "" And Right(Path$, 1) <> Slash$
    StringLength - 1
    Path$ = Left(Path$, StringLength)
  Wend
  
  ProcedureReturn Path$
  
EndProcedure
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.

As I wrote previously, personally I am fine with the method that davido posted in his original message -- and I can't see why this should not be safe.
However, if I wanted to write some code for this myself, then I'd do it like this:

//edit:
Code changed according to helpy's hint (see below)

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
   #DirSep$ = "/\"
CompilerElse
   #DirSep$ = "/"
CompilerEndIf


Procedure.s ParentDirectory (path$)
   Protected posn.i
   
   posn = Len(path$) - 1
   While posn > 0 And FindString(#DirSep$, Mid(path$, posn, 1)) = 0
      posn - 1
   Wend
   
   ProcedureReturn Left(path$, posn)
EndProcedure
Using pointers will probably yield even faster code.
Last edited by Little John on Sat Sep 16, 2017 1:40 pm, edited 1 time in total.
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 »

Hi Little John,
Thank you for clarifying the issue. :D
I shall continue using code similar to that in my first post.
In the unlikely event it should go pear-shaped, I can always revert to your enhanced version of Sicro's Code.
DE AA EB
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

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

Post by Mijikai »

Heres another solution :)

Code: Select all

;ParentPath() x64 (Unicode)
;by Mijikai

Procedure.i ParentPath(Path.i)
  !mov rsi,[p.v_Path]
  !mov rcx,rsi
  !xor rax,rax
  !ParentPathLoop:
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    !cmp dword[rcx],05Ch
  CompilerElse
    !cmp dword[rcx],02Fh
  CompilerEndIf
  !je ParentPathExit
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    !cmp word[rcx],05Ch
  CompilerElse
    !cmp word[rcx],02Fh
  CompilerEndIf
  !jne ParentPathNext
  !mov rax,rcx
  !ParentPathNext:
  !inc rcx
  !cmp word[rcx],0h
  !jne ParentPathLoop
  !ParentPathExit:
  !test rax,rax
  !jz ParentPathReturn
  !mov word[rax+1h],0h
  !ParentPathReturn:
EndProcedure

Path.s = GetCurrentDirectory()
Debug Path
ParentPath(@Path)
Debug Path
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 »

It is also possible to use "/" with file functions on windows!
Should'nt your functions also handle this case?
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:It is also possible to use "/" with file functions on windows!
Should'nt your functions also handle this case?
Oops, I had almost forgotten about that. Thank you for the hint :!:
I've changed my above code accordingly. While doing so, I realized that also RTrim() is not necessary. :-)

The method with GetPathPart() doesn't need to be changed, since GetPathPart() handles both slash characters as expected (tested with PB 5.61 x64 on Windows 10).
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 »

Another version, that does not only allow to get the parent directory, but by means of an optional parameter also the grandparent directory, the great grandparent directory etc.
I don't know whether anyone (including me) will ever need this, though. :-)

Code: Select all

EnableExplicit


CompilerIf #PB_Compiler_OS = #PB_OS_Windows
   #DirSep$ = "/\"
CompilerElse
   #DirSep$ = "/"
CompilerEndIf


Procedure.s ParentDirectory (path$, levelsUp.i=1)
   ; in : path$   : source path, with or without trailing (back)slash
   ;      levelsUp: number of levels to go up:
   ;                1 -> parent directory
   ;                2 -> grandparent directory
   ;                3 -> great grandparent directory
   ;                etc.
   ; out: return value: path to desired directory, with trailing (back)slash;
   ;                    or unaltered 'path$' if 'levelsUp' < 1;
   ;                    or "" if 'levelsUp' >= number of levels in 'path$' 
   Protected.i posn, levelCount=0
   
   posn = Len(path$)
   While posn > 0  And levelCount < levelsUp
      posn - 1
      If FindString(#DirSep$, Mid(path$, posn, 1))
         levelCount + 1
      EndIf   
   Wend
   
   ProcedureReturn Left(path$, posn)
EndProcedure


; -- Demo
Define path$ = "F:\Users\LJ\Documents\"

Debug "'" + ParentDirectory(path$, 0) + "'"
Debug "'" + ParentDirectory(path$, 1) + "'"
Debug "'" + ParentDirectory(path$, 2) + "'"
Debug "'" + ParentDirectory(path$, 3) + "'"
Debug "'" + ParentDirectory(path$, 4) + "'"
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 »

One more version:

Code: Select all

Procedure.s GetParentDirectory(Path.s)
  Protected *c.Character
  Protected *cTest.Character
  
  *c = @Path
  If (Not *c) Or Not (*c\c)
    ; Path is empty
    ProcedureReturn #Empty$
  EndIf
  
  *cTest = *c + ((Len(Path) - 1) * SizeOf(Character))
  While *cTest >= *c
    *cTest - SizeOf(Character)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      If *cTest\c = '/' Or *cTest\c = '\' : Break : EndIf
    CompilerElse
      If *cTest\c = '/' : Break : EndIf
    CompilerEndIf
  Wend
  
  If *cTest < *c
    ; Path does not contain path separator
    ProcedureReturn #Empty$
  EndIf
  
  ProcedureReturn PeekS(*c, (*cTest - *c) / SizeOf(Character) + 1)
EndProcedure
Windows 10 / Windows 7
PB Last Final / Last Beta Testing
Post Reply