ed-precompiled_prism 1.5.2-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. checksums.yaml +7 -0
  2. data/BSDmakefile +58 -0
  3. data/CHANGELOG.md +723 -0
  4. data/CODE_OF_CONDUCT.md +76 -0
  5. data/CONTRIBUTING.md +58 -0
  6. data/LICENSE.md +7 -0
  7. data/Makefile +110 -0
  8. data/README.md +143 -0
  9. data/config.yml +4714 -0
  10. data/docs/build_system.md +119 -0
  11. data/docs/configuration.md +68 -0
  12. data/docs/cruby_compilation.md +27 -0
  13. data/docs/design.md +53 -0
  14. data/docs/encoding.md +121 -0
  15. data/docs/fuzzing.md +88 -0
  16. data/docs/heredocs.md +36 -0
  17. data/docs/javascript.md +118 -0
  18. data/docs/local_variable_depth.md +229 -0
  19. data/docs/mapping.md +117 -0
  20. data/docs/parser_translation.md +24 -0
  21. data/docs/parsing_rules.md +22 -0
  22. data/docs/releasing.md +98 -0
  23. data/docs/relocation.md +34 -0
  24. data/docs/ripper_translation.md +72 -0
  25. data/docs/ruby_api.md +44 -0
  26. data/docs/ruby_parser_translation.md +19 -0
  27. data/docs/serialization.md +233 -0
  28. data/docs/testing.md +55 -0
  29. data/ext/prism/api_node.c +6941 -0
  30. data/ext/prism/api_pack.c +276 -0
  31. data/ext/prism/extconf.rb +127 -0
  32. data/ext/prism/extension.c +1419 -0
  33. data/ext/prism/extension.h +19 -0
  34. data/include/prism/ast.h +8220 -0
  35. data/include/prism/defines.h +260 -0
  36. data/include/prism/diagnostic.h +456 -0
  37. data/include/prism/encoding.h +283 -0
  38. data/include/prism/node.h +129 -0
  39. data/include/prism/options.h +482 -0
  40. data/include/prism/pack.h +163 -0
  41. data/include/prism/parser.h +933 -0
  42. data/include/prism/prettyprint.h +34 -0
  43. data/include/prism/regexp.h +43 -0
  44. data/include/prism/static_literals.h +121 -0
  45. data/include/prism/util/pm_buffer.h +236 -0
  46. data/include/prism/util/pm_char.h +204 -0
  47. data/include/prism/util/pm_constant_pool.h +218 -0
  48. data/include/prism/util/pm_integer.h +130 -0
  49. data/include/prism/util/pm_list.h +103 -0
  50. data/include/prism/util/pm_memchr.h +29 -0
  51. data/include/prism/util/pm_newline_list.h +113 -0
  52. data/include/prism/util/pm_string.h +200 -0
  53. data/include/prism/util/pm_strncasecmp.h +32 -0
  54. data/include/prism/util/pm_strpbrk.h +46 -0
  55. data/include/prism/version.h +29 -0
  56. data/include/prism.h +408 -0
  57. data/lib/prism/3.0/prism.so +0 -0
  58. data/lib/prism/3.1/prism.so +0 -0
  59. data/lib/prism/3.2/prism.so +0 -0
  60. data/lib/prism/3.3/prism.so +0 -0
  61. data/lib/prism/3.4/prism.so +0 -0
  62. data/lib/prism/compiler.rb +801 -0
  63. data/lib/prism/desugar_compiler.rb +392 -0
  64. data/lib/prism/dispatcher.rb +2210 -0
  65. data/lib/prism/dot_visitor.rb +4762 -0
  66. data/lib/prism/dsl.rb +1003 -0
  67. data/lib/prism/ffi.rb +570 -0
  68. data/lib/prism/inspect_visitor.rb +2392 -0
  69. data/lib/prism/lex_compat.rb +928 -0
  70. data/lib/prism/mutation_compiler.rb +772 -0
  71. data/lib/prism/node.rb +18816 -0
  72. data/lib/prism/node_ext.rb +511 -0
  73. data/lib/prism/pack.rb +230 -0
  74. data/lib/prism/parse_result/comments.rb +188 -0
  75. data/lib/prism/parse_result/errors.rb +66 -0
  76. data/lib/prism/parse_result/newlines.rb +155 -0
  77. data/lib/prism/parse_result.rb +911 -0
  78. data/lib/prism/pattern.rb +269 -0
  79. data/lib/prism/polyfill/append_as_bytes.rb +15 -0
  80. data/lib/prism/polyfill/byteindex.rb +13 -0
  81. data/lib/prism/polyfill/scan_byte.rb +14 -0
  82. data/lib/prism/polyfill/unpack1.rb +14 -0
  83. data/lib/prism/polyfill/warn.rb +36 -0
  84. data/lib/prism/prism.so +0 -0
  85. data/lib/prism/reflection.rb +416 -0
  86. data/lib/prism/relocation.rb +505 -0
  87. data/lib/prism/serialize.rb +2398 -0
  88. data/lib/prism/string_query.rb +31 -0
  89. data/lib/prism/translation/parser/builder.rb +62 -0
  90. data/lib/prism/translation/parser/compiler.rb +2234 -0
  91. data/lib/prism/translation/parser/lexer.rb +820 -0
  92. data/lib/prism/translation/parser.rb +374 -0
  93. data/lib/prism/translation/parser33.rb +13 -0
  94. data/lib/prism/translation/parser34.rb +13 -0
  95. data/lib/prism/translation/parser35.rb +13 -0
  96. data/lib/prism/translation/parser_current.rb +24 -0
  97. data/lib/prism/translation/ripper/sexp.rb +126 -0
  98. data/lib/prism/translation/ripper/shim.rb +5 -0
  99. data/lib/prism/translation/ripper.rb +3474 -0
  100. data/lib/prism/translation/ruby_parser.rb +1929 -0
  101. data/lib/prism/translation.rb +16 -0
  102. data/lib/prism/visitor.rb +813 -0
  103. data/lib/prism.rb +97 -0
  104. data/prism.gemspec +174 -0
  105. data/rbi/prism/compiler.rbi +12 -0
  106. data/rbi/prism/dsl.rbi +524 -0
  107. data/rbi/prism/inspect_visitor.rbi +12 -0
  108. data/rbi/prism/node.rbi +8734 -0
  109. data/rbi/prism/node_ext.rbi +107 -0
  110. data/rbi/prism/parse_result.rbi +404 -0
  111. data/rbi/prism/reflection.rbi +58 -0
  112. data/rbi/prism/string_query.rbi +12 -0
  113. data/rbi/prism/translation/parser.rbi +11 -0
  114. data/rbi/prism/translation/parser33.rbi +6 -0
  115. data/rbi/prism/translation/parser34.rbi +6 -0
  116. data/rbi/prism/translation/parser35.rbi +6 -0
  117. data/rbi/prism/translation/ripper.rbi +15 -0
  118. data/rbi/prism/visitor.rbi +473 -0
  119. data/rbi/prism.rbi +66 -0
  120. data/sig/prism/compiler.rbs +9 -0
  121. data/sig/prism/dispatcher.rbs +19 -0
  122. data/sig/prism/dot_visitor.rbs +6 -0
  123. data/sig/prism/dsl.rbs +351 -0
  124. data/sig/prism/inspect_visitor.rbs +22 -0
  125. data/sig/prism/lex_compat.rbs +10 -0
  126. data/sig/prism/mutation_compiler.rbs +159 -0
  127. data/sig/prism/node.rbs +4028 -0
  128. data/sig/prism/node_ext.rbs +149 -0
  129. data/sig/prism/pack.rbs +43 -0
  130. data/sig/prism/parse_result/comments.rbs +38 -0
  131. data/sig/prism/parse_result.rbs +196 -0
  132. data/sig/prism/pattern.rbs +13 -0
  133. data/sig/prism/reflection.rbs +50 -0
  134. data/sig/prism/relocation.rbs +185 -0
  135. data/sig/prism/serialize.rbs +8 -0
  136. data/sig/prism/string_query.rbs +11 -0
  137. data/sig/prism/visitor.rbs +169 -0
  138. data/sig/prism.rbs +254 -0
  139. data/src/diagnostic.c +850 -0
  140. data/src/encoding.c +5235 -0
  141. data/src/node.c +8676 -0
  142. data/src/options.c +328 -0
  143. data/src/pack.c +509 -0
  144. data/src/prettyprint.c +8941 -0
  145. data/src/prism.c +23361 -0
  146. data/src/regexp.c +790 -0
  147. data/src/serialize.c +2268 -0
  148. data/src/static_literals.c +617 -0
  149. data/src/token_type.c +703 -0
  150. data/src/util/pm_buffer.c +357 -0
  151. data/src/util/pm_char.c +318 -0
  152. data/src/util/pm_constant_pool.c +342 -0
  153. data/src/util/pm_integer.c +670 -0
  154. data/src/util/pm_list.c +49 -0
  155. data/src/util/pm_memchr.c +35 -0
  156. data/src/util/pm_newline_list.c +125 -0
  157. data/src/util/pm_string.c +381 -0
  158. data/src/util/pm_strncasecmp.c +36 -0
  159. data/src/util/pm_strpbrk.c +206 -0
  160. metadata +203 -0
@@ -0,0 +1,49 @@
1
+ #include "prism/util/pm_list.h"
2
+
3
+ /**
4
+ * Returns true if the given list is empty.
5
+ */
6
+ PRISM_EXPORTED_FUNCTION bool
7
+ pm_list_empty_p(pm_list_t *list) {
8
+ return list->head == NULL;
9
+ }
10
+
11
+ /**
12
+ * Returns the size of the list.
13
+ */
14
+ PRISM_EXPORTED_FUNCTION size_t
15
+ pm_list_size(pm_list_t *list) {
16
+ return list->size;
17
+ }
18
+
19
+ /**
20
+ * Append a node to the given list.
21
+ */
22
+ void
23
+ pm_list_append(pm_list_t *list, pm_list_node_t *node) {
24
+ if (list->head == NULL) {
25
+ list->head = node;
26
+ } else {
27
+ list->tail->next = node;
28
+ }
29
+
30
+ list->tail = node;
31
+ list->size++;
32
+ }
33
+
34
+ /**
35
+ * Deallocate the internal state of the given list.
36
+ */
37
+ PRISM_EXPORTED_FUNCTION void
38
+ pm_list_free(pm_list_t *list) {
39
+ pm_list_node_t *node = list->head;
40
+ pm_list_node_t *next;
41
+
42
+ while (node != NULL) {
43
+ next = node->next;
44
+ xfree(node);
45
+ node = next;
46
+ }
47
+
48
+ list->size = 0;
49
+ }
@@ -0,0 +1,35 @@
1
+ #include "prism/util/pm_memchr.h"
2
+
3
+ #define PRISM_MEMCHR_TRAILING_BYTE_MINIMUM 0x40
4
+
5
+ /**
6
+ * We need to roll our own memchr to handle cases where the encoding changes and
7
+ * we need to search for a character in a buffer that could be the trailing byte
8
+ * of a multibyte character.
9
+ */
10
+ void *
11
+ pm_memchr(const void *memory, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding) {
12
+ if (encoding_changed && encoding->multibyte && character >= PRISM_MEMCHR_TRAILING_BYTE_MINIMUM) {
13
+ const uint8_t *source = (const uint8_t *) memory;
14
+ size_t index = 0;
15
+
16
+ while (index < number) {
17
+ if (source[index] == character) {
18
+ return (void *) (source + index);
19
+ }
20
+
21
+ size_t width = encoding->char_width(source + index, (ptrdiff_t) (number - index));
22
+ if (width == 0) {
23
+ return NULL;
24
+ }
25
+
26
+ index += width;
27
+ }
28
+
29
+ return NULL;
30
+ } else {
31
+ return memchr(memory, character, number);
32
+ }
33
+ }
34
+
35
+ #undef PRISM_MEMCHR_TRAILING_BYTE_MINIMUM
@@ -0,0 +1,125 @@
1
+ #include "prism/util/pm_newline_list.h"
2
+
3
+ /**
4
+ * Initialize a new newline list with the given capacity. Returns true if the
5
+ * allocation of the offsets succeeds, otherwise returns false.
6
+ */
7
+ bool
8
+ pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity) {
9
+ list->offsets = (size_t *) xcalloc(capacity, sizeof(size_t));
10
+ if (list->offsets == NULL) return false;
11
+
12
+ list->start = start;
13
+
14
+ // This is 1 instead of 0 because we want to include the first line of the
15
+ // file as having offset 0, which is set because of calloc.
16
+ list->size = 1;
17
+ list->capacity = capacity;
18
+
19
+ return true;
20
+ }
21
+
22
+ /**
23
+ * Clear out the newlines that have been appended to the list.
24
+ */
25
+ void
26
+ pm_newline_list_clear(pm_newline_list_t *list) {
27
+ list->size = 1;
28
+ }
29
+
30
+ /**
31
+ * Append a new offset to the newline list. Returns true if the reallocation of
32
+ * the offsets succeeds (if one was necessary), otherwise returns false.
33
+ */
34
+ bool
35
+ pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor) {
36
+ if (list->size == list->capacity) {
37
+ size_t *original_offsets = list->offsets;
38
+
39
+ list->capacity = (list->capacity * 3) / 2;
40
+ list->offsets = (size_t *) xcalloc(list->capacity, sizeof(size_t));
41
+ if (list->offsets == NULL) return false;
42
+
43
+ memcpy(list->offsets, original_offsets, list->size * sizeof(size_t));
44
+ xfree(original_offsets);
45
+ }
46
+
47
+ assert(*cursor == '\n');
48
+ assert(cursor >= list->start);
49
+ size_t newline_offset = (size_t) (cursor - list->start + 1);
50
+
51
+ assert(list->size == 0 || newline_offset > list->offsets[list->size - 1]);
52
+ list->offsets[list->size++] = newline_offset;
53
+
54
+ return true;
55
+ }
56
+
57
+ /**
58
+ * Returns the line of the given offset. If the offset is not in the list, the
59
+ * line of the closest offset less than the given offset is returned.
60
+ */
61
+ int32_t
62
+ pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) {
63
+ assert(cursor >= list->start);
64
+ size_t offset = (size_t) (cursor - list->start);
65
+
66
+ size_t left = 0;
67
+ size_t right = list->size - 1;
68
+
69
+ while (left <= right) {
70
+ size_t mid = left + (right - left) / 2;
71
+
72
+ if (list->offsets[mid] == offset) {
73
+ return ((int32_t) mid) + start_line;
74
+ }
75
+
76
+ if (list->offsets[mid] < offset) {
77
+ left = mid + 1;
78
+ } else {
79
+ right = mid - 1;
80
+ }
81
+ }
82
+
83
+ return ((int32_t) left) + start_line - 1;
84
+ }
85
+
86
+ /**
87
+ * Returns the line and column of the given offset. If the offset is not in the
88
+ * list, the line and column of the closest offset less than the given offset
89
+ * are returned.
90
+ */
91
+ pm_line_column_t
92
+ pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) {
93
+ assert(cursor >= list->start);
94
+ size_t offset = (size_t) (cursor - list->start);
95
+
96
+ size_t left = 0;
97
+ size_t right = list->size - 1;
98
+
99
+ while (left <= right) {
100
+ size_t mid = left + (right - left) / 2;
101
+
102
+ if (list->offsets[mid] == offset) {
103
+ return ((pm_line_column_t) { ((int32_t) mid) + start_line, 0 });
104
+ }
105
+
106
+ if (list->offsets[mid] < offset) {
107
+ left = mid + 1;
108
+ } else {
109
+ right = mid - 1;
110
+ }
111
+ }
112
+
113
+ return ((pm_line_column_t) {
114
+ .line = ((int32_t) left) + start_line - 1,
115
+ .column = (uint32_t) (offset - list->offsets[left - 1])
116
+ });
117
+ }
118
+
119
+ /**
120
+ * Free the internal memory allocated for the newline list.
121
+ */
122
+ void
123
+ pm_newline_list_free(pm_newline_list_t *list) {
124
+ xfree(list->offsets);
125
+ }
@@ -0,0 +1,381 @@
1
+ #include "prism/util/pm_string.h"
2
+
3
+ static const uint8_t empty_source[] = "";
4
+
5
+ /**
6
+ * Returns the size of the pm_string_t struct. This is necessary to allocate the
7
+ * correct amount of memory in the FFI backend.
8
+ */
9
+ PRISM_EXPORTED_FUNCTION size_t
10
+ pm_string_sizeof(void) {
11
+ return sizeof(pm_string_t);
12
+ }
13
+
14
+ /**
15
+ * Initialize a shared string that is based on initial input.
16
+ */
17
+ void
18
+ pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end) {
19
+ assert(start <= end);
20
+
21
+ *string = (pm_string_t) {
22
+ .type = PM_STRING_SHARED,
23
+ .source = start,
24
+ .length = (size_t) (end - start)
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Initialize an owned string that is responsible for freeing allocated memory.
30
+ */
31
+ void
32
+ pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) {
33
+ *string = (pm_string_t) {
34
+ .type = PM_STRING_OWNED,
35
+ .source = source,
36
+ .length = length
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Initialize a constant string that doesn't own its memory source.
42
+ */
43
+ void
44
+ pm_string_constant_init(pm_string_t *string, const char *source, size_t length) {
45
+ *string = (pm_string_t) {
46
+ .type = PM_STRING_CONSTANT,
47
+ .source = (const uint8_t *) source,
48
+ .length = length
49
+ };
50
+ }
51
+
52
+ #ifdef _WIN32
53
+ /**
54
+ * Represents a file handle on Windows, where the path will need to be freed
55
+ * when the file is closed.
56
+ */
57
+ typedef struct {
58
+ /** The path to the file, which will become allocated memory. */
59
+ WCHAR *path;
60
+
61
+ /** The handle to the file, which will start as uninitialized memory. */
62
+ HANDLE file;
63
+ } pm_string_file_handle_t;
64
+
65
+ /**
66
+ * Open the file indicated by the filepath parameter for reading on Windows.
67
+ * Perform any kind of normalization that needs to happen on the filepath.
68
+ */
69
+ static pm_string_init_result_t
70
+ pm_string_file_handle_open(pm_string_file_handle_t *handle, const char *filepath) {
71
+ int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
72
+ if (length == 0) return PM_STRING_INIT_ERROR_GENERIC;
73
+
74
+ handle->path = xmalloc(sizeof(WCHAR) * ((size_t) length));
75
+ if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) {
76
+ xfree(handle->path);
77
+ return PM_STRING_INIT_ERROR_GENERIC;
78
+ }
79
+
80
+ handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
81
+ if (handle->file == INVALID_HANDLE_VALUE) {
82
+ pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC;
83
+
84
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
85
+ DWORD attributes = GetFileAttributesW(handle->path);
86
+ if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
87
+ result = PM_STRING_INIT_ERROR_DIRECTORY;
88
+ }
89
+ }
90
+
91
+ xfree(handle->path);
92
+ return result;
93
+ }
94
+
95
+ return PM_STRING_INIT_SUCCESS;
96
+ }
97
+
98
+ /**
99
+ * Close the file handle and free the path.
100
+ */
101
+ static void
102
+ pm_string_file_handle_close(pm_string_file_handle_t *handle) {
103
+ xfree(handle->path);
104
+ CloseHandle(handle->file);
105
+ }
106
+ #endif
107
+
108
+ /**
109
+ * Read the file indicated by the filepath parameter into source and load its
110
+ * contents and size into the given `pm_string_t`. The given `pm_string_t`
111
+ * should be freed using `pm_string_free` when it is no longer used.
112
+ *
113
+ * We want to use demand paging as much as possible in order to avoid having to
114
+ * read the entire file into memory (which could be detrimental to performance
115
+ * for large files). This means that if we're on windows we'll use
116
+ * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use
117
+ * `mmap`, and on other POSIX systems we'll use `read`.
118
+ */
119
+ PRISM_EXPORTED_FUNCTION pm_string_init_result_t
120
+ pm_string_mapped_init(pm_string_t *string, const char *filepath) {
121
+ #ifdef _WIN32
122
+ // Open the file for reading.
123
+ pm_string_file_handle_t handle;
124
+ pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath);
125
+ if (result != PM_STRING_INIT_SUCCESS) return result;
126
+
127
+ // Get the file size.
128
+ DWORD file_size = GetFileSize(handle.file, NULL);
129
+ if (file_size == INVALID_FILE_SIZE) {
130
+ pm_string_file_handle_close(&handle);
131
+ return PM_STRING_INIT_ERROR_GENERIC;
132
+ }
133
+
134
+ // If the file is empty, then we don't need to do anything else, we'll set
135
+ // the source to a constant empty string and return.
136
+ if (file_size == 0) {
137
+ pm_string_file_handle_close(&handle);
138
+ *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 };
139
+ return PM_STRING_INIT_SUCCESS;
140
+ }
141
+
142
+ // Create a mapping of the file.
143
+ HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL);
144
+ if (mapping == NULL) {
145
+ pm_string_file_handle_close(&handle);
146
+ return PM_STRING_INIT_ERROR_GENERIC;
147
+ }
148
+
149
+ // Map the file into memory.
150
+ uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
151
+ CloseHandle(mapping);
152
+ pm_string_file_handle_close(&handle);
153
+
154
+ if (source == NULL) {
155
+ return PM_STRING_INIT_ERROR_GENERIC;
156
+ }
157
+
158
+ *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size };
159
+ return PM_STRING_INIT_SUCCESS;
160
+ #elif defined(_POSIX_MAPPED_FILES)
161
+ // Open the file for reading
162
+ int fd = open(filepath, O_RDONLY);
163
+ if (fd == -1) {
164
+ return PM_STRING_INIT_ERROR_GENERIC;
165
+ }
166
+
167
+ // Stat the file to get the file size
168
+ struct stat sb;
169
+ if (fstat(fd, &sb) == -1) {
170
+ close(fd);
171
+ return PM_STRING_INIT_ERROR_GENERIC;
172
+ }
173
+
174
+ // Ensure it is a file and not a directory
175
+ if (S_ISDIR(sb.st_mode)) {
176
+ close(fd);
177
+ return PM_STRING_INIT_ERROR_DIRECTORY;
178
+ }
179
+
180
+ // mmap the file descriptor to virtually get the contents
181
+ size_t size = (size_t) sb.st_size;
182
+ uint8_t *source = NULL;
183
+
184
+ if (size == 0) {
185
+ close(fd);
186
+ *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 };
187
+ return PM_STRING_INIT_SUCCESS;
188
+ }
189
+
190
+ source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
191
+ if (source == MAP_FAILED) {
192
+ close(fd);
193
+ return PM_STRING_INIT_ERROR_GENERIC;
194
+ }
195
+
196
+ close(fd);
197
+ *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size };
198
+ return PM_STRING_INIT_SUCCESS;
199
+ #else
200
+ return pm_string_file_init(string, filepath);
201
+ #endif
202
+ }
203
+
204
+ /**
205
+ * Read the file indicated by the filepath parameter into source and load its
206
+ * contents and size into the given `pm_string_t`. The given `pm_string_t`
207
+ * should be freed using `pm_string_free` when it is no longer used.
208
+ */
209
+ PRISM_EXPORTED_FUNCTION pm_string_init_result_t
210
+ pm_string_file_init(pm_string_t *string, const char *filepath) {
211
+ #ifdef _WIN32
212
+ // Open the file for reading.
213
+ pm_string_file_handle_t handle;
214
+ pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath);
215
+ if (result != PM_STRING_INIT_SUCCESS) return result;
216
+
217
+ // Get the file size.
218
+ DWORD file_size = GetFileSize(handle.file, NULL);
219
+ if (file_size == INVALID_FILE_SIZE) {
220
+ pm_string_file_handle_close(&handle);
221
+ return PM_STRING_INIT_ERROR_GENERIC;
222
+ }
223
+
224
+ // If the file is empty, then we don't need to do anything else, we'll set
225
+ // the source to a constant empty string and return.
226
+ if (file_size == 0) {
227
+ pm_string_file_handle_close(&handle);
228
+ *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 };
229
+ return PM_STRING_INIT_SUCCESS;
230
+ }
231
+
232
+ // Create a buffer to read the file into.
233
+ uint8_t *source = xmalloc(file_size);
234
+ if (source == NULL) {
235
+ pm_string_file_handle_close(&handle);
236
+ return PM_STRING_INIT_ERROR_GENERIC;
237
+ }
238
+
239
+ // Read the contents of the file
240
+ DWORD bytes_read;
241
+ if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) {
242
+ pm_string_file_handle_close(&handle);
243
+ return PM_STRING_INIT_ERROR_GENERIC;
244
+ }
245
+
246
+ // Check the number of bytes read
247
+ if (bytes_read != file_size) {
248
+ xfree(source);
249
+ pm_string_file_handle_close(&handle);
250
+ return PM_STRING_INIT_ERROR_GENERIC;
251
+ }
252
+
253
+ pm_string_file_handle_close(&handle);
254
+ *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = (size_t) file_size };
255
+ return PM_STRING_INIT_SUCCESS;
256
+ #elif defined(PRISM_HAS_FILESYSTEM)
257
+ // Open the file for reading
258
+ int fd = open(filepath, O_RDONLY);
259
+ if (fd == -1) {
260
+ return PM_STRING_INIT_ERROR_GENERIC;
261
+ }
262
+
263
+ // Stat the file to get the file size
264
+ struct stat sb;
265
+ if (fstat(fd, &sb) == -1) {
266
+ close(fd);
267
+ return PM_STRING_INIT_ERROR_GENERIC;
268
+ }
269
+
270
+ // Ensure it is a file and not a directory
271
+ if (S_ISDIR(sb.st_mode)) {
272
+ close(fd);
273
+ return PM_STRING_INIT_ERROR_DIRECTORY;
274
+ }
275
+
276
+ // Check the size to see if it's empty
277
+ size_t size = (size_t) sb.st_size;
278
+ if (size == 0) {
279
+ close(fd);
280
+ *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 };
281
+ return PM_STRING_INIT_SUCCESS;
282
+ }
283
+
284
+ size_t length = (size_t) size;
285
+ uint8_t *source = xmalloc(length);
286
+ if (source == NULL) {
287
+ close(fd);
288
+ return PM_STRING_INIT_ERROR_GENERIC;
289
+ }
290
+
291
+ long bytes_read = (long) read(fd, source, length);
292
+ close(fd);
293
+
294
+ if (bytes_read == -1) {
295
+ xfree(source);
296
+ return PM_STRING_INIT_ERROR_GENERIC;
297
+ }
298
+
299
+ *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length };
300
+ return PM_STRING_INIT_SUCCESS;
301
+ #else
302
+ (void) string;
303
+ (void) filepath;
304
+ perror("pm_string_file_init is not implemented for this platform");
305
+ return PM_STRING_INIT_ERROR_GENERIC;
306
+ #endif
307
+ }
308
+
309
+ /**
310
+ * Ensure the string is owned. If it is not, then reinitialize it as owned and
311
+ * copy over the previous source.
312
+ */
313
+ void
314
+ pm_string_ensure_owned(pm_string_t *string) {
315
+ if (string->type == PM_STRING_OWNED) return;
316
+
317
+ size_t length = pm_string_length(string);
318
+ const uint8_t *source = pm_string_source(string);
319
+
320
+ uint8_t *memory = xmalloc(length);
321
+ if (!memory) return;
322
+
323
+ pm_string_owned_init(string, memory, length);
324
+ memcpy((void *) string->source, source, length);
325
+ }
326
+
327
+ /**
328
+ * Compare the underlying lengths and bytes of two strings. Returns 0 if the
329
+ * strings are equal, a negative number if the left string is less than the
330
+ * right string, and a positive number if the left string is greater than the
331
+ * right string.
332
+ */
333
+ int
334
+ pm_string_compare(const pm_string_t *left, const pm_string_t *right) {
335
+ size_t left_length = pm_string_length(left);
336
+ size_t right_length = pm_string_length(right);
337
+
338
+ if (left_length < right_length) {
339
+ return -1;
340
+ } else if (left_length > right_length) {
341
+ return 1;
342
+ }
343
+
344
+ return memcmp(pm_string_source(left), pm_string_source(right), left_length);
345
+ }
346
+
347
+ /**
348
+ * Returns the length associated with the string.
349
+ */
350
+ PRISM_EXPORTED_FUNCTION size_t
351
+ pm_string_length(const pm_string_t *string) {
352
+ return string->length;
353
+ }
354
+
355
+ /**
356
+ * Returns the start pointer associated with the string.
357
+ */
358
+ PRISM_EXPORTED_FUNCTION const uint8_t *
359
+ pm_string_source(const pm_string_t *string) {
360
+ return string->source;
361
+ }
362
+
363
+ /**
364
+ * Free the associated memory of the given string.
365
+ */
366
+ PRISM_EXPORTED_FUNCTION void
367
+ pm_string_free(pm_string_t *string) {
368
+ void *memory = (void *) string->source;
369
+
370
+ if (string->type == PM_STRING_OWNED) {
371
+ xfree(memory);
372
+ #ifdef PRISM_HAS_MMAP
373
+ } else if (string->type == PM_STRING_MAPPED && string->length) {
374
+ #if defined(_WIN32)
375
+ UnmapViewOfFile(memory);
376
+ #elif defined(_POSIX_MAPPED_FILES)
377
+ munmap(memory, string->length);
378
+ #endif
379
+ #endif /* PRISM_HAS_MMAP */
380
+ }
381
+ }
@@ -0,0 +1,36 @@
1
+ #include "prism/util/pm_strncasecmp.h"
2
+
3
+ /**
4
+ * A locale-insensitive version of `tolower(3)`
5
+ */
6
+ static inline int
7
+ pm_tolower(int c)
8
+ {
9
+ if ('A' <= c && c <= 'Z') {
10
+ return c | 0x20;
11
+ }
12
+ return c;
13
+ }
14
+
15
+ /**
16
+ * Compare two strings, ignoring case, up to the given length. Returns 0 if the
17
+ * strings are equal, a negative number if string1 is less than string2, or a
18
+ * positive number if string1 is greater than string2.
19
+ *
20
+ * Note that this is effectively our own implementation of strncasecmp, but it's
21
+ * not available on all of the platforms we want to support so we're rolling it
22
+ * here.
23
+ */
24
+ int
25
+ pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length) {
26
+ size_t offset = 0;
27
+ int difference = 0;
28
+
29
+ while (offset < length && string1[offset] != '\0') {
30
+ if (string2[offset] == '\0') return string1[offset];
31
+ if ((difference = pm_tolower(string1[offset]) - pm_tolower(string2[offset])) != 0) return difference;
32
+ offset++;
33
+ }
34
+
35
+ return difference;
36
+ }