1#include "prism/internal/source.h"
3#include "prism/internal/allocator.h"
4#include "prism/internal/buffer.h"
12#elif defined(_POSIX_MAPPED_FILES)
16#elif defined(PRISM_HAS_FILESYSTEM)
21static const uint8_t empty_source[] =
"";
27pm_source_alloc(
const uint8_t *source,
size_t length, pm_source_type_t type) {
29 if (result == NULL) abort();
44pm_source_constant_new(
const uint8_t *data,
size_t length) {
45 return pm_source_alloc(data, length, PM_SOURCE_CONSTANT);
52pm_source_shared_new(
const uint8_t *data,
size_t length) {
53 return pm_source_alloc(data, length, PM_SOURCE_SHARED);
60pm_source_owned_new(uint8_t *data,
size_t length) {
61 return pm_source_alloc(data, length, PM_SOURCE_OWNED);
78} pm_source_file_handle_t;
84pm_source_file_handle_open(pm_source_file_handle_t *handle,
const char *filepath) {
85 int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
88 handle->path_size =
sizeof(WCHAR) * ((
size_t) length);
89 handle->path =
xmalloc(handle->path_size);
90 if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) {
91 xfree_sized(handle->path, handle->path_size);
95 handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
96 if (handle->file == INVALID_HANDLE_VALUE) {
99 if (GetLastError() == ERROR_ACCESS_DENIED) {
100 DWORD attributes = GetFileAttributesW(handle->path);
101 if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
106 xfree_sized(handle->path, handle->path_size);
117pm_source_file_handle_close(pm_source_file_handle_t *handle) {
118 xfree_sized(handle->path, handle->path_size);
119 CloseHandle(handle->file);
132 pm_source_file_handle_t handle;
133 *result = pm_source_file_handle_open(&handle, filepath);
137 DWORD file_size = GetFileSize(handle.file, NULL);
138 if (file_size == INVALID_FILE_SIZE) {
139 pm_source_file_handle_close(&handle);
145 if (file_size == 0) {
146 pm_source_file_handle_close(&handle);
148 return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
152 HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL);
153 if (mapping == NULL) {
154 pm_source_file_handle_close(&handle);
160 uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
161 CloseHandle(mapping);
162 pm_source_file_handle_close(&handle);
164 if (source == NULL) {
170 return pm_source_alloc(source, (
size_t) file_size, PM_SOURCE_MAPPED);
171#elif defined(_POSIX_MAPPED_FILES)
173 int fd = open(filepath, O_RDONLY | open_flags);
181 if (fstat(fd, &sb) == -1) {
188 if (S_ISDIR(sb.st_mode)) {
198 if (!S_ISREG(sb.st_mode)) {
205 size_t size = (size_t) sb.st_size;
210 return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
213 uint8_t *source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
214 if (source == MAP_FAILED) {
222 return pm_source_alloc(source, size, PM_SOURCE_MAPPED);
225 return pm_source_file_new(filepath, result);
236 pm_source_file_handle_t handle;
237 *result = pm_source_file_handle_open(&handle, filepath);
241 const DWORD file_size = GetFileSize(handle.file, NULL);
242 if (file_size == INVALID_FILE_SIZE) {
243 pm_source_file_handle_close(&handle);
249 if (file_size == 0) {
250 pm_source_file_handle_close(&handle);
252 return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
256 uint8_t *source =
xmalloc(file_size);
257 if (source == NULL) {
258 pm_source_file_handle_close(&handle);
265 if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) {
266 xfree_sized(source, file_size);
267 pm_source_file_handle_close(&handle);
273 if (bytes_read != file_size) {
274 xfree_sized(source, file_size);
275 pm_source_file_handle_close(&handle);
280 pm_source_file_handle_close(&handle);
282 return pm_source_alloc(source, (
size_t) file_size, PM_SOURCE_OWNED);
283#elif defined(PRISM_HAS_FILESYSTEM)
285 int fd = open(filepath, O_RDONLY);
293 if (fstat(fd, &sb) == -1) {
300 if (S_ISDIR(sb.st_mode)) {
307 size_t size = (size_t) sb.st_size;
311 return pm_source_alloc(empty_source, 0, PM_SOURCE_CONSTANT);
314 const size_t length = (size_t) size;
315 uint8_t *source =
xmalloc(length);
316 if (source == NULL) {
322 ssize_t bytes_read = read(fd, source, length);
325 if (bytes_read == -1 || (
size_t) bytes_read != length) {
326 xfree_sized(source, length);
332 return pm_source_alloc(source, length, PM_SOURCE_OWNED);
336 perror(
"pm_source_file_new is not implemented for this platform");
348 pm_source_t *source = pm_source_alloc(NULL, 0, PM_SOURCE_STREAM);
349 source->stream.buffer = pm_buffer_new();
350 source->stream.stream = stream;
351 source->stream.fgets = fgets;
352 source->stream.feof = feof;
353 source->stream.eof =
false;
368#define LINE_SIZE 4096
369 char line[LINE_SIZE];
371 while (memset(line,
'\n', LINE_SIZE), source->stream.fgets(line, LINE_SIZE, source->stream.stream) != NULL) {
372 size_t length = LINE_SIZE;
373 while (length > 0 && line[length - 1] ==
'\n') length--;
375 if (length == LINE_SIZE) {
382 pm_buffer_append_string(buffer, line, length);
388 pm_buffer_append_string(buffer, line, length);
398 if (strncmp(line,
"__END__", 7) == 0) {
399 source->source = (
const uint8_t *) pm_buffer_value(buffer);
400 source->length = pm_buffer_length(buffer);
405 if (strncmp(line,
"__END__\n", 8) == 0) {
406 source->source = (
const uint8_t *) pm_buffer_value(buffer);
407 source->length = pm_buffer_length(buffer);
412 if (strncmp(line,
"__END__\r\n", 9) == 0) {
413 source->source = (
const uint8_t *) pm_buffer_value(buffer);
414 source->length = pm_buffer_length(buffer);
424 if (source->stream.feof(source->stream.stream)) {
431 source->stream.eof =
true;
432 source->source = (
const uint8_t *) pm_buffer_value(buffer);
433 source->length = pm_buffer_length(buffer);
442 return source->stream.eof;
450 switch (source->type) {
451 case PM_SOURCE_CONSTANT:
452 case PM_SOURCE_SHARED:
455 case PM_SOURCE_OWNED:
456 xfree_sized((
void *) source->source, source->length);
458 case PM_SOURCE_MAPPED:
460 if (source->length > 0) {
461 UnmapViewOfFile((
void *) source->source);
463#elif defined(_POSIX_MAPPED_FILES)
464 if (source->length > 0) {
465 munmap((
void *) source->source, source->length);
469 case PM_SOURCE_STREAM:
470 pm_buffer_free(source->stream.buffer);
482 return source->length;
490 return source->source;
#define xmalloc
Old name of ruby_xmalloc.
VALUE type(ANYARGS)
ANYARGS-ed function type.
int() pm_source_stream_feof_t(void *stream)
This function is used to check whether a stream is at EOF.
char *() pm_source_stream_fgets_t(char *string, int size, void *stream)
This function is used to retrieve a line of input from a stream.
pm_source_init_result_t
Represents the result of initializing a source from a file.
@ PM_SOURCE_INIT_ERROR_GENERIC
Indicates a generic error from a source init function, where the type of error should be read from er...
@ PM_SOURCE_INIT_SUCCESS
Indicates that the source was successfully initialized.
@ PM_SOURCE_INIT_ERROR_NON_REGULAR
Indicates that the file is not a regular file (e.g.
@ PM_SOURCE_INIT_ERROR_DIRECTORY
Indicates that the file that was attempted to be opened was a directory.