27 #define IS_File(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(File)))
28 #define AS_File(o) ((struct File*)AS_OBJECT(o))
30 #define IS_BinaryFile(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(BinaryFile)))
31 #define AS_BinaryFile(o) ((struct File*)AS_OBJECT(o))
42 #define IS_Directory(o) (krk_isInstanceOf(o, KRK_BASE_CLASS(Directory)))
43 #define AS_Directory(o) ((struct Directory*)AS_OBJECT(o))
45 #define CURRENT_CTYPE struct File *
46 #define CURRENT_NAME self
49 FUNCTION_TAKES_AT_LEAST(1);
50 FUNCTION_TAKES_AT_MOST(2);
52 if (argc == 2 && !IS_STRING(argv[1]))
return TYPE_ERROR(str,argv[1]);
56 arg = OBJECT_VAL(S(
"r"));
60 if (AS_STRING(argv[1])->length == 0)
return krk_runtimeError(
vm.exceptions->typeError,
"open: mode string must not be empty");
61 for (
size_t i = 0; i < AS_STRING(argv[1])->length-1; ++i) {
62 if (AS_CSTRING(argv[1])[i] ==
'b') {
63 return krk_runtimeError(
vm.exceptions->typeError,
"open: 'b' mode indicator must appear at end of mode string");
67 if (AS_CSTRING(argv[1])[AS_STRING(argv[1])->length-1] ==
'b') {
76 FILE * file = fopen(filename->chars, AS_CSTRING(
krk_peek(0)));
77 if (!file)
return krk_runtimeError(
vm.exceptions->ioError,
"open: failed to open file; system returned: %s", strerror(errno));
87 ((
struct File*)fileObject)->filePtr = file;
91 return OBJECT_VAL(fileObject);
94 #define BLOCK_SIZE 1024
96 KRK_Method(
File,__str__) {
100 if (!
krk_tableGet(&self->inst.fields, OBJECT_VAL(S(
"filename")), &filename) || !IS_STRING(filename))
return krk_runtimeError(
vm.exceptions->baseException,
"Corrupt File");
101 if (!
krk_tableGet(&self->inst.fields, OBJECT_VAL(S(
"modestr")), &modestr) || !IS_STRING(modestr))
return krk_runtimeError(
vm.exceptions->baseException,
"Corrupt File");
103 return krk_stringFromFormat(
"<%s file '%S', mode '%S' at %p>", self->filePtr ?
"open" :
"closed", AS_STRING(filename), AS_STRING(modestr), (
void*)
self);
106 KRK_Method(
File,readline) {
108 FILE * file =
self->filePtr;
110 if (!file || feof(file)) {
115 size_t spaceAvailable = 0;
116 char * buffer = NULL;
119 if (spaceAvailable < sizeRead + BLOCK_SIZE) {
120 spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
121 buffer = realloc(buffer, spaceAvailable);
124 char * target = &buffer[sizeRead];
125 while (sizeRead < spaceAvailable) {
131 if (c ==
'\n')
goto _finish_line;
135 }
while (!feof(file));
137 _finish_line: (void)0;
146 return OBJECT_VAL(out);
149 KRK_Method(
File,readlines) {
156 if (IS_NONE(line))
break;
168 KRK_Method(
File,read) {
169 METHOD_TAKES_AT_MOST(1);
171 krk_integer_type sizeToRead = -1;
173 CHECK_ARG(1,
int,krk_integer_type,sizeFromArg);
174 if (sizeFromArg < -1)
return krk_runtimeError(
vm.exceptions->valueError,
"size must be >= -1");
175 sizeToRead = sizeFromArg;
179 FILE * file =
self->filePtr;
181 if (!file || feof(file)) {
187 size_t spaceAvailable = 0;
188 char * buffer = NULL;
190 if (sizeToRead == -1) {
192 if (spaceAvailable < sizeRead + BLOCK_SIZE) {
193 spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
194 buffer = realloc(buffer, spaceAvailable);
197 char * target = &buffer[sizeRead];
198 size_t newlyRead = fread(target, 1, BLOCK_SIZE, file);
201 if (newlyRead < BLOCK_SIZE) {
208 sizeRead += newlyRead;
209 }
while (!feof(file));
211 spaceAvailable = sizeToRead;
212 buffer = realloc(buffer, spaceAvailable);
213 sizeRead = fread(buffer, 1, sizeToRead, file);
219 return OBJECT_VAL(out);
222 KRK_Method(
File,write) {
223 METHOD_TAKES_EXACTLY(1);
224 if (!IS_STRING(argv[1]))
return TYPE_ERROR(str,argv[1]);
226 FILE * file =
self->filePtr;
228 if (!file || feof(file)) {
232 return INTEGER_VAL(fwrite(AS_CSTRING(argv[1]), 1, AS_STRING(argv[1])->length, file));
235 KRK_Method(
File,close) {
237 FILE * file =
self->filePtr;
238 if (file) fclose(file);
239 self->filePtr = NULL;
243 KRK_Method(
File,flush) {
245 FILE * file =
self->filePtr;
246 if (file) fflush(file);
250 KRK_Method(
File,__init__) {
251 return krk_runtimeError(
vm.exceptions->typeError,
"File objects can not be instantiated; use fileio.open() to obtain File objects.");
254 KRK_Method(
File,__enter__) {
257 KRK_Method(
File,__exit__) {
258 return FUNC_NAME(
File,close)(1,argv,0);
261 static void makeFileInstance(
KrkInstance * module,
const char name[], FILE * file,
const char mode[]) {
271 ((
struct File*)fileObject)->filePtr = file;
272 ((
struct File*)fileObject)->unowned = 1;
281 KRK_Method(BinaryFile,readline) {
283 FILE * file =
self->filePtr;
285 if (!file || feof(file)) {
290 size_t spaceAvailable = 0;
291 char * buffer = NULL;
294 if (spaceAvailable < sizeRead + BLOCK_SIZE) {
295 spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
296 buffer = realloc(buffer, spaceAvailable);
299 char * target = &buffer[sizeRead];
300 while (sizeRead < spaceAvailable) {
306 if (c ==
'\n')
goto _finish_line;
310 }
while (!feof(file));
312 _finish_line: (void)0;
321 return OBJECT_VAL(out);
324 KRK_Method(BinaryFile,readlines) {
330 KrkValue line = FUNC_NAME(BinaryFile,readline)(1, argv, 0);
331 if (IS_NONE(line))
break;
343 KRK_Method(BinaryFile,read) {
344 METHOD_TAKES_AT_MOST(1);
346 krk_integer_type sizeToRead = -1;
348 CHECK_ARG(1,
int,krk_integer_type,sizeFromArg);
349 if (sizeFromArg < -1)
return krk_runtimeError(
vm.exceptions->valueError,
"size must be >= -1");
350 sizeToRead = sizeFromArg;
354 FILE * file =
self->filePtr;
356 if (!file || feof(file)) {
362 size_t spaceAvailable = 0;
363 char * buffer = NULL;
365 if (sizeToRead == -1) {
367 if (spaceAvailable < sizeRead + BLOCK_SIZE) {
368 spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
369 buffer = realloc(buffer, spaceAvailable);
372 char * target = &buffer[sizeRead];
373 size_t newlyRead = fread(target, 1, BLOCK_SIZE, file);
377 if (newlyRead < BLOCK_SIZE) {
384 sizeRead += newlyRead;
385 }
while (!feof(file));
387 spaceAvailable = sizeToRead;
388 buffer = realloc(buffer, spaceAvailable);
389 sizeRead = fread(buffer, 1, sizeToRead, file);
395 return OBJECT_VAL(out);
398 KRK_Method(BinaryFile,write) {
399 METHOD_TAKES_EXACTLY(1);
400 if (!IS_BYTES(argv[1]))
return TYPE_ERROR(bytes,argv[1]);
402 FILE * file =
self->filePtr;
404 if (!file || feof(file)) {
408 return INTEGER_VAL(fwrite(AS_BYTES(argv[1])->bytes, 1, AS_BYTES(argv[1])->length, file));
414 struct File * me = (
void *)
self;
415 if (me->filePtr && !me->unowned) {
424 closedir(me->dirPtr);
429 KRK_Function(opendir) {
430 FUNCTION_TAKES_EXACTLY(1);
433 DIR * dir = opendir(path->chars);
434 if (!dir)
return krk_runtimeError(
vm.exceptions->ioError,
"opendir: %s", strerror(errno));
440 dirObj->dirPtr = dir;
445 #define CURRENT_CTYPE struct Directory *
449 if (!self->dirPtr)
return argv[0];
450 struct dirent * entry = readdir(self->dirPtr);
451 if (!entry)
return argv[0];
470 closedir(self->dirPtr);
479 if (!
krk_tableGet(&self->inst.fields, OBJECT_VAL(S(
"path")), &path) || !IS_STRING(path))
482 return krk_stringFromFormat(
"<%s directory '%S' at %p>", self->dirPtr ?
"open" :
"closed", AS_STRING(path), (
void*)
self);
489 return FUNC_NAME(
Directory,close)(1,argv,0);
498 "@brief Provides access to C <stdio> buffered file I/O functions.\n\n"
499 "The @c fileio module provides classes and functions for reading "
500 "and writing files using the system's buffer I/O interfaces, as "
501 "well as classes for listing the contents of directories."
506 KRK_DOC(
File,
"Interface to a buffered file stream.");
507 File->allocSize =
sizeof(
struct File);
508 File->_ongcsweep = _file_sweep;
511 KRK_DOC(BIND_METHOD(
File,read),
"@brief Read from the stream.\n"
512 "@arguments bytes=-1\n\n"
513 "Reads up to @p bytes bytes from the stream. If @p bytes is @c -1 then reading "
514 "will continue until the system returns _end of file_.");
515 KRK_DOC(BIND_METHOD(
File,readline),
"@brief Read one line from the stream.");
516 KRK_DOC(BIND_METHOD(
File,readlines),
"@brief Read the entire stream and return a list of lines.");
517 KRK_DOC(BIND_METHOD(
File,write),
"@brief Write to the stream.\n"
518 "@arguments data\n\n"
519 "Writes the contents of @p data to the stream.");
520 KRK_DOC(BIND_METHOD(
File,close),
"@brief Close the stream and flush any remaining buffered writes.");
521 KRK_DOC(BIND_METHOD(
File,flush),
"@brief Flush unbuffered writes to the stream.");
522 BIND_METHOD(
File,__str__);
523 KRK_DOC(BIND_METHOD(
File,__init__),
"@bsnote{%File objects can not be initialized using this constructor. "
524 "Use the <a class=\"el\" href=\"#open\">open()</a> function instead.}");
525 BIND_METHOD(
File,__enter__);
526 BIND_METHOD(
File,__exit__);
532 "Equivalent to @ref File but using @ref bytes instead of string @ref str."
534 BIND_METHOD(BinaryFile,read);
535 BIND_METHOD(BinaryFile,readline);
536 BIND_METHOD(BinaryFile,readlines);
537 BIND_METHOD(BinaryFile,write);
542 "Represents an opened file system directory."
547 KRK_DOC(BIND_METHOD(
Directory,__iter__),
"@brief Iterates over the contents of the directory.\n\n"
548 "Each iteration returns @ref dict with two entries: <i>\"name\"</i> and <i>\"inode\"</i>.");
549 KRK_DOC(BIND_METHOD(
Directory,__call__),
"@brief Yields one iteration through the directory.");
551 KRK_DOC(BIND_METHOD(
Directory,__exit__),
"@brief Closes the directory upon exit from a @c with block.");
552 KRK_DOC(BIND_METHOD(
Directory,close),
"@brief Close the directory.\n\nFurther reads can not be made after the directory has been closed.");
556 makeFileInstance(module,
"stdin", stdin,
"r");
557 makeFileInstance(module,
"stdout", stdout,
"w");
558 makeFileInstance(module,
"stderr", stderr,
"w");
561 KRK_DOC(BIND_FUNC(module,open),
"@brief Open a file.\n"
562 "@arguments path,mode=\"r\"\n\n"
563 "Opens @p path using the modestring @p mode. Supported modestring characters depend on the system implementation. "
564 "If the last character of @p mode is @c 'b' a @ref BinaryFile will be returned. If the file could not be opened, "
565 "an @ref IOError will be raised.");
566 KRK_DOC(BIND_FUNC(module,opendir),
"@brief Open a directory for scanning.\n"
567 "@arguments path\n\n"
568 "Opens the directory at @p path and returns a @ref Directory object. If @p path could not be opened or is not "
569 "a directory, @ref IOError will be raised.");
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
void krk_module_init_fileio(void)
Initialize the built-in 'fileio' module.
Functions for dealing with garbage collection and memory allocation.
Struct definitions for core object types.
OBject for a C DIR* stream.
Object for a C FILE* stream.
Immutable sequence of bytes.
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
KrkClass * krk_makeClass(KrkInstance *module, KrkClass **_class, const char *name, KrkClass *base)
Convenience function for creating new types.
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw)
Create a dict object.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
KrkTable fields
Attributes table.
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
The most basic object type.
Immutable sequence of Unicode codepoints.
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
KrkNative * krk_defineNative(KrkTable *table, const char *name, NativeFn function)
Attach a native C function to an attribute table.
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Stack reference or primative value.
Utilities for creating native bindings.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
void krk_push(KrkValue value)
Push a stack value.
KrkValue krk_peek(int distance)
Peek down from the top of the stack.