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.
- checksums.yaml +7 -0
- data/.clang-format +5 -0
- data/.dockerignore +10 -0
- data/.gitignore +58 -0
- data/.gitmodules +6 -0
- data/.rspec +6 -0
- data/.simplecov +4 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +12 -0
- data/Rakefile +15 -0
- data/exe/contrast_service +29 -0
- data/ext/build_funchook.rb +48 -0
- data/ext/cs__assess_active_record_named/cs__active_record_named.c +47 -0
- data/ext/cs__assess_active_record_named/cs__active_record_named.h +10 -0
- data/ext/cs__assess_active_record_named/extconf.rb +2 -0
- data/ext/cs__assess_array/cs__assess_array.c +38 -0
- data/ext/cs__assess_array/cs__assess_array.h +9 -0
- data/ext/cs__assess_array/extconf.rb +2 -0
- data/ext/cs__assess_basic_object/cs__assess_basic_object.c +50 -0
- data/ext/cs__assess_basic_object/cs__assess_basic_object.h +17 -0
- data/ext/cs__assess_basic_object/extconf.rb +2 -0
- data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +86 -0
- data/ext/cs__assess_fiber_track/cs__assess_fiber_track.h +34 -0
- data/ext/cs__assess_fiber_track/extconf.rb +2 -0
- data/ext/cs__assess_hash/cs__assess_hash.c +64 -0
- data/ext/cs__assess_hash/cs__assess_hash.h +24 -0
- data/ext/cs__assess_hash/extconf.rb +2 -0
- data/ext/cs__assess_kernel/cs__assess_kernel.c +36 -0
- data/ext/cs__assess_kernel/cs__assess_kernel.h +10 -0
- data/ext/cs__assess_kernel/extconf.rb +2 -0
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +47 -0
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +18 -0
- data/ext/cs__assess_marshal_module/extconf.rb +2 -0
- data/ext/cs__assess_module/cs__assess_module.c +78 -0
- data/ext/cs__assess_module/cs__assess_module.h +25 -0
- data/ext/cs__assess_module/extconf.rb +2 -0
- data/ext/cs__assess_regexp/cs__assess_regexp.c +48 -0
- data/ext/cs__assess_regexp/cs__assess_regexp.h +22 -0
- data/ext/cs__assess_regexp/extconf.rb +2 -0
- data/ext/cs__assess_regexp_track/cs__assess_regexp_track.c +63 -0
- data/ext/cs__assess_regexp_track/cs__assess_regexp_track.h +29 -0
- data/ext/cs__assess_regexp_track/extconf.rb +2 -0
- data/ext/cs__assess_string/cs__assess_string.c +38 -0
- data/ext/cs__assess_string/cs__assess_string.h +19 -0
- data/ext/cs__assess_string/extconf.rb +2 -0
- data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +31 -0
- data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.h +13 -0
- data/ext/cs__assess_string_interpolation26/extconf.rb +2 -0
- data/ext/cs__common/cs__common.c +60 -0
- data/ext/cs__common/cs__common.h +28 -0
- data/ext/cs__common/extconf.rb +20 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.c +445 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.h +196 -0
- data/ext/cs__contrast_patch/extconf.rb +2 -0
- data/ext/cs__protect_kernel/cs__protect_kernel.c +37 -0
- data/ext/cs__protect_kernel/cs__protect_kernel.h +11 -0
- data/ext/cs__protect_kernel/extconf.rb +2 -0
- data/ext/cs__scope/cs__scope.c +96 -0
- data/ext/cs__scope/cs__scope.h +33 -0
- data/ext/cs__scope/extconf.rb +2 -0
- data/ext/extconf_common.rb +49 -0
- data/funchook/LICENSE +360 -0
- data/funchook/Makefile +29 -0
- data/funchook/Makefile.in +29 -0
- data/funchook/README.md +121 -0
- data/funchook/appveyor.yml +42 -0
- data/funchook/autogen.sh +3 -0
- data/funchook/autom4te.cache/output.0 +4976 -0
- data/funchook/autom4te.cache/requests +78 -0
- data/funchook/autom4te.cache/traces.0 +364 -0
- data/funchook/config.guess +1530 -0
- data/funchook/config.log +490 -0
- data/funchook/config.status +1016 -0
- data/funchook/config.sub +1773 -0
- data/funchook/configure +4976 -0
- data/funchook/configure.ac +59 -0
- data/funchook/distorm/COPYING +26 -0
- data/funchook/distorm/MANIFEST +25 -0
- data/funchook/distorm/MANIFEST.in +4 -0
- data/funchook/distorm/README.md +12 -0
- data/funchook/distorm/disOps/disOps.py +795 -0
- data/funchook/distorm/disOps/x86db.py +404 -0
- data/funchook/distorm/disOps/x86header.py +247 -0
- data/funchook/distorm/disOps/x86sets.py +1664 -0
- data/funchook/distorm/examples/cs/TestdiStorm/Program.cs +79 -0
- data/funchook/distorm/examples/cs/TestdiStorm/Properties/AssemblyInfo.cs +36 -0
- data/funchook/distorm/examples/cs/TestdiStorm/TestdiStorm.csproj +69 -0
- data/funchook/distorm/examples/cs/distorm-net.sln +26 -0
- data/funchook/distorm/examples/cs/distorm-net/CodeInfo.cs +23 -0
- data/funchook/distorm/examples/cs/distorm-net/DecodedInst.cs +15 -0
- data/funchook/distorm/examples/cs/distorm-net/DecodedResult.cs +14 -0
- data/funchook/distorm/examples/cs/distorm-net/DecomposedInst.cs +36 -0
- data/funchook/distorm/examples/cs/distorm-net/DecomposedResult.cs +14 -0
- data/funchook/distorm/examples/cs/distorm-net/Opcodes.cs +1268 -0
- data/funchook/distorm/examples/cs/distorm-net/Opcodes.tt +37 -0
- data/funchook/distorm/examples/cs/distorm-net/Operand.cs +25 -0
- data/funchook/distorm/examples/cs/distorm-net/Properties/AssemblyInfo.cs +36 -0
- data/funchook/distorm/examples/cs/distorm-net/diStorm3.cs +411 -0
- data/funchook/distorm/examples/cs/distorm-net/distorm-net.csproj +80 -0
- data/funchook/distorm/examples/cs/readme +3 -0
- data/funchook/distorm/examples/ddk/README +48 -0
- data/funchook/distorm/examples/ddk/distorm.ini +11 -0
- data/funchook/distorm/examples/ddk/dummy.c +15 -0
- data/funchook/distorm/examples/ddk/main.c +91 -0
- data/funchook/distorm/examples/ddk/makefile +1 -0
- data/funchook/distorm/examples/ddk/sources +10 -0
- data/funchook/distorm/examples/java/Makefile +23 -0
- data/funchook/distorm/examples/java/distorm/src/Main.java +43 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/CodeInfo.java +27 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedInst.java +32 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecodedResult.java +11 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedInst.java +89 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/DecomposedResult.java +11 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/OpcodeEnum.java +131 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/Opcodes.java +1123 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/Operand.java +24 -0
- data/funchook/distorm/examples/java/distorm/src/diStorm3/distorm3.java +41 -0
- data/funchook/distorm/examples/java/jdistorm.c +405 -0
- data/funchook/distorm/examples/java/jdistorm.h +40 -0
- data/funchook/distorm/examples/java/jdistorm.sln +20 -0
- data/funchook/distorm/examples/java/jdistorm.vcproj +208 -0
- data/funchook/distorm/examples/linux/Makefile +15 -0
- data/funchook/distorm/examples/linux/main.c +181 -0
- data/funchook/distorm/examples/tests/Makefile +15 -0
- data/funchook/distorm/examples/tests/main.cpp +42 -0
- data/funchook/distorm/examples/tests/main.py +66 -0
- data/funchook/distorm/examples/tests/test_distorm3.py +1672 -0
- data/funchook/distorm/examples/tests/tests.sln +20 -0
- data/funchook/distorm/examples/tests/tests.vcxproj +82 -0
- data/funchook/distorm/examples/tests/tests.vcxproj.filters +22 -0
- data/funchook/distorm/examples/win32/disasm.sln +25 -0
- data/funchook/distorm/examples/win32/disasm.vcxproj +201 -0
- data/funchook/distorm/examples/win32/disasm.vcxproj.filters +14 -0
- data/funchook/distorm/examples/win32/main.cpp +163 -0
- data/funchook/distorm/include/distorm.h +482 -0
- data/funchook/distorm/include/mnemonics.h +301 -0
- data/funchook/distorm/make/linux/Makefile +28 -0
- data/funchook/distorm/make/mac/Makefile +24 -0
- data/funchook/distorm/make/win32/cdistorm.vcxproj +239 -0
- data/funchook/distorm/make/win32/cdistorm.vcxproj.filters +80 -0
- data/funchook/distorm/make/win32/distorm.sln +25 -0
- data/funchook/distorm/make/win32/resource.h +14 -0
- data/funchook/distorm/make/win32/resource.rc +99 -0
- data/funchook/distorm/python/distorm3/__init__.py +957 -0
- data/funchook/distorm/python/distorm3/sample.py +51 -0
- data/funchook/distorm/setup.cfg +10 -0
- data/funchook/distorm/setup.py +266 -0
- data/funchook/distorm/src/config.h +169 -0
- data/funchook/distorm/src/decoder.c +641 -0
- data/funchook/distorm/src/decoder.h +33 -0
- data/funchook/distorm/src/distorm.c +413 -0
- data/funchook/distorm/src/instructions.c +597 -0
- data/funchook/distorm/src/instructions.h +463 -0
- data/funchook/distorm/src/insts.c +7939 -0
- data/funchook/distorm/src/insts.h +64 -0
- data/funchook/distorm/src/mnemonics.c +284 -0
- data/funchook/distorm/src/operands.c +1290 -0
- data/funchook/distorm/src/operands.h +28 -0
- data/funchook/distorm/src/prefix.c +368 -0
- data/funchook/distorm/src/prefix.h +64 -0
- data/funchook/distorm/src/textdefs.c +172 -0
- data/funchook/distorm/src/textdefs.h +57 -0
- data/funchook/distorm/src/wstring.c +47 -0
- data/funchook/distorm/src/wstring.h +35 -0
- data/funchook/distorm/src/x86defs.h +82 -0
- data/funchook/include/funchook.h +123 -0
- data/funchook/install-sh +527 -0
- data/funchook/src/Makefile +70 -0
- data/funchook/src/Makefile.in +70 -0
- data/funchook/src/__strerror.h +109 -0
- data/funchook/src/config.h +101 -0
- data/funchook/src/config.h.in +100 -0
- data/funchook/src/decoder.o +0 -0
- data/funchook/src/distorm.o +0 -0
- data/funchook/src/funchook.c +440 -0
- data/funchook/src/funchook.o +0 -0
- data/funchook/src/funchook_internal.h +155 -0
- data/funchook/src/funchook_io.c +182 -0
- data/funchook/src/funchook_io.h +64 -0
- data/funchook/src/funchook_io.o +0 -0
- data/funchook/src/funchook_syscall.S +134 -0
- data/funchook/src/funchook_syscall.o +0 -0
- data/funchook/src/funchook_unix.c +480 -0
- data/funchook/src/funchook_unix.o +0 -0
- data/funchook/src/funchook_windows.c +397 -0
- data/funchook/src/funchook_x86.c +622 -0
- data/funchook/src/funchook_x86.o +0 -0
- data/funchook/src/instructions.o +0 -0
- data/funchook/src/insts.o +0 -0
- data/funchook/src/libfunchook.so +0 -0
- data/funchook/src/mnemonics.o +0 -0
- data/funchook/src/operands.o +0 -0
- data/funchook/src/os_func.c +115 -0
- data/funchook/src/os_func.h +75 -0
- data/funchook/src/os_func.o +0 -0
- data/funchook/src/os_func_unix.c +94 -0
- data/funchook/src/os_func_unix.o +0 -0
- data/funchook/src/os_func_windows.c +32 -0
- data/funchook/src/prefix.o +0 -0
- data/funchook/src/printf_base.c +1688 -0
- data/funchook/src/printf_base.h +46 -0
- data/funchook/src/printf_base.o +0 -0
- data/funchook/src/textdefs.o +0 -0
- data/funchook/src/wstring.o +0 -0
- data/funchook/test/Makefile +43 -0
- data/funchook/test/Makefile.in +43 -0
- data/funchook/test/funchook_test +0 -0
- data/funchook/test/libfunchook_test.c +25 -0
- data/funchook/test/libfunchook_test.so +0 -0
- data/funchook/test/libfunchook_test2.c +18 -0
- data/funchook/test/suffix.list +600 -0
- data/funchook/test/test_main.c +430 -0
- data/funchook/test/test_main.o +0 -0
- data/funchook/test/x86_64_test.S +10 -0
- data/funchook/test/x86_64_test.o +0 -0
- data/funchook/test/x86_test.S +339 -0
- data/funchook/win32/config.h +1 -0
- data/funchook/win32/funchook.sln +52 -0
- data/funchook/win32/funchook.vcxproj +188 -0
- data/funchook/win32/funchook.vcxproj.filters +84 -0
- data/funchook/win32/funchook_test.vcxproj +170 -0
- data/funchook/win32/funchook_test.vcxproj.filters +22 -0
- data/funchook/win32/funchook_test_dll.vcxproj +184 -0
- data/funchook/win32/funchook_test_dll.vcxproj.filters +30 -0
- data/funchook/win32/funchook_test_exe.def +3 -0
- data/lib/contrast-agent.rb +8 -0
- data/lib/contrast.rb +57 -0
- data/lib/contrast/agent.rb +80 -0
- data/lib/contrast/agent/assess.rb +45 -0
- data/lib/contrast/agent/assess/adjusted_span.rb +25 -0
- data/lib/contrast/agent/assess/class_reverter.rb +82 -0
- data/lib/contrast/agent/assess/contrast_event.rb +398 -0
- data/lib/contrast/agent/assess/frozen_properties.rb +41 -0
- data/lib/contrast/agent/assess/insulator.rb +53 -0
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +78 -0
- data/lib/contrast/agent/assess/policy/patcher.rb +85 -0
- data/lib/contrast/agent/assess/policy/policy.rb +116 -0
- data/lib/contrast/agent/assess/policy/policy_node.rb +289 -0
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +44 -0
- data/lib/contrast/agent/assess/policy/preshift.rb +94 -0
- data/lib/contrast/agent/assess/policy/propagation_method.rb +260 -0
- data/lib/contrast/agent/assess/policy/propagation_node.rb +127 -0
- data/lib/contrast/agent/assess/policy/propagator.rb +35 -0
- data/lib/contrast/agent/assess/policy/propagator/append.rb +54 -0
- data/lib/contrast/agent/assess/policy/propagator/base.rb +37 -0
- data/lib/contrast/agent/assess/policy/propagator/center.rb +73 -0
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +36 -0
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +62 -0
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +55 -0
- data/lib/contrast/agent/assess/policy/propagator/keep.rb +26 -0
- data/lib/contrast/agent/assess/policy/propagator/next.rb +42 -0
- data/lib/contrast/agent/assess/policy/propagator/prepend.rb +50 -0
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +76 -0
- data/lib/contrast/agent/assess/policy/propagator/replace.rb +27 -0
- data/lib/contrast/agent/assess/policy/propagator/reverse.rb +38 -0
- data/lib/contrast/agent/assess/policy/propagator/select.rb +86 -0
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +60 -0
- data/lib/contrast/agent/assess/policy/propagator/split.rb +49 -0
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +169 -0
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +81 -0
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +79 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +209 -0
- data/lib/contrast/agent/assess/policy/source_node.rb +62 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +209 -0
- data/lib/contrast/agent/assess/policy/trigger_node.rb +198 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +77 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +31 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +40 -0
- data/lib/contrast/agent/assess/properties.rb +392 -0
- data/lib/contrast/agent/assess/rule.rb +18 -0
- data/lib/contrast/agent/assess/rule/base.rb +72 -0
- data/lib/contrast/agent/assess/rule/csrf.rb +66 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_action.rb +28 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +69 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_watcher.rb +132 -0
- data/lib/contrast/agent/assess/rule/provider.rb +21 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +62 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +73 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +121 -0
- data/lib/contrast/agent/assess/rule/redos.rb +68 -0
- data/lib/contrast/agent/assess/rule/response_scanning_rule.rb +47 -0
- data/lib/contrast/agent/assess/rule/response_watcher.rb +36 -0
- data/lib/contrast/agent/assess/rule/watcher.rb +36 -0
- data/lib/contrast/agent/assess/tag.rb +151 -0
- data/lib/contrast/agent/at_exit_hook.rb +33 -0
- data/lib/contrast/agent/class_reopener.rb +195 -0
- data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +26 -0
- data/lib/contrast/agent/deadzone/policy/policy.rb +57 -0
- data/lib/contrast/agent/disable_reaction.rb +24 -0
- data/lib/contrast/agent/exclusion_matcher.rb +190 -0
- data/lib/contrast/agent/feature_state.rb +379 -0
- data/lib/contrast/agent/inventory/policy/policy.rb +32 -0
- data/lib/contrast/agent/inventory/policy/trigger_node.rb +22 -0
- data/lib/contrast/agent/logger_manager.rb +116 -0
- data/lib/contrast/agent/middleware.rb +352 -0
- data/lib/contrast/agent/module_data.rb +16 -0
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +37 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +58 -0
- data/lib/contrast/agent/patching/policy/method_policy.rb +94 -0
- data/lib/contrast/agent/patching/policy/module_policy.rb +116 -0
- data/lib/contrast/agent/patching/policy/patch.rb +312 -0
- data/lib/contrast/agent/patching/policy/patch_status.rb +192 -0
- data/lib/contrast/agent/patching/policy/patcher.rb +310 -0
- data/lib/contrast/agent/patching/policy/policy.rb +138 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +80 -0
- data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +28 -0
- data/lib/contrast/agent/patching/policy/trigger_node.rb +81 -0
- data/lib/contrast/agent/protect/policy/policy.rb +37 -0
- data/lib/contrast/agent/protect/policy/trigger_node.rb +23 -0
- data/lib/contrast/agent/protect/rule.rb +58 -0
- data/lib/contrast/agent/protect/rule/base.rb +300 -0
- data/lib/contrast/agent/protect/rule/base_service.rb +88 -0
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +156 -0
- data/lib/contrast/agent/protect/rule/csrf.rb +118 -0
- data/lib/contrast/agent/protect/rule/csrf/csrf_evaluator.rb +103 -0
- data/lib/contrast/agent/protect/rule/csrf/csrf_token_injector.rb +85 -0
- data/lib/contrast/agent/protect/rule/default_scanner.rb +300 -0
- data/lib/contrast/agent/protect/rule/deserialization.rb +193 -0
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +80 -0
- data/lib/contrast/agent/protect/rule/no_sqli.rb +101 -0
- data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +40 -0
- data/lib/contrast/agent/protect/rule/path_traversal.rb +143 -0
- data/lib/contrast/agent/protect/rule/sqli.rb +101 -0
- data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +16 -0
- data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +38 -0
- data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +22 -0
- data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +19 -0
- data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +20 -0
- data/lib/contrast/agent/protect/rule/xss.rb +24 -0
- data/lib/contrast/agent/protect/rule/xxe.rb +120 -0
- data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +82 -0
- data/lib/contrast/agent/railtie.rb +30 -0
- data/lib/contrast/agent/reaction_processor.rb +47 -0
- data/lib/contrast/agent/request.rb +493 -0
- data/lib/contrast/agent/request_context.rb +225 -0
- data/lib/contrast/agent/require_state.rb +61 -0
- data/lib/contrast/agent/response.rb +215 -0
- data/lib/contrast/agent/rewriter.rb +244 -0
- data/lib/contrast/agent/scope.rb +28 -0
- data/lib/contrast/agent/service_heartbeat.rb +37 -0
- data/lib/contrast/agent/settings_state.rb +148 -0
- data/lib/contrast/agent/socket_client.rb +125 -0
- data/lib/contrast/agent/thread.rb +26 -0
- data/lib/contrast/agent/tracepoint_hook.rb +51 -0
- data/lib/contrast/agent/version.rb +8 -0
- data/lib/contrast/api.rb +17 -0
- data/lib/contrast/api/.gitkeep +0 -0
- data/lib/contrast/api/connection_status.rb +49 -0
- data/lib/contrast/api/socket.rb +43 -0
- data/lib/contrast/api/speedracer.rb +206 -0
- data/lib/contrast/api/tcp_socket.rb +31 -0
- data/lib/contrast/api/unix_socket.rb +25 -0
- data/lib/contrast/common_agent_configuration.rb +86 -0
- data/lib/contrast/components/agent.rb +85 -0
- data/lib/contrast/components/app_context.rb +188 -0
- data/lib/contrast/components/assess.rb +67 -0
- data/lib/contrast/components/config.rb +135 -0
- data/lib/contrast/components/contrast_service.rb +113 -0
- data/lib/contrast/components/heap_dump.rb +34 -0
- data/lib/contrast/components/interface.rb +178 -0
- data/lib/contrast/components/inventory.rb +23 -0
- data/lib/contrast/components/logger.rb +92 -0
- data/lib/contrast/components/protect.rb +38 -0
- data/lib/contrast/components/sampling.rb +41 -0
- data/lib/contrast/components/scope.rb +106 -0
- data/lib/contrast/components/settings.rb +140 -0
- data/lib/contrast/config.rb +33 -0
- data/lib/contrast/config/agent_configuration.rb +24 -0
- data/lib/contrast/config/application_configuration.rb +27 -0
- data/lib/contrast/config/assess_configuration.rb +22 -0
- data/lib/contrast/config/assess_rules_configuration.rb +18 -0
- data/lib/contrast/config/base_configuration.rb +105 -0
- data/lib/contrast/config/default_value.rb +16 -0
- data/lib/contrast/config/exception_configuration.rb +21 -0
- data/lib/contrast/config/heap_dump_configuration.rb +23 -0
- data/lib/contrast/config/inventory_configuration.rb +20 -0
- data/lib/contrast/config/logger_configuration.rb +20 -0
- data/lib/contrast/config/protect_configuration.rb +20 -0
- data/lib/contrast/config/protect_rule_configuration.rb +37 -0
- data/lib/contrast/config/protect_rules_configuration.rb +30 -0
- data/lib/contrast/config/root_configuration.rb +26 -0
- data/lib/contrast/config/ruby_configuration.rb +39 -0
- data/lib/contrast/config/sampling_configuration.rb +22 -0
- data/lib/contrast/config/server_configuration.rb +23 -0
- data/lib/contrast/config/service_configuration.rb +22 -0
- data/lib/contrast/configuration.rb +214 -0
- data/lib/contrast/core_extensions/assess.rb +51 -0
- data/lib/contrast/core_extensions/assess/array.rb +58 -0
- data/lib/contrast/core_extensions/assess/assess_extension.rb +145 -0
- data/lib/contrast/core_extensions/assess/basic_object.rb +15 -0
- data/lib/contrast/core_extensions/assess/erb.rb +42 -0
- data/lib/contrast/core_extensions/assess/exec_trigger.rb +48 -0
- data/lib/contrast/core_extensions/assess/fiber.rb +125 -0
- data/lib/contrast/core_extensions/assess/hash.rb +22 -0
- data/lib/contrast/core_extensions/assess/kernel.rb +95 -0
- data/lib/contrast/core_extensions/assess/module.rb +14 -0
- data/lib/contrast/core_extensions/assess/regexp.rb +206 -0
- data/lib/contrast/core_extensions/assess/string.rb +75 -0
- data/lib/contrast/core_extensions/assess/tilt_template_trigger.rb +73 -0
- data/lib/contrast/core_extensions/delegator.rb +14 -0
- data/lib/contrast/core_extensions/eval_trigger.rb +52 -0
- data/lib/contrast/core_extensions/inventory.rb +22 -0
- data/lib/contrast/core_extensions/inventory/datastores.rb +37 -0
- data/lib/contrast/core_extensions/module.rb +42 -0
- data/lib/contrast/core_extensions/object.rb +27 -0
- data/lib/contrast/core_extensions/protect.rb +20 -0
- data/lib/contrast/core_extensions/protect/applies_command_injection_rule.rb +70 -0
- data/lib/contrast/core_extensions/protect/applies_deserialization_rule.rb +58 -0
- data/lib/contrast/core_extensions/protect/applies_no_sqli_rule.rb +81 -0
- data/lib/contrast/core_extensions/protect/applies_path_traversal_rule.rb +119 -0
- data/lib/contrast/core_extensions/protect/applies_sqli_rule.rb +63 -0
- data/lib/contrast/core_extensions/protect/applies_xxe_rule.rb +141 -0
- data/lib/contrast/core_extensions/protect/kernel.rb +30 -0
- data/lib/contrast/core_extensions/protect/psych.rb +7 -0
- data/lib/contrast/core_extensions/thread.rb +31 -0
- data/lib/contrast/internal_exception.rb +8 -0
- data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +48 -0
- data/lib/contrast/rails_extensions/assess/active_record.rb +32 -0
- data/lib/contrast/rails_extensions/assess/active_record_named.rb +61 -0
- data/lib/contrast/rails_extensions/assess/configuration.rb +26 -0
- data/lib/contrast/rails_extensions/buffer.rb +30 -0
- data/lib/contrast/rails_extensions/rack.rb +45 -0
- data/lib/contrast/security_exception.rb +14 -0
- data/lib/contrast/sinatra_extensions/assess/cookie.rb +26 -0
- data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +59 -0
- data/lib/contrast/tasks/service.rb +95 -0
- data/lib/contrast/utils/assess/sampling_util.rb +96 -0
- data/lib/contrast/utils/assess/tracking_util.rb +39 -0
- data/lib/contrast/utils/boolean_util.rb +33 -0
- data/lib/contrast/utils/cache.rb +69 -0
- data/lib/contrast/utils/class_util.rb +58 -0
- data/lib/contrast/utils/comment_range.rb +19 -0
- data/lib/contrast/utils/data_store_util.rb +23 -0
- data/lib/contrast/utils/duck_utils.rb +58 -0
- data/lib/contrast/utils/env_configuration_item.rb +52 -0
- data/lib/contrast/utils/environment_util.rb +152 -0
- data/lib/contrast/utils/freeze_util.rb +36 -0
- data/lib/contrast/utils/gemfile_reader.rb +191 -0
- data/lib/contrast/utils/hash_digest.rb +148 -0
- data/lib/contrast/utils/heap_dump_util.rb +113 -0
- data/lib/contrast/utils/invalid_configuration_util.rb +88 -0
- data/lib/contrast/utils/inventory_util.rb +126 -0
- data/lib/contrast/utils/io_util.rb +61 -0
- data/lib/contrast/utils/object_share.rb +117 -0
- data/lib/contrast/utils/operating_environment.rb +38 -0
- data/lib/contrast/utils/os.rb +49 -0
- data/lib/contrast/utils/path_util.rb +151 -0
- data/lib/contrast/utils/performs_logging.rb +152 -0
- data/lib/contrast/utils/preflight_util.rb +13 -0
- data/lib/contrast/utils/prevent_serialization.rb +52 -0
- data/lib/contrast/utils/rack_assess_session_cookie.rb +104 -0
- data/lib/contrast/utils/rails_assess_configuration.rb +95 -0
- data/lib/contrast/utils/random_util.rb +22 -0
- data/lib/contrast/utils/resource_loader.rb +23 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +74 -0
- data/lib/contrast/utils/scope_util.rb +99 -0
- data/lib/contrast/utils/service_response_util.rb +116 -0
- data/lib/contrast/utils/service_sender_util.rb +98 -0
- data/lib/contrast/utils/sha256_builder.rb +69 -0
- data/lib/contrast/utils/sinatra_helper.rb +49 -0
- data/lib/contrast/utils/stack_trace_utils.rb +209 -0
- data/lib/contrast/utils/string_utils.rb +72 -0
- data/lib/contrast/utils/tag_util.rb +139 -0
- data/lib/contrast/utils/thread_tracker.rb +54 -0
- data/lib/contrast/utils/timer.rb +78 -0
- data/resources/assess/policy.json +1673 -0
- data/resources/csrf/inject.js +44 -0
- data/resources/deadzone/policy.json +55 -0
- data/resources/factory-bot-spec/spec_helper.rb +30 -0
- data/resources/inventory/policy.json +110 -0
- data/resources/protect/policy.json +417 -0
- data/resources/rubocops/kernel/catch_cop.rb +37 -0
- data/resources/rubocops/kernel/require_cop.rb +37 -0
- data/resources/rubocops/kernel/require_relative_cop.rb +33 -0
- data/resources/rubocops/module/autoload_cop.rb +37 -0
- data/resources/rubocops/module/const_defined_cop.rb +37 -0
- data/resources/rubocops/module/const_get_cop.rb +37 -0
- data/resources/rubocops/module/const_set_cop.rb +37 -0
- data/resources/rubocops/module/constants_cop.rb +37 -0
- data/resources/rubocops/module/name_cop.rb +37 -0
- data/resources/rubocops/object/class_cop.rb +37 -0
- data/resources/rubocops/object/freeze_cop.rb +37 -0
- data/resources/rubocops/object/frozen_cop.rb +37 -0
- data/resources/rubocops/object/is_a_cop.rb +37 -0
- data/resources/rubocops/object/method_cop.rb +37 -0
- data/resources/rubocops/object/respond_to_cop.rb +37 -0
- data/resources/rubocops/object/singleton_class_cop.rb +37 -0
- data/resources/rubocops/regexp/spelling_cop.rb +44 -0
- data/resources/rubocops/thread/new_cop.rb +39 -0
- data/resources/ruby-spec/ancestors_spec.rb +70 -0
- data/resources/ruby-spec/modulo_spec.rb +831 -0
- data/resources/ruby-spec/parameters_spec.rb +261 -0
- data/resources/ruby-spec/ruby_spec_spec_helper.rb +35 -0
- data/resources/test_marker.txt +1 -0
- data/ruby-agent.gemspec +129 -0
- data/service_executables/.gitkeep +0 -0
- data/service_executables/VERSION +1 -0
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +945 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
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
|
+
}
|
|
Binary file
|
|
@@ -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, ¶ms[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 = ¶ms[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
|
+
}
|