Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions PRIMITIVES.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@ added to them too.
* Return the ASCII character corresponding to the given integer.
* `cons`
* Add the element to the start of the given (potentially empty) list.
* `entries`
* Return the names of all files in the given directory.
* See [test/entries.lisp](test/entries.lisp) for an example
* `environment`
* Return a list of all environmental variables.
* `exit`
Expand Down Expand Up @@ -223,6 +220,9 @@ The implementation of these primitives can be found in the file [stdlib.slisp](s
* Does the given path exist as a directory?
* `even?`
* Return 1 if the given number is even, nil otherwise.
* `entries`
* Return the names of all files in the given directory.
* See [test/entries.lisp](test/entries.lisp) for an example
* `every`
* Does every list item return non-nil when the given function is called?
* `exists?`
Expand Down
37 changes: 37 additions & 0 deletions compiler/template.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2441,6 +2441,43 @@ FUNC fn_sys_strat
TAG_INTEGER_REG rax
ret

;; Allow updating the Nth byte of the given string.
;;
;; This function is dangerous as it has no bound checking, we could add
;; it since we know the size of all allocations made with alloc..
;;
;; For the moment it is a workaround for the fact our strings can't have
;; embedded null-characters - if they do "explode" and "substr" don't work
;; any longer.
;;
;; TODO: Add bound-checking.
;;
FUNC fn_sys_stratBANG
mov rbx, rdi ; type-check arg1
GET_TAG_BITS rbx
cmp rbx, TAG_ID_STRING
jne type_error
mov rbx, rsi ; type-check arg2
GET_TAG_BITS rbx
cmp rbx, TAG_ID_INTEGER
jne type_error

UNTAG_REG rdi
UNTAG_REG rsi
UNTAG_REG rdx

; RDI points to the string, add the RSI/offset to it
add rdi, rsi

; Load and return the character/byte as an integer.
mov byte [rdi], dl
mov rax, rdx
and rax, 0xFF
TAG_INTEGER_REG rax
ret



;; join the two given strings and return a new one.
FUNC fn_sys_strcat
mov rbx, rdi
Expand Down
1 change: 0 additions & 1 deletion inception.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@
(register-builtin "sys_chr" (lambda (args) (sys_chr (car args))))
(register-builtin "sys_cons" (lambda (args) (sys_cons (car args) (cadr args))))
(register-builtin "sys_divide" (lambda (args) (sys_divide (car args) (cadr args))))
(register-builtin "sys_entries" (lambda (args) (sys_entries (car args))))
(register-builtin "sys_and" (lambda (args) (sys_and (car args) (cadr args))))
(register-builtin "sys_environment" (lambda (args) (sys_environment)))
(register-builtin "sys_exit" (lambda (args) (sys_exit (car args))))
Expand Down
78 changes: 74 additions & 4 deletions stdlib.slisp
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@ reap orphaned memory."
"Join A and B into a list"
(sys_cons a b))

(defun entries (str)
"Return the names of all filesystem entries beneath the given directory."
(sys_entries str))

(defun environment ()
"Return a list of all known environmental variables, and their values."
(sys_environment))
Expand Down Expand Up @@ -390,6 +386,80 @@ do the right thing for each entry in the given list."
(if (= 1 (car res))
t))))

(defconst SYS_getdents64 217)

(defconst O_RDONLY 0)
(defconst O_DIRECTORY 65536)

(defun entries (path)
"Return a list of directory entries beneath PATH.
Return nil on failure.

The implementation here is either horrid, or awesome. You decide."

(let ((fd 0)
(size 8192) ; size of the pool we read entries into.
(buf (alloc size)) ; Allocate that pool for the results.
(result nil)
(n 0)
(pos 0))

(set! fd (syscall SYS_open path (+ O_RDONLY O_DIRECTORY) 0))
(if (< fd 0)
nil

(do
;; Read a batch of directory entries.
(set! n (syscall SYS_getdents64 fd buf size))

(while (> n 0)

(set! pos 0)

;; Walk the linux_dirent64 records.
(while (< pos n)

;; offset 16: uint16 d_reclen
;; offset 18: uint8 d_type
;; offset 19: char[] d_name

(let ((reclen (u16 buf (+ pos 16)))
(name-pos (+ pos 19))
(name-len 0))

;; Find the NUL terminator in d_name.
(while (and
(< name-len (- reclen 19))
(not (= (u8 buf (+ name-pos name-len)) 0)))
(set! name-len (+ name-len 1)))

;; Allocate name + terminating NUL to copy the entry's filename into.
(let ((name (alloc (+ name-len 1)))
(i 0))

;; Copy the name byte-by-byte.
(while (< i name-len)
(sys_strat! name i
(u8 buf (+ name-pos i)))
(set! i (+ i 1)))

;; Add the terminating NUL.
(sys_strat! name name-len 0)

;; Add name to the result list.
(set! result (cons name result)))

(set! pos (+ pos reclen))))
(set! n (syscall SYS_getdents64 fd buf size)))

(if (< n 0)
(do
(syscall SYS_close fd)
nil)
(do
(syscall SYS_close fd)
result))))))

(defun exists? (path)
"Does the named path exist?"
(cons? (stat path)))
Expand Down
Loading