contrast-agent 3.8.4

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 (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
+ }