aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-03-01 14:45:36 -0500
committergit <svn-admin@ruby-lang.org>2024-03-06 17:45:56 +0000
commitb88973165a9e970793eb187a4223d7521031ebc3 (patch)
tree0635a6caaf33a252faec3bef29d394bd077fa1b9
parent6ea01d204ec4cc100378caf7993f4c353a19152f (diff)
downloadruby-b88973165a9e970793eb187a4223d7521031ebc3.tar.gz
[ruby/prism] Parse files from Ruby API using fread, not mmap
https://github.com/ruby/prism/commit/62d4376a53
-rw-r--r--prism/extension.c2
-rw-r--r--prism/util/pm_string.c104
-rw-r--r--prism/util/pm_string.h11
3 files changed, 115 insertions, 2 deletions
diff --git a/prism/extension.c b/prism/extension.c
index c14e5165db..0ae4a30b26 100644
--- a/prism/extension.c
+++ b/prism/extension.c
@@ -254,7 +254,7 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options) {
const char * string_source = (const char *) pm_string_source(&options->filepath);
- if (!pm_string_mapped_init(input, string_source)) {
+ if (!pm_string_file_init(input, string_source)) {
pm_options_free(options);
#ifdef _WIN32
diff --git a/prism/util/pm_string.c b/prism/util/pm_string.c
index fea3f1d2cf..753429a233 100644
--- a/prism/util/pm_string.c
+++ b/prism/util/pm_string.c
@@ -58,7 +58,7 @@ pm_string_constant_init(pm_string_t *string, const char *source, size_t length)
* `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use
* `mmap`, and on other POSIX systems we'll use `read`.
*/
-bool
+PRISM_EXPORTED_FUNCTION bool
pm_string_mapped_init(pm_string_t *string, const char *filepath) {
#ifdef _WIN32
// Open the file for reading.
@@ -144,6 +144,108 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) {
}
/**
+ * Read the file indicated by the filepath parameter into source and load its
+ * contents and size into the given `pm_string_t`. The given `pm_string_t`
+ * should be freed using `pm_string_free` when it is no longer used.
+ */
+PRISM_EXPORTED_FUNCTION bool
+pm_string_file_init(pm_string_t *string, const char *filepath) {
+#ifdef _WIN32
+ // Open the file for reading.
+ HANDLE file = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (file == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ // Get the file size.
+ DWORD file_size = GetFileSize(file, NULL);
+ if (file_size == INVALID_FILE_SIZE) {
+ CloseHandle(file);
+ return false;
+ }
+
+ // If the file is empty, then we don't need to do anything else, we'll set
+ // the source to a constant empty string and return.
+ if (file_size == 0) {
+ CloseHandle(file);
+ const uint8_t source[] = "";
+ *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
+ return true;
+ }
+
+ // Create a buffer to read the file into.
+ uint8_t *source = malloc(file_size);
+ if (source == NULL) {
+ CloseHandle(file);
+ return false;
+ }
+
+ // Read the contents of the file
+ DWORD bytes_read;
+ if (!ReadFile(file, source, file_size, &bytes_read, NULL)) {
+ CloseHandle(file);
+ return false;
+ }
+
+ // Check the number of bytes read
+ if (bytes_read != file_size) {
+ free(source);
+ CloseHandle(file);
+ return false;
+ }
+
+ CloseHandle(file);
+ *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = (size_t) file_size };
+ return true;
+#elif defined(_POSIX_MAPPED_FILES)
+ FILE *file = fopen(filepath, "rb");
+ if (file == NULL) {
+ return false;
+ }
+
+ fseek(file, 0, SEEK_END);
+ long file_size = ftell(file);
+
+ if (file_size == -1) {
+ fclose(file);
+ return false;
+ }
+
+ if (file_size == 0) {
+ fclose(file);
+ const uint8_t source[] = "";
+ *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
+ return true;
+ }
+
+ size_t length = (size_t) file_size;
+ uint8_t *source = malloc(length);
+ if (source == NULL) {
+ fclose(file);
+ return false;
+ }
+
+ fseek(file, 0, SEEK_SET);
+ size_t bytes_read = fread(source, length, 1, file);
+ fclose(file);
+
+ if (bytes_read != 1) {
+ free(source);
+ return false;
+ }
+
+ *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length };
+ return true;
+#else
+ (void) string;
+ (void) filepath;
+ perror("pm_string_file_init is not implemented for this platform");
+ return false;
+#endif
+}
+
+/**
* Returns the memory size associated with the string.
*/
size_t
diff --git a/prism/util/pm_string.h b/prism/util/pm_string.h
index d6442fc608..a68e2a7c91 100644
--- a/prism/util/pm_string.h
+++ b/prism/util/pm_string.h
@@ -110,6 +110,17 @@ void pm_string_constant_init(pm_string_t *string, const char *source, size_t len
PRISM_EXPORTED_FUNCTION bool pm_string_mapped_init(pm_string_t *string, const char *filepath);
/**
+ * Read the file indicated by the filepath parameter into source and load its
+ * contents and size into the given `pm_string_t`. The given `pm_string_t`
+ * should be freed using `pm_string_free` when it is no longer used.
+ *
+ * @param string The string to initialize.
+ * @param filepath The filepath to read.
+ * @return Whether or not the file was successfully read.
+ */
+PRISM_EXPORTED_FUNCTION bool pm_string_file_init(pm_string_t *string, const char *filepath);
+
+/**
* Returns the memory size associated with the string.
*
* @param string The string to get the memory size of.