contrast-agent 3.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (500) hide show
  1. checksums.yaml +7 -0
  2. data/.clang-format +5 -0
  3. data/.dockerignore +10 -0
  4. data/.gitignore +58 -0
  5. data/.gitmodules +6 -0
  6. data/.rspec +6 -0
  7. data/.simplecov +4 -0
  8. data/Gemfile +7 -0
  9. data/LICENSE.txt +12 -0
  10. data/Rakefile +15 -0
  11. data/exe/contrast_service +29 -0
  12. data/ext/build_funchook.rb +48 -0
  13. data/ext/cs__assess_active_record_named/cs__active_record_named.c +47 -0
  14. data/ext/cs__assess_active_record_named/cs__active_record_named.h +10 -0
  15. data/ext/cs__assess_active_record_named/extconf.rb +2 -0
  16. data/ext/cs__assess_array/cs__assess_array.c +38 -0
  17. data/ext/cs__assess_array/cs__assess_array.h +9 -0
  18. data/ext/cs__assess_array/extconf.rb +2 -0
  19. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +50 -0
  20. data/ext/cs__assess_basic_object/cs__assess_basic_object.h +17 -0
  21. data/ext/cs__assess_basic_object/extconf.rb +2 -0
  22. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +86 -0
  23. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.h +34 -0
  24. data/ext/cs__assess_fiber_track/extconf.rb +2 -0
  25. data/ext/cs__assess_hash/cs__assess_hash.c +64 -0
  26. data/ext/cs__assess_hash/cs__assess_hash.h +24 -0
  27. data/ext/cs__assess_hash/extconf.rb +2 -0
  28. data/ext/cs__assess_kernel/cs__assess_kernel.c +36 -0
  29. data/ext/cs__assess_kernel/cs__assess_kernel.h +10 -0
  30. data/ext/cs__assess_kernel/extconf.rb +2 -0
  31. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +47 -0
  32. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +18 -0
  33. data/ext/cs__assess_marshal_module/extconf.rb +2 -0
  34. data/ext/cs__assess_module/cs__assess_module.c +78 -0
  35. data/ext/cs__assess_module/cs__assess_module.h +25 -0
  36. data/ext/cs__assess_module/extconf.rb +2 -0
  37. data/ext/cs__assess_regexp/cs__assess_regexp.c +48 -0
  38. data/ext/cs__assess_regexp/cs__assess_regexp.h +22 -0
  39. data/ext/cs__assess_regexp/extconf.rb +2 -0
  40. data/ext/cs__assess_regexp_track/cs__assess_regexp_track.c +63 -0
  41. data/ext/cs__assess_regexp_track/cs__assess_regexp_track.h +29 -0
  42. data/ext/cs__assess_regexp_track/extconf.rb +2 -0
  43. data/ext/cs__assess_string/cs__assess_string.c +38 -0
  44. data/ext/cs__assess_string/cs__assess_string.h +19 -0
  45. data/ext/cs__assess_string/extconf.rb +2 -0
  46. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +31 -0
  47. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.h +13 -0
  48. data/ext/cs__assess_string_interpolation26/extconf.rb +2 -0
  49. data/ext/cs__common/cs__common.c +60 -0
  50. data/ext/cs__common/cs__common.h +28 -0
  51. data/ext/cs__common/extconf.rb +20 -0
  52. data/ext/cs__contrast_patch/cs__contrast_patch.c +445 -0
  53. data/ext/cs__contrast_patch/cs__contrast_patch.h +196 -0
  54. data/ext/cs__contrast_patch/extconf.rb +2 -0
  55. data/ext/cs__protect_kernel/cs__protect_kernel.c +37 -0
  56. data/ext/cs__protect_kernel/cs__protect_kernel.h +11 -0
  57. data/ext/cs__protect_kernel/extconf.rb +2 -0
  58. data/ext/cs__scope/cs__scope.c +96 -0
  59. data/ext/cs__scope/cs__scope.h +33 -0
  60. data/ext/cs__scope/extconf.rb +2 -0
  61. data/ext/extconf_common.rb +49 -0
  62. data/funchook/LICENSE +360 -0
  63. data/funchook/Makefile +29 -0
  64. data/funchook/Makefile.in +29 -0
  65. data/funchook/README.md +121 -0
  66. data/funchook/appveyor.yml +42 -0
  67. data/funchook/autogen.sh +3 -0
  68. data/funchook/autom4te.cache/output.0 +4976 -0
  69. data/funchook/autom4te.cache/requests +78 -0
  70. data/funchook/autom4te.cache/traces.0 +364 -0
  71. data/funchook/config.guess +1530 -0
  72. data/funchook/config.log +490 -0
  73. data/funchook/config.status +1016 -0
  74. data/funchook/config.sub +1773 -0
  75. data/funchook/configure +4976 -0
  76. data/funchook/configure.ac +59 -0
  77. data/funchook/distorm/COPYING +26 -0
  78. data/funchook/distorm/MANIFEST +25 -0
  79. data/funchook/distorm/MANIFEST.in +4 -0
  80. data/funchook/distorm/README.md +12 -0
  81. data/funchook/distorm/disOps/disOps.py +795 -0
  82. data/funchook/distorm/disOps/x86db.py +404 -0
  83. data/funchook/distorm/disOps/x86header.py +247 -0
  84. data/funchook/distorm/disOps/x86sets.py +1664 -0
  85. data/funchook/distorm/examples/cs/TestdiStorm/Program.cs +79 -0
  86. data/funchook/distorm/examples/cs/TestdiStorm/Properties/AssemblyInfo.cs +36 -0
  87. data/funchook/distorm/examples/cs/TestdiStorm/TestdiStorm.csproj +69 -0
  88. data/funchook/distorm/examples/cs/distorm-net.sln +26 -0
  89. data/funchook/distorm/examples/cs/distorm-net/CodeInfo.cs +23 -0
  90. data/funchook/distorm/examples/cs/distorm-net/DecodedInst.cs +15 -0
  91. data/funchook/distorm/examples/cs/distorm-net/DecodedResult.cs +14 -0
  92. data/funchook/distorm/examples/cs/distorm-net/DecomposedInst.cs +36 -0
  93. data/funchook/distorm/examples/cs/distorm-net/DecomposedResult.cs +14 -0
  94. data/funchook/distorm/examples/cs/distorm-net/Opcodes.cs +1268 -0
  95. data/funchook/distorm/examples/cs/distorm-net/Opcodes.tt +37 -0
  96. data/funchook/distorm/examples/cs/distorm-net/Operand.cs +25 -0
  97. data/funchook/distorm/examples/cs/distorm-net/Properties/AssemblyInfo.cs +36 -0
  98. data/funchook/distorm/examples/cs/distorm-net/diStorm3.cs +411 -0
  99. data/funchook/distorm/examples/cs/distorm-net/distorm-net.csproj +80 -0
  100. data/funchook/distorm/examples/cs/readme +3 -0
  101. data/funchook/distorm/examples/ddk/README +48 -0
  102. data/funchook/distorm/examples/ddk/distorm.ini +11 -0
  103. data/funchook/distorm/examples/ddk/dummy.c +15 -0
  104. data/funchook/distorm/examples/ddk/main.c +91 -0
  105. data/funchook/distorm/examples/ddk/makefile +1 -0
  106. data/funchook/distorm/examples/ddk/sources +10 -0
  107. data/funchook/distorm/examples/java/Makefile +23 -0
  108. data/funchook/distorm/examples/java/distorm/src/Main.java +43 -0
  109. data/funchook/distorm/examples/java/distorm/src/diStorm3/CodeInfo.java +27 -0
  110. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedInst.java +32 -0
  111. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedResult.java +11 -0
  112. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedInst.java +89 -0
  113. data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedResult.java +11 -0
  114. data/funchook/distorm/examples/java/distorm/src/diStorm3/OpcodeEnum.java +131 -0
  115. data/funchook/distorm/examples/java/distorm/src/diStorm3/Opcodes.java +1123 -0
  116. data/funchook/distorm/examples/java/distorm/src/diStorm3/Operand.java +24 -0
  117. data/funchook/distorm/examples/java/distorm/src/diStorm3/distorm3.java +41 -0
  118. data/funchook/distorm/examples/java/jdistorm.c +405 -0
  119. data/funchook/distorm/examples/java/jdistorm.h +40 -0
  120. data/funchook/distorm/examples/java/jdistorm.sln +20 -0
  121. data/funchook/distorm/examples/java/jdistorm.vcproj +208 -0
  122. data/funchook/distorm/examples/linux/Makefile +15 -0
  123. data/funchook/distorm/examples/linux/main.c +181 -0
  124. data/funchook/distorm/examples/tests/Makefile +15 -0
  125. data/funchook/distorm/examples/tests/main.cpp +42 -0
  126. data/funchook/distorm/examples/tests/main.py +66 -0
  127. data/funchook/distorm/examples/tests/test_distorm3.py +1672 -0
  128. data/funchook/distorm/examples/tests/tests.sln +20 -0
  129. data/funchook/distorm/examples/tests/tests.vcxproj +82 -0
  130. data/funchook/distorm/examples/tests/tests.vcxproj.filters +22 -0
  131. data/funchook/distorm/examples/win32/disasm.sln +25 -0
  132. data/funchook/distorm/examples/win32/disasm.vcxproj +201 -0
  133. data/funchook/distorm/examples/win32/disasm.vcxproj.filters +14 -0
  134. data/funchook/distorm/examples/win32/main.cpp +163 -0
  135. data/funchook/distorm/include/distorm.h +482 -0
  136. data/funchook/distorm/include/mnemonics.h +301 -0
  137. data/funchook/distorm/make/linux/Makefile +28 -0
  138. data/funchook/distorm/make/mac/Makefile +24 -0
  139. data/funchook/distorm/make/win32/cdistorm.vcxproj +239 -0
  140. data/funchook/distorm/make/win32/cdistorm.vcxproj.filters +80 -0
  141. data/funchook/distorm/make/win32/distorm.sln +25 -0
  142. data/funchook/distorm/make/win32/resource.h +14 -0
  143. data/funchook/distorm/make/win32/resource.rc +99 -0
  144. data/funchook/distorm/python/distorm3/__init__.py +957 -0
  145. data/funchook/distorm/python/distorm3/sample.py +51 -0
  146. data/funchook/distorm/setup.cfg +10 -0
  147. data/funchook/distorm/setup.py +266 -0
  148. data/funchook/distorm/src/config.h +169 -0
  149. data/funchook/distorm/src/decoder.c +641 -0
  150. data/funchook/distorm/src/decoder.h +33 -0
  151. data/funchook/distorm/src/distorm.c +413 -0
  152. data/funchook/distorm/src/instructions.c +597 -0
  153. data/funchook/distorm/src/instructions.h +463 -0
  154. data/funchook/distorm/src/insts.c +7939 -0
  155. data/funchook/distorm/src/insts.h +64 -0
  156. data/funchook/distorm/src/mnemonics.c +284 -0
  157. data/funchook/distorm/src/operands.c +1290 -0
  158. data/funchook/distorm/src/operands.h +28 -0
  159. data/funchook/distorm/src/prefix.c +368 -0
  160. data/funchook/distorm/src/prefix.h +64 -0
  161. data/funchook/distorm/src/textdefs.c +172 -0
  162. data/funchook/distorm/src/textdefs.h +57 -0
  163. data/funchook/distorm/src/wstring.c +47 -0
  164. data/funchook/distorm/src/wstring.h +35 -0
  165. data/funchook/distorm/src/x86defs.h +82 -0
  166. data/funchook/include/funchook.h +123 -0
  167. data/funchook/install-sh +527 -0
  168. data/funchook/src/Makefile +70 -0
  169. data/funchook/src/Makefile.in +70 -0
  170. data/funchook/src/__strerror.h +109 -0
  171. data/funchook/src/config.h +101 -0
  172. data/funchook/src/config.h.in +100 -0
  173. data/funchook/src/decoder.o +0 -0
  174. data/funchook/src/distorm.o +0 -0
  175. data/funchook/src/funchook.c +440 -0
  176. data/funchook/src/funchook.o +0 -0
  177. data/funchook/src/funchook_internal.h +155 -0
  178. data/funchook/src/funchook_io.c +182 -0
  179. data/funchook/src/funchook_io.h +64 -0
  180. data/funchook/src/funchook_io.o +0 -0
  181. data/funchook/src/funchook_syscall.S +134 -0
  182. data/funchook/src/funchook_syscall.o +0 -0
  183. data/funchook/src/funchook_unix.c +480 -0
  184. data/funchook/src/funchook_unix.o +0 -0
  185. data/funchook/src/funchook_windows.c +397 -0
  186. data/funchook/src/funchook_x86.c +622 -0
  187. data/funchook/src/funchook_x86.o +0 -0
  188. data/funchook/src/instructions.o +0 -0
  189. data/funchook/src/insts.o +0 -0
  190. data/funchook/src/libfunchook.so +0 -0
  191. data/funchook/src/mnemonics.o +0 -0
  192. data/funchook/src/operands.o +0 -0
  193. data/funchook/src/os_func.c +115 -0
  194. data/funchook/src/os_func.h +75 -0
  195. data/funchook/src/os_func.o +0 -0
  196. data/funchook/src/os_func_unix.c +94 -0
  197. data/funchook/src/os_func_unix.o +0 -0
  198. data/funchook/src/os_func_windows.c +32 -0
  199. data/funchook/src/prefix.o +0 -0
  200. data/funchook/src/printf_base.c +1688 -0
  201. data/funchook/src/printf_base.h +46 -0
  202. data/funchook/src/printf_base.o +0 -0
  203. data/funchook/src/textdefs.o +0 -0
  204. data/funchook/src/wstring.o +0 -0
  205. data/funchook/test/Makefile +43 -0
  206. data/funchook/test/Makefile.in +43 -0
  207. data/funchook/test/funchook_test +0 -0
  208. data/funchook/test/libfunchook_test.c +25 -0
  209. data/funchook/test/libfunchook_test.so +0 -0
  210. data/funchook/test/libfunchook_test2.c +18 -0
  211. data/funchook/test/suffix.list +600 -0
  212. data/funchook/test/test_main.c +430 -0
  213. data/funchook/test/test_main.o +0 -0
  214. data/funchook/test/x86_64_test.S +10 -0
  215. data/funchook/test/x86_64_test.o +0 -0
  216. data/funchook/test/x86_test.S +339 -0
  217. data/funchook/win32/config.h +1 -0
  218. data/funchook/win32/funchook.sln +52 -0
  219. data/funchook/win32/funchook.vcxproj +188 -0
  220. data/funchook/win32/funchook.vcxproj.filters +84 -0
  221. data/funchook/win32/funchook_test.vcxproj +170 -0
  222. data/funchook/win32/funchook_test.vcxproj.filters +22 -0
  223. data/funchook/win32/funchook_test_dll.vcxproj +184 -0
  224. data/funchook/win32/funchook_test_dll.vcxproj.filters +30 -0
  225. data/funchook/win32/funchook_test_exe.def +3 -0
  226. data/lib/contrast-agent.rb +8 -0
  227. data/lib/contrast.rb +57 -0
  228. data/lib/contrast/agent.rb +80 -0
  229. data/lib/contrast/agent/assess.rb +45 -0
  230. data/lib/contrast/agent/assess/adjusted_span.rb +25 -0
  231. data/lib/contrast/agent/assess/class_reverter.rb +82 -0
  232. data/lib/contrast/agent/assess/contrast_event.rb +398 -0
  233. data/lib/contrast/agent/assess/frozen_properties.rb +41 -0
  234. data/lib/contrast/agent/assess/insulator.rb +53 -0
  235. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +78 -0
  236. data/lib/contrast/agent/assess/policy/patcher.rb +85 -0
  237. data/lib/contrast/agent/assess/policy/policy.rb +116 -0
  238. data/lib/contrast/agent/assess/policy/policy_node.rb +289 -0
  239. data/lib/contrast/agent/assess/policy/policy_scanner.rb +44 -0
  240. data/lib/contrast/agent/assess/policy/preshift.rb +94 -0
  241. data/lib/contrast/agent/assess/policy/propagation_method.rb +260 -0
  242. data/lib/contrast/agent/assess/policy/propagation_node.rb +127 -0
  243. data/lib/contrast/agent/assess/policy/propagator.rb +35 -0
  244. data/lib/contrast/agent/assess/policy/propagator/append.rb +54 -0
  245. data/lib/contrast/agent/assess/policy/propagator/base.rb +37 -0
  246. data/lib/contrast/agent/assess/policy/propagator/center.rb +73 -0
  247. data/lib/contrast/agent/assess/policy/propagator/custom.rb +36 -0
  248. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +62 -0
  249. data/lib/contrast/agent/assess/policy/propagator/insert.rb +55 -0
  250. data/lib/contrast/agent/assess/policy/propagator/keep.rb +26 -0
  251. data/lib/contrast/agent/assess/policy/propagator/next.rb +42 -0
  252. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +50 -0
  253. data/lib/contrast/agent/assess/policy/propagator/remove.rb +76 -0
  254. data/lib/contrast/agent/assess/policy/propagator/replace.rb +27 -0
  255. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +38 -0
  256. data/lib/contrast/agent/assess/policy/propagator/select.rb +86 -0
  257. data/lib/contrast/agent/assess/policy/propagator/splat.rb +60 -0
  258. data/lib/contrast/agent/assess/policy/propagator/split.rb +49 -0
  259. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +169 -0
  260. data/lib/contrast/agent/assess/policy/propagator/trim.rb +81 -0
  261. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +79 -0
  262. data/lib/contrast/agent/assess/policy/source_method.rb +209 -0
  263. data/lib/contrast/agent/assess/policy/source_node.rb +62 -0
  264. data/lib/contrast/agent/assess/policy/trigger_method.rb +209 -0
  265. data/lib/contrast/agent/assess/policy/trigger_node.rb +198 -0
  266. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +77 -0
  267. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +31 -0
  268. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +40 -0
  269. data/lib/contrast/agent/assess/properties.rb +392 -0
  270. data/lib/contrast/agent/assess/rule.rb +18 -0
  271. data/lib/contrast/agent/assess/rule/base.rb +72 -0
  272. data/lib/contrast/agent/assess/rule/csrf.rb +66 -0
  273. data/lib/contrast/agent/assess/rule/csrf/csrf_action.rb +28 -0
  274. data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +69 -0
  275. data/lib/contrast/agent/assess/rule/csrf/csrf_watcher.rb +132 -0
  276. data/lib/contrast/agent/assess/rule/provider.rb +21 -0
  277. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +62 -0
  278. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +73 -0
  279. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +121 -0
  280. data/lib/contrast/agent/assess/rule/redos.rb +68 -0
  281. data/lib/contrast/agent/assess/rule/response_scanning_rule.rb +47 -0
  282. data/lib/contrast/agent/assess/rule/response_watcher.rb +36 -0
  283. data/lib/contrast/agent/assess/rule/watcher.rb +36 -0
  284. data/lib/contrast/agent/assess/tag.rb +151 -0
  285. data/lib/contrast/agent/at_exit_hook.rb +33 -0
  286. data/lib/contrast/agent/class_reopener.rb +195 -0
  287. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +26 -0
  288. data/lib/contrast/agent/deadzone/policy/policy.rb +57 -0
  289. data/lib/contrast/agent/disable_reaction.rb +24 -0
  290. data/lib/contrast/agent/exclusion_matcher.rb +190 -0
  291. data/lib/contrast/agent/feature_state.rb +379 -0
  292. data/lib/contrast/agent/inventory/policy/policy.rb +32 -0
  293. data/lib/contrast/agent/inventory/policy/trigger_node.rb +22 -0
  294. data/lib/contrast/agent/logger_manager.rb +116 -0
  295. data/lib/contrast/agent/middleware.rb +352 -0
  296. data/lib/contrast/agent/module_data.rb +16 -0
  297. data/lib/contrast/agent/patching/policy/after_load_patch.rb +37 -0
  298. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +58 -0
  299. data/lib/contrast/agent/patching/policy/method_policy.rb +94 -0
  300. data/lib/contrast/agent/patching/policy/module_policy.rb +116 -0
  301. data/lib/contrast/agent/patching/policy/patch.rb +312 -0
  302. data/lib/contrast/agent/patching/policy/patch_status.rb +192 -0
  303. data/lib/contrast/agent/patching/policy/patcher.rb +310 -0
  304. data/lib/contrast/agent/patching/policy/policy.rb +138 -0
  305. data/lib/contrast/agent/patching/policy/policy_node.rb +80 -0
  306. data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +28 -0
  307. data/lib/contrast/agent/patching/policy/trigger_node.rb +81 -0
  308. data/lib/contrast/agent/protect/policy/policy.rb +37 -0
  309. data/lib/contrast/agent/protect/policy/trigger_node.rb +23 -0
  310. data/lib/contrast/agent/protect/rule.rb +58 -0
  311. data/lib/contrast/agent/protect/rule/base.rb +300 -0
  312. data/lib/contrast/agent/protect/rule/base_service.rb +88 -0
  313. data/lib/contrast/agent/protect/rule/cmd_injection.rb +156 -0
  314. data/lib/contrast/agent/protect/rule/csrf.rb +118 -0
  315. data/lib/contrast/agent/protect/rule/csrf/csrf_evaluator.rb +103 -0
  316. data/lib/contrast/agent/protect/rule/csrf/csrf_token_injector.rb +85 -0
  317. data/lib/contrast/agent/protect/rule/default_scanner.rb +300 -0
  318. data/lib/contrast/agent/protect/rule/deserialization.rb +193 -0
  319. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +80 -0
  320. data/lib/contrast/agent/protect/rule/no_sqli.rb +101 -0
  321. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +40 -0
  322. data/lib/contrast/agent/protect/rule/path_traversal.rb +143 -0
  323. data/lib/contrast/agent/protect/rule/sqli.rb +101 -0
  324. data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +16 -0
  325. data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +38 -0
  326. data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +22 -0
  327. data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +19 -0
  328. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +20 -0
  329. data/lib/contrast/agent/protect/rule/xss.rb +24 -0
  330. data/lib/contrast/agent/protect/rule/xxe.rb +120 -0
  331. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +82 -0
  332. data/lib/contrast/agent/railtie.rb +30 -0
  333. data/lib/contrast/agent/reaction_processor.rb +47 -0
  334. data/lib/contrast/agent/request.rb +493 -0
  335. data/lib/contrast/agent/request_context.rb +225 -0
  336. data/lib/contrast/agent/require_state.rb +61 -0
  337. data/lib/contrast/agent/response.rb +215 -0
  338. data/lib/contrast/agent/rewriter.rb +244 -0
  339. data/lib/contrast/agent/scope.rb +28 -0
  340. data/lib/contrast/agent/service_heartbeat.rb +37 -0
  341. data/lib/contrast/agent/settings_state.rb +148 -0
  342. data/lib/contrast/agent/socket_client.rb +125 -0
  343. data/lib/contrast/agent/thread.rb +26 -0
  344. data/lib/contrast/agent/tracepoint_hook.rb +51 -0
  345. data/lib/contrast/agent/version.rb +8 -0
  346. data/lib/contrast/api.rb +17 -0
  347. data/lib/contrast/api/.gitkeep +0 -0
  348. data/lib/contrast/api/connection_status.rb +49 -0
  349. data/lib/contrast/api/socket.rb +43 -0
  350. data/lib/contrast/api/speedracer.rb +206 -0
  351. data/lib/contrast/api/tcp_socket.rb +31 -0
  352. data/lib/contrast/api/unix_socket.rb +25 -0
  353. data/lib/contrast/common_agent_configuration.rb +86 -0
  354. data/lib/contrast/components/agent.rb +85 -0
  355. data/lib/contrast/components/app_context.rb +188 -0
  356. data/lib/contrast/components/assess.rb +67 -0
  357. data/lib/contrast/components/config.rb +135 -0
  358. data/lib/contrast/components/contrast_service.rb +113 -0
  359. data/lib/contrast/components/heap_dump.rb +34 -0
  360. data/lib/contrast/components/interface.rb +178 -0
  361. data/lib/contrast/components/inventory.rb +23 -0
  362. data/lib/contrast/components/logger.rb +92 -0
  363. data/lib/contrast/components/protect.rb +38 -0
  364. data/lib/contrast/components/sampling.rb +41 -0
  365. data/lib/contrast/components/scope.rb +106 -0
  366. data/lib/contrast/components/settings.rb +140 -0
  367. data/lib/contrast/config.rb +33 -0
  368. data/lib/contrast/config/agent_configuration.rb +24 -0
  369. data/lib/contrast/config/application_configuration.rb +27 -0
  370. data/lib/contrast/config/assess_configuration.rb +22 -0
  371. data/lib/contrast/config/assess_rules_configuration.rb +18 -0
  372. data/lib/contrast/config/base_configuration.rb +105 -0
  373. data/lib/contrast/config/default_value.rb +16 -0
  374. data/lib/contrast/config/exception_configuration.rb +21 -0
  375. data/lib/contrast/config/heap_dump_configuration.rb +23 -0
  376. data/lib/contrast/config/inventory_configuration.rb +20 -0
  377. data/lib/contrast/config/logger_configuration.rb +20 -0
  378. data/lib/contrast/config/protect_configuration.rb +20 -0
  379. data/lib/contrast/config/protect_rule_configuration.rb +37 -0
  380. data/lib/contrast/config/protect_rules_configuration.rb +30 -0
  381. data/lib/contrast/config/root_configuration.rb +26 -0
  382. data/lib/contrast/config/ruby_configuration.rb +39 -0
  383. data/lib/contrast/config/sampling_configuration.rb +22 -0
  384. data/lib/contrast/config/server_configuration.rb +23 -0
  385. data/lib/contrast/config/service_configuration.rb +22 -0
  386. data/lib/contrast/configuration.rb +214 -0
  387. data/lib/contrast/core_extensions/assess.rb +51 -0
  388. data/lib/contrast/core_extensions/assess/array.rb +58 -0
  389. data/lib/contrast/core_extensions/assess/assess_extension.rb +145 -0
  390. data/lib/contrast/core_extensions/assess/basic_object.rb +15 -0
  391. data/lib/contrast/core_extensions/assess/erb.rb +42 -0
  392. data/lib/contrast/core_extensions/assess/exec_trigger.rb +48 -0
  393. data/lib/contrast/core_extensions/assess/fiber.rb +125 -0
  394. data/lib/contrast/core_extensions/assess/hash.rb +22 -0
  395. data/lib/contrast/core_extensions/assess/kernel.rb +95 -0
  396. data/lib/contrast/core_extensions/assess/module.rb +14 -0
  397. data/lib/contrast/core_extensions/assess/regexp.rb +206 -0
  398. data/lib/contrast/core_extensions/assess/string.rb +75 -0
  399. data/lib/contrast/core_extensions/assess/tilt_template_trigger.rb +73 -0
  400. data/lib/contrast/core_extensions/delegator.rb +14 -0
  401. data/lib/contrast/core_extensions/eval_trigger.rb +52 -0
  402. data/lib/contrast/core_extensions/inventory.rb +22 -0
  403. data/lib/contrast/core_extensions/inventory/datastores.rb +37 -0
  404. data/lib/contrast/core_extensions/module.rb +42 -0
  405. data/lib/contrast/core_extensions/object.rb +27 -0
  406. data/lib/contrast/core_extensions/protect.rb +20 -0
  407. data/lib/contrast/core_extensions/protect/applies_command_injection_rule.rb +70 -0
  408. data/lib/contrast/core_extensions/protect/applies_deserialization_rule.rb +58 -0
  409. data/lib/contrast/core_extensions/protect/applies_no_sqli_rule.rb +81 -0
  410. data/lib/contrast/core_extensions/protect/applies_path_traversal_rule.rb +119 -0
  411. data/lib/contrast/core_extensions/protect/applies_sqli_rule.rb +63 -0
  412. data/lib/contrast/core_extensions/protect/applies_xxe_rule.rb +141 -0
  413. data/lib/contrast/core_extensions/protect/kernel.rb +30 -0
  414. data/lib/contrast/core_extensions/protect/psych.rb +7 -0
  415. data/lib/contrast/core_extensions/thread.rb +31 -0
  416. data/lib/contrast/internal_exception.rb +8 -0
  417. data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +48 -0
  418. data/lib/contrast/rails_extensions/assess/active_record.rb +32 -0
  419. data/lib/contrast/rails_extensions/assess/active_record_named.rb +61 -0
  420. data/lib/contrast/rails_extensions/assess/configuration.rb +26 -0
  421. data/lib/contrast/rails_extensions/buffer.rb +30 -0
  422. data/lib/contrast/rails_extensions/rack.rb +45 -0
  423. data/lib/contrast/security_exception.rb +14 -0
  424. data/lib/contrast/sinatra_extensions/assess/cookie.rb +26 -0
  425. data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +59 -0
  426. data/lib/contrast/tasks/service.rb +95 -0
  427. data/lib/contrast/utils/assess/sampling_util.rb +96 -0
  428. data/lib/contrast/utils/assess/tracking_util.rb +39 -0
  429. data/lib/contrast/utils/boolean_util.rb +33 -0
  430. data/lib/contrast/utils/cache.rb +69 -0
  431. data/lib/contrast/utils/class_util.rb +58 -0
  432. data/lib/contrast/utils/comment_range.rb +19 -0
  433. data/lib/contrast/utils/data_store_util.rb +23 -0
  434. data/lib/contrast/utils/duck_utils.rb +58 -0
  435. data/lib/contrast/utils/env_configuration_item.rb +52 -0
  436. data/lib/contrast/utils/environment_util.rb +152 -0
  437. data/lib/contrast/utils/freeze_util.rb +36 -0
  438. data/lib/contrast/utils/gemfile_reader.rb +191 -0
  439. data/lib/contrast/utils/hash_digest.rb +148 -0
  440. data/lib/contrast/utils/heap_dump_util.rb +113 -0
  441. data/lib/contrast/utils/invalid_configuration_util.rb +88 -0
  442. data/lib/contrast/utils/inventory_util.rb +126 -0
  443. data/lib/contrast/utils/io_util.rb +61 -0
  444. data/lib/contrast/utils/object_share.rb +117 -0
  445. data/lib/contrast/utils/operating_environment.rb +38 -0
  446. data/lib/contrast/utils/os.rb +49 -0
  447. data/lib/contrast/utils/path_util.rb +151 -0
  448. data/lib/contrast/utils/performs_logging.rb +152 -0
  449. data/lib/contrast/utils/preflight_util.rb +13 -0
  450. data/lib/contrast/utils/prevent_serialization.rb +52 -0
  451. data/lib/contrast/utils/rack_assess_session_cookie.rb +104 -0
  452. data/lib/contrast/utils/rails_assess_configuration.rb +95 -0
  453. data/lib/contrast/utils/random_util.rb +22 -0
  454. data/lib/contrast/utils/resource_loader.rb +23 -0
  455. data/lib/contrast/utils/ruby_ast_rewriter.rb +74 -0
  456. data/lib/contrast/utils/scope_util.rb +99 -0
  457. data/lib/contrast/utils/service_response_util.rb +116 -0
  458. data/lib/contrast/utils/service_sender_util.rb +98 -0
  459. data/lib/contrast/utils/sha256_builder.rb +69 -0
  460. data/lib/contrast/utils/sinatra_helper.rb +49 -0
  461. data/lib/contrast/utils/stack_trace_utils.rb +209 -0
  462. data/lib/contrast/utils/string_utils.rb +72 -0
  463. data/lib/contrast/utils/tag_util.rb +139 -0
  464. data/lib/contrast/utils/thread_tracker.rb +54 -0
  465. data/lib/contrast/utils/timer.rb +78 -0
  466. data/resources/assess/policy.json +1673 -0
  467. data/resources/csrf/inject.js +44 -0
  468. data/resources/deadzone/policy.json +55 -0
  469. data/resources/factory-bot-spec/spec_helper.rb +30 -0
  470. data/resources/inventory/policy.json +110 -0
  471. data/resources/protect/policy.json +417 -0
  472. data/resources/rubocops/kernel/catch_cop.rb +37 -0
  473. data/resources/rubocops/kernel/require_cop.rb +37 -0
  474. data/resources/rubocops/kernel/require_relative_cop.rb +33 -0
  475. data/resources/rubocops/module/autoload_cop.rb +37 -0
  476. data/resources/rubocops/module/const_defined_cop.rb +37 -0
  477. data/resources/rubocops/module/const_get_cop.rb +37 -0
  478. data/resources/rubocops/module/const_set_cop.rb +37 -0
  479. data/resources/rubocops/module/constants_cop.rb +37 -0
  480. data/resources/rubocops/module/name_cop.rb +37 -0
  481. data/resources/rubocops/object/class_cop.rb +37 -0
  482. data/resources/rubocops/object/freeze_cop.rb +37 -0
  483. data/resources/rubocops/object/frozen_cop.rb +37 -0
  484. data/resources/rubocops/object/is_a_cop.rb +37 -0
  485. data/resources/rubocops/object/method_cop.rb +37 -0
  486. data/resources/rubocops/object/respond_to_cop.rb +37 -0
  487. data/resources/rubocops/object/singleton_class_cop.rb +37 -0
  488. data/resources/rubocops/regexp/spelling_cop.rb +44 -0
  489. data/resources/rubocops/thread/new_cop.rb +39 -0
  490. data/resources/ruby-spec/ancestors_spec.rb +70 -0
  491. data/resources/ruby-spec/modulo_spec.rb +831 -0
  492. data/resources/ruby-spec/parameters_spec.rb +261 -0
  493. data/resources/ruby-spec/ruby_spec_spec_helper.rb +35 -0
  494. data/resources/test_marker.txt +1 -0
  495. data/ruby-agent.gemspec +129 -0
  496. data/service_executables/.gitkeep +0 -0
  497. data/service_executables/VERSION +1 -0
  498. data/service_executables/linux/contrast-service +0 -0
  499. data/service_executables/mac/contrast-service +0 -0
  500. metadata +945 -0
Binary file
Binary file
Binary file
@@ -0,0 +1,115 @@
1
+ /* -*- indent-tabs-mode: nil -*-
2
+ *
3
+ * This file is part of Funchook.
4
+ * https://github.com/kubo/funchook
5
+ *
6
+ * Funchook is free software: you can redistribute it and/or modify it
7
+ * under the terms of the GNU General Public License as published by the
8
+ * Free Software Foundation, either version 2 of the License, or (at your
9
+ * option) any later version.
10
+ *
11
+ * As a special exception, the copyright holders of this library give you
12
+ * permission to link this library with independent modules to produce an
13
+ * executable, regardless of the license terms of these independent
14
+ * modules, and to copy and distribute the resulting executable under
15
+ * terms of your choice, provided that you also meet, for each linked
16
+ * independent module, the terms and conditions of the license of that
17
+ * module. An independent module is a module which is not derived from or
18
+ * based on this library. If you modify this library, you may extend this
19
+ * exception to your version of the library, but you are not obliged to
20
+ * do so. If you do not wish to do so, delete this exception statement
21
+ * from your version.
22
+ *
23
+ * Funchook is distributed in the hope that it will be useful, but WITHOUT
24
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26
+ * for more details.
27
+ *
28
+ * You should have received a copy of the GNU General Public License
29
+ * along with Funchook. If not, see <http://www.gnu.org/licenses/>.
30
+ */
31
+ #include <sys/types.h>
32
+ #include "printf_base.h"
33
+ #include "os_func.h"
34
+
35
+ /* same with memcmp in libc not to use the function in libc */
36
+ #ifndef _MSC_VER
37
+ #undef memcmp
38
+ int memcmp(const void *s1, const void *s2, size_t n)
39
+ {
40
+ const unsigned char *c1 = (unsigned char *)s1;
41
+ const unsigned char *c2 = (unsigned char *)s2;
42
+ while (n--) {
43
+ if (*c1 != *c2) {
44
+ return *c1 > *c2 ? 1 : -1;
45
+ }
46
+ c1++; c2++;
47
+ }
48
+ return 0;
49
+ }
50
+ #endif
51
+
52
+ /* same with memcmp in libc not to use the function in libc */
53
+ #ifndef _MSC_VER
54
+ #undef memcpy
55
+ void *memcpy(void *dest, const void *src, size_t n)
56
+ {
57
+ char *d = (char*)dest;
58
+ const char *s = (const char *)src;
59
+ while (n--) {
60
+ *(d++) = *(s++);
61
+ }
62
+ return dest;
63
+ }
64
+ #endif
65
+
66
+ char *funchook_strlcpy(char *dest, const char *src, size_t n)
67
+ {
68
+ if (n != 0) {
69
+ char *d = dest;
70
+ while (--n > 0 && *src) {
71
+ *(d++) = *(src++);
72
+ }
73
+ *d = '\0';
74
+ }
75
+ return dest;
76
+ }
77
+
78
+ int funchook_snprintf(char *str, size_t size, const char *format, ...)
79
+ {
80
+ va_list ap;
81
+ int rv;
82
+
83
+ va_start(ap, format);
84
+ rv = funchook_vsnprintf(str, size, format, ap);
85
+ va_end(ap);
86
+ return rv;
87
+ }
88
+
89
+ typedef struct {
90
+ char *str;
91
+ char *end;
92
+ } snprintf_arg_t;
93
+
94
+ static int snprintf_putc(char c, void *handle)
95
+ {
96
+ snprintf_arg_t *arg = (snprintf_arg_t *)handle;
97
+ if (arg->str < arg->end) {
98
+ *(arg->str++) = c;
99
+ }
100
+ return 0;
101
+ }
102
+
103
+ int funchook_vsnprintf(char *str, size_t size, const char *format, va_list ap)
104
+ {
105
+ snprintf_arg_t arg;
106
+ int rv;
107
+
108
+ arg.str = str;
109
+ arg.end = str + size - 1;
110
+ rv = printf_base(snprintf_putc, &arg, format, ap);
111
+ if (size > 0) {
112
+ *arg.str = '\0';
113
+ }
114
+ return rv;
115
+ }
@@ -0,0 +1,75 @@
1
+ /* -*- indent-tabs-mode: nil -*-
2
+ *
3
+ * This file is part of Funchook.
4
+ * https://github.com/kubo/funchook
5
+ *
6
+ * Funchook is free software: you can redistribute it and/or modify it
7
+ * under the terms of the GNU General Public License as published by the
8
+ * Free Software Foundation, either version 2 of the License, or (at your
9
+ * option) any later version.
10
+ *
11
+ * As a special exception, the copyright holders of this library give you
12
+ * permission to link this library with independent modules to produce an
13
+ * executable, regardless of the license terms of these independent
14
+ * modules, and to copy and distribute the resulting executable under
15
+ * terms of your choice, provided that you also meet, for each linked
16
+ * independent module, the terms and conditions of the license of that
17
+ * module. An independent module is a module which is not derived from or
18
+ * based on this library. If you modify this library, you may extend this
19
+ * exception to your version of the library, but you are not obliged to
20
+ * do so. If you do not wish to do so, delete this exception statement
21
+ * from your version.
22
+ *
23
+ * Funchook is distributed in the hope that it will be useful, but WITHOUT
24
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26
+ * for more details.
27
+ *
28
+ * You should have received a copy of the GNU General Public License
29
+ * along with Funchook. If not, see <http://www.gnu.org/licenses/>.
30
+ */
31
+ #ifndef OS_FUNC_H
32
+ #define OS_FUNC_H 1
33
+ #include <stdarg.h>
34
+
35
+ /* os_func.c */
36
+ char *funchook_strlcpy(char *dest, const char *src, size_t n);
37
+ int funchook_snprintf(char *str, size_t size, const char *format, ...);
38
+ int funchook_vsnprintf(char *str, size_t size, const char *format, va_list ap);
39
+
40
+ #undef strlcpy
41
+ #define strlcpy funchook_strlcpy
42
+ #undef snprintf
43
+ #define snprintf funchook_snprintf
44
+ #undef vsnprintf
45
+ #define vsnprintf funchook_vsnprintf
46
+
47
+ #ifdef WIN32
48
+ /* os_func_windows.c */
49
+ /* no function for now */
50
+ #else
51
+ #include <sys/types.h>
52
+ /* os_func_unix.c */
53
+ extern int funchook_os_errno;
54
+ long funchook_os_syscall(long, ...);
55
+ int funchook_os_open(const char *pathname, int flags, ...);
56
+ int funchook_os_close(int fd);
57
+ ssize_t funchook_os_read(int fd, void *buf, size_t count);
58
+ ssize_t funchook_os_write(int fd, const void *buf, size_t count);
59
+ void *funchook_os_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
60
+ int funchook_os_munmap(void *addr, size_t length);
61
+ int funchook_os_mprotect(void *addr, size_t len, int prot);
62
+
63
+ #undef errno
64
+ #define errno funchook_os_errno
65
+ #define syscall funchook_os_syscall
66
+ #define open funchook_os_open
67
+ #define close funchook_os_close
68
+ #define read funchook_os_read
69
+ #define write funchook_os_write
70
+ #define mmap funchook_os_mmap
71
+ #define munmap funchook_os_munmap
72
+ #define mprotect funchook_os_mprotect
73
+ #endif
74
+
75
+ #endif /* OS_FUNC_H */
Binary file
@@ -0,0 +1,94 @@
1
+ /* -*- indent-tabs-mode: nil -*-
2
+ *
3
+ * This file is part of Funchook.
4
+ * https://github.com/kubo/funchook
5
+ *
6
+ * Funchook is free software: you can redistribute it and/or modify it
7
+ * under the terms of the GNU General Public License as published by the
8
+ * Free Software Foundation, either version 2 of the License, or (at your
9
+ * option) any later version.
10
+ *
11
+ * As a special exception, the copyright holders of this library give you
12
+ * permission to link this library with independent modules to produce an
13
+ * executable, regardless of the license terms of these independent
14
+ * modules, and to copy and distribute the resulting executable under
15
+ * terms of your choice, provided that you also meet, for each linked
16
+ * independent module, the terms and conditions of the license of that
17
+ * module. An independent module is a module which is not derived from or
18
+ * based on this library. If you modify this library, you may extend this
19
+ * exception to your version of the library, but you are not obliged to
20
+ * do so. If you do not wish to do so, delete this exception statement
21
+ * from your version.
22
+ *
23
+ * Funchook is distributed in the hope that it will be useful, but WITHOUT
24
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26
+ * for more details.
27
+ *
28
+ * You should have received a copy of the GNU General Public License
29
+ * along with Funchook. If not, see <http://www.gnu.org/licenses/>.
30
+ */
31
+ #if defined __linux
32
+ #define _GNU_SOURCE
33
+ #endif
34
+ #include <sys/types.h>
35
+ #include <sys/syscall.h>
36
+ #include <errno.h>
37
+ #include "os_func.h"
38
+
39
+ int funchook_os_errno;
40
+
41
+ /* Dont' include unistd.h on macOS.
42
+ * macOS defines syscall as int syscall(int, ...).
43
+ * But it truncates syscall(SYS_mmap, ...)'s return value to 32 bits.
44
+ */
45
+ long syscall(long, ...);
46
+
47
+ int funchook_os_open(const char *pathname, int flags, ...)
48
+ {
49
+ mode_t mode;
50
+ va_list ap;
51
+
52
+ va_start(ap, flags);
53
+ mode = (mode_t)va_arg(ap, long);
54
+ va_end(ap);
55
+ return (int)syscall(SYS_open, pathname, flags, mode);
56
+ }
57
+
58
+ int funchook_os_close(int fd)
59
+ {
60
+ return (int)syscall(SYS_close, fd);
61
+ }
62
+
63
+ ssize_t funchook_os_read(int fd, void *buf, size_t count)
64
+ {
65
+ return (ssize_t)syscall(SYS_read, fd, buf, count);
66
+ }
67
+
68
+ ssize_t funchook_os_write(int fd, const void *buf, size_t count)
69
+ {
70
+ return (ssize_t)syscall(SYS_write, fd, buf, count);
71
+ }
72
+
73
+ void *funchook_os_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
74
+ {
75
+ #if defined(__linux) && defined(__i386)
76
+ if (offset & 4095) {
77
+ errno = EINVAL;
78
+ return (void*)-1;
79
+ }
80
+ return (void*)syscall(SYS_mmap2, addr, length, prot, flags, fd, (long)(offset >> 12));
81
+ #else
82
+ return (void*)syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
83
+ #endif
84
+ }
85
+
86
+ int funchook_os_munmap(void *addr, size_t length)
87
+ {
88
+ return (int)syscall(SYS_munmap, addr, length);
89
+ }
90
+
91
+ int funchook_os_mprotect(void *addr, size_t len, int prot)
92
+ {
93
+ return (int)syscall(SYS_mprotect, addr, len, prot);
94
+ }
@@ -0,0 +1,32 @@
1
+ /* -*- indent-tabs-mode: nil -*-
2
+ *
3
+ * This file is part of Funchook.
4
+ * https://github.com/kubo/funchook
5
+ *
6
+ * Funchook is free software: you can redistribute it and/or modify it
7
+ * under the terms of the GNU General Public License as published by the
8
+ * Free Software Foundation, either version 2 of the License, or (at your
9
+ * option) any later version.
10
+ *
11
+ * As a special exception, the copyright holders of this library give you
12
+ * permission to link this library with independent modules to produce an
13
+ * executable, regardless of the license terms of these independent
14
+ * modules, and to copy and distribute the resulting executable under
15
+ * terms of your choice, provided that you also meet, for each linked
16
+ * independent module, the terms and conditions of the license of that
17
+ * module. An independent module is a module which is not derived from or
18
+ * based on this library. If you modify this library, you may extend this
19
+ * exception to your version of the library, but you are not obliged to
20
+ * do so. If you do not wish to do so, delete this exception statement
21
+ * from your version.
22
+ *
23
+ * Funchook is distributed in the hope that it will be useful, but WITHOUT
24
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26
+ * for more details.
27
+ *
28
+ * You should have received a copy of the GNU General Public License
29
+ * along with Funchook. If not, see <http://www.gnu.org/licenses/>.
30
+ */
31
+
32
+ /* no function for now */
Binary file
@@ -0,0 +1,1688 @@
1
+ /* -*- indent-tabs-mode: nil -*-
2
+ *
3
+ * printf_base - base function to make printf-like functions
4
+ * https://github.com/kubo/printf_base
5
+ *
6
+ * Copyright (C) 2016 Kubo Takehiro <kubo@jiubao.org>
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted provided that the following conditions are met:
10
+ *
11
+ * 1. Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ *
14
+ * 2. Redistributions in binary form must reproduce the above
15
+ * copyright notice, this list of conditions and the following
16
+ * disclaimer in the documentation and/or other materials provided
17
+ * with the distribution.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR
20
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
23
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
29
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ *
31
+ * The views and conclusions contained in the software and documentation
32
+ * are those of the authors and should not be interpreted as representing
33
+ * official policies, either expressed or implied, of the authors.
34
+ */
35
+ #ifndef _GNU_SOURCE
36
+ #define _GNU_SOURCE
37
+ #endif
38
+ #include <stdio.h>
39
+ #include <stdint.h>
40
+ #include <stdlib.h>
41
+ #include <stddef.h>
42
+ #include <string.h>
43
+ #ifdef WIN32
44
+ #include <malloc.h>
45
+ #ifndef alloca
46
+ #define alloca _alloca
47
+ #endif
48
+ #else
49
+ #include <alloca.h>
50
+ #endif
51
+ #include "printf_base.h"
52
+
53
+ #ifdef PFB_NO_EXTERNAL_FUNC
54
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
55
+ #define PFB_NO_WIDE_CHAR_FORMAT
56
+ #endif
57
+ #ifndef PFB_NO_FLOATING_POINT_FORMAT
58
+ #define PFB_NO_FLOATING_POINT_FORMAT
59
+ #endif
60
+ #endif
61
+
62
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
63
+ #include <wchar.h>
64
+ #endif
65
+ #ifndef PFB_NO_FLOATING_POINT_FORMAT
66
+ #include <math.h>
67
+ #endif
68
+
69
+ #ifdef __GNUC__
70
+ #ifndef HAVE_LONG_DOUBLE
71
+ #define HAVE_LONG_DOUBLE
72
+ #endif
73
+ #endif
74
+
75
+ #ifdef HAVE_LONG_DOUBLE
76
+ #define pfb_floor floorl
77
+ #define pfb_frexp frexpl
78
+ #define pfb_log10 log10l
79
+ #define pfb_pow powl
80
+ typedef long double pfb_double;
81
+ #else
82
+ #define pfb_floor floor
83
+ #define pfb_frexp frexp
84
+ #define pfb_log10 log10
85
+ #define pfb_pow pow
86
+ typedef double pfb_double;
87
+ #endif
88
+
89
+ #define PUTC(chr) do { \
90
+ if (func(chr, handle) == -1) { \
91
+ return -1; \
92
+ } \
93
+ outlen++; \
94
+ } while (0)
95
+
96
+ #define COND_PUTC(chr) do { \
97
+ if (func && func(chr, handle) == -1) { \
98
+ return -1; \
99
+ } \
100
+ outlen++; \
101
+ } while (0)
102
+
103
+ #define PUTC_N(chr, num) do { \
104
+ int n = (num); \
105
+ while (n-- > 0) { \
106
+ PUTC(chr); \
107
+ } \
108
+ } while (0)
109
+
110
+ #define COND_PUTC_N(chr, num) do { \
111
+ int n = (num); \
112
+ if (func) { \
113
+ while (n-- > 0) { \
114
+ PUTC(chr); \
115
+ } \
116
+ } else { \
117
+ outlen += n; \
118
+ } \
119
+ } while (0)
120
+
121
+ #define PUT_HEX(val) do { \
122
+ int ival = (val); \
123
+ if (ival < 10) { \
124
+ PUTC(ival + '0'); \
125
+ } else if (param->upper) { \
126
+ PUTC((ival - 10) + 'A'); \
127
+ } else { \
128
+ PUTC((ival - 10) + 'a'); \
129
+ } \
130
+ } while (0)
131
+
132
+ #define PUTS(ptr, len) do { \
133
+ const char *p = (ptr); \
134
+ const char *e = p + (len); \
135
+ while (p < e) { \
136
+ PUTC(*p); \
137
+ p++; \
138
+ } \
139
+ } while (0)
140
+
141
+ #ifdef PFB_NO_EXTERNAL_FUNC
142
+ static inline int pfb_strlen(const char *s)
143
+ {
144
+ const char *t = s;
145
+ while (*t) {
146
+ t++;
147
+ }
148
+ return (int)(t - s);
149
+ }
150
+ #define strlen pfb_strlen
151
+ static inline void *pfb_memset(void *s, int c, size_t n)
152
+ {
153
+ /* add volatile to suppress optimization to replace this function with memset by 'gcc -O3'. */
154
+ char * volatile t = (char *)s;
155
+ while (n-- > 0) {
156
+ *(t++) = c;
157
+ }
158
+ return s;
159
+ }
160
+ #undef memset
161
+ #define memset pfb_memset
162
+ #endif
163
+
164
+ enum length_modifier {
165
+ /* */ LM_INT,
166
+ /* hh */ LM_CHAR,
167
+ /* h */ LM_SHORT,
168
+ /* l */ LM_LONG,
169
+ /* ll */ LM_LONGLONG,
170
+ /* L */ LM_LONGDOUBLE,
171
+ /* j */ LM_INTMAX_T,
172
+ /* z */ LM_SIZE_T,
173
+ /* t */ LM_PTRDIFF_T,
174
+ };
175
+
176
+ enum arg_type {
177
+ AT_INT,
178
+ AT_UINT,
179
+ AT_DBL,
180
+ AT_PTR,
181
+ };
182
+
183
+ typedef union {
184
+ int64_t ival;
185
+ uint64_t uival;
186
+ pfb_double dbl;
187
+ char *ptr;
188
+ } val_t;
189
+
190
+ typedef struct param {
191
+ const char *begin_pos;
192
+ const char *end_pos;
193
+ /* flag characters */
194
+ unsigned char alternate_form:1;
195
+ unsigned char zero_padded:1;
196
+ unsigned char left_adjusted:1;
197
+ unsigned char blank:1;
198
+ unsigned char add_sign:1;
199
+ unsigned char thousands_grouping:1;
200
+ /* other flags */
201
+ unsigned char width_is_va_pos:1;
202
+ unsigned char prec_is_va_pos:1;
203
+ unsigned char prec_is_set:1;
204
+ unsigned char upper:1;
205
+ /* field width */
206
+ int width;
207
+ /* precision */
208
+ int prec;
209
+ /* length modifier */
210
+ enum length_modifier lm;
211
+ /* conversion_specifier */
212
+ enum arg_type arg_type;
213
+ int (*output_func)(pfb_putc_t func, void *handle, const struct param *param, int len);
214
+ union {
215
+ int va_pos;
216
+ val_t val;
217
+ } u;
218
+ } param_t;
219
+
220
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
221
+ static int is_wchar_length_modifier(enum length_modifier lm)
222
+ {
223
+ switch (lm) {
224
+ case LM_LONG:
225
+ case LM_LONGLONG:
226
+ case LM_LONGDOUBLE:
227
+ case LM_INTMAX_T:
228
+ case LM_SIZE_T:
229
+ case LM_PTRDIFF_T:
230
+ return 1;
231
+ default:
232
+ return 0;
233
+ }
234
+ }
235
+ #endif
236
+
237
+ static int parse_format(const char *format, param_t *params, size_t num_param);
238
+ static int parse_one_param(const char **format, param_t *param, int *va_pos);
239
+ static int get_decimal(const char **str);
240
+ static int get_va_pos(const char **format);
241
+ static const char *parse_flag_characters(const char *format, param_t *param);
242
+ static const char *parse_field_width(const char *format, param_t *param);
243
+ static const char *parse_precision(const char *format, param_t *param);
244
+ static const char *parse_length_modifier(const char *format, param_t *param);
245
+ static const char *parse_conversion_specifier(const char *format, param_t *param);
246
+ static void fill_params(param_t *params, size_t num_param, va_list ap);
247
+ static int get_prec(const param_t *param, int default_prec);
248
+ static int get_zero_padded(const param_t *param);
249
+ static int output(pfb_putc_t func, void *handle, const char *format, const param_t *params, size_t num_param);
250
+ static int output_int(pfb_putc_t func, void *handle, const param_t *param, int len);
251
+ static int output_oct(pfb_putc_t func, void *handle, const param_t *param, int len);
252
+ static int output_uint(pfb_putc_t func, void *handle, const param_t *param, int len);
253
+ static int output_hex(pfb_putc_t func, void *handle, const param_t *param, int len);
254
+ #ifndef PFB_NO_FLOATING_POINT_FORMAT
255
+ static int output_edbl(pfb_putc_t func, void *handle, const param_t *param, int len);
256
+ static int output_fdbl(pfb_putc_t func, void *handle, const param_t *param, int len);
257
+ static int output_gdbl(pfb_putc_t func, void *handle, const param_t *param, int len);
258
+ static int output_adbl(pfb_putc_t func, void *handle, const param_t *param, int len);
259
+ static int output_no_finite_dbl(pfb_putc_t func, void *handle, const param_t *param);
260
+ #endif
261
+ static int output_chr(pfb_putc_t func, void *handle, const param_t *param, int len);
262
+ static int output_str(pfb_putc_t func, void *handle, const param_t *param, int len);
263
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
264
+ static int output_wch(pfb_putc_t func, void *handle, const param_t *param, int len);
265
+ static int output_wcs(pfb_putc_t func, void *handle, const param_t *param, int len);
266
+ #endif
267
+ static int output_ptr(pfb_putc_t func, void *handle, const param_t *param, int len);
268
+ static int output_num_written(pfb_putc_t func, void *handle, const param_t *param, int len);
269
+ static int output_percent_char(pfb_putc_t func, void *handle, const param_t *param, int len);
270
+
271
+ int printf_base(pfb_putc_t func, void *handle, const char *format, va_list ap)
272
+ {
273
+ const char *fmt;
274
+ int num_param = 0;
275
+ param_t *params = NULL;
276
+
277
+ for (fmt = format; *fmt != '\0'; fmt++) {
278
+ if (*fmt == '%') {
279
+ num_param++;
280
+ }
281
+ }
282
+ if (num_param != 0) {
283
+ size_t sz = num_param * sizeof(param_t);
284
+ params = alloca(sz);
285
+ memset(params, 0, sz);
286
+ num_param = parse_format(format, params, num_param);
287
+ fill_params(params, num_param, ap);
288
+ }
289
+ return output(func, handle, format, params, num_param);
290
+ }
291
+
292
+ typedef struct {
293
+ pfb_write_t write;
294
+ void *handle;
295
+ int used;
296
+ char buf[4096];
297
+ } write_arg_t;
298
+
299
+ static int write_func(int chr, write_arg_t *arg)
300
+ {
301
+ if (arg->used == sizeof(arg->buf)) {
302
+ if (arg->write(arg->handle, arg->buf, sizeof(arg->buf)) != sizeof(arg->buf)) {
303
+ return -1;
304
+ }
305
+ arg->used = 0;
306
+ }
307
+ arg->buf[arg->used++] = chr;
308
+ return 0;
309
+ }
310
+
311
+ int printf_base_with_buffering(pfb_write_t func, void *handle, const char *format, va_list ap)
312
+ {
313
+ write_arg_t arg;
314
+ int rv;
315
+
316
+ arg.write = func;
317
+ arg.handle = handle;
318
+ arg.used = 0;
319
+ rv = printf_base((pfb_putc_t)write_func, &arg, format, ap);
320
+ if (rv == -1) {
321
+ return -1;
322
+ }
323
+ if (func(handle, arg.buf, arg.used) != arg.used) {
324
+ return -1;
325
+ }
326
+ return rv;
327
+ }
328
+
329
+ static int parse_format(const char *format, param_t *params, size_t num_param)
330
+ {
331
+ int param_idx = 0;
332
+ int va_pos = 1;
333
+
334
+ while (*format != '\0') {
335
+ if (*format == '%' && parse_one_param(&format, &params[param_idx], &va_pos) == 0) {
336
+ param_idx++;
337
+ } else {
338
+ format++;
339
+ }
340
+ }
341
+ return param_idx;
342
+ }
343
+
344
+ static int parse_one_param(const char **format, param_t *param, int *va_pos)
345
+ {
346
+ const char *fmt = *format + 1;
347
+
348
+ param->begin_pos = *format;
349
+ param->u.va_pos = get_va_pos(&fmt);
350
+ if ((fmt = parse_flag_characters(fmt, param)) == NULL) {
351
+ return -1;
352
+ }
353
+ if ((fmt = parse_field_width(fmt, param)) == NULL) {
354
+ return -1;
355
+ }
356
+ if ((fmt = parse_precision(fmt, param)) == NULL) {
357
+ return -1;
358
+ }
359
+ if ((fmt = parse_length_modifier(fmt, param)) == NULL) {
360
+ return -1;
361
+ }
362
+ if ((fmt = parse_conversion_specifier(fmt, param)) == NULL) {
363
+ return -1;
364
+ }
365
+ if (param->width == 0 && param->width_is_va_pos) {
366
+ param->width = (*va_pos)++;
367
+ }
368
+ if (param->prec == 0 && param->prec_is_va_pos) {
369
+ param->prec = (*va_pos)++;
370
+ }
371
+ if (param->u.va_pos == 0) {
372
+ param->u.va_pos = (*va_pos)++;
373
+ }
374
+ param->end_pos = *format = fmt;
375
+ return 0;
376
+ }
377
+
378
+ static int get_decimal(const char **str)
379
+ {
380
+ const char *s = *str;
381
+ int num = 0;
382
+
383
+ while ('0' <= *s && *s <= '9') {
384
+ num *= 10;
385
+ num += *(s++) - '0';
386
+ }
387
+ *str = s;
388
+ return num;
389
+ }
390
+
391
+ static int get_va_pos(const char **format)
392
+ {
393
+ const char *str = *format;
394
+ int pos = get_decimal(&str);
395
+ if (pos > 0 && *str == '$') {
396
+ *format = str + 1;
397
+ return pos;
398
+ }
399
+ return 0;
400
+ }
401
+
402
+ static const char *parse_flag_characters(const char *format, param_t *param)
403
+ {
404
+ while (1) {
405
+ switch (*format) {
406
+ case '#':
407
+ param->alternate_form = 1;
408
+ break;
409
+ case '0':
410
+ param->zero_padded = 1;
411
+ break;
412
+ case '-':
413
+ param->left_adjusted = 1;
414
+ break;
415
+ case ' ':
416
+ param->blank = 1;
417
+ break;
418
+ case '+':
419
+ param->add_sign = 1;
420
+ break;
421
+ case '\'':
422
+ param->thousands_grouping = 1;
423
+ break;
424
+ default:
425
+ return format;
426
+ }
427
+ format++;
428
+ }
429
+ }
430
+
431
+ static const char *parse_field_width(const char *format, param_t *param)
432
+ {
433
+ if (*format == '*') {
434
+ format++;
435
+ param->width = get_va_pos(&format);
436
+ param->width_is_va_pos = 1;
437
+ return format;
438
+ }
439
+ param->width = get_decimal(&format);
440
+ return format;
441
+ }
442
+
443
+ static const char *parse_precision(const char *format, param_t *param)
444
+ {
445
+ if (*format != '.') {
446
+ return format;
447
+ }
448
+ param->prec_is_set = 1;
449
+ format++;
450
+ if (*format == '*') {
451
+ format++;
452
+ param->prec = get_va_pos(&format);
453
+ param->prec_is_va_pos = 1;
454
+ return format;
455
+ }
456
+ param->prec = get_decimal(&format);
457
+ return format;
458
+ }
459
+
460
+ static const char *parse_length_modifier(const char *format, param_t *param)
461
+ {
462
+ switch (format[0]) {
463
+ case 'h':
464
+ if (format[1] == 'h') {
465
+ param->lm = LM_CHAR;
466
+ return format + 2;
467
+ } else {
468
+ param->lm = LM_SHORT;
469
+ return format + 1;
470
+ }
471
+ case 'l':
472
+ if (format[1] == 'l') {
473
+ param->lm = LM_LONGLONG;
474
+ return format + 2;
475
+ } else {
476
+ param->lm = LM_LONG;
477
+ return format + 1;
478
+ }
479
+ case 'L':
480
+ param->lm = LM_LONGDOUBLE;
481
+ return format + 1;
482
+ case 'j':
483
+ param->lm = LM_INTMAX_T;
484
+ return format + 1;
485
+ case 'z':
486
+ param->lm = LM_SIZE_T;
487
+ return format + 1;
488
+ case 't':
489
+ param->lm = LM_PTRDIFF_T;
490
+ return format + 1;
491
+ #ifdef PFB_MSVC_FORMAT
492
+ case 'w':
493
+ param->lm = LM_LONG;
494
+ return format + 1;
495
+ case 'I':
496
+ if (format[1] == '6' && format[2] == '4') {
497
+ param->lm = LM_LONGLONG;
498
+ return format + 3;
499
+ }
500
+ if (format[1] == '3' && format[2] == '2') {
501
+ param->lm = LM_INT;
502
+ return format + 3;
503
+ }
504
+ param->lm = LM_SIZE_T;
505
+ return format + 1;
506
+ #endif
507
+ }
508
+ param->lm = LM_INT;
509
+ return format;
510
+ }
511
+
512
+ static const char *parse_conversion_specifier(const char *format, param_t *param)
513
+ {
514
+ switch (*format) {
515
+ case 'd':
516
+ case 'i':
517
+ param->arg_type = AT_INT;
518
+ param->output_func = output_int;
519
+ return format + 1;
520
+ case 'o':
521
+ param->arg_type = AT_UINT;
522
+ param->output_func = output_oct;
523
+ return format + 1;
524
+ case 'u':
525
+ param->arg_type = AT_UINT;
526
+ param->output_func = output_uint;
527
+ return format + 1;
528
+ case 'X':
529
+ param->upper = 1;
530
+ /* FALLTHROUGH */
531
+ case 'x':
532
+ param->arg_type = AT_UINT;
533
+ param->output_func = output_hex;
534
+ return format + 1;
535
+ #ifndef PFB_NO_FLOATING_POINT_FORMAT
536
+ case 'E':
537
+ param->upper = 1;
538
+ /* FALLTHROUGH */
539
+ case 'e':
540
+ param->arg_type = AT_DBL;
541
+ param->output_func = output_edbl;
542
+ return format + 1;
543
+ case 'F':
544
+ param->upper = 1;
545
+ /* FALLTHROUGH */
546
+ case 'f':
547
+ param->arg_type = AT_DBL;
548
+ param->output_func = output_fdbl;
549
+ return format + 1;
550
+ case 'G':
551
+ param->upper = 1;
552
+ /* FALLTHROUGH */
553
+ case 'g':
554
+ param->arg_type = AT_DBL;
555
+ param->output_func = output_gdbl;
556
+ return format + 1;
557
+ case 'A':
558
+ param->upper = 1;
559
+ /* FALLTHROUGH */
560
+ case 'a':
561
+ param->arg_type = AT_DBL;
562
+ param->output_func = output_adbl;
563
+ return format + 1;
564
+ #endif
565
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
566
+ case 'C':
567
+ param->lm = LM_LONG;
568
+ /* FALLTHROUGH */
569
+ #endif
570
+ case 'c':
571
+ param->arg_type = AT_INT;
572
+ param->output_func = output_chr;
573
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
574
+ if (is_wchar_length_modifier(param->lm)) {
575
+ param->output_func = output_wch;
576
+ }
577
+ #endif
578
+ return format + 1;
579
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
580
+ case 'S':
581
+ param->lm = LM_LONG;
582
+ /* FALLTHROUGH */
583
+ #endif
584
+ case 's':
585
+ param->arg_type = AT_PTR;
586
+ param->output_func = output_str;
587
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
588
+ if (is_wchar_length_modifier(param->lm)) {
589
+ param->output_func = output_wcs;
590
+ }
591
+ #endif
592
+ return format + 1;
593
+ case 'p':
594
+ param->lm = LM_SIZE_T;
595
+ param->arg_type = AT_UINT;
596
+ param->output_func = output_ptr;
597
+ return format + 1;
598
+ case 'n':
599
+ param->arg_type = AT_PTR;
600
+ param->output_func = output_num_written;
601
+ return format + 1;
602
+ case '%':
603
+ param->output_func = output_percent_char;
604
+ param->u.va_pos = -1;
605
+ return format + 1;
606
+ }
607
+ return NULL;
608
+ }
609
+
610
+ static void fill_params(param_t *params, size_t num_param, va_list ap)
611
+ {
612
+ param_t *param, *param_end = params + num_param;
613
+ int max_pos = 0;
614
+ int i;
615
+ val_t *vals;
616
+
617
+ for (param = params; param < param_end; param++) {
618
+ if (max_pos < param->u.va_pos) {
619
+ max_pos = param->u.va_pos;
620
+ }
621
+ if (param->width_is_va_pos && max_pos < param->width) {
622
+ max_pos = param->width;
623
+ }
624
+ if (param->prec_is_va_pos && max_pos < param->prec) {
625
+ max_pos = param->prec;
626
+ }
627
+ }
628
+ vals = alloca(max_pos * sizeof(val_t));
629
+ memset(vals, 0, max_pos * sizeof(val_t));
630
+ for (i = 0; i < max_pos; i++) {
631
+ for (param = params; param < param_end; param++) {
632
+ if (param->u.va_pos == i + 1) {
633
+ switch (param->arg_type) {
634
+ case AT_INT:
635
+ switch (param->lm) {
636
+ case LM_INT:
637
+ vals[i].ival = va_arg(ap, int);
638
+ break;
639
+ case LM_CHAR:
640
+ vals[i].ival = (char)va_arg(ap, int);
641
+ break;
642
+ case LM_SHORT:
643
+ vals[i].ival = (short)va_arg(ap, int);
644
+ break;
645
+ case LM_LONG:
646
+ vals[i].ival = va_arg(ap, long);
647
+ break;
648
+ case LM_LONGLONG:
649
+ vals[i].ival = va_arg(ap, int64_t);
650
+ break;
651
+ case LM_LONGDOUBLE:
652
+ vals[i].ival = va_arg(ap, long);
653
+ break;
654
+ case LM_INTMAX_T:
655
+ vals[i].ival = va_arg(ap, intmax_t);
656
+ break;
657
+ case LM_SIZE_T:
658
+ vals[i].ival = va_arg(ap, intptr_t);
659
+ break;
660
+ case LM_PTRDIFF_T:
661
+ vals[i].ival = va_arg(ap, ptrdiff_t);
662
+ break;
663
+ }
664
+ break;
665
+ case AT_UINT:
666
+ switch (param->lm) {
667
+ case LM_INT:
668
+ vals[i].uival = va_arg(ap, unsigned int);
669
+ break;
670
+ case LM_CHAR:
671
+ vals[i].uival = (unsigned char)va_arg(ap, unsigned int);
672
+ break;
673
+ case LM_SHORT:
674
+ vals[i].uival = (unsigned short)va_arg(ap, unsigned int);
675
+ break;
676
+ case LM_LONG:
677
+ vals[i].uival = va_arg(ap, unsigned long);
678
+ break;
679
+ case LM_LONGLONG:
680
+ vals[i].uival = va_arg(ap, uint64_t);
681
+ break;
682
+ case LM_LONGDOUBLE:
683
+ vals[i].uival = va_arg(ap, unsigned long);
684
+ break;
685
+ case LM_INTMAX_T:
686
+ vals[i].uival = va_arg(ap, uintmax_t);
687
+ break;
688
+ case LM_SIZE_T:
689
+ vals[i].uival = va_arg(ap, uintptr_t);
690
+ break;
691
+ case LM_PTRDIFF_T:
692
+ vals[i].uival = va_arg(ap, ptrdiff_t);
693
+ break;
694
+ }
695
+ break;
696
+ case AT_DBL:
697
+ switch (param->lm) {
698
+ case LM_LONGLONG:
699
+ case LM_LONGDOUBLE:
700
+ vals[i].dbl = va_arg(ap, pfb_double);
701
+ break;
702
+ default:
703
+ vals[i].dbl = va_arg(ap, double);
704
+ break;
705
+ }
706
+ break;
707
+ case AT_PTR:
708
+ vals[i].ptr = va_arg(ap, void *);
709
+ break;
710
+ }
711
+ break;
712
+ } else if (param->width_is_va_pos && param->width == i + 1) {
713
+ param->width = va_arg(ap, int);
714
+ if (param->width < 0) {
715
+ param->left_adjusted = 1;
716
+ param->width = -param->width;
717
+ }
718
+ break;
719
+ } else if (param->prec_is_va_pos && param->prec == i + 1) {
720
+ param->prec = va_arg(ap, int);
721
+ break;
722
+ }
723
+ }
724
+ if (param == param_end) {
725
+ va_arg(ap, int); /* skip this argument */
726
+ }
727
+ }
728
+ for (param = params; param < param_end; param++) {
729
+ if (param->u.va_pos > 0) {
730
+ param->u.val = vals[param->u.va_pos - 1];
731
+ }
732
+ }
733
+ }
734
+
735
+ static int get_prec(const param_t *param, int default_prec)
736
+ {
737
+ if (!param->prec_is_set) {
738
+ return default_prec;
739
+ } else if (param->prec > 0) {
740
+ return param->prec;
741
+ } else {
742
+ return 0;
743
+ }
744
+ }
745
+
746
+ static int get_zero_padded(const param_t *param)
747
+ {
748
+ if (param->prec_is_set) {
749
+ return 0;
750
+ } else {
751
+ return param->zero_padded;
752
+ }
753
+ }
754
+
755
+ static int output(pfb_putc_t func, void *handle, const char *format, const param_t *params, size_t num_param)
756
+ {
757
+ const char *last_pos = format;
758
+ int outlen = 0;
759
+ size_t i;
760
+
761
+ for (i = 0; i < num_param; i++) {
762
+ const param_t *param = &params[i];
763
+ int rv;
764
+
765
+ while (last_pos < param->begin_pos) {
766
+ PUTC(*(last_pos++));
767
+ }
768
+ rv = param->output_func(func, handle, param, outlen);
769
+ if (rv == -1) {
770
+ return rv;
771
+ }
772
+ outlen += rv;
773
+ last_pos = param->end_pos;
774
+ }
775
+ while (*last_pos) {
776
+ PUTC(*(last_pos++));
777
+ }
778
+ return outlen;
779
+ }
780
+
781
+ static int output_int(pfb_putc_t func, void *handle, const param_t *param, int len)
782
+ {
783
+ char buf[30];
784
+ int64_t ival = param->u.val.ival;
785
+ int prec = get_prec(param, 1);
786
+ int zero_padded = get_zero_padded(param);
787
+ int outlen = 0;
788
+ int datalen;
789
+ int bufused;
790
+ char sign = 0;
791
+ int padding_len;
792
+ int i;
793
+
794
+ if (ival < 0) {
795
+ ival = -ival;
796
+ sign = '-';
797
+ } else if (param->add_sign) {
798
+ sign = '+';
799
+ } else if (param->blank) {
800
+ sign = ' ';
801
+ }
802
+ if (ival == 0 && prec == 0) {
803
+ i = sizeof(buf);
804
+ } else {
805
+ for (i = sizeof(buf) - 1; i >= 0; i--) {
806
+ buf[i] = (ival % 10) + '0';
807
+ ival /= 10;
808
+ if (ival == 0) {
809
+ break;
810
+ }
811
+ }
812
+ }
813
+ bufused = sizeof(buf) - i;
814
+ /* calculate padding length */
815
+ datalen = bufused;
816
+ if (datalen < prec) {
817
+ datalen = prec;
818
+ }
819
+ if (sign) {
820
+ datalen++;
821
+ }
822
+ padding_len = param->width - datalen;
823
+ /* put characters */
824
+ if (!param->left_adjusted && !zero_padded) {
825
+ PUTC_N(' ', padding_len);
826
+ }
827
+ if (sign) {
828
+ PUTC(sign);
829
+ }
830
+ if (!param->left_adjusted && zero_padded) {
831
+ PUTC_N('0', padding_len);
832
+ }
833
+ PUTC_N('0', prec - bufused);
834
+ PUTS(buf + i, bufused);
835
+ if (param->left_adjusted) {
836
+ PUTC_N(' ', padding_len);
837
+ }
838
+ return outlen;
839
+ }
840
+
841
+ static int output_oct(pfb_putc_t func, void *handle, const param_t *param, int len)
842
+ {
843
+ char buf[30];
844
+ int64_t uival = param->u.val.uival;
845
+ int prec = get_prec(param, 1);
846
+ int zero_padded = get_zero_padded(param);
847
+ int outlen = 0;
848
+ int datalen;
849
+ int bufused;
850
+ int padding_len;
851
+ int i;
852
+
853
+ if (uival == 0) {
854
+ i = sizeof(buf);
855
+ if (param->alternate_form || prec != 0) {
856
+ buf[--i] = '0';
857
+ }
858
+ } else {
859
+ for (i = sizeof(buf) - 1; i >= 0; i--) {
860
+ buf[i] = (uival & 7) + '0';
861
+ uival >>= 3;
862
+ if (uival == 0) {
863
+ break;
864
+ }
865
+ }
866
+ if (param->alternate_form) {
867
+ buf[--i] = '0';
868
+ }
869
+ }
870
+ bufused = sizeof(buf) - i;
871
+ /* calculate padding length */
872
+ datalen = bufused;
873
+ if (datalen < prec) {
874
+ datalen = prec;
875
+ }
876
+ padding_len = param->width - datalen;
877
+ /* put characters */
878
+ if (!param->left_adjusted) {
879
+ if (zero_padded) {
880
+ PUTC_N('0', padding_len);
881
+ } else {
882
+ PUTC_N(' ', padding_len);
883
+ }
884
+ }
885
+ PUTC_N('0', prec - bufused);
886
+ PUTS(buf + i, bufused);
887
+ if (param->left_adjusted) {
888
+ PUTC_N(' ', padding_len);
889
+ }
890
+ return outlen;
891
+ }
892
+
893
+ static int output_uint(pfb_putc_t func, void *handle, const param_t *param, int len)
894
+ {
895
+ char buf[30];
896
+ int64_t uival = param->u.val.uival;
897
+ int prec = get_prec(param, 1);
898
+ int zero_padded = get_zero_padded(param);
899
+ int outlen = 0;
900
+ int datalen;
901
+ int bufused;
902
+ int padding_len;
903
+ int i;
904
+
905
+ if (uival == 0) {
906
+ i = sizeof(buf);
907
+ if (prec != 0) {
908
+ buf[--i] = '0';
909
+ }
910
+ } else {
911
+ for (i = sizeof(buf) - 1; i >= 0; i--) {
912
+ buf[i] = (uival % 10) + '0';
913
+ uival /= 10;
914
+ if (uival == 0) {
915
+ break;
916
+ }
917
+ }
918
+ }
919
+ bufused = sizeof(buf) - i;
920
+ /* calculate padding length */
921
+ datalen = bufused;
922
+ if (datalen < prec) {
923
+ datalen = prec;
924
+ }
925
+ padding_len = param->width - datalen;
926
+ /* put characters */
927
+ if (!param->left_adjusted) {
928
+ if (zero_padded) {
929
+ PUTC_N('0', padding_len);
930
+ } else {
931
+ PUTC_N(' ', padding_len);
932
+ }
933
+ }
934
+ PUTC_N('0', prec - bufused);
935
+ PUTS(buf + i, bufused);
936
+ if (param->left_adjusted) {
937
+ PUTC_N(' ', padding_len);
938
+ }
939
+ return outlen;
940
+ }
941
+
942
+ static int output_hex(pfb_putc_t func, void *handle, const param_t *param, int len)
943
+ {
944
+ char buf[30];
945
+ int64_t uival = param->u.val.uival;
946
+ int prec = get_prec(param, 1);
947
+ int zero_padded = get_zero_padded(param);
948
+ char alternate_form = param->alternate_form;
949
+ int outlen = 0;
950
+ int datalen;
951
+ int bufused;
952
+ int padding_len;
953
+ int i;
954
+
955
+ if (uival == 0) {
956
+ i = sizeof(buf);
957
+ if (prec != 0) {
958
+ buf[--i] = '0';
959
+ }
960
+ alternate_form = 0;
961
+ } else {
962
+ for (i = sizeof(buf) - 1; i >= 0; i--) {
963
+ if ((uival & 0xf) < 10) {
964
+ buf[i] = (uival & 0xf) + '0';
965
+ } else {
966
+ buf[i] = (uival & 0xf) - 10 + ((param->upper) ? 'A' : 'a');
967
+ }
968
+ uival >>= 4;
969
+ if (uival == 0) {
970
+ break;
971
+ }
972
+ }
973
+ }
974
+ bufused = sizeof(buf) - i;
975
+ /* calculate padding length */
976
+ datalen = bufused;
977
+ if (datalen < prec) {
978
+ datalen = prec;
979
+ }
980
+ if (alternate_form) {
981
+ datalen += 2;
982
+ }
983
+ padding_len = param->width - datalen;
984
+ /* put characters */
985
+ if (!param->left_adjusted && !zero_padded) {
986
+ PUTC_N(' ', padding_len);
987
+ }
988
+ if (alternate_form) {
989
+ PUTC('0');
990
+ PUTC((param->upper) ? 'X' : 'x');
991
+ }
992
+ if (!param->left_adjusted && zero_padded) {
993
+ PUTC_N('0', padding_len);
994
+ }
995
+ PUTC_N('0', prec - bufused);
996
+ PUTS(buf + i, bufused);
997
+ if (param->left_adjusted) {
998
+ PUTC_N(' ', padding_len);
999
+ }
1000
+ return outlen;
1001
+ }
1002
+
1003
+ #ifndef PFB_NO_FLOATING_POINT_FORMAT
1004
+ static int output_edbl(pfb_putc_t func, void *handle, const param_t *param, int len)
1005
+ {
1006
+ pfb_double dbl = param->u.val.dbl;
1007
+ int prec = get_prec(param, 6);
1008
+ int outlen = 0;
1009
+ int exp = 0;
1010
+ char sign = 0;
1011
+ int padding_len;
1012
+
1013
+ if (!isfinite(dbl)) {
1014
+ return output_no_finite_dbl(func, handle, param);
1015
+ }
1016
+ if (signbit(dbl)) {
1017
+ dbl = -dbl;
1018
+ sign = '-';
1019
+ } else if (param->add_sign) {
1020
+ sign = '+';
1021
+ } else if (param->blank) {
1022
+ sign = ' ';
1023
+ }
1024
+ padding_len = param->width - (prec + 5);
1025
+ if (dbl != 0.0) {
1026
+ while (dbl >= 10.0) {
1027
+ dbl /= 10.0;
1028
+ exp++;
1029
+ }
1030
+ while (dbl < 1.0) {
1031
+ dbl *= 10.0;
1032
+ exp--;
1033
+ }
1034
+ dbl += 0.5 * pfb_pow(0.1, prec);
1035
+ } else {
1036
+ dbl = 0.0;
1037
+ exp = 0;
1038
+ }
1039
+ if (prec > 0 || param->alternate_form) {
1040
+ padding_len--;
1041
+ }
1042
+ if (sign) {
1043
+ padding_len--;
1044
+ }
1045
+ /* put characters */
1046
+ if (!param->left_adjusted && !param->zero_padded) {
1047
+ PUTC_N(' ', padding_len);
1048
+ }
1049
+ if (sign) {
1050
+ PUTC(sign);
1051
+ }
1052
+ if (!param->left_adjusted && param->zero_padded) {
1053
+ PUTC_N('0', padding_len);
1054
+ }
1055
+ PUTC((int)dbl + '0');
1056
+ if (prec > 0 || param->alternate_form) {
1057
+ PUTC('.');
1058
+ }
1059
+ while (prec-- > 0) {
1060
+ pfb_double intpart = pfb_floor(dbl);
1061
+ dbl -= intpart;
1062
+ dbl *= 10.0;
1063
+ PUTC((int)dbl + '0');
1064
+ }
1065
+ PUTC(param->upper ? 'E' : 'e');
1066
+ if (exp >= 0) {
1067
+ PUTC('+');
1068
+ } else {
1069
+ PUTC('-');
1070
+ exp = -exp;
1071
+ }
1072
+ PUTC((exp / 10) + '0');
1073
+ PUTC((exp % 10) + '0');
1074
+ if (param->left_adjusted) {
1075
+ PUTC_N(' ', padding_len);
1076
+ }
1077
+ return outlen;
1078
+ }
1079
+
1080
+ static int output_fdbl(pfb_putc_t func, void *handle, const param_t *param, int len)
1081
+ {
1082
+ pfb_double dbl = param->u.val.dbl;
1083
+ int prec = get_prec(param, 6);
1084
+ pfb_double intpart = 0.0;
1085
+ pfb_double d = 10.0;
1086
+ int ilen = 1; /* length of integer part */
1087
+ int datalen;
1088
+ int outlen = 0;
1089
+ int padding_len;
1090
+ char sign = 0;
1091
+
1092
+ if (!isfinite(dbl)) {
1093
+ return output_no_finite_dbl(func, handle, param);
1094
+ }
1095
+ if (signbit(dbl)) {
1096
+ dbl = -dbl;
1097
+ sign = '-';
1098
+ } else if (param->add_sign) {
1099
+ sign = '+';
1100
+ } else if (param->blank) {
1101
+ sign = ' ';
1102
+ }
1103
+ if (dbl != 0.0) {
1104
+ if (prec > 0) {
1105
+ dbl += 0.5 * pfb_pow(0.1, prec);
1106
+ }
1107
+ intpart = pfb_floor(dbl);
1108
+ while (dbl >= d) {
1109
+ d *= 10.0;
1110
+ ilen++;
1111
+ }
1112
+ }
1113
+ datalen = ilen + prec;
1114
+ if (sign) {
1115
+ datalen++;
1116
+ }
1117
+ if (prec || param->alternate_form) {
1118
+ datalen++; /* dot */
1119
+ }
1120
+ padding_len = param->width - datalen;
1121
+ /* put characters */
1122
+ if (!param->left_adjusted && !param->zero_padded) {
1123
+ PUTC_N(' ', padding_len);
1124
+ }
1125
+ if (sign) {
1126
+ PUTC(sign);
1127
+ }
1128
+ if (!param->left_adjusted && param->zero_padded) {
1129
+ PUTC_N('0', padding_len);
1130
+ }
1131
+ d /= 10.0;
1132
+ while (ilen-- > 0) {
1133
+ pfb_double top_dec = pfb_floor(intpart / d);
1134
+ PUTC((int)top_dec + '0');
1135
+ intpart -= top_dec * d;
1136
+ d /= 10.0;
1137
+ }
1138
+ if (prec || param->alternate_form) {
1139
+ PUTC('.');
1140
+ }
1141
+ while (prec-- > 0) {
1142
+ intpart = pfb_floor(dbl);
1143
+ dbl -= intpart;
1144
+ dbl *= 10.0;
1145
+ PUTC((int)dbl + '0');
1146
+ }
1147
+ if (param->left_adjusted) {
1148
+ PUTC_N(' ', padding_len);
1149
+ }
1150
+ return outlen;
1151
+ }
1152
+
1153
+ static inline int out_gdbl(pfb_putc_t func, void *handle, const param_t *param, pfb_double intpart, pfb_double fracpart, int ilen, int flen, int exp)
1154
+ {
1155
+ int outlen = 0;
1156
+ int num_zeros = 0;
1157
+ int dot = 0;
1158
+ if (ilen == 1) {
1159
+ COND_PUTC((int)intpart + '0');
1160
+ } else {
1161
+ pfb_double d = pfb_pow(10.0, ilen - 1);
1162
+ do {
1163
+ int ival = (int)(intpart / d);
1164
+ COND_PUTC(ival + '0');
1165
+ intpart -= ival * d;
1166
+ d /= 10.0;
1167
+ } while (d >= 1.0);
1168
+ }
1169
+ fracpart *= 10.0;
1170
+ while (flen-- > 0) {
1171
+ int ival = (int)fracpart;
1172
+ if (ival == 0) {
1173
+ num_zeros++;
1174
+ } else {
1175
+ if (!dot) {
1176
+ COND_PUTC('.');
1177
+ dot = 1;
1178
+ }
1179
+ if (num_zeros) {
1180
+ COND_PUTC_N('0', num_zeros);
1181
+ num_zeros = 0;
1182
+ }
1183
+ COND_PUTC(ival + '0');
1184
+ }
1185
+ fracpart -= ival;
1186
+ fracpart *= 10.0;
1187
+ }
1188
+ if (param->alternate_form) {
1189
+ if (!dot) {
1190
+ COND_PUTC('.');
1191
+ }
1192
+ if (num_zeros) {
1193
+ COND_PUTC_N('0', num_zeros);
1194
+ }
1195
+ }
1196
+ if (exp) {
1197
+ COND_PUTC(param->upper ? 'E' : 'e');
1198
+ if (exp > 0) {
1199
+ COND_PUTC('+');
1200
+ } else {
1201
+ COND_PUTC('-');
1202
+ exp = -exp;
1203
+ }
1204
+ COND_PUTC((exp / 10) + '0');
1205
+ COND_PUTC((exp % 10) + '0');
1206
+ }
1207
+ return outlen;
1208
+ }
1209
+
1210
+ static int output_gdbl(pfb_putc_t func, void *handle, const param_t *param, int len)
1211
+ {
1212
+ pfb_double dbl = param->u.val.dbl;
1213
+ int prec = get_prec(param, 6);
1214
+ int outlen = 0;
1215
+ pfb_double intpart;
1216
+ pfb_double fracpart;
1217
+ int ilen; /* length of integer part */
1218
+ int flen; /* length of fractional part */
1219
+ int exp = 0;
1220
+ int padding_len;
1221
+ char sign = 0;
1222
+ int rv;
1223
+
1224
+ if (!isfinite(dbl)) {
1225
+ return output_no_finite_dbl(func, handle, param);
1226
+ }
1227
+ if (prec == 0) {
1228
+ prec = 1;
1229
+ }
1230
+ if (signbit(dbl)) {
1231
+ dbl = -dbl;
1232
+ sign = '-';
1233
+ } else if (param->add_sign) {
1234
+ sign = '+';
1235
+ } else if (param->blank) {
1236
+ sign = ' ';
1237
+ }
1238
+ if (dbl != 0.0) {
1239
+ exp = (int)pfb_floor(pfb_log10(dbl));
1240
+ dbl += pfb_pow(10.0, exp - prec + 1) / 2;
1241
+ if (dbl >= pfb_pow(10.0, exp + 1)) {
1242
+ exp++;
1243
+ }
1244
+
1245
+ if (exp < -4 || exp > prec) {
1246
+ dbl /= pfb_pow(10.0, exp);
1247
+ ilen = 1;
1248
+ flen = prec - 1;
1249
+ } else {
1250
+ if (exp >= 0) {
1251
+ ilen = exp + 1;
1252
+ flen = prec - ilen;
1253
+ } else {
1254
+ ilen = 1;
1255
+ flen = prec - exp - 1;
1256
+ }
1257
+ exp = 0;
1258
+ }
1259
+ intpart = pfb_floor(dbl);
1260
+ fracpart = dbl - intpart;
1261
+ } else {
1262
+ intpart = 0.0;
1263
+ fracpart = 0.0;
1264
+ ilen = 0;
1265
+ flen = prec - 1;
1266
+ exp = 0;
1267
+ }
1268
+ padding_len = param->width - out_gdbl(NULL, NULL, param, intpart, fracpart, ilen, flen, exp);
1269
+ if (sign) {
1270
+ padding_len--;
1271
+ }
1272
+ /* put characters */
1273
+ if (!param->left_adjusted && !param->zero_padded) {
1274
+ PUTC_N(' ', padding_len);
1275
+ }
1276
+ if (sign) {
1277
+ PUTC(sign);
1278
+ }
1279
+ if (!param->left_adjusted && param->zero_padded) {
1280
+ PUTC_N('0', padding_len);
1281
+ }
1282
+ rv = out_gdbl(func, handle, param, intpart, fracpart, ilen, flen, exp);
1283
+ if (rv == -1) {
1284
+ return rv;
1285
+ }
1286
+ outlen += rv;
1287
+ if (param->left_adjusted) {
1288
+ PUTC_N(' ', padding_len);
1289
+ }
1290
+ return outlen;
1291
+ }
1292
+
1293
+ static int output_adbl(pfb_putc_t func, void *handle, const param_t *param, int len)
1294
+ {
1295
+ pfb_double dbl = param->u.val.dbl;
1296
+ int prec = get_prec(param, 6);
1297
+ int outlen = 0;
1298
+ int exp;
1299
+ char exp_sign;
1300
+ char sign = 0;
1301
+ int padding_len;
1302
+
1303
+ if (!isfinite(dbl)) {
1304
+ return output_no_finite_dbl(func, handle, param);
1305
+ }
1306
+ if (signbit(dbl)) {
1307
+ dbl = -dbl;
1308
+ sign = '-';
1309
+ } else if (param->add_sign) {
1310
+ sign = '+';
1311
+ } else if (param->blank) {
1312
+ sign = ' ';
1313
+ }
1314
+ padding_len = param->width - (prec + 6);
1315
+ dbl = pfb_frexp(dbl, &exp);
1316
+ if (dbl != 0.0) {
1317
+ switch (param->lm) {
1318
+ case LM_LONGLONG:
1319
+ case LM_LONGDOUBLE:
1320
+ dbl *= (1 << 4);
1321
+ exp -= 4;
1322
+ break;
1323
+ default:
1324
+ dbl *= (1 << 1);
1325
+ exp -= 1;
1326
+ break;
1327
+ }
1328
+ dbl += 0.5 * pfb_pow(0.0625, prec);
1329
+ }
1330
+ if (exp >= 0) {
1331
+ exp_sign = '+';
1332
+ } else {
1333
+ exp = - exp;
1334
+ exp_sign = '-';
1335
+ }
1336
+ if (exp > 10) {
1337
+ padding_len--;
1338
+ }
1339
+ if (prec > 0 || param->alternate_form) {
1340
+ padding_len--;
1341
+ }
1342
+ if (sign) {
1343
+ padding_len--;
1344
+ }
1345
+ /* put characters */
1346
+ if (!param->left_adjusted && !param->zero_padded) {
1347
+ PUTC_N(' ', padding_len);
1348
+ }
1349
+ if (sign) {
1350
+ PUTC(sign);
1351
+ }
1352
+ PUTC('0');
1353
+ PUTC(param->upper ? 'X' : 'x');
1354
+ if (!param->left_adjusted && param->zero_padded) {
1355
+ PUTC_N('0', padding_len);
1356
+ }
1357
+ PUT_HEX((int)dbl);
1358
+ if (prec > 0) {
1359
+ PUTC('.');
1360
+ while (prec-- > 0) {
1361
+ pfb_double intpart = pfb_floor(dbl);
1362
+ dbl -= intpart;
1363
+ dbl *= 16.0;
1364
+ PUT_HEX((int)dbl);
1365
+ }
1366
+ } else if (param->alternate_form) {
1367
+ PUTC('.');
1368
+ }
1369
+ PUTC(param->upper ? 'P' : 'p');
1370
+ PUTC(exp_sign);
1371
+ if (exp < 10) {
1372
+ PUTC(exp + '0');
1373
+ } else {
1374
+ PUTC((exp / 10) + '0');
1375
+ PUTC((exp % 10) + '0');
1376
+ }
1377
+ if (param->left_adjusted) {
1378
+ PUTC_N(' ', padding_len);
1379
+ }
1380
+ return outlen;
1381
+ }
1382
+
1383
+ static int output_no_finite_dbl(pfb_putc_t func, void *handle, const param_t *param)
1384
+ {
1385
+ pfb_double dbl = param->u.val.dbl;
1386
+ int outlen = 0;
1387
+ const char *str;
1388
+ size_t slen;
1389
+ int padding_len;
1390
+ char sign = 0;
1391
+
1392
+ if (signbit(dbl)) {
1393
+ sign = '-';
1394
+ } else if (param->add_sign) {
1395
+ sign = '+';
1396
+ } else if (param->blank) {
1397
+ sign = ' ';
1398
+ }
1399
+ if (isnan(dbl)) {
1400
+ str = param->upper ? "NAN" : "nan";
1401
+ slen = 3;
1402
+ } else {
1403
+ str = param->upper ? "INF" : "inf";
1404
+ slen = 3;
1405
+ }
1406
+ padding_len = (int)(param->width - slen);
1407
+ if (sign) {
1408
+ padding_len--;
1409
+ }
1410
+ /* put characters */
1411
+ if (!param->left_adjusted) {
1412
+ PUTC_N(' ', padding_len);
1413
+ }
1414
+ if (sign) {
1415
+ PUTC(sign);
1416
+ }
1417
+ PUTS(str, slen);
1418
+ if (param->left_adjusted) {
1419
+ PUTC_N(' ', padding_len);
1420
+ }
1421
+ return outlen;
1422
+ }
1423
+ #endif
1424
+
1425
+ static int output_chr(pfb_putc_t func, void *handle, const param_t *param, int len)
1426
+ {
1427
+ int outlen = 0;
1428
+ if (!param->left_adjusted) {
1429
+ PUTC_N(' ', param->width - 1);
1430
+ }
1431
+ PUTC((char)param->u.val.ival);
1432
+ if (param->left_adjusted) {
1433
+ PUTC_N(' ', param->width - 1);
1434
+ }
1435
+ return outlen;
1436
+ }
1437
+
1438
+ static int output_str(pfb_putc_t func, void *handle, const param_t *param, int len)
1439
+ {
1440
+ const char *str = param->u.val.ptr;
1441
+ size_t slen = 0;
1442
+ int outlen = 0;
1443
+
1444
+ if (str == NULL) {
1445
+ if (param->prec_is_set && param->prec < 6) {
1446
+ str = "";
1447
+ slen = 0;
1448
+ } else {
1449
+ str = "(null)";
1450
+ slen = 6;
1451
+ }
1452
+ } else {
1453
+ if (param->prec_is_set) {
1454
+ for (slen = 0; str[slen] != 0; slen++) {
1455
+ if (slen == (size_t)param->prec) {
1456
+ break;
1457
+ }
1458
+ }
1459
+ } else {
1460
+ slen = strlen(str);
1461
+ }
1462
+ }
1463
+ if (!param->left_adjusted) {
1464
+ PUTC_N(' ', (int)(param->width - slen));
1465
+ }
1466
+ PUTS(str, slen);
1467
+ if (param->left_adjusted) {
1468
+ PUTC_N(' ', (int)(param->width - slen));
1469
+ }
1470
+ return outlen;
1471
+ }
1472
+
1473
+ #ifndef PFB_NO_WIDE_CHAR_FORMAT
1474
+ static int output_wcs(pfb_putc_t func, void *handle, const param_t *param, int len)
1475
+ {
1476
+ const wchar_t *wcs = (const wchar_t *)param->u.val.ptr;
1477
+ char *str;
1478
+ size_t slen;
1479
+ int outlen = 0;
1480
+ int use_malloc = 0;
1481
+
1482
+ if (wcs == NULL) {
1483
+ if (param->prec_is_set && param->prec < 6) {
1484
+ str = "";
1485
+ slen = 0;
1486
+ } else {
1487
+ str = "(null)";
1488
+ slen = 6;
1489
+ }
1490
+ } else {
1491
+ mbstate_t mbstate;
1492
+ size_t wlen;
1493
+ size_t prec = SIZE_MAX;
1494
+ size_t sz;
1495
+ int i;
1496
+
1497
+ if (param->prec_is_set) {
1498
+ if (param->prec > 0) {
1499
+ prec = (size_t)param->prec;
1500
+ } else {
1501
+ prec = 0;
1502
+ }
1503
+ }
1504
+ for (wlen = 0; wcs[wlen] != 0; wlen++) {
1505
+ if (wlen == prec) {
1506
+ break;
1507
+ }
1508
+ }
1509
+ if (wlen > 4096) {
1510
+ str = malloc(4 * wlen);
1511
+ if (str == NULL) {
1512
+ return -1;
1513
+ }
1514
+ use_malloc = 1;
1515
+ } else {
1516
+ str = alloca(4 * wlen);
1517
+ }
1518
+ slen = 0;
1519
+ memset(&mbstate, 0, sizeof(mbstate_t));
1520
+ for (i = 0; i < wlen; i++) {
1521
+ sz = wcrtomb(str + slen, wcs[i], &mbstate);
1522
+ if (sz != (size_t)-1) {
1523
+ if (slen + sz > prec) {
1524
+ break;
1525
+ }
1526
+ slen += sz;
1527
+ if (slen == prec) {
1528
+ break;
1529
+ }
1530
+ }
1531
+ }
1532
+ if (i == wlen) {
1533
+ sz = wcrtomb(str + slen, L'\0', &mbstate);
1534
+ if (sz != (size_t)-1) {
1535
+ while (sz > 0 && str[slen + sz - 1] == '\0') {
1536
+ sz--;
1537
+ }
1538
+ if (slen + sz <= prec) {
1539
+ slen += sz;
1540
+ }
1541
+ }
1542
+ }
1543
+ }
1544
+ if (!param->left_adjusted) {
1545
+ PUTC_N(' ', (int)(param->width - slen));
1546
+ }
1547
+ PUTS(str, slen);
1548
+ if (param->left_adjusted) {
1549
+ PUTC_N(' ', (int)(param->width - slen));
1550
+ }
1551
+ if (use_malloc) {
1552
+ free(str);
1553
+ }
1554
+ return outlen;
1555
+ }
1556
+
1557
+ static int output_wch(pfb_putc_t func, void *handle, const param_t *param, int len)
1558
+ {
1559
+ wchar_t wch = (wchar_t)param->u.val.ival;
1560
+ mbstate_t mbstate;
1561
+ char str[10];
1562
+ size_t slen;
1563
+ int outlen = 0;
1564
+
1565
+ memset(&mbstate, 0, sizeof(mbstate_t));
1566
+ slen = wcrtomb(str, wch, &mbstate);
1567
+ if (slen != (size_t)-1) {
1568
+ while (slen > 0 && str[slen - 1] == '\0') {
1569
+ slen--;
1570
+ }
1571
+ } else {
1572
+ slen = 0;
1573
+ }
1574
+ if (!param->left_adjusted) {
1575
+ PUTC_N(' ', (int)(param->width - slen));
1576
+ }
1577
+ PUTS(str, slen);
1578
+ if (param->left_adjusted) {
1579
+ PUTC_N(' ', (int)(param->width - slen));
1580
+ }
1581
+ return outlen;
1582
+ }
1583
+ #endif
1584
+
1585
+ static int output_ptr(pfb_putc_t func, void *handle, const param_t *param, int len)
1586
+ {
1587
+ char buf[30];
1588
+ int64_t uival = param->u.val.uival;
1589
+ int i;
1590
+ int prec;
1591
+ int outlen = 0;
1592
+ int datalen;
1593
+ int bufused;
1594
+ char sign = 0;
1595
+
1596
+ if (uival == 0) {
1597
+ if (!param->left_adjusted) {
1598
+ PUTC_N(' ', param->width - 5);
1599
+ }
1600
+ PUTS("(nil)", 5);
1601
+ if (param->left_adjusted) {
1602
+ PUTC_N(' ', param->width - 5);
1603
+ }
1604
+ return outlen;
1605
+ }
1606
+
1607
+ if (param->add_sign) {
1608
+ sign = '+';
1609
+ } else if (param->blank) {
1610
+ sign = ' ';
1611
+ }
1612
+
1613
+ for (i = sizeof(buf) - 1; i >= 0; i--) {
1614
+ if ((uival & 0xf) < 10) {
1615
+ buf[i] = (uival & 0xf) + '0';
1616
+ } else {
1617
+ buf[i] = (uival & 0xf) - 10 + ((param->upper) ? 'A' : 'a');
1618
+ }
1619
+ uival >>= 4;
1620
+ if (uival == 0) {
1621
+ break;
1622
+ }
1623
+ }
1624
+ bufused = sizeof(buf) - i;
1625
+ /* calculate padding length */
1626
+ prec = bufused;
1627
+ if (param->prec_is_set && prec < param->prec) {
1628
+ prec = param->prec;
1629
+ }
1630
+ datalen = prec + 2;
1631
+ if (sign) {
1632
+ datalen++;
1633
+ }
1634
+ /* put characters */
1635
+ if (!param->left_adjusted) {
1636
+ PUTC_N(' ', param->width - datalen);
1637
+ }
1638
+ if (sign) {
1639
+ PUTC(sign);
1640
+ }
1641
+ PUTC('0');
1642
+ PUTC((param->upper) ? 'X' : 'x');
1643
+ PUTC_N('0', prec - bufused);
1644
+ PUTS(buf + i, bufused);
1645
+ if (param->left_adjusted) {
1646
+ PUTC_N(' ', param->width - datalen);
1647
+ }
1648
+ return outlen;
1649
+ }
1650
+
1651
+ static int output_num_written(pfb_putc_t func, void *handle, const param_t *param, int len)
1652
+ {
1653
+ const char *addr = param->u.val.ptr;
1654
+ switch (param->lm) {
1655
+ case LM_CHAR:
1656
+ *(unsigned char*)addr = len;
1657
+ break;
1658
+ case LM_SHORT:
1659
+ *(unsigned short*)addr = len;
1660
+ break;
1661
+ case LM_LONG:
1662
+ *(long*)addr = len;
1663
+ break;
1664
+ case LM_LONGLONG:
1665
+ *(int64_t*)addr = len;
1666
+ break;
1667
+ case LM_INTMAX_T:
1668
+ *(intmax_t*)addr = len;
1669
+ break;
1670
+ case LM_SIZE_T:
1671
+ *(size_t*)addr = len;
1672
+ break;
1673
+ case LM_PTRDIFF_T:
1674
+ *(ptrdiff_t*)addr = len;
1675
+ break;
1676
+ default:
1677
+ *(int*)addr = len;
1678
+ break;
1679
+ }
1680
+ return 0;
1681
+ }
1682
+
1683
+ static int output_percent_char(pfb_putc_t func, void *handle, const param_t *param, int len)
1684
+ {
1685
+ int outlen = 0;
1686
+ PUTC('%');
1687
+ return outlen;
1688
+ }