CreateDirectory() recursively or CreatePath()

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
User avatar
NicTheQuick
Addict
Addict
Posts: 1227
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: CreateDirectory() recursively or CreatePath()

Post by NicTheQuick »

Bisonte wrote:Also from TS-Soft (this should work on all platforms) slightly modified :

Code: Select all

    tmp + "\"
I wonder how that should work if there is a backslash right in the code.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
skywalk
Addict
Addict
Posts: 4003
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: CreateDirectory() recursively or CreatePath()

Post by skywalk »

This is what I use, and it is not recursive.

Code: Select all

;-! OS_PATH_SEPARATOR
; Not #OS_PATH_SEP$ due to ;BUG; PB v573 does not support @#OS_PATH_SEP$
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  Global.s OS_PATH_SEP$ = #PS$
CompilerElse
  Global.s OS_PATH_SEP$ = #NPS$
CompilerEndIf
Macro PB_CP
  ;ProgramFilename() + #COLON2$ + #PB_Compiler_File + #COLON2$ + #PB_Compiler_Procedure
  GetFilePart(#PB_Compiler_File, #PB_FileSystem_NoExtension) + "::" + #PB_Compiler_Procedure
EndMacro
Macro MRE(txt)    ; MessageRequester Error = #MB_ICONHAND | #MB_ICONSTOP | #MB_ICONERROR
  MessageRequester(PB_CP, txt, #MB_ICONERROR)
EndMacro
ImportC ""
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    _wcslen_(*String) As "wcslen"
    _wcsstr_(*String1, *String2) As "wcsstr"
  CompilerElse
    _wcslen_(*String) As "_wcslen"
    _wcsstr_(*String1, *String2) As "_wcsstr"
  CompilerEndIf
EndImport
Procedure.i SplitC(*String.Character, Array A$(1), *Delimiter)
  ;nco2k, http://www.purebasic.fr/english/viewtopic.php?p=516082#p516082
  ;skywalk; modified to catch trailing null's.
  ; Ex. "1,2,3,," Splits with ',' -> [1][2][3][][].
  Protected.i *StringEnd, DelimiterLength, ArrayIndex
  Protected.i Resize = 511
  Protected.i nStrings = ArraySize(A$())
  If *String    ; Avoid 'Pointer is null' if pointing to an array element = Empty$
    If *String\c
      DelimiterLength = _wcslen_(*Delimiter) * SizeOf(Character)
      If DelimiterLength
        Repeat
          *StringEnd = _wcsstr_(*String, *Delimiter)
          If *StringEnd
            A$(ArrayIndex) = PeekS(*String, (*StringEnd - *String) / SizeOf(Character))
            ArrayIndex + 1
            If ArrayIndex > nStrings
              nStrings + Resize
              ReDim A$(nStrings)
            EndIf
            *String = *StringEnd + DelimiterLength
          Else
            Break
          EndIf
        ForEver
      EndIf
      ReDim A$(ArrayIndex)
      A$(ArrayIndex) = PeekS(*String)   ; Catch final trailing null's if any.
      ArrayIndex + 1
    EndIf
  EndIf
  ProcedureReturn ArrayIndex
EndProcedure
Procedure.i SF_HasBadChar(s$)
  ; Verify that string does not contain illegal characters, since it will be used for a filename.
  ; such as: /, \, :, *, ?, ", <, >, |    ; Windows 10
  Protected Dim A$(10)
  Protected.i i, ri
  A$(0) = #PS$  ;"\"
  A$(1) = #NPS$ ;"/"
  A$(2) = ":"
  A$(3) = "*"
  A$(4) = "?"
  A$(5) = #DQUOTE$
  A$(6) = "<"
  A$(7) = ">"
  A$(8) = "|"
  For i = 0 To 8
    If FindString(s$, A$(i))
      ri = 1
      Break
    EndIf
  Next i
  ProcedureReturn ri
EndProcedure
Procedure.i FL_CreateFullDirPath(DirPath$)
  ; REV:  100405, skywalk
  ; REV:  180325, skywalk
  ;       Bug in FileSize() for existing path queried with a bad char?
  ;       Allows wildcards in its search: ?,*, including '<','>'.
  ; No recursion.
  ; Windows rejects certain characters within pathname:
  ;   / \ : * ? " < > |
  Protected.i i, k, ri
  CompilerIf 0
    ; Check if path exists?
    If FL_FileExists(DirPath$) = -1
      ProcedureReturn 1
    Else
      ri = CreateDirectory(DirPath$)
      If FL_FileExists(DirPath$) = -1
        ProcedureReturn 1
      EndIf
    EndIf
  CompilerEndIf
  Protected.s TestPath$
  Protected Dim tmppath$(0)
  k = SplitC(@DirPath$, tmppath$(), @OS_PATH_SEP$) ;BUG; PB v573 does not support @#OS_PATH_SEP$
  If k > 1
    TestPath$ = tmppath$(0)
    i = 1   ; Do not allow creation of 1st dir entry, "c:\"
    Repeat
      If SF_HasBadChar(tmppath$(i)) = 0
        TestPath$ = TestPath$ + OS_PATH_SEP$ + tmppath$(i)
        ri = CreateDirectory(TestPath$)
        Delay(5)
        If (ri = 0) And (i = k)
          i = 0
          MRE("Error creating dir structure:" + #CRLF$ + DirPath$ + #CRLF$ + "Verify Write access to drive.")
          Break
        EndIf
        i + 1
      Else
        i = 0
        MRE("Error creating dir structure:" + #CRLF$ + DirPath$ + #CRLF$ + "May contain invalid character.")
        Break
      EndIf
    Until i = k
    ProcedureReturn i
  Else
    ProcedureReturn i
  EndIf
EndProcedure
Debug FL_CreateFullDirPath("c:\try3\z1\z2\z3\z4\z5")
Debug FL_CreateFullDirPath("c:/try3/z1/z2/z3/z4/")
Debug FL_CreateFullDirPath("c:\try3\z\zz\|txt")
;FL_CreateFullDirPath("c:\try3\z\z*z\")
;FL_CreateFullDirPath("c:\try2\try 3\try 4\")
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
BarryG
Addict
Addict
Posts: 3330
Joined: Thu Apr 18, 2019 8:17 am

Re: CreateDirectory() recursively or CreatePath()

Post by BarryG »

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  Global.s OS_PATH_SEP$ = #PS$
CompilerElse
  Global.s OS_PATH_SEP$ = #NPS$
CompilerEndIf
I thought #PS$ was supposed to hold the correct path separator (backslash or forwardslash) depending on the OS being compiled for? Why CompilerIf here?
User avatar
skywalk
Addict
Addict
Posts: 4003
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: CreateDirectory() recursively or CreatePath()

Post by skywalk »

Hmmm, I needed a non constant string variable for @path$. @#PS$ is not allowed.

I don't think the contents of #PS$ change per OS, else there would only be 1 constant. No?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Demivec
Addict
Addict
Posts: 4091
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: CreateDirectory() recursively or CreatePath()

Post by Demivec »

skywalk wrote:Hmmm, I needed a non constant string variable for @path$. @#PS$ is not allowed.

I don't think the contents of #PS$ change per OS, else there would only be 1 constant. No?
Constants like #PB_Compiler_#PB_Compiler_Debugger change so why not one that changes with the OS used?
User avatar
skywalk
Addict
Addict
Posts: 4003
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: CreateDirectory() recursively or CreatePath()

Post by skywalk »

Just a hunch, cause there are not 2 #debugger constants like #PS and #NPS.
Why is there no #PB_OS_PATH_SEP$?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Demivec
Addict
Addict
Posts: 4091
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: CreateDirectory() recursively or CreatePath()

Post by Demivec »

skywalk wrote:Just a hunch, cause there are not 2 #debugger constants like #PS and #NPS.
Why is there no #PB_OS_PATH_SEP$?
I agree the name is a little vague. I'm guessing it was to keep it short and as terse as possible, similar to the #LF$, #CR$, #CRLF$ constants.
BarryG
Addict
Addict
Posts: 3330
Joined: Thu Apr 18, 2019 8:17 am

Re: CreateDirectory() recursively or CreatePath()

Post by BarryG »

skywalk wrote:I don't think the contents of #PS$ change per OS, else there would only be 1 constant. No?
No. That's why #PS$ was introduced, to work on all OSes. It's in the Help:

Code: Select all

Added: #PS, #NPS, #PS$ and #NPS$ constants (Path seperator character depending of the OS)
skywalk wrote:Why is there no #PB_OS_PATH_SEP$?
There is - just what I said above.
User avatar
skywalk
Addict
Addict
Posts: 4003
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: CreateDirectory() recursively or CreatePath()

Post by skywalk »

Dude? You are not explaining why there is #PS$ and #NPS$????
If the compiler changes the value per OS, why the 2 constants?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
collectordave
Addict
Addict
Posts: 1309
Joined: Fri Aug 28, 2015 6:10 pm
Location: Portugal

Re: CreateDirectory() recursively or CreatePath()

Post by collectordave »

#PS$ does change depending on the OS.

I can only assume that #NPS$ is NOT #PS$.

Debugged both on the MAC

Code: Select all

Debug #PS$
Debug #NPS$
and I get

/
\
Any intelligent fool can make things bigger and more complex. It takes a touch of genius — and a lot of courage to move in the opposite direction.
User avatar
Demivec
Addict
Addict
Posts: 4091
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: CreateDirectory() recursively or CreatePath()

Post by Demivec »

A quote from viewtopic.php?f=13&t=72340&p=533252&hil ... er#p533252
NicTheQuick wrote:Consider the following code:

Code: Select all

Debug #PS
Debug #NPS
Debug #PS$
Debug #NPS$
On Linux the result is:

Code: Select all

47
92
/
\
On Windows the result is:

Code: Select all

92
47
\
/
User avatar
skywalk
Addict
Addict
Posts: 4003
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: CreateDirectory() recursively or CreatePath()

Post by skywalk »

Cool, thanks for confirming. Bummer I still need the global string variable for the byref parameter.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
BarryG
Addict
Addict
Posts: 3330
Joined: Thu Apr 18, 2019 8:17 am

Re: CreateDirectory() recursively or CreatePath()

Post by BarryG »

skywalk wrote:Dude? You are not explaining why there is #PS$ and #NPS$????
If the compiler changes the value per OS, why the 2 constants?
I didn't write the manual, so I don't know. All I know is that #PS$ stands for path separator, but I don't know what the N in #NPS$ would mean. The manual doesn't say (as I quoted it).
User avatar
NicTheQuick
Addict
Addict
Posts: 1227
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: CreateDirectory() recursively or CreatePath()

Post by NicTheQuick »

skywalk wrote:This is what I use, and it is not recursive.

Code: Select all

...
The procedure "SF_HasBadChar" is wrong on Linux. On Linux the only character which is not allowed for file names is the forward slash or path separator.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
skywalk
Addict
Addict
Posts: 4003
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: CreateDirectory() recursively or CreatePath()

Post by skywalk »

Yes, that makes sense. I am merely trying to maintain compatibility with Windows transfers between Linux servers.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Post Reply