zsv 1.3.0

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 (240) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +36 -0
  3. data/LICENSE +21 -0
  4. data/README.md +311 -0
  5. data/ext/zsv/common.h +34 -0
  6. data/ext/zsv/extconf.rb +137 -0
  7. data/ext/zsv/options.c +126 -0
  8. data/ext/zsv/options.h +31 -0
  9. data/ext/zsv/options_internal.h +8 -0
  10. data/ext/zsv/parser.c +300 -0
  11. data/ext/zsv/parser.h +62 -0
  12. data/ext/zsv/row.c +122 -0
  13. data/ext/zsv/row.h +39 -0
  14. data/ext/zsv/vendor/zsv-1.3.0/app/2db.c +756 -0
  15. data/ext/zsv/vendor/zsv-1.3.0/app/2json.c +381 -0
  16. data/ext/zsv/vendor/zsv-1.3.0/app/2tsv.c +228 -0
  17. data/ext/zsv/vendor/zsv-1.3.0/app/builtin/help.c +123 -0
  18. data/ext/zsv/vendor/zsv-1.3.0/app/builtin/license.c +39 -0
  19. data/ext/zsv/vendor/zsv-1.3.0/app/builtin/register.c +104 -0
  20. data/ext/zsv/vendor/zsv-1.3.0/app/builtin/thirdparty.c +41 -0
  21. data/ext/zsv/vendor/zsv-1.3.0/app/builtin/unregister.c +1 -0
  22. data/ext/zsv/vendor/zsv-1.3.0/app/builtin/version.c +14 -0
  23. data/ext/zsv/vendor/zsv-1.3.0/app/check/simdutf_wrapper.h +19 -0
  24. data/ext/zsv/vendor/zsv-1.3.0/app/check/utf8.c +116 -0
  25. data/ext/zsv/vendor/zsv-1.3.0/app/check.c +194 -0
  26. data/ext/zsv/vendor/zsv-1.3.0/app/cli.c +796 -0
  27. data/ext/zsv/vendor/zsv-1.3.0/app/cli_const.h +41 -0
  28. data/ext/zsv/vendor/zsv-1.3.0/app/cli_export.h +16 -0
  29. data/ext/zsv/vendor/zsv-1.3.0/app/cli_ini.c +280 -0
  30. data/ext/zsv/vendor/zsv-1.3.0/app/cli_internal.h +36 -0
  31. data/ext/zsv/vendor/zsv-1.3.0/app/compare.c +913 -0
  32. data/ext/zsv/vendor/zsv-1.3.0/app/compare.h +23 -0
  33. data/ext/zsv/vendor/zsv-1.3.0/app/compare_added_column.c +20 -0
  34. data/ext/zsv/vendor/zsv-1.3.0/app/compare_internal.h +140 -0
  35. data/ext/zsv/vendor/zsv-1.3.0/app/compare_sort.c +91 -0
  36. data/ext/zsv/vendor/zsv-1.3.0/app/compare_unique_colname.c +81 -0
  37. data/ext/zsv/vendor/zsv-1.3.0/app/count-pull.c +82 -0
  38. data/ext/zsv/vendor/zsv-1.3.0/app/count.c +404 -0
  39. data/ext/zsv/vendor/zsv-1.3.0/app/desc.c +569 -0
  40. data/ext/zsv/vendor/zsv-1.3.0/app/echo.c +365 -0
  41. data/ext/zsv/vendor/zsv-1.3.0/app/ext_example/my_extension.c +366 -0
  42. data/ext/zsv/vendor/zsv-1.3.0/app/ext_example/mysheet_extension.c +341 -0
  43. data/ext/zsv/vendor/zsv-1.3.0/app/ext_template/YOUR_EXTENSION_zsvext.c +263 -0
  44. data/ext/zsv/vendor/zsv-1.3.0/app/external/inih/ini.c +298 -0
  45. data/ext/zsv/vendor/zsv-1.3.0/app/external/inih/ini.h +157 -0
  46. data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/json_numeric.c +177 -0
  47. data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/jsonwriter.c +444 -0
  48. data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/jsonwriter.h +145 -0
  49. data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/utils.c +110 -0
  50. data/ext/zsv/vendor/zsv-1.3.0/app/external/memfile-1.0/include/memfile.h +15 -0
  51. data/ext/zsv/vendor/zsv-1.3.0/app/external/memfile-1.0/src/memfile.c +64 -0
  52. data/ext/zsv/vendor/zsv-1.3.0/app/external/sglib/sglib.h +1955 -0
  53. data/ext/zsv/vendor/zsv-1.3.0/app/external/simdutf/simdutf.h +6802 -0
  54. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3.c +230517 -0
  55. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3.h +12174 -0
  56. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_and_csv_vtab.c +2 -0
  57. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-mem.c +142 -0
  58. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-mem.h +49 -0
  59. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-zsv.c +485 -0
  60. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab.c +1015 -0
  61. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3ext.h +663 -0
  62. data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/vtab_helper.c +85 -0
  63. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_common.h +75 -0
  64. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_gen.h +167 -0
  65. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_parse.h +228 -0
  66. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_tree.h +186 -0
  67. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_version.h +23 -0
  68. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_common.h +76 -0
  69. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_gen.h +167 -0
  70. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_parse.h +238 -0
  71. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_tree.h +186 -0
  72. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl.c +184 -0
  73. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_alloc.c +52 -0
  74. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_alloc.h +34 -0
  75. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_buf.c +103 -0
  76. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_buf.h +57 -0
  77. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_bytestack.h +69 -0
  78. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_encode.c +220 -0
  79. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_encode.h +34 -0
  80. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_gen.c +362 -0
  81. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_lex.c +764 -0
  82. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_lex.h +117 -0
  83. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_parser.c +508 -0
  84. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_parser.h +78 -0
  85. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_tree.c +505 -0
  86. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_version.c +7 -0
  87. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper/json_value.h +59 -0
  88. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper/yajl_helper.h +208 -0
  89. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper.c +795 -0
  90. data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper_internal.h +28 -0
  91. data/ext/zsv/vendor/zsv-1.3.0/app/flatten.c +851 -0
  92. data/ext/zsv/vendor/zsv-1.3.0/app/jq.c +106 -0
  93. data/ext/zsv/vendor/zsv-1.3.0/app/jq.h +6 -0
  94. data/ext/zsv/vendor/zsv-1.3.0/app/mv.c +113 -0
  95. data/ext/zsv/vendor/zsv-1.3.0/app/noop.c +90 -0
  96. data/ext/zsv/vendor/zsv-1.3.0/app/overwrite.c +295 -0
  97. data/ext/zsv/vendor/zsv-1.3.0/app/paste.c +175 -0
  98. data/ext/zsv/vendor/zsv-1.3.0/app/pretty.c +693 -0
  99. data/ext/zsv/vendor/zsv-1.3.0/app/prop.c +980 -0
  100. data/ext/zsv/vendor/zsv-1.3.0/app/rm.c +131 -0
  101. data/ext/zsv/vendor/zsv-1.3.0/app/select/fixed.c +130 -0
  102. data/ext/zsv/vendor/zsv-1.3.0/app/select/internal.h +118 -0
  103. data/ext/zsv/vendor/zsv-1.3.0/app/select/parallel.c +45 -0
  104. data/ext/zsv/vendor/zsv-1.3.0/app/select/parallel.h +41 -0
  105. data/ext/zsv/vendor/zsv-1.3.0/app/select/processing.c +107 -0
  106. data/ext/zsv/vendor/zsv-1.3.0/app/select/rand.c +20 -0
  107. data/ext/zsv/vendor/zsv-1.3.0/app/select/regex.c +61 -0
  108. data/ext/zsv/vendor/zsv-1.3.0/app/select/search.c +14 -0
  109. data/ext/zsv/vendor/zsv-1.3.0/app/select/selection.c +192 -0
  110. data/ext/zsv/vendor/zsv-1.3.0/app/select/usage.c +72 -0
  111. data/ext/zsv/vendor/zsv-1.3.0/app/select-pull.c +812 -0
  112. data/ext/zsv/vendor/zsv-1.3.0/app/select.c +753 -0
  113. data/ext/zsv/vendor/zsv-1.3.0/app/serialize.c +372 -0
  114. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/curses.h +15 -0
  115. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/cursor.c +119 -0
  116. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/errors.c +45 -0
  117. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/file.c +63 -0
  118. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/file.h +12 -0
  119. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/filter.c +166 -0
  120. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/handlers.c +214 -0
  121. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/handlers_internal.h +128 -0
  122. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/help.c +43 -0
  123. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/index.c +81 -0
  124. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/index.h +25 -0
  125. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/key-bindings.c +325 -0
  126. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/key-bindings.h +73 -0
  127. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/lexer.c +203 -0
  128. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/newline_handler.c +7 -0
  129. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/pivot.c +318 -0
  130. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/procedure.c +134 -0
  131. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/procedure.h +119 -0
  132. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/read-data.c +322 -0
  133. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/screen_buffer.c +203 -0
  134. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/screen_buffer.h +36 -0
  135. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sheet-sql.c +167 -0
  136. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sheet_internal.h +36 -0
  137. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sqlfilter.c +153 -0
  138. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/terminfo.c +32 -0
  139. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/transformation.c +312 -0
  140. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/transformation.h +29 -0
  141. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/ui_buffer.c +266 -0
  142. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/usage.c +9 -0
  143. data/ext/zsv/vendor/zsv-1.3.0/app/sheet/utf8-width.c +60 -0
  144. data/ext/zsv/vendor/zsv-1.3.0/app/sheet.c +1007 -0
  145. data/ext/zsv/vendor/zsv-1.3.0/app/sql.c +453 -0
  146. data/ext/zsv/vendor/zsv-1.3.0/app/sql_internal.c +101 -0
  147. data/ext/zsv/vendor/zsv-1.3.0/app/sql_internal.h +49 -0
  148. data/ext/zsv/vendor/zsv-1.3.0/app/stack.c +393 -0
  149. data/ext/zsv/vendor/zsv-1.3.0/app/utils/arg.c +322 -0
  150. data/ext/zsv/vendor/zsv-1.3.0/app/utils/cache.c +228 -0
  151. data/ext/zsv/vendor/zsv-1.3.0/app/utils/cat.c +91 -0
  152. data/ext/zsv/vendor/zsv-1.3.0/app/utils/chunk.c +240 -0
  153. data/ext/zsv/vendor/zsv-1.3.0/app/utils/chunk.h +63 -0
  154. data/ext/zsv/vendor/zsv-1.3.0/app/utils/clock.c +57 -0
  155. data/ext/zsv/vendor/zsv-1.3.0/app/utils/db.c +148 -0
  156. data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs-no-jq.c +2 -0
  157. data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs.c +427 -0
  158. data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs_from_json.c +253 -0
  159. data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs_to_json.c +121 -0
  160. data/ext/zsv/vendor/zsv-1.3.0/app/utils/dl.c +20 -0
  161. data/ext/zsv/vendor/zsv-1.3.0/app/utils/emcc/fs_api.c +159 -0
  162. data/ext/zsv/vendor/zsv-1.3.0/app/utils/err.c +24 -0
  163. data/ext/zsv/vendor/zsv-1.3.0/app/utils/file-mem.c +180 -0
  164. data/ext/zsv/vendor/zsv-1.3.0/app/utils/file.c +256 -0
  165. data/ext/zsv/vendor/zsv-1.3.0/app/utils/index.c +197 -0
  166. data/ext/zsv/vendor/zsv-1.3.0/app/utils/index.h +49 -0
  167. data/ext/zsv/vendor/zsv-1.3.0/app/utils/jq.c +400 -0
  168. data/ext/zsv/vendor/zsv-1.3.0/app/utils/json.c +120 -0
  169. data/ext/zsv/vendor/zsv-1.3.0/app/utils/mem.c +18 -0
  170. data/ext/zsv/vendor/zsv-1.3.0/app/utils/memmem.c +132 -0
  171. data/ext/zsv/vendor/zsv-1.3.0/app/utils/os.c +178 -0
  172. data/ext/zsv/vendor/zsv-1.3.0/app/utils/overwrite.c +258 -0
  173. data/ext/zsv/vendor/zsv-1.3.0/app/utils/overwrite_writer.c +246 -0
  174. data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8-test.c +123 -0
  175. data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8.c +153 -0
  176. data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8.h +54 -0
  177. data/ext/zsv/vendor/zsv-1.3.0/app/utils/prop.c +267 -0
  178. data/ext/zsv/vendor/zsv-1.3.0/app/utils/signal.c +53 -0
  179. data/ext/zsv/vendor/zsv-1.3.0/app/utils/string.c +357 -0
  180. data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/dir_exists_longpath.c +83 -0
  181. data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/dl.c +33 -0
  182. data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/fopen_longpath.c +184 -0
  183. data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/foreach_dirent_longpath.c +292 -0
  184. data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/io.c +259 -0
  185. data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/io.h +13 -0
  186. data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/mkdir_longpath.c +255 -0
  187. data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/remove_longpath.c +96 -0
  188. data/ext/zsv/vendor/zsv-1.3.0/app/utils/writer.c +361 -0
  189. data/ext/zsv/vendor/zsv-1.3.0/app/zsv_command.h +40 -0
  190. data/ext/zsv/vendor/zsv-1.3.0/app/zsv_command_standalone.c +16 -0
  191. data/ext/zsv/vendor/zsv-1.3.0/app/zsv_main.h +44 -0
  192. data/ext/zsv/vendor/zsv-1.3.0/examples/js/zsv_parser_api_dummy.c +3 -0
  193. data/ext/zsv/vendor/zsv-1.3.0/examples/lib/parse_by_chunk.c +100 -0
  194. data/ext/zsv/vendor/zsv-1.3.0/examples/lib/print_my_column.c +143 -0
  195. data/ext/zsv/vendor/zsv-1.3.0/examples/lib/pull.c +89 -0
  196. data/ext/zsv/vendor/zsv-1.3.0/examples/lib/simple.c +123 -0
  197. data/ext/zsv/vendor/zsv-1.3.0/fuzz/fuzz.c +16 -0
  198. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/api.h +336 -0
  199. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/common.h +361 -0
  200. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/implementation.h +62 -0
  201. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/implementation_private.h +113 -0
  202. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/sheet.h +73 -0
  203. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext.h +329 -0
  204. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/arg.h +90 -0
  205. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/cache.h +49 -0
  206. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/clock.h +36 -0
  207. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/compiler.h +58 -0
  208. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/db.h +19 -0
  209. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/dirs.h +147 -0
  210. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/dl.h +22 -0
  211. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/emcc/fs_api.h +28 -0
  212. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/err.h +22 -0
  213. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/file-mem.h +17 -0
  214. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/file.h +99 -0
  215. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/jq.h +65 -0
  216. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/json.h +19 -0
  217. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/mem.h +19 -0
  218. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/memmem.h +13 -0
  219. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/os.h +54 -0
  220. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/overwrite.h +71 -0
  221. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/overwrite_writer.h +53 -0
  222. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/prop.h +107 -0
  223. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/signal.h +18 -0
  224. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/sql.h +11 -0
  225. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/string.h +148 -0
  226. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/utf8.h +41 -0
  227. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/win/dl.h +25 -0
  228. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/writer.h +101 -0
  229. data/ext/zsv/vendor/zsv-1.3.0/include/zsv/zsv_export.h +33 -0
  230. data/ext/zsv/vendor/zsv-1.3.0/include/zsv.h +20 -0
  231. data/ext/zsv/vendor/zsv-1.3.0/src/vector_delim.c +60 -0
  232. data/ext/zsv/vendor/zsv-1.3.0/src/zsv.c +484 -0
  233. data/ext/zsv/vendor/zsv-1.3.0/src/zsv_internal.c +731 -0
  234. data/ext/zsv/vendor/zsv-1.3.0/src/zsv_scan_delim.c +285 -0
  235. data/ext/zsv/vendor/zsv-1.3.0/src/zsv_scan_fixed.c +88 -0
  236. data/ext/zsv/vendor/zsv-1.3.0/src/zsv_strencode.c +51 -0
  237. data/ext/zsv/zsv_ext.c +343 -0
  238. data/lib/zsv/version.rb +5 -0
  239. data/lib/zsv.rb +81 -0
  240. metadata +340 -0
@@ -0,0 +1,357 @@
1
+ /*
2
+ * Copyright (C) 2021 Liquidaty and the zsv/lib contributors
3
+ * All rights reserved
4
+ *
5
+ * This file is part of zsv/lib, distributed under the license defined at
6
+ * https://opensource.org/licenses/MIT
7
+ */
8
+
9
+ #include <string.h>
10
+ #include <stdint.h>
11
+ #include <ctype.h>
12
+ #include <stdlib.h>
13
+ #include <stdio.h>
14
+
15
+ #include <zsv/utils/compiler.h>
16
+ #include <zsv/utils/utf8.h>
17
+ #include <zsv/utils/string.h>
18
+
19
+ #ifdef ZSV_UTILS_STRING_STANDALONE
20
+ #include "../../src/zsv_strencode.c"
21
+ #endif
22
+
23
+ #ifndef NO_UTF8PROC
24
+ #include <utf8proc.h>
25
+
26
+ static utf8proc_int32_t utf8proc_tolower1(utf8proc_int32_t codepoint, void *data) {
27
+ (void)data;
28
+ return utf8proc_tolower(codepoint);
29
+ }
30
+
31
+ static unsigned char *utf8proc_tolower_str(const unsigned char *str, size_t *len) {
32
+ // note: for some unknown reason, this func intermittently can fail on win (compiled w mingw64) when called in a tight
33
+ // loop may be related to realloc()
34
+ utf8proc_uint8_t *output;
35
+ utf8proc_option_t options = {0};
36
+ /* options = UTF8PROC_COMPOSE | UTF8PROC_COMPAT
37
+ | UTF8PROC_CASEFOLD | UTF8PROC_IGNORE | UTF8PROC_STRIPMARK | UTF8PROC_STRIPCC | UTF8PROC_STRIPNA;
38
+ */
39
+ // utf8proc_map_custom allocates new mem
40
+ options = UTF8PROC_STRIPNA;
41
+ *len = (size_t)utf8proc_map_custom((const utf8proc_uint8_t *)str, (utf8proc_ssize_t)*len, &output, options,
42
+ utf8proc_tolower1, NULL);
43
+ return (unsigned char *)output;
44
+ }
45
+ #endif // ndef NO_UTF8PROC
46
+
47
+ // zsv_strtolowercase(): to do: utf8 support
48
+ unsigned char *zsv_strtolowercase_w_err(const unsigned char *s, size_t *lenp, int *err) {
49
+ *err = 0;
50
+ #ifndef NO_UTF8PROC
51
+ size_t len_orig = *lenp;
52
+ unsigned char *new_s = utf8proc_tolower_str(s, lenp);
53
+ if (!new_s && len_orig) {
54
+ *err = 1;
55
+ unsigned char *tmp_s = malloc(len_orig + 1);
56
+ if (tmp_s) {
57
+ memcpy(tmp_s, s, len_orig);
58
+ tmp_s[len_orig] = '\0';
59
+ *lenp = zsv_strencode(tmp_s, len_orig, '?', NULL, NULL);
60
+ new_s = utf8proc_tolower_str(tmp_s, lenp);
61
+ free(tmp_s);
62
+ }
63
+ }
64
+ #else // ndef NO_UTF8PROC
65
+ unsigned char *new_s = malloc((*lenp + 1) * sizeof(*new_s));
66
+ if (new_s) {
67
+ for (size_t i = 0, j = *lenp; i < j; i++)
68
+ new_s[i] = tolower(s[i]);
69
+ new_s[*lenp] = '\0';
70
+ }
71
+ #endif // ndef NO_UTF8PROC
72
+ return new_s;
73
+ }
74
+
75
+ unsigned char *zsv_strtolowercase(const unsigned char *s, size_t *lenp) {
76
+ int err;
77
+ size_t len_orig = *lenp;
78
+ unsigned char *result = zsv_strtolowercase_w_err(s, lenp, &err);
79
+ if (err)
80
+ fprintf(stderr, "Warning: malformed UTF8 '%.*s'\n", (int)len_orig, s);
81
+ return result;
82
+ }
83
+
84
+ // zsv_strstr(): strstr
85
+ const unsigned char *zsv_strstr(const unsigned char *hay, const unsigned char *needle) {
86
+ return (const unsigned char *)strstr((const char *)hay, (const char *)needle);
87
+ }
88
+
89
+ /*
90
+ * zsv_stricmp, zsv_strincmp(): case-insensitive comparison
91
+ *
92
+ * @param s1 string to convert
93
+ * @param len1 length of s1
94
+ * @param s2 string to convert
95
+ * @param len2 length of s2
96
+ */
97
+ int zsv_stricmp(const unsigned char *s1, const unsigned char *s2) {
98
+ return zsv_strincmp(s1, strlen((const char *)s1), s2, strlen((const char *)s2));
99
+ }
100
+
101
+ int zsv_strincmp_ascii(const unsigned char *s1, size_t len1, const unsigned char *s2, size_t len2) {
102
+ while (len1 && len2) {
103
+ if (!*s1)
104
+ return *s2 == 0 ? 0 : -1;
105
+ if (!*s2)
106
+ return 1;
107
+ int c1 = tolower(*s1);
108
+ int c2 = tolower(*s2);
109
+ if (c1 == c2) {
110
+ s1++, s2++, len1--, len2--;
111
+ } else
112
+ return c1 < c2 ? -1 : 1;
113
+ }
114
+ return len1 > len2 ? 1 : len1 < len2 ? -1 : 0;
115
+ }
116
+
117
+ int zsv_strincmp(const unsigned char *s1, size_t len1, const unsigned char *s2, size_t len2) {
118
+ #ifndef NO_UTF8PROC
119
+ unsigned char *lc1 = zsv_strtolowercase(s1, &len1);
120
+ unsigned char *lc2 = zsv_strtolowercase(s2, &len2);
121
+ int result;
122
+ if (VERY_UNLIKELY(!lc1 || !lc2))
123
+ fprintf(stderr, "Out of memory!\n"), result = -2;
124
+ else
125
+ result = strcmp((char *)lc1, (char *)lc2);
126
+ free(lc1);
127
+ free(lc2);
128
+ return result;
129
+ #else
130
+ return zsv_strincmp_ascii(s1, len1, s2, len2);
131
+ #endif
132
+ }
133
+
134
+ __attribute__((always_inline)) static inline const unsigned char *zsv_strtrim_left_inline(
135
+ const char unsigned *restrict s, size_t *lenp) {
136
+ utf8proc_ssize_t bytes_read;
137
+ utf8proc_int32_t codepoint = 0;
138
+ size_t len = *lenp;
139
+ utf8proc_category_t category;
140
+
141
+ // trim front
142
+ while ((bytes_read = zsv_strnext(s, len, &codepoint)) > 0 &&
143
+ ((category = utf8proc_category(codepoint)) == UTF8PROC_CATEGORY_ZS || category == UTF8PROC_CATEGORY_ZL ||
144
+ category == UTF8PROC_CATEGORY_ZP)) {
145
+ s += bytes_read;
146
+ len -= bytes_read;
147
+ }
148
+ *lenp = len;
149
+ return s;
150
+ }
151
+
152
+ __attribute__((always_inline)) static inline const unsigned char *zsv_strtrim_right_inline(
153
+ const char unsigned *restrict s, size_t *lenp) {
154
+ utf8proc_ssize_t bytes_read;
155
+ utf8proc_int32_t codepoint = 0;
156
+ size_t len = *lenp;
157
+ utf8proc_category_t category;
158
+
159
+ // trim back
160
+ while ((bytes_read = zsv_strlast(s, len, (int32_t *)&codepoint)) > 0 &&
161
+ ((category = utf8proc_category(codepoint)) == UTF8PROC_CATEGORY_ZS || category == UTF8PROC_CATEGORY_ZL ||
162
+ category == UTF8PROC_CATEGORY_ZP)) {
163
+ len -= bytes_read;
164
+ }
165
+ *lenp = len;
166
+ return s;
167
+ }
168
+
169
+ const unsigned char *zsv_strtrim_right(const char unsigned *restrict s, size_t *lenp) {
170
+ return zsv_strtrim_right_inline(s, lenp);
171
+ }
172
+
173
+ const unsigned char *zsv_strtrim_left(const char unsigned *restrict s, size_t *lenp) {
174
+ return zsv_strtrim_left_inline(s, lenp);
175
+ }
176
+
177
+ const unsigned char *zsv_strtrim(const char unsigned *restrict s, size_t *lenp) {
178
+ s = zsv_strtrim_left_inline(s, lenp);
179
+ return zsv_strtrim_right_inline(s, lenp);
180
+ }
181
+
182
+ size_t zsv_strnext(const unsigned char *s, size_t len, int32_t *codepoint) {
183
+ utf8proc_ssize_t bytes_read = utf8proc_iterate(s, len, (utf8proc_int32_t *)codepoint);
184
+ if (bytes_read < 1)
185
+ return 0;
186
+ return (size_t)bytes_read;
187
+ }
188
+
189
+ /**
190
+ * Return the 1-based position of the last byte
191
+ */
192
+ __attribute__((always_inline)) static inline size_t zsv_strlast_position(const unsigned char *s, size_t len) {
193
+ // from the end, search backwards for the first byte that begins with 0 or 11
194
+ while (len && !(s[len - 1] < 128 || s[len - 1] >= 192))
195
+ len--;
196
+ return len;
197
+ }
198
+
199
+ size_t zsv_strlast(const unsigned char *s, size_t len, int32_t *codepoint) {
200
+ size_t position = zsv_strlast_position(s, len);
201
+ if (position) {
202
+ position--;
203
+ return zsv_strnext(s + position, len - position, codepoint);
204
+ }
205
+ return 0;
206
+ }
207
+
208
+ /**
209
+ * Check if the next char is a currency char. If so, return its length, else return 0
210
+ */
211
+ size_t zsv_strnext_is_currency(const unsigned char *s, size_t len) {
212
+ utf8proc_int32_t codepoint;
213
+ utf8proc_ssize_t bytes_read = utf8proc_iterate(s, len, &codepoint);
214
+ if (VERY_LIKELY(bytes_read > 0)) {
215
+ utf8proc_category_t category = utf8proc_category(codepoint);
216
+ if (category == UTF8PROC_CATEGORY_SC)
217
+ return (size_t)bytes_read;
218
+ }
219
+ return 0;
220
+ }
221
+
222
+ /**
223
+ * Check if the next char is a plus or minus. If so, return its length, else return 0
224
+ */
225
+ size_t zsv_strnext_is_sign(const unsigned char *s, size_t len) {
226
+ if (len && *s == '+')
227
+ return 1;
228
+
229
+ utf8proc_int32_t codepoint;
230
+ utf8proc_ssize_t bytes_read = utf8proc_iterate(s, len, &codepoint);
231
+ if (VERY_LIKELY(bytes_read > 0)) {
232
+ utf8proc_category_t category = utf8proc_category(codepoint);
233
+ if (category == UTF8PROC_CATEGORY_PD)
234
+ return (size_t)bytes_read;
235
+ }
236
+ return 0;
237
+ }
238
+
239
+ /**
240
+ * zsv_strwhite(): convert consecutive white to single space
241
+ *
242
+ * @param s string to convert
243
+ * @param len length of input string
244
+ * @param flags bitfield of ZSV_STRWHITE_FLAG_XXX values
245
+ */
246
+ size_t zsv_strwhite(unsigned char *s, size_t len, unsigned int flags) {
247
+ int this_is_space, last_was_space = 0;
248
+ size_t new_len = 0;
249
+ char replacement = ' ';
250
+ int clen;
251
+
252
+ for (size_t i = 0; i < len; i += clen) {
253
+ #ifndef NO_UTF8PROC
254
+ clen = ZSV_UTF8_CHARLEN(s[i]);
255
+ this_is_space = 0;
256
+ if (UNLIKELY(clen < 1 || i + clen > len)) { // bad UTF8. replace w '?'
257
+ clen = 1;
258
+ s[i] = '?';
259
+ } else if (UNLIKELY(clen > 1)) { // multi-byte UTF8
260
+ utf8proc_int32_t codepoint;
261
+ utf8proc_ssize_t bytes_read = utf8proc_iterate(s + i, clen, &codepoint);
262
+ if (UNLIKELY(bytes_read < 1)) { // error! but this could only happen if ZSV_UTF8_CHARLEN was wrong
263
+ clen = 1;
264
+ s[i] = '?';
265
+ } else {
266
+ utf8proc_category_t category = utf8proc_category(codepoint);
267
+ switch (category) { // Unicode space categories
268
+ case UTF8PROC_CATEGORY_ZL: // line separator
269
+ case UTF8PROC_CATEGORY_ZP: // paragraph separator
270
+ this_is_space = 1;
271
+ s[i] = (flags & ZSV_STRWHITE_FLAG_NO_EMBEDDED_NEWLINE ? ' ' : '\n');
272
+ break;
273
+ case UTF8PROC_CATEGORY_ZS: // regular space
274
+ this_is_space = 1;
275
+ s[i] = ' ';
276
+ break;
277
+ default:
278
+ break;
279
+ }
280
+ }
281
+ } else { // regular ascii, clen == 1
282
+ this_is_space = isspace(s[i]);
283
+ }
284
+ #else // no UTF8PROC, assume clen = 1
285
+ {
286
+ clen = 1;
287
+ this_is_space = isspace(s[i]);
288
+ }
289
+ #endif // ndef NO_UTF8PROC
290
+
291
+ if (this_is_space) {
292
+ if (UNLIKELY((s[i] == '\n' || s[i] == '\r')) && !(flags & ZSV_STRWHITE_FLAG_NO_EMBEDDED_NEWLINE))
293
+ replacement = '\n';
294
+ else if (!last_was_space)
295
+ replacement = ' ';
296
+ last_was_space = 1;
297
+ } else {
298
+ // current position is not a space
299
+ if (last_was_space)
300
+ s[new_len++] = replacement;
301
+ for (int j = 0; j < clen; j++)
302
+ s[new_len++] = s[i + j];
303
+ last_was_space = 0;
304
+ }
305
+ }
306
+ return new_len;
307
+ }
308
+
309
+ size_t zsv_strip_trailing_zeros(const char *s, size_t len) {
310
+ if (len && memchr(s, '.', len)) {
311
+ while (len && s[len - 1] == '0')
312
+ len--;
313
+ if (len && s[len - 1] == '.')
314
+ len--;
315
+ }
316
+ return len;
317
+ }
318
+
319
+ /**
320
+ * zsv_strunescape_backslash(): convert consecutive white to single space
321
+ *
322
+ * @param s string to convert
323
+ * @param len length of input string
324
+ * @param flags bitfield of ZSV_STRWHITE_FLAG_XXX values
325
+ */
326
+ size_t zsv_strunescape_backslash(unsigned char *s, size_t len) {
327
+ if (len == 0 || !memchr(s, '\\', len - 1))
328
+ return len;
329
+ size_t j = 0;
330
+ for (size_t i = 0; i < len; i++, j++) {
331
+ if (UNLIKELY(s[i] == '\\' && i + 1 < len && memchr("tnr", s[i + 1], 3))) {
332
+ ++i;
333
+ s[j] = s[i] == 't' ? '\t' : s[i] == 'n' ? '\n' : '\r';
334
+ } else
335
+ s[j] = s[i];
336
+ }
337
+ return j;
338
+ }
339
+
340
+ // zsv_strtod_exact(const char *s): return error; if 0, set value of *d
341
+ int zsv_strtod_exact(const char *s, double *d) {
342
+ if (!*s)
343
+ return 1;
344
+ char *end;
345
+ *d = strtod(s, &end);
346
+ if (*end)
347
+ return 1;
348
+ return 0;
349
+ }
350
+
351
+ #ifndef ZSV_STRING_LIB_ONLY
352
+ struct zsv_cell zsv_get_cell_trimmed(zsv_parser parser, size_t ix) {
353
+ struct zsv_cell c = zsv_get_cell(parser, ix);
354
+ c.str = (unsigned char *)zsv_strtrim(c.str, &c.len);
355
+ return c;
356
+ }
357
+ #endif
@@ -0,0 +1,83 @@
1
+ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
2
+ #include <windows.h>
3
+ #include <stdlib.h> // For malloc, free
4
+ #include <wchar.h> // Optional, primarily for wcslen if needed
5
+ #include <string.h> // For strncmp, wcslen, wcscpy_s, wcscat_s
6
+ #include <shlwapi.h> // For PathIsRelativeA
7
+ #include <stdio.h> // For printf, fprintf in main
8
+ // Link against -lShlwapi.for PathIsRelativeA
9
+
10
+ #include "io.h"
11
+
12
+ /**
13
+ * Check if a directory exists on Windows, supporting long paths (> MAX_PATH).
14
+ * Handles paths with or without the \\?\ prefix.
15
+ * Works even if directory exists but permissions are limited (as long as attributes can be read).
16
+ *
17
+ * @param path_utf8 The path to check (assumed to be UTF-8 encoded).
18
+ * @return Non-zero (true) if the path exists and is a directory, 0 (false) otherwise.
19
+ */
20
+ int zsv_dir_exists_winlp(const char *path_utf8) {
21
+ if (path_utf8 == NULL || path_utf8[0] == '\0') {
22
+ return 0; // Invalid or empty path
23
+ }
24
+
25
+ wchar_t *path_to_use;
26
+ DWORD rc = zsv_pathToPrefixedWidePath(path_utf8, &path_to_use);
27
+ if (rc)
28
+ return rc;
29
+
30
+ // --- 3. Call GetFileAttributesW ---
31
+ // fprintf(stderr, "Debug: Calling GetFileAttributesW with: %ls\n", path_to_use); // Debug print wide string
32
+ DWORD dwAttrib = GetFileAttributesW(path_to_use);
33
+
34
+ // --- 4. Check the result ---
35
+ int result;
36
+ if (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
37
+ // Path exists and it is a directory.
38
+ result = 1; // True
39
+ } else {
40
+ // Path does not exist, is not a directory, or access denied to get attributes.
41
+ // GetLastError() could distinguish these cases if needed.
42
+ // fprintf(stderr, "Debug: GetFileAttributesW failed or not a directory. Attributes: 0x%lX, LastError: %lu\n",
43
+ // dwAttrib, GetLastError());
44
+ result = 0; // False
45
+ }
46
+
47
+ // --- 5. Cleanup ---
48
+ free(path_to_use);
49
+ return result;
50
+ }
51
+
52
+ #ifdef ZSV_DIR_EXISTS_WINLP_TEST
53
+
54
+ // --- Main function for testing ---
55
+ int main(int argc, char *argv[]) {
56
+ // Check if a path argument was provided
57
+ if (argc != 2) {
58
+ // Note: argv[0] might not be UTF-8 on Windows console, print generic message
59
+ fprintf(stderr, "Usage: <program_name> <path_to_check>\n");
60
+ fprintf(stderr, "Example: %s C:\\Windows\n", argv[0] ? argv[0] : "checkdir");
61
+ fprintf(stderr, "Example: %s \"\\\\?\\C:\\Very Long Path Directory Name\"\n", argv[0] ? argv[0] : "checkdir");
62
+ fprintf(stderr, "Example: %s non_existent_dir\n", argv[0] ? argv[0] : "checkdir");
63
+ return 1; // Indicate error
64
+ }
65
+
66
+ // The path provided by the user
67
+ const char *path_to_check = argv[1];
68
+
69
+ printf("Checking path: '%s'\n", path_to_check);
70
+
71
+ // Call the directory checking function
72
+ int exists = zsv_dir_exists_winlp(path_to_check);
73
+
74
+ // Print the result
75
+ if (exists) {
76
+ printf("Result: Directory exists.\n");
77
+ } else {
78
+ printf("Result: Path does not exist or is not a directory.\n");
79
+ }
80
+
81
+ return 0; // Indicate success
82
+ }
83
+ #endif // ZSV_DIR_EXISTS_WINLP_TEST
@@ -0,0 +1,33 @@
1
+ /*
2
+ * Copyright (C) 2021 Liquidaty and the zsv/lib contributors
3
+ * All rights reserved
4
+ *
5
+ * This file is part of zsv/lib, distributed under the license defined at
6
+ * https://opensource.org/licenses/MIT
7
+ */
8
+
9
+ #ifdef _WIN32
10
+ #include <windows.h>
11
+ #include <zsv/utils/os.h>
12
+
13
+ #define RTLD_LAZY 0
14
+ void *dlsym(void *handle, const char *symbol) {
15
+ return (void *)GetProcAddress((HINSTANCE)(handle), (symbol));
16
+ }
17
+
18
+ void *dlopen(const char *dll_name, int flags) {
19
+ (void)flags;
20
+ wchar_t wbuf[PATH_MAX];
21
+ zsv_win_to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
22
+ return LoadLibraryW(wbuf);
23
+ }
24
+
25
+ int dlclose(void *handle) {
26
+ int result;
27
+ if (FreeLibrary((HMODULE)handle) != 0)
28
+ result = 0;
29
+ else
30
+ result = -1;
31
+ return result;
32
+ }
33
+ #endif
@@ -0,0 +1,184 @@
1
+ #include <windows.h>
2
+ #include <io.h> // For _open_osfhandle, _fdopen
3
+ #include <fcntl.h> // For _O_xxx flags
4
+ #include <stdio.h> // For FILE*, fopen modes, fclose etc.
5
+ #include <wchar.h> // For wchar_t
6
+ #include <stdlib.h> // For malloc, free
7
+
8
+ #include "io.h"
9
+
10
+ FILE *zsv_fopen_longpath(const char *utf8_path, const char *mode) {
11
+ wchar_t *wide_path_prefixed;
12
+ DWORD dwDesiredAccess = 0;
13
+ DWORD dwShareMode = FILE_SHARE_READ; // Example default
14
+ DWORD dwCreationDisposition = 0;
15
+ int c_runtime_flags = 0;
16
+ if (zsv_pathToPrefixedWidePath(utf8_path, &wide_path_prefixed))
17
+ return NULL;
18
+
19
+ // --- 2. Determine CreateFileW params and _open_osfhandle flags from mode string ---
20
+ if (strchr(mode, 'w')) {
21
+ dwDesiredAccess |= GENERIC_WRITE;
22
+ dwCreationDisposition = CREATE_ALWAYS; // Overwrite or create
23
+ c_runtime_flags |= _O_WRONLY;
24
+ } else if (strchr(mode, 'a')) {
25
+ dwDesiredAccess |= GENERIC_WRITE | FILE_APPEND_DATA; // Or just GENERIC_WRITE and seek later
26
+ dwCreationDisposition = OPEN_ALWAYS; // Append or create
27
+ c_runtime_flags |= _O_WRONLY | _O_APPEND;
28
+ } else { // Default to read
29
+ dwDesiredAccess |= GENERIC_READ;
30
+ dwCreationDisposition = OPEN_EXISTING;
31
+ c_runtime_flags |= _O_RDONLY;
32
+ }
33
+
34
+ if (strchr(mode, '+')) { // Read and write modes
35
+ dwDesiredAccess |= GENERIC_READ | GENERIC_WRITE;
36
+ c_runtime_flags &= ~(_O_RDONLY | _O_WRONLY); // Clear read/write only flags
37
+ c_runtime_flags |= _O_RDWR;
38
+ if (!strchr(mode, 'w')) { // If it wasn't 'w+', it implies 'r+' or 'a+'
39
+ dwCreationDisposition = OPEN_ALWAYS; // Make sure it opens if exists
40
+ }
41
+ }
42
+
43
+ if (strchr(mode, 'b')) {
44
+ c_runtime_flags |= _O_BINARY;
45
+ } else {
46
+ c_runtime_flags |= _O_TEXT;
47
+ }
48
+
49
+ // --- 3. Call CreateFileW ---
50
+ HANDLE hFile = CreateFileW(wide_path_prefixed, dwDesiredAccess, dwShareMode,
51
+ NULL, // Default security attributes
52
+ dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
53
+
54
+ free(wide_path_prefixed); // Don't need the string anymore
55
+
56
+ if (hFile == INVALID_HANDLE_VALUE) {
57
+ // Handle CreateFileW error (use GetLastError())
58
+ return NULL;
59
+ }
60
+
61
+ // --- 4. Convert HANDLE to C file descriptor ---
62
+ int fd = _open_osfhandle((intptr_t)hFile, c_runtime_flags);
63
+ if (fd == -1) {
64
+ // Handle _open_osfhandle error
65
+ CloseHandle(hFile); // Crucial: Close handle if fd conversion fails!
66
+ return NULL;
67
+ }
68
+
69
+ // --- 5. Convert file descriptor to FILE* stream ---
70
+ FILE *fp = _fdopen(fd, mode);
71
+ if (fp == NULL) {
72
+ // Handle _fdopen error
73
+ // Note: If _fdopen fails, the C runtime might or might not have
74
+ // taken ownership and closed the fd/handle. It's safer to assume
75
+ // it might not have, but closing the original hFile here is risky
76
+ // as _fdopen might have associated it. Usually, _close(fd) is
77
+ // appropriate here IF _fdopen fails, as _close *should* release the handle.
78
+ _close(fd); // Close the C descriptor; this should close the underlying handle.
79
+ return NULL;
80
+ }
81
+
82
+ // --- 6. Success ---
83
+ return fp;
84
+ // Remember: fclose(fp) will clean up fd and hFile later.
85
+ }
86
+
87
+ #ifdef ZSV_DIRS_FOPEN_LONGPATH_TEST
88
+
89
+ #include "win/io.c"
90
+
91
+ int main(int argc, char *argv[]) {
92
+ if (argc < 3 || argc > 4) {
93
+ fprintf(stderr, "Usage:\n");
94
+ fprintf(stderr, " For writing: %s w <absolute_filepath> [content_to_write]\n", argv[0]);
95
+ fprintf(stderr, " For reading: %s r <absolute_filepath>\n", argv[0]);
96
+ fprintf(stderr, "\nArguments:\n");
97
+ fprintf(stderr, " mode: 'w' (write - overwrites/creates) or 'r' (read)\n");
98
+ fprintf(stderr, " absolute_filepath: The full, absolute path to the file (can exceed MAX_PATH).\n");
99
+ fprintf(stderr, " Use quotes if the path contains spaces.\n");
100
+ fprintf(stderr, " content_to_write (optional): Text to write to the file if mode is 'w'.\n");
101
+ fprintf(stderr, " If omitted in write mode, default text is written.\n");
102
+ fprintf(stderr, "\nExample (Write):\n");
103
+ fprintf(stderr, " %s w \"C:\\Temp\\Long Path Folder\\very_long_filename_that_works.txt\" \"Hello Long World!\"\n",
104
+ argv[0]);
105
+ fprintf(stderr, "Example (Read):\n");
106
+ fprintf(stderr, " %s r \"\\\\?\\C:\\Temp\\Long Path Folder\\very_long_filename_that_works.txt\"\n", argv[0]);
107
+ return 1;
108
+ }
109
+
110
+ const char *mode_arg = argv[1];
111
+ const char *filepath_arg = argv[2];
112
+ const char *content_arg = (argc == 4 && strcmp(mode_arg, "w") == 0) ? argv[3] : NULL;
113
+ const char *default_content = "Default content written by fopen_longpath test.\n";
114
+
115
+ char file_mode[4] = ""; // e.g., "rb", "wt", etc. (Max 3 chars + null)
116
+
117
+ if (strcmp(mode_arg, "w") == 0) {
118
+ strcpy(file_mode, "w"); // Use text mode by default for simplicity
119
+ } else if (strcmp(mode_arg, "r") == 0) {
120
+ strcpy(file_mode, "r"); // Use text mode by default
121
+ } else {
122
+ fprintf(stderr, "Error: Invalid mode '%s'. Use 'r' or 'w'.\n", mode_arg);
123
+ return 1;
124
+ }
125
+
126
+ printf("Attempting to open file: %s (Mode: %s)\n", filepath_arg, file_mode);
127
+
128
+ FILE *fp = fopen_longpath(filepath_arg, file_mode);
129
+
130
+ if (fp == NULL) {
131
+ // fopen_longpath should have printed specific errors
132
+ fprintf(stderr, "Main: Failed to open file using fopen_longpath.\n");
133
+ return 1;
134
+ }
135
+
136
+ printf("Main: File opened successfully.\n");
137
+ int operation_status = 0; // 0 for success, non-zero for error
138
+
139
+ // --- Perform Read or Write ---
140
+ if (strcmp(mode_arg, "w") == 0) {
141
+ const char *content_to_write = (content_arg != NULL) ? content_arg : default_content;
142
+ printf("Main: Writing content: \"%s\"\n", content_to_write);
143
+ if (fputs(content_to_write, fp) == EOF) {
144
+ perror("Main: Error writing to file");
145
+ operation_status = 1;
146
+ } else {
147
+ // Add a newline if user content didn't end with one
148
+ if (content_to_write[strlen(content_to_write) - 1] != '\n') {
149
+ if (fputc('\n', fp) == EOF) {
150
+ perror("Main: Error writing newline to file");
151
+ operation_status = 1;
152
+ }
153
+ }
154
+ printf("Main: Write operation successful.\n");
155
+ }
156
+
157
+ } else { // Mode is 'r'
158
+ printf("Main: Reading file content:\n---\n");
159
+ char buffer[1024];
160
+ while (fgets(buffer, sizeof(buffer), fp) != NULL) {
161
+ printf("%s", buffer); // Print line including its newline
162
+ }
163
+ if (ferror(fp)) {
164
+ perror("Main: Error reading from file");
165
+ operation_status = 1;
166
+ } else {
167
+ printf("\n---\nMain: Read operation finished.\n");
168
+ // Reaching EOF without ferror is success
169
+ }
170
+ }
171
+
172
+ // --- Close the file ---
173
+ printf("Main: Closing file.\n");
174
+ if (fclose(fp) != 0) {
175
+ perror("Main: Error closing file");
176
+ // Continue, but report overall failure if write/read also failed
177
+ if (operation_status == 0)
178
+ operation_status = 1;
179
+ }
180
+
181
+ return operation_status; // 0 if all successful, 1 if any error occurred
182
+ }
183
+
184
+ #endif // ZSV_DIRS_FOPEN_LONGPATH_TEST