32 #define IS_File(o) (krk_isInstanceOf(o, fileio_File))
33 #define AS_File(o) ((struct File*)AS_OBJECT(o))
35 #define IS_BinaryFile(o) (krk_isInstanceOf(o, fileio_BinaryFile))
36 #define AS_BinaryFile(o) ((struct File*)AS_OBJECT(o))
47 #define IS_Directory(o) (krk_isInstanceOf(o, fileio_Directory))
48 #define AS_Directory(o) ((struct Directory*)AS_OBJECT(o))
50 #define CURRENT_CTYPE struct File *
51 #define CURRENT_NAME self
54 FUNCTION_TAKES_AT_LEAST(1);
55 FUNCTION_TAKES_AT_MOST(2);
57 if (argc == 2 && !IS_STRING(argv[1]))
return TYPE_ERROR(str,argv[1]);
61 arg = OBJECT_VAL(S(
"r"));
65 if (AS_STRING(argv[1])->length == 0)
return krk_runtimeError(
vm.exceptions->typeError,
"open: mode string must not be empty");
66 for (
size_t i = 0; i < AS_STRING(argv[1])->length-1; ++i) {
67 if (AS_CSTRING(argv[1])[i] ==
'b') {
68 return krk_runtimeError(
vm.exceptions->typeError,
"open: 'b' mode indicator must appear at end of mode string");
72 if (AS_CSTRING(argv[1])[AS_STRING(argv[1])->length-1] ==
'b') {
81 FILE * file = fopen(filename->chars, AS_CSTRING(
krk_peek(0)));
82 if (!file)
return krk_runtimeError(
vm.exceptions->ioError,
"open: failed to open file; system returned: %s", strerror(errno));
92 ((
struct File*)fileObject)->filePtr = file;
96 return OBJECT_VAL(fileObject);
99 #define BLOCK_SIZE 1024
101 KRK_Method(
File,__repr__) {
105 if (!
krk_tableGet(&self->inst.fields, OBJECT_VAL(S(
"filename")), &filename) || !IS_STRING(filename))
return krk_runtimeError(
vm.exceptions->baseException,
"Corrupt File");
106 if (!
krk_tableGet(&self->inst.fields, OBJECT_VAL(S(
"modestr")), &modestr) || !IS_STRING(modestr))
return krk_runtimeError(
vm.exceptions->baseException,
"Corrupt File");
108 return krk_stringFromFormat(
"<%s file '%S', mode '%S' at %p>", self->filePtr ?
"open" :
"closed", AS_STRING(filename), AS_STRING(modestr), (
void*)
self);
111 KRK_Method(
File,readline) {
113 FILE * file =
self->filePtr;
115 if (!file || feof(file)) {
120 size_t spaceAvailable = 0;
121 char * buffer = NULL;
124 if (spaceAvailable < sizeRead + BLOCK_SIZE) {
125 spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
126 buffer = realloc(buffer, spaceAvailable);
129 char * target = &buffer[sizeRead];
130 while (sizeRead < spaceAvailable) {
136 if (c ==
'\n')
goto _finish_line;
140 }
while (!feof(file));
142 _finish_line: (void)0;
151 return OBJECT_VAL(out);
154 KRK_Method(
File,readlines) {
161 if (IS_NONE(line))
break;
173 KRK_Method(
File,read) {
174 METHOD_TAKES_AT_MOST(1);
176 krk_integer_type sizeToRead = -1;
178 CHECK_ARG(1,
int,krk_integer_type,sizeFromArg);
179 if (sizeFromArg < -1)
return krk_runtimeError(
vm.exceptions->valueError,
"size must be >= -1");
180 sizeToRead = sizeFromArg;
184 FILE * file =
self->filePtr;
186 if (!file || feof(file)) {
192 size_t spaceAvailable = 0;
193 char * buffer = NULL;
195 if (sizeToRead == -1) {
197 if (spaceAvailable < sizeRead + BLOCK_SIZE) {
198 spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
199 buffer = realloc(buffer, spaceAvailable);
202 char * target = &buffer[sizeRead];
203 size_t newlyRead = fread(target, 1, BLOCK_SIZE, file);
206 if (newlyRead < BLOCK_SIZE) {
213 sizeRead += newlyRead;
214 }
while (!feof(file));
216 spaceAvailable = sizeToRead;
217 buffer = realloc(buffer, spaceAvailable);
218 sizeRead = fread(buffer, 1, sizeToRead, file);
224 return OBJECT_VAL(out);
227 KRK_Method(
File,write) {
228 METHOD_TAKES_EXACTLY(1);
229 if (!IS_STRING(argv[1]))
return TYPE_ERROR(str,argv[1]);
231 FILE * file =
self->filePtr;
233 if (!file || feof(file)) {
237 return INTEGER_VAL(fwrite(AS_CSTRING(argv[1]), 1, AS_STRING(argv[1])->length, file));
240 KRK_Method(
File,close) {
242 FILE * file =
self->filePtr;
243 if (file) fclose(file);
244 self->filePtr = NULL;
248 KRK_Method(
File,flush) {
250 FILE * file =
self->filePtr;
251 if (file) fflush(file);
255 KRK_Method(
File,__init__) {
256 return krk_runtimeError(
vm.exceptions->typeError,
"File objects can not be instantiated; use fileio.open() to obtain File objects.");
259 KRK_Method(
File,__enter__) {
262 KRK_Method(
File,__exit__) {
263 return FUNC_NAME(
File,close)(1,argv,0);
266 static void makeFileInstance(
KrkInstance * module,
const char name[], FILE * file,
const char mode[]) {
276 ((
struct File*)fileObject)->filePtr = file;
277 ((
struct File*)fileObject)->unowned = 1;
286 KRK_Method(BinaryFile,readline) {
288 FILE * file =
self->filePtr;
290 if (!file || feof(file)) {
295 size_t spaceAvailable = 0;
296 char * buffer = NULL;
299 if (spaceAvailable < sizeRead + BLOCK_SIZE) {
300 spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
301 buffer = realloc(buffer, spaceAvailable);
304 char * target = &buffer[sizeRead];
305 while (sizeRead < spaceAvailable) {
311 if (c ==
'\n')
goto _finish_line;
315 }
while (!feof(file));
317 _finish_line: (void)0;
326 return OBJECT_VAL(out);
329 KRK_Method(BinaryFile,readlines) {
335 KrkValue line = FUNC_NAME(BinaryFile,readline)(1, argv, 0);
336 if (IS_NONE(line))
break;
348 KRK_Method(BinaryFile,read) {
349 METHOD_TAKES_AT_MOST(1);
351 krk_integer_type sizeToRead = -1;
353 CHECK_ARG(1,
int,krk_integer_type,sizeFromArg);
354 if (sizeFromArg < -1)
return krk_runtimeError(
vm.exceptions->valueError,
"size must be >= -1");
355 sizeToRead = sizeFromArg;
359 FILE * file =
self->filePtr;
361 if (!file || feof(file)) {
367 size_t spaceAvailable = 0;
368 char * buffer = NULL;
370 if (sizeToRead == -1) {
372 if (spaceAvailable < sizeRead + BLOCK_SIZE) {
373 spaceAvailable = (spaceAvailable ? spaceAvailable * 2 : (2 * BLOCK_SIZE));
374 buffer = realloc(buffer, spaceAvailable);
377 char * target = &buffer[sizeRead];
378 size_t newlyRead = fread(target, 1, BLOCK_SIZE, file);
382 if (newlyRead < BLOCK_SIZE) {
389 sizeRead += newlyRead;
390 }
while (!feof(file));
392 spaceAvailable = sizeToRead;
393 buffer = realloc(buffer, spaceAvailable);
394 sizeRead = fread(buffer, 1, sizeToRead, file);
400 return OBJECT_VAL(out);
403 KRK_Method(BinaryFile,write) {
404 METHOD_TAKES_EXACTLY(1);
405 if (!IS_BYTES(argv[1]))
return TYPE_ERROR(bytes,argv[1]);
407 FILE * file =
self->filePtr;
409 if (!file || feof(file)) {
413 return INTEGER_VAL(fwrite(AS_BYTES(argv[1])->bytes, 1, AS_BYTES(argv[1])->length, file));
419 struct File * me = (
void *)
self;
420 if (me->filePtr && !me->unowned) {
429 closedir(me->dirPtr);
434 KRK_Function(opendir) {
435 FUNCTION_TAKES_EXACTLY(1);
438 DIR * dir = opendir(path->chars);
439 if (!dir)
return krk_runtimeError(
vm.exceptions->ioError,
"opendir: %s", strerror(errno));
445 dirObj->dirPtr = dir;
450 #define CURRENT_CTYPE struct Directory *
454 if (!self->dirPtr)
return argv[0];
455 struct dirent * entry = readdir(self->dirPtr);
456 if (!entry)
return argv[0];
475 closedir(self->dirPtr);
484 if (!
krk_tableGet(&self->inst.fields, OBJECT_VAL(S(
"path")), &path) || !IS_STRING(path))
487 return krk_stringFromFormat(
"<%s directory '%S' at %p>", self->dirPtr ?
"open" :
"closed", AS_STRING(path), (
void*)
self);
494 return FUNC_NAME(
Directory,close)(1,argv,0);
499 "@brief Provides access to C <stdio> buffered file I/O functions.\n\n"
500 "The @c fileio module provides classes and functions for reading "
501 "and writing files using the system's buffer I/O interfaces, as "
502 "well as classes for listing the contents of directories."
507 KRK_DOC(
File,
"Interface to a buffered file stream.");
508 File->allocSize =
sizeof(
struct File);
509 File->_ongcsweep = _file_sweep;
512 KRK_DOC(BIND_METHOD(
File,read),
"@brief Read from the stream.\n"
513 "@arguments bytes=-1\n\n"
514 "Reads up to @p bytes bytes from the stream. If @p bytes is @c -1 then reading "
515 "will continue until the system returns _end of file_.");
516 KRK_DOC(BIND_METHOD(
File,readline),
"@brief Read one line from the stream.");
517 KRK_DOC(BIND_METHOD(
File,readlines),
"@brief Read the entire stream and return a list of lines.");
518 KRK_DOC(BIND_METHOD(
File,write),
"@brief Write to the stream.\n"
519 "@arguments data\n\n"
520 "Writes the contents of @p data to the stream.");
521 KRK_DOC(BIND_METHOD(
File,close),
"@brief Close the stream and flush any remaining buffered writes.");
522 KRK_DOC(BIND_METHOD(
File,flush),
"@brief Flush unbuffered writes to the stream.");
523 BIND_METHOD(
File,__repr__);
524 KRK_DOC(BIND_METHOD(
File,__init__),
"@bsnote{%File objects can not be initialized using this constructor. "
525 "Use the <a class=\"el\" href=\"#open\">open()</a> function instead.}");
526 BIND_METHOD(
File,__enter__);
527 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.
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.
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.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
void krk_push(KrkValue value)
Push a stack value.
KrkValue krk_peek(int distance)
Peek down from the top of the stack.