FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour lMkDir() doubt
Posts: 253
Joined: Wed May 25, 2016 01:04 AM
Re: lMkDir() doubt
Posted: Sun Jun 15, 2025 12:31 AM
Otto wrote: Hi,
The recurring problem with lMkDir() – that it doesn't support recursive directory creation – has cost many of us time and nerves over the years, especially when trying to dynamically create paths with multiple intermediate folders.

Perhaps we could even maintain a small `x_compat.prg` library together – for commonly used functions such as:

StrTokenize()
DirSepDel()
FileOrDirExists()
MkDirRecursive()

Please test and improve.

Best regards,
Otto
#include "fivewin.ch"

/*
This is a complete, xHarbour-compatible recursive MkDirRecursive() function,
without any hb_ dependencies. It includes the helper functions DirSepDel() and DirSepToOS().

Recommended: maintain a shared hbcompat.prg utility library for frequently used functions like:

- StrTokenize()
- DirSepDel()
- FileOrDirExists()
- MkDirRecursive()
*/

func main

MkDirRecursive( "c:\SISTEMAS\SCANDOC\EMPRESA01\202505" )

return

FUNCTION MkDirRecursive( cPath )
   LOCAL aParts := {}
   LOCAL cPart := ""
   LOCAL i, cSep, cCurrent := ""

   // Normalize the path
   cPath := DirSepToOS( DirSepDel( cPath ) )
   cSep := IF( "WINDOWS" $ Upper( OS() ), "\", "/" )

   // Split path into parts
   aParts := StrTokenize( cPath, cSep )
    
   // Handle absolute paths like "C:"
   IF ":" $ aParts[1]
      cCurrent := aParts[1] + cSep
      i := 2
   ELSE
      cCurrent := aParts[1]
      i := 2
   ENDIF

   FOR i := i TO Len( aParts )
      cPart := aParts[i]
      IF !Empty( cPart )
         cCurrent += cPart
         IF !FileOrDirExists( cCurrent )
            MakeDir( cCurrent )
         ENDIF
      ENDIF
      cCurrent += cSep
   NEXT

RETURN .T.

FUNCTION IsWindows()
   RETURN Upper( OS() ) $ "WINDOWS"

FUNCTION DirSepDel( cPath )
   IF !Empty( cPath ) .AND. Right( cPath, 1 ) $ [ "\", "/" ]
      RETURN Left( cPath, Len( cPath ) - 1 )
   ENDIF
   RETURN cPath

FUNCTION DirSepToOS( cPath )
   LOCAL cSep := IF( OS() == "WINDOWS", "\", "/" )
   RETURN StrTran( cPath, "/", cSep )

FUNCTION StrTokenize( cString, cDelim )
   LOCAL aResult := {}, nPos := 1, nAt := 0

   DO WHILE .T.
      nAt := At( cDelim, SubStr( cString, nPos ) )
      IF nAt == 0
         AAdd( aResult, SubStr( cString, nPos ) )
         EXIT
      ENDIF
      AAdd( aResult, SubStr( cString, nPos, nAt - 1 ) )
      nPos += nAt
   ENDDO

RETURN aResult

FUNCTION FileOrDirExists( cPath )
   LOCAL h

   IF lIsDir( cPath )
      RETURN .T.
   ENDIF

   h := FOpen( cPath )
   IF h != -1
      FClose( h )
      RETURN .T.
   ENDIF

RETURN .F.
Thank You, I will try!
Posts: 253
Joined: Wed May 25, 2016 01:04 AM
Re: lMkDir() doubt
Posted: Sun Jun 15, 2025 12:34 AM
hua wrote: I use SHCreateDirectory(). Require to link in \bcc77\lib\psdk\shell32.lib for BCC.
It was something the late Rao introduced me to
* Create nested directory at one go
#pragma BEGINDUMP

#include <shlobj.h>
#include <hbapi.h>

HB_FUNC (SHCREATEDIRECTORY)
{
hb_retni( SHCreateDirectoryEx( NULL, hb_parc( 1 ), NULL ) );
}
Great Hua, thank You!
Posts: 1283
Joined: Fri Feb 10, 2006 02:34 PM
Re: lMkDir() doubt
Posted: Sun Jun 15, 2025 06:25 PM

Hi

? HB_DirBuild( <cDir> )

C.

Salutacions, saludos, regards

"...programar es fácil, hacer programas es difícil..."

UT Page -> https://carles9000.github.io/
Forum UT -> https://discord.gg/bq8a9yGMWh
HIX -> https://github.com/carles9000/hix
Posts: 1710
Joined: Tue Oct 28, 2008 06:26 PM
Re: lMkDir() doubt
Posted: Mon Jun 16, 2025 02:11 PM
Carles wrote: Hi

? HB_DirBuild( <cDir> )

C.
Muchas gracias Carles.
Excelente Función
Saludos,



Adhemar C.
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: lMkDir() doubt
Posted: Mon Jun 16, 2025 02:28 PM
// C:\FWH\SAMPLES\HBBUILD.PRG

/*
This example assumes that C:\TEST exists and uses HB_DirBuild()
twice to create a nested subdirectory under it:

Este ejemplo asume que C:\TEST existe y utiliza HB_DirBuild() dos veces para
crear un subdirectorio anidado debajo de él:
*/

#include "FiveWin.ch"

FUNCTION Main() // Only HARBOUR

   LOCAL nResult

   hb_DirBuild( "c:\test\one" )    // Create top-most one

   nResult := hb_DirBuild( "c:\test\one\two" )

   IF( .NOT. nResult ) // .F.

      ? "Cannot make directory, DOS error: ", nResult

      QUIT

   ENDIF

RETURN NIL

/*
También puedes usar algo como esto:

HB_DirBuild( ".\test" )
*/
Regards, saludos.
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: lMkDir() doubt
Posted: Mon Jun 16, 2025 03:14 PM
// C:\FWH\SAMPLES\HBBUILD2.PRG - HARBOUR / XHARBOUR

// The example demonstrates how to create nested sub-directories
// in the current directory

#include "FiveWin.ch"

FUNCTION Main()

      LOCAL i, j, aSubDir, cSubDir, nError
      LOCAL aNewDir := { ;
                         "Pagtos\salarios",    ;
                         "Pagtos\Compras",     ;
                         "Clientes\marketing", ;
                         "Clientes\ordenes",   ;
                         "Clientes\suporte" }

      FOR i := 1 TO LEN( aNewDir )

         cSubDir := CurDrive()+ ":\" + CurDir() + "\"
         aSubDir := HB_ATokens( aNewDir[i], "\" )

         FOR j:=1 TO Len( aSubDir )

            cSubDir += aSubDir[j] + "\"

            nError := MakeDir( cSubDir )

            IF nError == 0

               ? "Directory", cSubDir, "successfully created"

            ELSEIF nError == 5

               ? "Directory", cSubDir, "exists already"

            ELSE

               ? "Error for", cSubDir, LTrim( Str( nError ) )

            ENDIF

         NEXT j

      NEXT i

RETURN NIL

// FIN / END
Regards, saludos.
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341

Continue the discussion