| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | #include "master.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | namespace factor { | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | /* Simple wrappers for ANSI C I/O functions, used for bootstrapping.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Note the ugly loop logic in almost every function; we have to handle EINTR | 
					
						
							|  |  |  | and restart the operation if the system call was interrupted. Naive | 
					
						
							|  |  |  | applications don't do this, but then they quickly fail if one enables | 
					
						
							|  |  |  | itimer()s or other signals. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The Factor library provides platform-specific code for Unix and Windows | 
					
						
							|  |  |  | with many more capabilities so these words are not usually used in | 
					
						
							|  |  |  | normal operation. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::init_c_io() { | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |   special_objects[OBJ_STDIN] = allot_alien(false_object, (cell)stdin); | 
					
						
							|  |  |  |   special_objects[OBJ_STDOUT] = allot_alien(false_object, (cell)stdout); | 
					
						
							|  |  |  |   special_objects[OBJ_STDERR] = allot_alien(false_object, (cell)stderr); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 04:12:45 -05:00
										 |  |  | /* Allocates memory */ | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::io_error() { | 
					
						
							|  |  |  |   if (errno == EINTR) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   general_error(ERROR_IO, tag_fixnum(errno), false_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FILE* factor_vm::safe_fopen(char* filename, char* mode) { | 
					
						
							|  |  |  |   FILE* file; | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     file = fopen(filename, mode); | 
					
						
							|  |  |  |     if (file == NULL) | 
					
						
							|  |  |  |       io_error(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return file; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int factor_vm::safe_fgetc(FILE* stream) { | 
					
						
							|  |  |  |   int c; | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     c = getc(stream); | 
					
						
							|  |  |  |     if (c == EOF) { | 
					
						
							|  |  |  |       if (feof(stream)) | 
					
						
							|  |  |  |         return EOF; | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         io_error(); | 
					
						
							|  |  |  |     } else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t factor_vm::safe_fread(void* ptr, size_t size, size_t nitems, | 
					
						
							|  |  |  |                              FILE* stream) { | 
					
						
							|  |  |  |   size_t items_read = 0; | 
					
						
							|  |  |  |   size_t ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   do { | 
					
						
							|  |  |  |     ret = fread((void*)((int*)ptr + items_read * size), size, | 
					
						
							|  |  |  |                 nitems - items_read, stream); | 
					
						
							|  |  |  |     if (ret == 0) { | 
					
						
							|  |  |  |       if (feof(stream)) | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         io_error(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     items_read += ret; | 
					
						
							|  |  |  |   } while (items_read != nitems); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return items_read; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::safe_fputc(int c, FILE* stream) { | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     if (putc(c, stream) == EOF) | 
					
						
							|  |  |  |       io_error(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t factor_vm::safe_fwrite(void* ptr, size_t size, size_t nitems, | 
					
						
							|  |  |  |                               FILE* stream) { | 
					
						
							|  |  |  |   size_t items_written = 0; | 
					
						
							|  |  |  |   size_t ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   do { | 
					
						
							|  |  |  |     ret = fwrite((void*)((int*)ptr + items_written * size), size, | 
					
						
							|  |  |  |                  nitems - items_written, stream); | 
					
						
							|  |  |  |     if (ret == 0) | 
					
						
							|  |  |  |       io_error(); | 
					
						
							|  |  |  |     items_written += ret; | 
					
						
							|  |  |  |   } while (items_written != nitems); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return items_written; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int factor_vm::safe_ftell(FILE* stream) { | 
					
						
							|  |  |  |   off_t offset; | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     if ((offset = FTELL(stream)) == -1) | 
					
						
							|  |  |  |       io_error(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return offset; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::safe_fseek(FILE* stream, off_t offset, int whence) { | 
					
						
							|  |  |  |   switch (whence) { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |       whence = SEEK_SET; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							|  |  |  |       whence = SEEK_CUR; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 2: | 
					
						
							|  |  |  |       whence = SEEK_END; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       critical_error("Bad value for whence", whence); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     if (FSEEK(stream, offset, whence) == -1) | 
					
						
							|  |  |  |       io_error(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::safe_fflush(FILE* stream) { | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     if (fflush(stream) == EOF) | 
					
						
							|  |  |  |       io_error(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::safe_fclose(FILE* stream) { | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     if (fclose(stream) == EOF) | 
					
						
							|  |  |  |       io_error(); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::primitive_fopen() { | 
					
						
							|  |  |  |   data_root<byte_array> mode(ctx->pop(), this); | 
					
						
							|  |  |  |   data_root<byte_array> path(ctx->pop(), this); | 
					
						
							|  |  |  |   mode.untag_check(this); | 
					
						
							|  |  |  |   path.untag_check(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   FILE* file; | 
					
						
							|  |  |  |   file = safe_fopen((char*)(path.untagged() + 1), (char*)(mode.untagged() + 1)); | 
					
						
							|  |  |  |   ctx->push(allot_alien(file)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FILE* factor_vm::pop_file_handle() { return (FILE*)alien_offset(ctx->pop()); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FILE* factor_vm::peek_file_handle() { return (FILE*)alien_offset(ctx->peek()); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::primitive_fgetc() { | 
					
						
							|  |  |  |   FILE* file = peek_file_handle(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int c = safe_fgetc(file); | 
					
						
							|  |  |  |   if (c == EOF && feof(file)) { | 
					
						
							|  |  |  |     clearerr(file); | 
					
						
							|  |  |  |     ctx->replace(false_object); | 
					
						
							|  |  |  |   } else | 
					
						
							|  |  |  |     ctx->replace(tag_fixnum(c)); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 04:12:45 -05:00
										 |  |  | /* Allocates memory (from_unsigned_cell())*/ | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::primitive_fread() { | 
					
						
							|  |  |  |   FILE* file = pop_file_handle(); | 
					
						
							|  |  |  |   void* buf = (void*)alien_offset(ctx->pop()); | 
					
						
							| 
									
										
										
										
											2014-07-08 01:34:36 -04:00
										 |  |  |   cell size = unbox_array_size(); | 
					
						
							| 
									
										
										
										
											2013-03-22 12:17:02 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   if (size == 0) { | 
					
						
							|  |  |  |     ctx->push(from_unsigned_cell(0)); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   size_t c = safe_fread(buf, 1, size, file); | 
					
						
							|  |  |  |   if (c == 0 || feof(file)) | 
					
						
							|  |  |  |     clearerr(file); | 
					
						
							|  |  |  |   ctx->push(from_unsigned_cell(c)); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::primitive_fputc() { | 
					
						
							|  |  |  |   FILE* file = pop_file_handle(); | 
					
						
							|  |  |  |   fixnum ch = to_fixnum(ctx->pop()); | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |   safe_fputc((int)ch, file); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::primitive_fwrite() { | 
					
						
							|  |  |  |   FILE* file = pop_file_handle(); | 
					
						
							|  |  |  |   cell length = to_cell(ctx->pop()); | 
					
						
							|  |  |  |   char* text = alien_offset(ctx->pop()); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   if (length == 0) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   size_t written = safe_fwrite(text, 1, length, file); | 
					
						
							|  |  |  |   if (written != length) | 
					
						
							|  |  |  |     io_error(); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::primitive_ftell() { | 
					
						
							|  |  |  |   FILE* file = peek_file_handle(); | 
					
						
							|  |  |  |   ctx->replace(from_signed_8(safe_ftell(file))); | 
					
						
							| 
									
										
										
										
											2009-10-03 19:20:35 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::primitive_fseek() { | 
					
						
							|  |  |  |   FILE* file = pop_file_handle(); | 
					
						
							| 
									
										
										
										
											2013-05-13 00:53:47 -04:00
										 |  |  |   int whence = (int)to_fixnum(ctx->pop()); | 
					
						
							|  |  |  |   off_t offset = (off_t)to_signed_8(ctx->pop()); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   safe_fseek(file, offset, whence); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::primitive_fflush() { | 
					
						
							|  |  |  |   FILE* file = pop_file_handle(); | 
					
						
							|  |  |  |   safe_fflush(file); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | void factor_vm::primitive_fclose() { | 
					
						
							|  |  |  |   FILE* file = pop_file_handle(); | 
					
						
							|  |  |  |   safe_fclose(file); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This function is used by FFI I/O. Accessing the errno global directly is
 | 
					
						
							|  |  |  | not portable, since on some libc's errno is not a global but a funky macro that | 
					
						
							|  |  |  | reads thread-local storage. */ | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | VM_C_API int err_no() { return errno; } | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | VM_C_API void set_err_no(int err) { errno = err; } | 
					
						
							| 
									
										
										
										
											2009-05-04 02:46:13 -04:00
										 |  |  | } |