| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 10:26:04 -04:00
										 |  |  | // Simple wrappers for ANSI C I/O functions, used for bootstrapping.
 | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 10:26:04 -04:00
										 |  |  | // 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.
 | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 10:26:04 -04:00
										 |  |  | // 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.
 | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 20:11:28 -04:00
										 |  |  | size_t raw_fread(void* ptr, size_t size, size_t nitems, FILE* stream) { | 
					
						
							|  |  |  |   FACTOR_ASSERT(nitems > 0); | 
					
						
							| 
									
										
										
										
											2015-05-29 20:29:57 -04:00
										 |  |  |   size_t items_read = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   do { | 
					
						
							| 
									
										
										
										
											2015-05-31 18:21:32 -04:00
										 |  |  |     size_t ret = fread((void*)((int*)ptr + items_read * size), size, | 
					
						
							|  |  |  |                        nitems - items_read, stream); | 
					
						
							| 
									
										
										
										
											2015-05-29 20:29:57 -04:00
										 |  |  |     if (ret == 0) { | 
					
						
							| 
									
										
										
										
											2015-05-31 18:21:32 -04:00
										 |  |  |       if (feof(stream)) { | 
					
						
							| 
									
										
										
										
											2015-05-29 20:29:57 -04:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2015-05-31 18:21:32 -04:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-05-29 20:29:57 -04:00
										 |  |  |       else if (errno != EINTR) { | 
					
						
							| 
									
										
										
										
											2015-06-04 20:11:28 -04:00
										 |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2015-05-29 20:29:57 -04:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     items_read += ret; | 
					
						
							|  |  |  |   } while (items_read != nitems); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return items_read; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 08:44:37 -04:00
										 |  |  | // Call fclose() once only. Issues #1335, #908.
 | 
					
						
							| 
									
										
										
										
											2015-05-29 20:29:57 -04:00
										 |  |  | int raw_fclose(FILE* stream) { | 
					
						
							|  |  |  |   if (fclose(stream) == EOF && errno != EINTR) | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 10:26:04 -04:00
										 |  |  | // Allocates memory
 | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  | void factor_vm::io_error_if_not_EINTR() { | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   if (errno == EINTR) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   general_error(ERROR_IO, tag_fixnum(errno), false_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-29 17:08:45 -04:00
										 |  |  | FILE* factor_vm::safe_fopen(char* filename, const char* mode) { | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   FILE* file; | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     file = fopen(filename, mode); | 
					
						
							|  |  |  |     if (file == NULL) | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  |       io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  |         io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |     } else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 20:11:28 -04:00
										 |  |  | size_t factor_vm::safe_fread(void* ptr, size_t size, size_t nitems, | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |                              FILE* stream) { | 
					
						
							| 
									
										
										
										
											2015-06-04 20:11:28 -04:00
										 |  |  |   size_t ret = raw_fread(ptr, size, nitems, stream); | 
					
						
							|  |  |  |   if (ret == 0 && !feof(stream)) | 
					
						
							| 
									
										
										
										
											2015-05-29 20:29:57 -04:00
										 |  |  |     io_error_if_not_EINTR(); | 
					
						
							|  |  |  |   return ret; | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::safe_fputc(int c, FILE* stream) { | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     if (putc(c, stream) == EOF) | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  |       io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  |       io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  |       io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |     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: | 
					
						
							| 
									
										
										
										
											2017-06-24 19:43:31 -04:00
										 |  |  |       general_error(ERROR_IO, tag_fixnum(EINVAL), false_object); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     if (FSEEK(stream, offset, whence) == -1) | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  |       io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |     else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::safe_fflush(FILE* stream) { | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     if (fflush(stream) == EOF) | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  |       io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |     else | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void factor_vm::primitive_fopen() { | 
					
						
							| 
									
										
										
										
											2016-11-30 08:28:39 -05:00
										 |  |  |   byte_array *mode = untag_check<byte_array>(ctx->pop()); | 
					
						
							|  |  |  |   byte_array *path = untag_check<byte_array>(ctx->pop()); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-30 08:28:39 -05:00
										 |  |  |   FILE* file = safe_fopen((char*)(path + 1), (char*)(mode + 1)); | 
					
						
							| 
									
										
										
										
											2015-08-18 02:18:41 -04:00
										 |  |  |   ctx->push(allot_alien((cell)file)); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-30 08:28:39 -05:00
										 |  |  | FILE* factor_vm::pop_file_handle() { | 
					
						
							|  |  |  |   return (FILE*)alien_offset(ctx->pop()); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-30 08:28:39 -05:00
										 |  |  | FILE* factor_vm::peek_file_handle() { | 
					
						
							|  |  |  |   return (FILE*)alien_offset(ctx->peek()); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 10:26:04 -04: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; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-04 20:11:28 -04:00
										 |  |  |   size_t c = safe_fread(buf, 1, size, file); | 
					
						
							| 
									
										
										
										
											2013-05-11 22:06:53 -04:00
										 |  |  |   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) | 
					
						
							| 
									
										
										
										
											2015-06-03 17:35:48 -04:00
										 |  |  |     io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											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(); | 
					
						
							| 
									
										
										
										
											2015-09-29 17:08:45 -04:00
										 |  |  |   if (raw_fclose(file) == -1) | 
					
						
							|  |  |  |     io_error_if_not_EINTR(); | 
					
						
							| 
									
										
										
										
											2009-05-02 05:04:19 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-21 10:26:04 -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
										 |  |  | } |