From 886ea27d5437a3e66cb43cbf253959e41ac452b0 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 20 Oct 2023 15:29:40 +0200 Subject: [PATCH] Implemented directory walk --- build/Build.go | 36 +++++++++-------- cli/Build.go | 2 +- cli/Help.go | 2 +- cli/System.go | 2 +- cli/cli_test.go | 2 +- directory/Walk.go | 61 +++++++++++++++++++++++++++++ {build/elf => elf}/ELF64.go | 0 {build/elf => elf}/Header.go | 0 {build/elf => elf}/ProgramHeader.go | 0 {build/elf => elf}/SectionHeader.go | 0 {build/elf => elf}/elf.md | 0 errors/InvalidPath.go | 15 +++++++ {cli/log => log}/log.go | 0 13 files changed, 100 insertions(+), 20 deletions(-) create mode 100644 directory/Walk.go rename {build/elf => elf}/ELF64.go (100%) rename {build/elf => elf}/Header.go (100%) rename {build/elf => elf}/ProgramHeader.go (100%) rename {build/elf => elf}/SectionHeader.go (100%) rename {build/elf => elf}/elf.md (100%) create mode 100644 errors/InvalidPath.go rename {cli/log => log}/log.go (100%) diff --git a/build/Build.go b/build/Build.go index c9c6943..368b711 100644 --- a/build/Build.go +++ b/build/Build.go @@ -5,9 +5,12 @@ import ( "bytes" "os" "path/filepath" + "strings" - "git.akyoto.dev/cli/q/build/elf" - "git.akyoto.dev/cli/q/cli/log" + "git.akyoto.dev/cli/q/directory" + "git.akyoto.dev/cli/q/elf" + "git.akyoto.dev/cli/q/errors" + "git.akyoto.dev/cli/q/log" ) // Build describes a compiler build. @@ -43,29 +46,25 @@ func (build *Build) Run() error { return nil } -// Executable returns the path to the executable. -func (build *Build) Executable() string { - return filepath.Join(build.Directory, build.Name) -} - // Compile compiles all the functions. func (build *Build) Compile() error { - file, err := os.Open(build.Directory) + stat, err := os.Stat(build.Directory) if err != nil { return err } - defer file.Close() - files, err := file.Readdirnames(0) - - if err != nil { - return err + if !stat.IsDir() { + return &errors.InvalidDirectory{Path: build.Directory} } - for _, name := range files { - log.Info.Println(name) - } + directory.Walk(build.Directory, func(file string) { + if !strings.HasSuffix(file, ".q") { + return + } + + log.Info.Println(file) + }) build.Code.Write([]byte{ 0xb8, 0x01, 0x00, 0x00, 0x00, // mov eax, 1 @@ -83,6 +82,11 @@ func (build *Build) Compile() error { return nil } +// Executable returns the path to the executable. +func (build *Build) Executable() string { + return filepath.Join(build.Directory, build.Name) +} + // writeToDisk writes the executable file to disk. func writeToDisk(filePath string, code []byte, data []byte) error { file, err := os.Create(filePath) diff --git a/cli/Build.go b/cli/Build.go index b579dbf..7c8eac5 100644 --- a/cli/Build.go +++ b/cli/Build.go @@ -2,7 +2,7 @@ package cli import ( "git.akyoto.dev/cli/q/build" - "git.akyoto.dev/cli/q/cli/log" + "git.akyoto.dev/cli/q/log" ) // Build builds an executable. diff --git a/cli/Help.go b/cli/Help.go index 61ba523..e34dc6c 100644 --- a/cli/Help.go +++ b/cli/Help.go @@ -1,7 +1,7 @@ package cli import ( - "git.akyoto.dev/cli/q/cli/log" + "git.akyoto.dev/cli/q/log" ) // Help shows the command line argument usage. diff --git a/cli/System.go b/cli/System.go index 1b847aa..36fde71 100644 --- a/cli/System.go +++ b/cli/System.go @@ -4,7 +4,7 @@ import ( "os" "runtime" - "git.akyoto.dev/cli/q/cli/log" + "git.akyoto.dev/cli/q/log" ) // System shows system information. diff --git a/cli/cli_test.go b/cli/cli_test.go index c1e5861..111df5d 100644 --- a/cli/cli_test.go +++ b/cli/cli_test.go @@ -6,7 +6,7 @@ import ( "testing" "git.akyoto.dev/cli/q/cli" - "git.akyoto.dev/cli/q/cli/log" + "git.akyoto.dev/cli/q/log" "git.akyoto.dev/go/assert" ) diff --git a/directory/Walk.go b/directory/Walk.go new file mode 100644 index 0000000..5595e3e --- /dev/null +++ b/directory/Walk.go @@ -0,0 +1,61 @@ +package directory + +import ( + "syscall" + "unsafe" +) + +const blockSize = 8 << 10 + +// Walk calls your callback function for every file name inside the directory. +// It doesn't distinguish between files and directories. +func Walk(directory string, callBack func(string)) { + fd, err := syscall.Open(directory, 0, 0) + + if err != nil { + panic(err) + } + + defer syscall.Close(fd) + buffer := make([]byte, blockSize) + + for { + n, err := syscall.ReadDirent(fd, buffer) + + if err != nil { + panic(err) + } + + if n <= 0 { + break + } + + readBuffer := buffer[:n] + + for len(readBuffer) > 0 { + dirent := (*syscall.Dirent)(unsafe.Pointer(&readBuffer[0])) + readBuffer = readBuffer[dirent.Reclen:] + + // Skip deleted files + if dirent.Ino == 0 { + continue + } + + // Skip hidden files + if dirent.Name[0] == '.' { + continue + } + + for i, c := range dirent.Name { + if c != 0 { + continue + } + + bytePointer := (*byte)(unsafe.Pointer(&dirent.Name[0])) + name := unsafe.String(bytePointer, i) + callBack(name) + break + } + } + } +} diff --git a/build/elf/ELF64.go b/elf/ELF64.go similarity index 100% rename from build/elf/ELF64.go rename to elf/ELF64.go diff --git a/build/elf/Header.go b/elf/Header.go similarity index 100% rename from build/elf/Header.go rename to elf/Header.go diff --git a/build/elf/ProgramHeader.go b/elf/ProgramHeader.go similarity index 100% rename from build/elf/ProgramHeader.go rename to elf/ProgramHeader.go diff --git a/build/elf/SectionHeader.go b/elf/SectionHeader.go similarity index 100% rename from build/elf/SectionHeader.go rename to elf/SectionHeader.go diff --git a/build/elf/elf.md b/elf/elf.md similarity index 100% rename from build/elf/elf.md rename to elf/elf.md diff --git a/errors/InvalidPath.go b/errors/InvalidPath.go new file mode 100644 index 0000000..0b71fcf --- /dev/null +++ b/errors/InvalidPath.go @@ -0,0 +1,15 @@ +package errors + +import "fmt" + +type InvalidDirectory struct { + Path string +} + +func (err *InvalidDirectory) Error() string { + if err.Path == "" { + return "Invalid directory" + } + + return fmt.Sprintf("Invalid directory '%s'", err.Path) +} diff --git a/cli/log/log.go b/log/log.go similarity index 100% rename from cli/log/log.go rename to log/log.go