Skip to content

feat(core): add more IO extensions (exists?, mkdir, rmdir, cwd)#1518

Open
sqrew wants to merge 3 commits intocarp-lang:masterfrom
sqrew:stdlib-io-extensions
Open

feat(core): add more IO extensions (exists?, mkdir, rmdir, cwd)#1518
sqrew wants to merge 3 commits intocarp-lang:masterfrom
sqrew:stdlib-io-extensions

Conversation

@sqrew
Copy link
Copy Markdown
Contributor

@sqrew sqrew commented Mar 25, 2026

Adds several cross-platform IO extensions to the standard library:

  • IO.file-exists? and IO.dir-exists?
  • IO.create-dir (wraps mkdir)
  • IO.remove-dir (wraps rmdir)
  • IO.get-cwd (wraps getcwd)
  • IO.set-cwd (wraps chdir)

Includes corresponding cross-platform C wrappers in core/carp_io.h and comprehensive tests in test/io.carp.

sqrew added 2 commits March 21, 2026 14:28
…set-cwd)

Adds cross-platform wrappers for mkdir, rmdir, getcwd, and chdir to IO.Raw
and high-level Result-returning versions to the IO module. Also fixes several
typos in existing IO documentation and updates tests to cover new functionality.
#include <direct.h>
#define getcwd _getcwd
#define chdir _chdir
#else
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Windows is not happy with this change quite yet.

@sqrew sqrew force-pushed the stdlib-io-extensions branch from 04d80da to c9fba4a Compare April 2, 2026 19:46
@sqrew
Copy link
Copy Markdown
Contributor Author

sqrew commented Apr 2, 2026

Added cross-platform Windows implementation for list-dir and get-cwd, and fixed the missing headers in carp_io.h. Consolidated tests into test/io.carp. Thanks!

@eriksvedang eriksvedang requested a review from hellerve April 9, 2026 07:34
}
closedir(d);
} else {
result.len = -1;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think returning an array of length -1 is safe or sensible here. We should find a different error condition (also for all the functions on top of this one).

Comment on lines +247 to +252
(doc file-exists? "Checks if a file exists at the given path.")
(register file-exists? (Fn [&String] Bool))

(doc dir-exists? "Checks if a directory exists at the given path.")
(register dir-exists? (Fn [&String] Bool))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those should probably also be in IO.Raw.

(let [res (IO.Raw.get-cwd)]
(if (null? res)
(Result.Error (fmt "Failed to get current working directory: %s" &(System.error-text)))
(let [s (String.from-cstr res)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The C side already returns a String. We should fix the function signature on the C side to avoid a double allocation.

""
"Returns a (Result Bool String) indicating success or failure.")
(defn copy-file [src dest]
(Result.and-then (read-file src)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads the complete file into memory. We should probably do a chunked read-write.

#ifdef _WIN32
return _mkdir(*path);
#else
return mkdir(*path, 0777);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is using 0777 really desirable here?

(doc open-file
"Opens a [FILE](#file) with the given name using a designated mode"
"(e.g. [r]ead, [w]rite, [a]ppend), [rb] read binary...)."
"(e.g. [r]ead, [w]rite, [a]ppend), [rb] read binary...."
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We open a paren here, so we should also close it.

data
&(write-then-read data "io_carp_testdata.txt")
"write-file then read-file" ))
(let [res (write-then-read data "io_carp_testdata.txt")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the let change here? Should be fine without?

"append-file appends to existing file"))))
(do
(IO.Raw.unlink! file-name)
(let [s (Result.unsafe-from-success result)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same let-change here. Why? We also don’t need a do inside a let-do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants