mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2026-09-15 11:55:10 -05:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb1442b734 | ||
|
|
87b7e53973 | ||
|
|
2e45f095ba | ||
|
|
e12cd63ba2 | ||
|
|
8804e667b3 | ||
|
|
f5b8af3f2a | ||
|
|
ab6c3fc8bc | ||
|
|
7a56fab96e |
21
Dockerfile.dev
Normal file
21
Dockerfile.dev
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
FROM --platform=amd64 debian:11.6-slim@sha256:f7d141c1ec6af549958a7a2543365a7829c2cdc4476308ec2e182f8a7c59b519
|
||||||
|
|
||||||
|
LABEL description="Development environment for bemanitools"
|
||||||
|
|
||||||
|
# mingw-w64-gcc has 32-bit and 64-bit toolchains
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
mingw-w64 \
|
||||||
|
mingw-w64-common \
|
||||||
|
make \
|
||||||
|
zip \
|
||||||
|
git \
|
||||||
|
clang-format \
|
||||||
|
python3-pip \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN pip3 install mdformat
|
||||||
|
|
||||||
|
RUN mkdir /bemanitools
|
||||||
|
WORKDIR /bemanitools
|
||||||
|
|
||||||
|
ENV SHELL /bin/bash
|
||||||
38
GNUmakefile
38
GNUmakefile
@@ -13,8 +13,10 @@ BUILDDIR ?= build
|
|||||||
|
|
||||||
builddir_docker := $(BUILDDIR)/docker
|
builddir_docker := $(BUILDDIR)/docker
|
||||||
|
|
||||||
docker_container_name := "bemanitools-build"
|
docker_build_container_name := "bemanitools-build"
|
||||||
docker_image_name := "bemanitools-build:latest"
|
docker_build_image_name := "bemanitools-build:latest"
|
||||||
|
docker_dev_container_name := "bemanitools-dev"
|
||||||
|
docker_dev_image_name := "bemanitools-dev:latest"
|
||||||
|
|
||||||
depdir := $(BUILDDIR)/dep
|
depdir := $(BUILDDIR)/dep
|
||||||
objdir := $(BUILDDIR)/obj
|
objdir := $(BUILDDIR)/obj
|
||||||
@@ -41,6 +43,7 @@ FORCE:
|
|||||||
|
|
||||||
.PHONY: \
|
.PHONY: \
|
||||||
build-docker \
|
build-docker \
|
||||||
|
dev-docker \
|
||||||
clean \
|
clean \
|
||||||
code-format \
|
code-format \
|
||||||
doc-format \
|
doc-format \
|
||||||
@@ -89,21 +92,38 @@ version:
|
|||||||
$(V)echo "$(gitrev)" > version
|
$(V)echo "$(gitrev)" > version
|
||||||
|
|
||||||
build-docker:
|
build-docker:
|
||||||
$(V)docker rm -f $(docker_container_name) 2> /dev/null || true
|
$(V)docker rm -f $(docker_build_container_name) 2> /dev/null || true
|
||||||
$(V)docker \
|
$(V)docker \
|
||||||
build \
|
build \
|
||||||
-t $(docker_image_name) \
|
-t $(docker_build_image_name) \
|
||||||
-f Dockerfile \
|
-f Dockerfile.build \
|
||||||
.
|
.
|
||||||
$(V)docker \
|
$(V)docker \
|
||||||
run \
|
run \
|
||||||
--volume $(shell pwd):/bemanitools \
|
--volume $(shell pwd):/bemanitools \
|
||||||
--name $(docker_container_name) \
|
--name $(docker_build_container_name) \
|
||||||
$(docker_image_name)
|
$(docker_build_image_name)
|
||||||
|
|
||||||
|
dev-docker:
|
||||||
|
$(V)docker rm -f $(docker_dev_container_name) 2> /dev/null || true
|
||||||
|
$(V)docker \
|
||||||
|
build \
|
||||||
|
-t $(docker_dev_image_name) \
|
||||||
|
-f Dockerfile.dev \
|
||||||
|
.
|
||||||
|
$(V)docker \
|
||||||
|
run \
|
||||||
|
--interactive \
|
||||||
|
--tty \
|
||||||
|
--volume $(shell pwd):/bemanitools \
|
||||||
|
--name $(docker_dev_container_name) \
|
||||||
|
$(docker_dev_image_name)
|
||||||
|
|
||||||
clean-docker:
|
clean-docker:
|
||||||
$(V)docker rm -f $(docker_container_name) || true
|
$(V)docker rm -f $(docker_dev_container_name) || true
|
||||||
$(V)docker image rm -f $(docker_image_name) || true
|
$(V)docker image rm -f $(docker_dev_image_name) || true
|
||||||
|
$(V)docker rm -f $(docker_build_container_name) || true
|
||||||
|
$(V)docker image rm -f $(docker_build_image_name) || true
|
||||||
$(V)rm -rf $(BUILDDIR)
|
$(V)rm -rf $(BUILDDIR)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ include src/main/bstio/Module.mk
|
|||||||
include src/main/camhook/Module.mk
|
include src/main/camhook/Module.mk
|
||||||
include src/main/cconfig/Module.mk
|
include src/main/cconfig/Module.mk
|
||||||
include src/main/config/Module.mk
|
include src/main/config/Module.mk
|
||||||
|
include src/main/core/Module.mk
|
||||||
include src/main/d3d9-util/Module.mk
|
include src/main/d3d9-util/Module.mk
|
||||||
include src/main/d3d9exhook/Module.mk
|
include src/main/d3d9exhook/Module.mk
|
||||||
include src/main/ddrhook-util/Module.mk
|
include src/main/ddrhook-util/Module.mk
|
||||||
@@ -710,6 +711,8 @@ $(zipdir)/ddr-14-to-18.zip: \
|
|||||||
build/bin/indep-32/eamio.dll \
|
build/bin/indep-32/eamio.dll \
|
||||||
build/bin/indep-32/geninput.dll \
|
build/bin/indep-32/geninput.dll \
|
||||||
dist/ddr/config.bat \
|
dist/ddr/config.bat \
|
||||||
|
dist/ddr/gamestart-17.bat \
|
||||||
|
dist/ddr/gamestart-18.bat \
|
||||||
dist/ddr/gamestart-14.bat \
|
dist/ddr/gamestart-14.bat \
|
||||||
dist/ddr/gamestart-15.bat \
|
dist/ddr/gamestart-15.bat \
|
||||||
dist/ddr/gamestart-16.bat \
|
dist/ddr/gamestart-16.bat \
|
||||||
@@ -728,6 +731,8 @@ $(zipdir)/ddr-16-to-18-x64.zip: \
|
|||||||
build/bin/indep-64/eamio.dll \
|
build/bin/indep-64/eamio.dll \
|
||||||
build/bin/indep-64/geninput.dll \
|
build/bin/indep-64/geninput.dll \
|
||||||
dist/ddr/config.bat \
|
dist/ddr/config.bat \
|
||||||
|
dist/ddr/gamestart-17.bat \
|
||||||
|
dist/ddr/gamestart-18.bat \
|
||||||
dist/ddr/gamestart-16.bat \
|
dist/ddr/gamestart-16.bat \
|
||||||
dist/ddr/gamestart-17.bat \
|
dist/ddr/gamestart-17.bat \
|
||||||
dist/ddr/gamestart-18.bat \
|
dist/ddr/gamestart-18.bat \
|
||||||
|
|||||||
@@ -220,6 +220,9 @@ void property_file_write(struct property *prop, const char *path);
|
|||||||
int property_set_flag(struct property *prop, int flags, int mask);
|
int property_set_flag(struct property *prop, int flags, int mask);
|
||||||
void property_destroy(struct property *prop);
|
void property_destroy(struct property *prop);
|
||||||
|
|
||||||
|
avs_error property_get_error(struct property *prop);
|
||||||
|
void property_clear_error(struct property *prop);
|
||||||
|
|
||||||
int property_psmap_import(
|
int property_psmap_import(
|
||||||
struct property *prop,
|
struct property *prop,
|
||||||
struct property_node *root,
|
struct property_node *root,
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ EXPORTS
|
|||||||
property_destroy
|
property_destroy
|
||||||
property_file_write
|
property_file_write
|
||||||
property_insert_read
|
property_insert_read
|
||||||
|
property_clear_error
|
||||||
|
property_get_error
|
||||||
property_mem_write
|
property_mem_write
|
||||||
property_read_query_memsize
|
property_read_query_memsize
|
||||||
property_search
|
property_search
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ EXPORTS
|
|||||||
property_destroy
|
property_destroy
|
||||||
property_file_write
|
property_file_write
|
||||||
property_insert_read
|
property_insert_read
|
||||||
|
property_clear_error
|
||||||
|
property_get_error
|
||||||
property_mem_write
|
property_mem_write
|
||||||
property_read_query_memsize
|
property_read_query_memsize
|
||||||
property_search
|
property_search
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ EXPORTS
|
|||||||
property_desc_to_buffer @246 NONAME
|
property_desc_to_buffer @246 NONAME
|
||||||
property_destroy @247 NONAME
|
property_destroy @247 NONAME
|
||||||
property_insert_read @255 NONAME
|
property_insert_read @255 NONAME
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_node_create @266 NONAME
|
property_node_create @266 NONAME
|
||||||
property_node_datasize @267 NONAME
|
property_node_datasize @267 NONAME
|
||||||
property_node_name @274 NONAME
|
property_node_name @274 NONAME
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ EXPORTS
|
|||||||
property_desc_to_buffer @201 NONAME
|
property_desc_to_buffer @201 NONAME
|
||||||
property_destroy @264 NONAME
|
property_destroy @264 NONAME
|
||||||
property_insert_read @23 NONAME
|
property_insert_read @23 NONAME
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_node_create @316 NONAME
|
property_node_create @316 NONAME
|
||||||
property_node_datasize @249 NONAME
|
property_node_datasize @249 NONAME
|
||||||
property_node_name @255 NONAME
|
property_node_name @255 NONAME
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ EXPORTS
|
|||||||
property_desc_to_buffer @201 NONAME == XC058ba50000cd
|
property_desc_to_buffer @201 NONAME == XC058ba50000cd
|
||||||
property_destroy @264 NONAME == XC058ba500010f
|
property_destroy @264 NONAME == XC058ba500010f
|
||||||
property_insert_read @23 NONAME == XC058ba5000016
|
property_insert_read @23 NONAME == XC058ba5000016
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_node_create @316 NONAME == XC058ba5000143
|
property_node_create @316 NONAME == XC058ba5000143
|
||||||
property_node_datasize @249 NONAME == XC058ba5000100
|
property_node_datasize @249 NONAME == XC058ba5000100
|
||||||
property_node_name @255 NONAME == XC058ba5000106
|
property_node_name @255 NONAME == XC058ba5000106
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ EXPORTS
|
|||||||
property_desc_to_buffer @131 NONAME
|
property_desc_to_buffer @131 NONAME
|
||||||
property_destroy @130 NONAME
|
property_destroy @130 NONAME
|
||||||
property_insert_read @133 NONAME
|
property_insert_read @133 NONAME
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_node_name @573 NONAME ==
|
property_node_name @573 NONAME ==
|
||||||
property_node_read @573 NONAME ==
|
property_node_read @573 NONAME ==
|
||||||
property_node_remove @148 NONAME
|
property_node_remove @148 NONAME
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ EXPORTS
|
|||||||
property_desc_to_buffer @129 NONAME
|
property_desc_to_buffer @129 NONAME
|
||||||
property_destroy @128 NONAME
|
property_destroy @128 NONAME
|
||||||
property_insert_read @131 NONAME
|
property_insert_read @131 NONAME
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_node_create @145 NONAME
|
property_node_create @145 NONAME
|
||||||
property_node_name @150 NONAME
|
property_node_name @150 NONAME
|
||||||
property_node_read @154 NONAME == XCd229cc0000f3
|
property_node_read @154 NONAME == XCd229cc0000f3
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ EXPORTS
|
|||||||
property_destroy @125 NONAME
|
property_destroy @125 NONAME
|
||||||
property_desc_to_buffer @126 NONAME
|
property_desc_to_buffer @126 NONAME
|
||||||
property_insert_read @128 NONAME
|
property_insert_read @128 NONAME
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_search @141 NONAME
|
property_search @141 NONAME
|
||||||
property_node_create @142 NONAME
|
property_node_create @142 NONAME
|
||||||
property_node_name @147 NONAME == XCnbrep7000092
|
property_node_name @147 NONAME == XCnbrep7000092
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ EXPORTS
|
|||||||
property_destroy @146 NONAME
|
property_destroy @146 NONAME
|
||||||
property_desc_to_buffer @147 NONAME
|
property_desc_to_buffer @147 NONAME
|
||||||
property_insert_read @149 NONAME
|
property_insert_read @149 NONAME
|
||||||
|
property_clear_error @158 NONAME == XCnbrep700009d
|
||||||
|
property_get_error @159 NONAME == XCnbrep700009e
|
||||||
property_search @162 NONAME
|
property_search @162 NONAME
|
||||||
property_node_create @163 NONAME
|
property_node_create @163 NONAME
|
||||||
property_node_name @168 NONAME == XCnbrep70000a7
|
property_node_name @168 NONAME == XCnbrep70000a7
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ EXPORTS
|
|||||||
property_destroy @146 NONAME
|
property_destroy @146 NONAME
|
||||||
property_desc_to_buffer @147 NONAME
|
property_desc_to_buffer @147 NONAME
|
||||||
property_insert_read @149 NONAME
|
property_insert_read @149 NONAME
|
||||||
|
property_clear_error @158 NONAME == XCgsqzn000009d
|
||||||
|
property_get_error @159 NONAME == XCgsqzn000009e
|
||||||
property_search @162 NONAME
|
property_search @162 NONAME
|
||||||
property_node_create @163 NONAME
|
property_node_create @163 NONAME
|
||||||
property_node_name @168 NONAME == XCgsqzn00000a7
|
property_node_name @168 NONAME == XCgsqzn00000a7
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ EXPORTS
|
|||||||
property_destroy
|
property_destroy
|
||||||
property_file_write
|
property_file_write
|
||||||
property_insert_read
|
property_insert_read
|
||||||
|
property_clear_error
|
||||||
|
property_get_error
|
||||||
property_mem_write
|
property_mem_write
|
||||||
property_read_query_memsize
|
property_read_query_memsize
|
||||||
property_search
|
property_search
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ EXPORTS
|
|||||||
property_desc_to_buffer @129 NONAME
|
property_desc_to_buffer @129 NONAME
|
||||||
property_destroy @128 NONAME
|
property_destroy @128 NONAME
|
||||||
property_insert_read @131 NONAME
|
property_insert_read @131 NONAME
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_node_create @145 NONAME
|
property_node_create @145 NONAME
|
||||||
property_node_name @150 NONAME
|
property_node_name @150 NONAME
|
||||||
property_node_read @154 NONAME == XCd229cc0000f3
|
property_node_read @154 NONAME == XCd229cc0000f3
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ EXPORTS
|
|||||||
property_desc_to_buffer @129 NONAME
|
property_desc_to_buffer @129 NONAME
|
||||||
property_destroy @128 NONAME
|
property_destroy @128 NONAME
|
||||||
property_insert_read @131 NONAME
|
property_insert_read @131 NONAME
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_node_create @145 NONAME
|
property_node_create @145 NONAME
|
||||||
property_node_name @573 NONAME ==
|
property_node_name @573 NONAME ==
|
||||||
property_node_read @573 NONAME ==
|
property_node_read @573 NONAME ==
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ EXPORTS
|
|||||||
property_destroy @125 NONAME
|
property_destroy @125 NONAME
|
||||||
property_desc_to_buffer @126 NONAME
|
property_desc_to_buffer @126 NONAME
|
||||||
property_insert_read @128 NONAME
|
property_insert_read @128 NONAME
|
||||||
|
property_clear_error @573 NONAME
|
||||||
|
property_get_error @573 NONAME
|
||||||
property_search @141 NONAME
|
property_search @141 NONAME
|
||||||
property_node_create @142 NONAME
|
property_node_create @142 NONAME
|
||||||
property_node_name @147 NONAME == XCnbrep7000092
|
property_node_name @147 NONAME == XCnbrep7000092
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ EXPORTS
|
|||||||
property_destroy @146 NONAME
|
property_destroy @146 NONAME
|
||||||
property_desc_to_buffer @147 NONAME
|
property_desc_to_buffer @147 NONAME
|
||||||
property_insert_read @149 NONAME
|
property_insert_read @149 NONAME
|
||||||
|
property_clear_error @158 NONAME == XCnbrep700009d
|
||||||
|
property_get_error @159 NONAME == XCnbrep700009e
|
||||||
property_search @162 NONAME
|
property_search @162 NONAME
|
||||||
property_node_create @163 NONAME
|
property_node_create @163 NONAME
|
||||||
property_node_name @168 NONAME == XCnbrep70000a7
|
property_node_name @168 NONAME == XCnbrep70000a7
|
||||||
property_node_remove @164 NONAME
|
property_node_remove @164 NONAME
|
||||||
property_node_type @169 NONAME == XCnbrep70000a8
|
property_node_type @169 NONAME == XCnbrep70000a8
|
||||||
property_node_clone @165 NONAME
|
property_node_clone @165 NONAME == XCnbrep70000a4
|
||||||
property_node_traversal @167 NONAME
|
property_node_traversal @167 NONAME
|
||||||
property_node_refdata @166 NONAME == XCnbrep70000a5
|
property_node_refdata @166 NONAME == XCnbrep70000a5
|
||||||
property_node_datasize @171 NONAME == XCnbrep70000aa
|
property_node_datasize @171 NONAME == XCnbrep70000aa
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ EXPORTS
|
|||||||
property_destroy @146 NONAME
|
property_destroy @146 NONAME
|
||||||
property_desc_to_buffer @147 NONAME
|
property_desc_to_buffer @147 NONAME
|
||||||
property_insert_read @149 NONAME
|
property_insert_read @149 NONAME
|
||||||
|
property_clear_error @158 NONAME == XCgsqzn000009d
|
||||||
|
property_get_error @159 NONAME == XCgsqzn000009e
|
||||||
property_search @162 NONAME
|
property_search @162 NONAME
|
||||||
property_node_create @163 NONAME
|
property_node_create @163 NONAME
|
||||||
property_node_name @168 NONAME == XCgsqzn00000a7
|
property_node_name @168 NONAME == XCgsqzn00000a7
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ libs += avs-util
|
|||||||
libs_avs-util := \
|
libs_avs-util := \
|
||||||
|
|
||||||
src_avs-util := \
|
src_avs-util := \
|
||||||
|
core-interop.c \
|
||||||
error.c \
|
error.c \
|
||||||
|
|||||||
16
src/main/avs-util/core-interop.c
Normal file
16
src/main/avs-util/core-interop.c
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include "core/log.h"
|
||||||
|
#include "core/thread.h"
|
||||||
|
|
||||||
|
#include "imports/avs.h"
|
||||||
|
|
||||||
|
void avs_util_core_interop_log_avs_impl_set()
|
||||||
|
{
|
||||||
|
core_log_impl_set(
|
||||||
|
log_body_misc, log_body_info, log_body_warning, log_body_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void avs_util_core_interop_thread_avs_impl_set()
|
||||||
|
{
|
||||||
|
core_thread_impl_set(
|
||||||
|
avs_thread_create, avs_thread_join, avs_thread_destroy);
|
||||||
|
}
|
||||||
7
src/main/avs-util/core-interop.h
Normal file
7
src/main/avs-util/core-interop.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef AVS_UTIL_CORE_INTEROP_H
|
||||||
|
#define AVS_UTIL_CORE_INTEROP_H
|
||||||
|
|
||||||
|
void avs_util_core_interop_log_avs_impl_set();
|
||||||
|
void avs_util_core_interop_thread_avs_impl_set();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -97,3 +97,13 @@ const char *avs_util_error_str(avs_error error)
|
|||||||
|
|
||||||
return avs_util_error_unknown;
|
return avs_util_error_unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *avs_util_property_error_get_and_clear(struct property *prop)
|
||||||
|
{
|
||||||
|
avs_error error;
|
||||||
|
|
||||||
|
error = property_get_error(prop);
|
||||||
|
property_clear_error(prop);
|
||||||
|
|
||||||
|
return avs_util_error_str(error);
|
||||||
|
}
|
||||||
@@ -5,4 +5,6 @@
|
|||||||
|
|
||||||
const char *avs_util_error_str(avs_error error);
|
const char *avs_util_error_str(avs_error error);
|
||||||
|
|
||||||
|
const char *avs_util_property_error_get_and_clear(struct property *prop);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
20
src/main/core/Module.mk
Normal file
20
src/main/core/Module.mk
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
libs += core
|
||||||
|
|
||||||
|
libs_core := \
|
||||||
|
util \
|
||||||
|
|
||||||
|
src_core := \
|
||||||
|
log-bt-ext.c \
|
||||||
|
log-bt.c \
|
||||||
|
log-sink-async.c \
|
||||||
|
log-sink-debug.c \
|
||||||
|
log-sink-file.c \
|
||||||
|
log-sink-list.c \
|
||||||
|
log-sink-mutex.c \
|
||||||
|
log-sink-null.c \
|
||||||
|
log-sink-std.c \
|
||||||
|
log.c \
|
||||||
|
thread-crt-ext.c \
|
||||||
|
thread-crt.c \
|
||||||
|
thread.c \
|
||||||
|
|
||||||
67
src/main/core/log-bt-ext.c
Normal file
67
src/main/core/log-bt-ext.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "core/log-bt.h"
|
||||||
|
#include "core/log-sink-debug.h"
|
||||||
|
#include "core/log-sink-file.h"
|
||||||
|
#include "core/log-sink-list.h"
|
||||||
|
#include "core/log-sink-mutex.h"
|
||||||
|
#include "core/log-sink-std.h"
|
||||||
|
#include "core/log.h"
|
||||||
|
|
||||||
|
void core_log_bt_ext_impl_set()
|
||||||
|
{
|
||||||
|
core_log_impl_set(
|
||||||
|
core_log_bt_log_misc,
|
||||||
|
core_log_bt_log_info,
|
||||||
|
core_log_bt_log_warning,
|
||||||
|
core_log_bt_log_fatal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_ext_init_with_stdout()
|
||||||
|
{
|
||||||
|
struct core_log_sink sink;
|
||||||
|
|
||||||
|
core_log_sink_std_out_open(true, &sink);
|
||||||
|
core_log_bt_init(&sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_ext_init_with_stderr()
|
||||||
|
{
|
||||||
|
struct core_log_sink sink;
|
||||||
|
|
||||||
|
core_log_sink_std_err_open(true, &sink);
|
||||||
|
core_log_bt_init(&sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_ext_init_with_debug()
|
||||||
|
{
|
||||||
|
struct core_log_sink sink;
|
||||||
|
|
||||||
|
core_log_sink_debug_open(&sink);
|
||||||
|
core_log_bt_init(&sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_ext_init_with_file(
|
||||||
|
const char *path, bool append, bool rotate, uint8_t max_rotations)
|
||||||
|
{
|
||||||
|
struct core_log_sink sink;
|
||||||
|
|
||||||
|
core_log_sink_file_open(path, append, rotate, max_rotations, &sink);
|
||||||
|
core_log_bt_init(&sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_ext_init_with_stdout_and_file(
|
||||||
|
const char *path, bool append, bool rotate, uint8_t max_rotations)
|
||||||
|
{
|
||||||
|
struct core_log_sink sinks[2];
|
||||||
|
struct core_log_sink sink_composed;
|
||||||
|
struct core_log_sink sink_mutex;
|
||||||
|
|
||||||
|
core_log_sink_std_out_open(true, &sinks[0]);
|
||||||
|
core_log_sink_file_open(path, append, rotate, max_rotations, &sinks[1]);
|
||||||
|
core_log_sink_list_open(sinks, 2, &sink_composed);
|
||||||
|
|
||||||
|
core_log_sink_mutex_open(&sink_composed, &sink_mutex);
|
||||||
|
|
||||||
|
core_log_bt_init(&sink_mutex);
|
||||||
|
}
|
||||||
59
src/main/core/log-bt-ext.h
Normal file
59
src/main/core/log-bt-ext.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#ifndef CORE_LOG_BT_EXT_H
|
||||||
|
#define CORE_LOG_BT_EXT_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current thread API implementation to use the bemanitools log
|
||||||
|
* implementation
|
||||||
|
*/
|
||||||
|
void core_log_bt_ext_impl_set();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to setup the bemanitools log implementation with a stdout sink.
|
||||||
|
*/
|
||||||
|
void core_log_bt_ext_init_with_stdout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to setup the bemanitools log implementation with a stderr sink.
|
||||||
|
*/
|
||||||
|
void core_log_bt_ext_init_with_stderr();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to setup the bemanitools log implementation with a OutputDebugStr
|
||||||
|
* sink.
|
||||||
|
*/
|
||||||
|
void core_log_bt_ext_init_with_debug();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to setup the bemanitools log implementation with a file sink
|
||||||
|
*
|
||||||
|
* @param path Path to the log file to write the log output to
|
||||||
|
* @param append If true, then append to an existing file, false to overwrite
|
||||||
|
* any existing file
|
||||||
|
* @param rotate If true, rotates an existing log file and creates a new one
|
||||||
|
* for this session
|
||||||
|
* @param max_rotations Max number of rotations for the log files
|
||||||
|
*/
|
||||||
|
void core_log_bt_ext_init_with_file(
|
||||||
|
const char *path, bool append, bool rotate, uint8_t max_rotations);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to setup the bemanitools log implementation with a stdout and file
|
||||||
|
* sink
|
||||||
|
*
|
||||||
|
* Important: This combined sink is guarded by a mutex to avoid data races on
|
||||||
|
* logging to two different sinks.
|
||||||
|
*
|
||||||
|
* @param path Path to the log file to write the log output to
|
||||||
|
* @param append If true, then append to an existing file, false to overwrite
|
||||||
|
* any existing file
|
||||||
|
* @param rotate If true, rotates an existing log file and creates a new one
|
||||||
|
* for this session
|
||||||
|
* @param max_rotations Max number of rotations for the log files
|
||||||
|
*/
|
||||||
|
void core_log_bt_ext_init_with_stdout_and_file(
|
||||||
|
const char *path, bool append, bool rotate, uint8_t max_rotations);
|
||||||
|
|
||||||
|
#endif
|
||||||
129
src/main/core/log-bt.c
Normal file
129
src/main/core/log-bt.c
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "core/log-bt.h"
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
#include "core/log.h"
|
||||||
|
|
||||||
|
#include "util/mem.h"
|
||||||
|
#include "util/str.h"
|
||||||
|
|
||||||
|
static enum core_log_bt_log_level _core_log_bt_log_level;
|
||||||
|
static struct core_log_sink *_core_log_bt_sink;
|
||||||
|
|
||||||
|
static void _core_log_bt_vformat_write(
|
||||||
|
enum core_log_bt_log_level level,
|
||||||
|
const char *module,
|
||||||
|
const char *fmt,
|
||||||
|
va_list ap)
|
||||||
|
{
|
||||||
|
static const char chars[] = "FFWIM";
|
||||||
|
|
||||||
|
char timestamp[64];
|
||||||
|
/* 64k so we can log data dumps of rs232 without crashing */
|
||||||
|
char msg[65536];
|
||||||
|
char line[65536];
|
||||||
|
int result;
|
||||||
|
|
||||||
|
time_t curtime;
|
||||||
|
struct tm *tm;
|
||||||
|
|
||||||
|
curtime = 0;
|
||||||
|
tm = NULL;
|
||||||
|
|
||||||
|
curtime = time(NULL);
|
||||||
|
tm = localtime(&curtime);
|
||||||
|
|
||||||
|
strftime(timestamp, sizeof(timestamp), "[%Y/%m/%d %H:%M:%S]", tm);
|
||||||
|
|
||||||
|
str_vformat(msg, sizeof(msg), fmt, ap);
|
||||||
|
|
||||||
|
result = str_format(
|
||||||
|
line,
|
||||||
|
sizeof(line),
|
||||||
|
"%s %c:%s: %s\n",
|
||||||
|
timestamp,
|
||||||
|
chars[level],
|
||||||
|
module,
|
||||||
|
msg);
|
||||||
|
|
||||||
|
_core_log_bt_sink->write(_core_log_bt_sink->ctx, line, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_init(const struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
if (sink == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
_core_log_bt_sink = xmalloc(sizeof(struct core_log_sink));
|
||||||
|
memcpy(_core_log_bt_sink, sink, sizeof(struct core_log_sink));
|
||||||
|
|
||||||
|
_core_log_bt_log_level = CORE_LOG_BT_LOG_LEVEL_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_level_set(enum core_log_bt_log_level level)
|
||||||
|
{
|
||||||
|
_core_log_bt_log_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_fini()
|
||||||
|
{
|
||||||
|
log_assert(_core_log_bt_sink);
|
||||||
|
|
||||||
|
_core_log_bt_sink->close(_core_log_bt_sink->ctx);
|
||||||
|
|
||||||
|
free(_core_log_bt_sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_log_fatal(const char *module, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_FATAL) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_core_log_bt_vformat_write(
|
||||||
|
CORE_LOG_BT_LOG_LEVEL_FATAL, module, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_log_warning(const char *module, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_WARNING) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_core_log_bt_vformat_write(
|
||||||
|
CORE_LOG_BT_LOG_LEVEL_WARNING, module, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_log_info(const char *module, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_INFO) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_core_log_bt_vformat_write(CORE_LOG_BT_LOG_LEVEL_INFO, module, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_log_misc(const char *module, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (_core_log_bt_log_level >= CORE_LOG_BT_LOG_LEVEL_MISC) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_core_log_bt_vformat_write(CORE_LOG_BT_LOG_LEVEL_MISC, module, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_bt_direct_sink_write(const char *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
_core_log_bt_sink->write(_core_log_bt_sink->ctx, chars, nchars);
|
||||||
|
}
|
||||||
87
src/main/core/log-bt.h
Normal file
87
src/main/core/log-bt.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef CORE_LOG_BT_H
|
||||||
|
#define CORE_LOG_BT_H
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log API implementation for games/applications without AVS
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum core_log_bt_log_level {
|
||||||
|
CORE_LOG_BT_LOG_LEVEL_OFF = 0,
|
||||||
|
CORE_LOG_BT_LOG_LEVEL_FATAL = 1,
|
||||||
|
CORE_LOG_BT_LOG_LEVEL_WARNING = 2,
|
||||||
|
CORE_LOG_BT_LOG_LEVEL_INFO = 3,
|
||||||
|
CORE_LOG_BT_LOG_LEVEL_MISC = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the logging backend
|
||||||
|
*
|
||||||
|
* This must be called as early as possible in your application to setup
|
||||||
|
* a logging sink according to your needs. Until this is finished, no
|
||||||
|
* log output is available.
|
||||||
|
*
|
||||||
|
* By default, logging is turned off entirely and must be enabled by setting
|
||||||
|
* a desired logging level explicitly.
|
||||||
|
*
|
||||||
|
* @param sink Pointer to a log sink implementation. The caller owns the memory
|
||||||
|
* of this.
|
||||||
|
*/
|
||||||
|
void core_log_bt_init(const struct core_log_sink *sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current logging level. This can be changed at any given time, e.g.
|
||||||
|
* to increase/decrease verbosity.
|
||||||
|
*
|
||||||
|
* @param level The logging level to set.
|
||||||
|
*/
|
||||||
|
void core_log_bt_level_set(enum core_log_bt_log_level level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup the logging backend.
|
||||||
|
*
|
||||||
|
* Ensure to call this on application exit and cleanup.
|
||||||
|
*/
|
||||||
|
void core_log_bt_fini();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the log API.
|
||||||
|
*/
|
||||||
|
void core_log_bt_log_fatal(const char *module, const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the log API.
|
||||||
|
*/
|
||||||
|
void core_log_bt_log_warning(const char *module, const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the log API.
|
||||||
|
*/
|
||||||
|
void core_log_bt_log_info(const char *module, const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the log API.
|
||||||
|
*/
|
||||||
|
void core_log_bt_log_misc(const char *module, const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow AVS to by-pass the core log API/engine.
|
||||||
|
*
|
||||||
|
* This function must only be called by AVS in an appropriate log callback
|
||||||
|
* function that is passed to avs_boot.
|
||||||
|
*
|
||||||
|
* AVS has it's own logging engine and manages aspects such as async logging,
|
||||||
|
* log levels and decorating log messages.
|
||||||
|
*
|
||||||
|
* Thus, proper interoperability only requires the writer/sink part to be shared
|
||||||
|
* with AVS.
|
||||||
|
*
|
||||||
|
* @param chars Buffer with text data to write to the configured sinks. The
|
||||||
|
* buffer might contain several log messages separated by newline
|
||||||
|
* characters.
|
||||||
|
* @param nchars Number of chars to write to the sink.
|
||||||
|
*/
|
||||||
|
void core_log_bt_direct_sink_write(const char *chars, size_t nchars);
|
||||||
|
|
||||||
|
#endif
|
||||||
23
src/main/core/log-sink-async.c
Normal file
23
src/main/core/log-sink-async.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
_core_log_sink_file_write(void *ctx, const char *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _core_log_sink_file_close(void *ctx)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_sink_async_open(struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
sink->ctx = NULL;
|
||||||
|
sink->write = _core_log_sink_file_write;
|
||||||
|
sink->close = _core_log_sink_file_close;
|
||||||
|
}
|
||||||
19
src/main/core/log-sink-async.h
Normal file
19
src/main/core/log-sink-async.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef CORE_LOG_SINK_ASYNC_H
|
||||||
|
#define CORE_LOG_SINK_ASYNC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a async log sink
|
||||||
|
*
|
||||||
|
* The sink passes data to log to a separate thread which executes the actual
|
||||||
|
* logging of the data.
|
||||||
|
*
|
||||||
|
* @param sink Pointer to allocated memory that receives the opened sink
|
||||||
|
*/
|
||||||
|
void core_log_sink_async_open(struct core_log_sink *sink);
|
||||||
|
|
||||||
|
#endif
|
||||||
23
src/main/core/log-sink-debug.c
Normal file
23
src/main/core/log-sink-debug.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include <debugapi.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
_core_log_sink_debug_write(void *ctx, const char *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
OutputDebugStringA(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _core_log_sink_debug_close(void *ctx)
|
||||||
|
{
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_sink_debug_open(struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
sink->ctx = NULL;
|
||||||
|
sink->write = _core_log_sink_debug_write;
|
||||||
|
sink->close = _core_log_sink_debug_close;
|
||||||
|
}
|
||||||
15
src/main/core/log-sink-debug.h
Normal file
15
src/main/core/log-sink-debug.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef CORE_LOG_SINK_DEBUG_H
|
||||||
|
#define CORE_LOG_SINK_DEBUG_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a log sink that uses OutputDebugStr
|
||||||
|
*
|
||||||
|
* @param sink Pointer to allocated memory that receives the opened sink
|
||||||
|
*/
|
||||||
|
void core_log_sink_debug_open(struct core_log_sink *sink);
|
||||||
|
|
||||||
|
#endif
|
||||||
92
src/main/core/log-sink-file.c
Normal file
92
src/main/core/log-sink-file.c
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
#include "util/fs.h"
|
||||||
|
#include "util/str.h"
|
||||||
|
|
||||||
|
static void _core_log_sink_file_rotate(const char *path, uint8_t max_rotations)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
char rotate_file[MAX_PATH];
|
||||||
|
char rotate_file_next[MAX_PATH];
|
||||||
|
char version[8];
|
||||||
|
char version_next[8];
|
||||||
|
|
||||||
|
for (i = max_rotations; i > 0; i++) {
|
||||||
|
str_cpy(rotate_file, sizeof(rotate_file), path);
|
||||||
|
str_cpy(rotate_file_next, sizeof(rotate_file_next), path);
|
||||||
|
|
||||||
|
if (i - 1 != 0) {
|
||||||
|
sprintf(version, ".%d", i);
|
||||||
|
} else {
|
||||||
|
memset(version, 0, sizeof(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(version_next, ".%d", i);
|
||||||
|
|
||||||
|
str_cat(rotate_file, sizeof(rotate_file), version);
|
||||||
|
str_cat(rotate_file_next, sizeof(rotate_file_next), version_next);
|
||||||
|
|
||||||
|
if (path_exists(rotate_file)) {
|
||||||
|
CopyFile(rotate_file, rotate_file_next, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_core_log_sink_file_write(void *ctx, const char *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
file = (FILE *) ctx;
|
||||||
|
|
||||||
|
fwrite(chars, 1, nchars, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _core_log_sink_file_close(void *ctx)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
file = (FILE *) ctx;
|
||||||
|
|
||||||
|
fflush(file);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_sink_file_open(
|
||||||
|
const char *path,
|
||||||
|
bool append,
|
||||||
|
bool rotate,
|
||||||
|
uint8_t max_rotations,
|
||||||
|
struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
if (rotate) {
|
||||||
|
_core_log_sink_file_rotate(path, max_rotations);
|
||||||
|
|
||||||
|
// Appending doesn't matter when file is rotated anyway
|
||||||
|
file = fopen(path, "w+");
|
||||||
|
} else {
|
||||||
|
if (append) {
|
||||||
|
file = fopen(path, "a+");
|
||||||
|
} else {
|
||||||
|
file = fopen(path, "w+");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
printf("Cannot open log file: %s", path);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
sink->ctx = (void *) file;
|
||||||
|
sink->write = _core_log_sink_file_write;
|
||||||
|
sink->close = _core_log_sink_file_close;
|
||||||
|
}
|
||||||
28
src/main/core/log-sink-file.h
Normal file
28
src/main/core/log-sink-file.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef CORE_LOG_SINK_FILE_H
|
||||||
|
#define CORE_LOG_SINK_FILE_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a log sink writing data to a file
|
||||||
|
*
|
||||||
|
* @param path Path to the log file to write the log output to
|
||||||
|
* @param append If true, then append to an existing file, false to overwrite
|
||||||
|
* any existing file
|
||||||
|
* @param rotate If true, rotates an existing log file and creates a new one
|
||||||
|
* for this session
|
||||||
|
* @param max_rotations Max number of rotations for the log files
|
||||||
|
* @param sink Pointer to allocated memory that receives the opened sink
|
||||||
|
*/
|
||||||
|
void core_log_sink_file_open(
|
||||||
|
const char *path,
|
||||||
|
bool append,
|
||||||
|
bool rotate,
|
||||||
|
uint8_t max_rotations,
|
||||||
|
struct core_log_sink *sink);
|
||||||
|
|
||||||
|
#endif
|
||||||
66
src/main/core/log-sink-list.c
Normal file
66
src/main/core/log-sink-list.c
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink-list.h"
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
#include "util/mem.h"
|
||||||
|
|
||||||
|
#define MAX_SINKS 8
|
||||||
|
|
||||||
|
struct core_log_sink_list {
|
||||||
|
struct core_log_sink entries[MAX_SINKS];
|
||||||
|
uint8_t num;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
_core_log_sink_list_write(void *ctx, const char *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
struct core_log_sink_list *sink_list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sink_list = (struct core_log_sink_list *) ctx;
|
||||||
|
|
||||||
|
for (i = 0; i < sink_list->num; i++) {
|
||||||
|
sink_list->entries[i].write(sink_list->entries[i].ctx, chars, nchars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _core_log_sink_list_close(void *ctx)
|
||||||
|
{
|
||||||
|
struct core_log_sink_list *sink_list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sink_list = (struct core_log_sink_list *) ctx;
|
||||||
|
|
||||||
|
for (i = 0; i < sink_list->num; i++) {
|
||||||
|
sink_list->entries[i].close(sink_list->entries[i].ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(sink_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_sink_list_open(
|
||||||
|
const struct core_log_sink *entry, uint8_t num, struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
struct core_log_sink_list *sink_list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (num > MAX_SINKS) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
sink_list = xmalloc(sizeof(struct core_log_sink_list));
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
sink_list->entries[i].ctx = entry[i].ctx;
|
||||||
|
sink_list->entries[i].write = entry[i].write;
|
||||||
|
sink_list->entries[i].close = entry[i].close;
|
||||||
|
}
|
||||||
|
|
||||||
|
sink_list->num = num;
|
||||||
|
|
||||||
|
sink->ctx = (void *) sink_list;
|
||||||
|
sink->write = _core_log_sink_list_write;
|
||||||
|
sink->close = _core_log_sink_list_close;
|
||||||
|
}
|
||||||
24
src/main/core/log-sink-list.h
Normal file
24
src/main/core/log-sink-list.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef CORE_LOG_SINK_LIST_H
|
||||||
|
#define CORE_LOG_SINK_LIST_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine multiple log sinks into a list of sinks.
|
||||||
|
*
|
||||||
|
* Upon invoking a list sink, all sinks contained within the list are
|
||||||
|
* being invoked in the configured order.
|
||||||
|
*
|
||||||
|
* @param entry A pointer to allocated memory with a sequence of opened sinks
|
||||||
|
* that you want to add to the list. Ownership of these sinks
|
||||||
|
* is transferred, i.e. closing the list sink closes its children.
|
||||||
|
* @param num The number of elements in the sequence of opened sinks pointed to.
|
||||||
|
* @param sink Pointer to allocated memory that receives the opened sink
|
||||||
|
*/
|
||||||
|
void core_log_sink_list_open(
|
||||||
|
const struct core_log_sink *entry, uint8_t num, struct core_log_sink *sink);
|
||||||
|
|
||||||
|
#endif
|
||||||
53
src/main/core/log-sink-mutex.c
Normal file
53
src/main/core/log-sink-mutex.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
#include "util/mem.h"
|
||||||
|
|
||||||
|
struct core_log_sink_mutex_ctx {
|
||||||
|
struct core_log_sink *child;
|
||||||
|
HANDLE mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
_core_log_sink_mutex_write(void *ctx_, const char *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
struct core_log_sink_mutex_ctx *ctx;
|
||||||
|
|
||||||
|
ctx = (struct core_log_sink_mutex_ctx *) ctx_;
|
||||||
|
|
||||||
|
WaitForSingleObject(ctx->mutex, INFINITE);
|
||||||
|
|
||||||
|
ctx->child->write(ctx->child->ctx, chars, nchars);
|
||||||
|
|
||||||
|
ReleaseMutex(ctx->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _core_log_sink_mutex_close(void *ctx_)
|
||||||
|
{
|
||||||
|
struct core_log_sink_mutex_ctx *ctx;
|
||||||
|
|
||||||
|
ctx = (struct core_log_sink_mutex_ctx *) ctx_;
|
||||||
|
|
||||||
|
CloseHandle(ctx->mutex);
|
||||||
|
|
||||||
|
ctx->child->close(ctx->child->ctx);
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_sink_mutex_open(
|
||||||
|
const struct core_log_sink *child_sink, struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
struct core_log_sink_mutex_ctx *ctx;
|
||||||
|
|
||||||
|
ctx = xmalloc(sizeof(struct core_log_sink_mutex_ctx));
|
||||||
|
|
||||||
|
memcpy(ctx->child, child_sink, sizeof(struct core_log_sink));
|
||||||
|
ctx->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||||
|
|
||||||
|
sink->ctx = ctx;
|
||||||
|
sink->write = _core_log_sink_mutex_write;
|
||||||
|
sink->close = _core_log_sink_mutex_close;
|
||||||
|
}
|
||||||
21
src/main/core/log-sink-mutex.h
Normal file
21
src/main/core/log-sink-mutex.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef CORE_LOG_SINK_MUTEX_H
|
||||||
|
#define CORE_LOG_SINK_MUTEX_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a sink that surrounds another sink with a mutex.
|
||||||
|
*
|
||||||
|
* Use this to make other sink implementations thread-safe.
|
||||||
|
*
|
||||||
|
* @param child_sink Another opened sink to surround with the mutex. Ownership
|
||||||
|
* of the sink is transferred, i.e. closing the mutex sink
|
||||||
|
* also closes the wrapped child sink.
|
||||||
|
* @param sink Pointer to allocated memory that receives the opened sink
|
||||||
|
*/
|
||||||
|
void core_log_sink_mutex_open(
|
||||||
|
const struct core_log_sink *child_sink, struct core_log_sink *sink);
|
||||||
|
|
||||||
|
#endif
|
||||||
21
src/main/core/log-sink-null.c
Normal file
21
src/main/core/log-sink-null.c
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
_core_log_sink_null_write(void *ctx, const char *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _core_log_sink_null_close(void *ctx)
|
||||||
|
{
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_sink_null_open(struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
sink->ctx = NULL;
|
||||||
|
sink->write = _core_log_sink_null_write;
|
||||||
|
sink->close = _core_log_sink_null_close;
|
||||||
|
}
|
||||||
17
src/main/core/log-sink-null.h
Normal file
17
src/main/core/log-sink-null.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef CORE_LOG_SINK_NULL_H
|
||||||
|
#define CORE_LOG_SINK_NULL_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a null/dummy sink.
|
||||||
|
*
|
||||||
|
* Use this to disable any logging entirely.
|
||||||
|
*
|
||||||
|
* @param sink Pointer to allocated memory that receives the opened sink
|
||||||
|
*/
|
||||||
|
void core_log_sink_null_open(struct core_log_sink *sink);
|
||||||
|
|
||||||
|
#endif
|
||||||
193
src/main/core/log-sink-std.c
Normal file
193
src/main/core/log-sink-std.c
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
#include "util/mem.h"
|
||||||
|
|
||||||
|
struct core_log_sink_std_ctx {
|
||||||
|
HANDLE handle;
|
||||||
|
bool color;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char _core_log_sink_std_determine_color(const char *str)
|
||||||
|
{
|
||||||
|
/* Add some color to make spotting warnings/errors easier.
|
||||||
|
Based on debug output level identifier. */
|
||||||
|
|
||||||
|
/* Avoids colored output on strings like "Windows" */
|
||||||
|
if (str[1] != ':') {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (str[0]) {
|
||||||
|
/* green */
|
||||||
|
case 'M':
|
||||||
|
return 10;
|
||||||
|
/* blue */
|
||||||
|
case 'I':
|
||||||
|
return 9;
|
||||||
|
/* yellow */
|
||||||
|
case 'W':
|
||||||
|
return 14;
|
||||||
|
/* red */
|
||||||
|
case 'F':
|
||||||
|
return 12;
|
||||||
|
/* default console color */
|
||||||
|
default:
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _core_log_sink_std_msg_coloring_len(const char *str)
|
||||||
|
{
|
||||||
|
// Expected format example: "I:boot: my log message"
|
||||||
|
|
||||||
|
const char *ptr;
|
||||||
|
size_t len;
|
||||||
|
int colon_count;
|
||||||
|
|
||||||
|
ptr = str;
|
||||||
|
len = 0;
|
||||||
|
colon_count = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// End of string = invalid log format
|
||||||
|
if (*ptr == '\0') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ptr == ':') {
|
||||||
|
colon_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colon_count == 2) {
|
||||||
|
// Skip current colon, next char is a space
|
||||||
|
return len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len++;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_core_log_sink_std_write(void *ctx_, const char *chars, size_t nchars)
|
||||||
|
{
|
||||||
|
static const size_t timestamp_len = strlen("[----/--/-- --:--:--]");
|
||||||
|
|
||||||
|
struct core_log_sink_std_ctx *ctx;
|
||||||
|
|
||||||
|
char color;
|
||||||
|
size_t color_len;
|
||||||
|
size_t msg_len;
|
||||||
|
const char *msg_start;
|
||||||
|
const char *msg_end;
|
||||||
|
DWORD written;
|
||||||
|
DWORD write_pos;
|
||||||
|
|
||||||
|
ctx = (struct core_log_sink_std_ctx *) ctx_;
|
||||||
|
|
||||||
|
if (ctx->color) {
|
||||||
|
write_pos = 0;
|
||||||
|
|
||||||
|
// Support multiple buffered log messages, e.g. from the AVS logging
|
||||||
|
// engine
|
||||||
|
while (write_pos < nchars) {
|
||||||
|
// Expects the AVS timestamp format
|
||||||
|
msg_start = chars + timestamp_len + 1; // +1 is the space
|
||||||
|
|
||||||
|
color_len = _core_log_sink_std_msg_coloring_len(msg_start);
|
||||||
|
|
||||||
|
// Check if we could detect which part to color, otherwise just
|
||||||
|
// write the whole log message without any coloring logic
|
||||||
|
if (color_len > 0) {
|
||||||
|
color = _core_log_sink_std_determine_color(msg_start);
|
||||||
|
|
||||||
|
// Timestamp
|
||||||
|
WriteConsole(
|
||||||
|
ctx->handle, chars, timestamp_len + 1, &written, NULL);
|
||||||
|
write_pos += written;
|
||||||
|
chars += written;
|
||||||
|
|
||||||
|
// Log level + module colored
|
||||||
|
SetConsoleTextAttribute(ctx->handle, color);
|
||||||
|
WriteConsole(ctx->handle, chars, color_len, &written, NULL);
|
||||||
|
write_pos += written;
|
||||||
|
chars += written;
|
||||||
|
SetConsoleTextAttribute(ctx->handle, 15);
|
||||||
|
|
||||||
|
msg_end = strchr(chars, '\n');
|
||||||
|
|
||||||
|
if (msg_end != NULL) {
|
||||||
|
msg_len = msg_end - chars;
|
||||||
|
|
||||||
|
// Write \n as well
|
||||||
|
msg_len++;
|
||||||
|
|
||||||
|
// Write actual message non colored
|
||||||
|
WriteConsole(ctx->handle, chars, msg_len, &written, NULL);
|
||||||
|
write_pos += written;
|
||||||
|
chars += written;
|
||||||
|
} else {
|
||||||
|
WriteConsole(
|
||||||
|
ctx->handle, chars, nchars - write_pos, &written, NULL);
|
||||||
|
write_pos += written;
|
||||||
|
chars += written;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WriteConsole(
|
||||||
|
ctx->handle,
|
||||||
|
chars + write_pos,
|
||||||
|
nchars - write_pos,
|
||||||
|
&written,
|
||||||
|
NULL);
|
||||||
|
write_pos += written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WriteConsole(ctx->handle, chars, nchars, &written, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _core_log_sink_std_close(void *ctx_)
|
||||||
|
{
|
||||||
|
struct core_log_sink_std_ctx *ctx;
|
||||||
|
|
||||||
|
ctx = (struct core_log_sink_std_ctx *) ctx_;
|
||||||
|
|
||||||
|
// Remark: Don't close the ctx->handle, see win API docs
|
||||||
|
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_sink_std_out_open(bool color, struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
struct core_log_sink_std_ctx *ctx;
|
||||||
|
|
||||||
|
ctx = xmalloc(sizeof(struct core_log_sink_std_ctx));
|
||||||
|
|
||||||
|
ctx->handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
ctx->color = color;
|
||||||
|
|
||||||
|
sink->ctx = (void *) ctx;
|
||||||
|
sink->write = _core_log_sink_std_write;
|
||||||
|
sink->close = _core_log_sink_std_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_sink_std_err_open(bool color, struct core_log_sink *sink)
|
||||||
|
{
|
||||||
|
struct core_log_sink_std_ctx *ctx;
|
||||||
|
|
||||||
|
ctx = xmalloc(sizeof(struct core_log_sink_std_ctx));
|
||||||
|
|
||||||
|
ctx->handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
ctx->color = color;
|
||||||
|
|
||||||
|
sink->ctx = (void *) ctx;
|
||||||
|
sink->write = _core_log_sink_std_write;
|
||||||
|
sink->close = _core_log_sink_std_close;
|
||||||
|
}
|
||||||
24
src/main/core/log-sink-std.h
Normal file
24
src/main/core/log-sink-std.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef CORE_LOG_SINK_STD_H
|
||||||
|
#define CORE_LOG_SINK_STD_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log-sink.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a sink that writes to stdout.
|
||||||
|
*
|
||||||
|
* @param color If true, messages are colored by log level.
|
||||||
|
* @param sink Pointer to allocated memory that receives the opened sink
|
||||||
|
*/
|
||||||
|
void core_log_sink_std_out_open(bool color, struct core_log_sink *sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a sink that writes to stderr.
|
||||||
|
*
|
||||||
|
* @param color If true, messages are colored by log level.
|
||||||
|
* @param sink Pointer to allocated memory that receives the opened sink
|
||||||
|
*/
|
||||||
|
void core_log_sink_std_err_open(bool color, struct core_log_sink *sink);
|
||||||
|
|
||||||
|
#endif
|
||||||
45
src/main/core/log-sink.h
Normal file
45
src/main/core/log-sink.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef CORE_LOG_SINK_H
|
||||||
|
#define CORE_LOG_SINK_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write function for a log sink implementation.
|
||||||
|
*
|
||||||
|
* Write the given data to your target output destination.
|
||||||
|
*
|
||||||
|
* @param ctx Context defined by the implementation when opening the sink.
|
||||||
|
* @param chars Buffer with text data to log. This can contain partial data of
|
||||||
|
* a single log line, a full log line terminated by a newline
|
||||||
|
* character or multiple log lines (each terminated by a newline
|
||||||
|
* character).
|
||||||
|
* @param nchars Number of characters to write.
|
||||||
|
*/
|
||||||
|
typedef void (*core_log_sink_write_t)(
|
||||||
|
void *ctx, const char *chars, size_t nchars);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close your log sink and cleanup resources
|
||||||
|
*
|
||||||
|
* Depending on your implementation, you might want to flush any
|
||||||
|
* outstanding/buffered data.
|
||||||
|
*
|
||||||
|
* @param ctx Context defined by the implementation when opening the sink.
|
||||||
|
*/
|
||||||
|
typedef void (*core_log_sink_close_t)(void *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log sink structure.
|
||||||
|
*
|
||||||
|
* This must be set-up and populated when opening your log sink implementation.
|
||||||
|
* The ctx field contains any arbitrary data that you need for your log sink
|
||||||
|
* to operate, e.g. a file handle, additional buffers etc. Make sure these
|
||||||
|
* resources are cleaned up upon closing the sink.
|
||||||
|
*/
|
||||||
|
struct core_log_sink {
|
||||||
|
void *ctx;
|
||||||
|
core_log_sink_write_t write;
|
||||||
|
core_log_sink_close_t close;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
74
src/main/core/log.c
Normal file
74
src/main/core/log.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log.h"
|
||||||
|
|
||||||
|
core_log_message_t _core_log_misc_impl;
|
||||||
|
core_log_message_t _core_log_info_impl;
|
||||||
|
core_log_message_t _core_log_warning_impl;
|
||||||
|
core_log_message_t _core_log_fatal_impl;
|
||||||
|
|
||||||
|
void core_log_impl_set(
|
||||||
|
core_log_message_t misc,
|
||||||
|
core_log_message_t info,
|
||||||
|
core_log_message_t warning,
|
||||||
|
core_log_message_t fatal)
|
||||||
|
{
|
||||||
|
if (misc == NULL || info == NULL || warning == NULL || fatal == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
_core_log_misc_impl = misc;
|
||||||
|
_core_log_info_impl = info;
|
||||||
|
_core_log_warning_impl = warning;
|
||||||
|
_core_log_fatal_impl = fatal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_log_impl_assign(core_log_impl_set_t impl_set)
|
||||||
|
{
|
||||||
|
if (_core_log_misc_impl == NULL || _core_log_info_impl == NULL ||
|
||||||
|
_core_log_warning_impl == NULL || _core_log_fatal_impl == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_set(
|
||||||
|
_core_log_misc_impl,
|
||||||
|
_core_log_info_impl,
|
||||||
|
_core_log_warning_impl,
|
||||||
|
_core_log_fatal_impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
core_log_message_t core_log_misc_impl_get()
|
||||||
|
{
|
||||||
|
if (_core_log_misc_impl == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _core_log_misc_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_log_message_t core_log_info_impl_get()
|
||||||
|
{
|
||||||
|
if (_core_log_info_impl == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _core_log_info_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_log_message_t core_log_warning_impl_get()
|
||||||
|
{
|
||||||
|
if (_core_log_warning_impl == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _core_log_warning_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_log_message_t core_log_fatal_impl_get()
|
||||||
|
{
|
||||||
|
if (_core_log_fatal_impl == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _core_log_fatal_impl;
|
||||||
|
}
|
||||||
197
src/main/core/log.h
Normal file
197
src/main/core/log.h
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
#ifndef CORE_LOG_H
|
||||||
|
#define CORE_LOG_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "util/defs.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The core log API of bemanitools.
|
||||||
|
*
|
||||||
|
* To a large extent, this reflects the AVS logging API and allows for swapping
|
||||||
|
* out the backends with different implementations. Most games should have some
|
||||||
|
* version of the AVS API available while some (legacy) games do not. These
|
||||||
|
* can use a bemanitools private logging implementation by configuring it
|
||||||
|
* in the bootstrapping process.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* BUILD_MODULE is passed in as a command-line #define by the makefile */
|
||||||
|
|
||||||
|
#ifndef LOG_MODULE
|
||||||
|
#define LOG_MODULE STRINGIFY(BUILD_MODULE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message on misc level
|
||||||
|
*
|
||||||
|
* Always use this interface in your application which hides the currently
|
||||||
|
* configured implementation.
|
||||||
|
*
|
||||||
|
* The macro is required to make things work with varargs.
|
||||||
|
* The log message is only printed if the log level is set to misc
|
||||||
|
*
|
||||||
|
* @param fmt printf format string
|
||||||
|
* @param ... Additional arguments according to the specified arguments in the
|
||||||
|
* printf format string
|
||||||
|
*/
|
||||||
|
#define log_misc(...) _core_log_misc_impl(LOG_MODULE, __VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message on info level
|
||||||
|
*
|
||||||
|
* Always use this interface in your application which hides the currently
|
||||||
|
* configured implementation.
|
||||||
|
*
|
||||||
|
* The macro is required to make things work with varargs.
|
||||||
|
* The log message is only printed if the log level is set to info or lower
|
||||||
|
*
|
||||||
|
* @param fmt printf format string
|
||||||
|
* @param ... Additional arguments according to the specified arguments in the
|
||||||
|
* printf format string
|
||||||
|
*/
|
||||||
|
#define log_info(...) _core_log_info_impl(LOG_MODULE, __VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message on warning level
|
||||||
|
*
|
||||||
|
* Always use this interface in your application which hides the currently
|
||||||
|
* configured implementation.
|
||||||
|
*
|
||||||
|
* The macro is required to make things work with varargs.
|
||||||
|
* The log message is only printed if the log level is set to warning or lower
|
||||||
|
*
|
||||||
|
* @param fmt printf format string
|
||||||
|
* @param ... Additional arguments according to the specified arguments in the
|
||||||
|
* printf format string
|
||||||
|
*/
|
||||||
|
#define log_warning(...) _core_log_warning_impl(LOG_MODULE, __VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message on fatal level
|
||||||
|
*
|
||||||
|
* Always use this interface in your application which hides the currently
|
||||||
|
* configured implementation.
|
||||||
|
*
|
||||||
|
* The macro is required to make things work with varargs.
|
||||||
|
* The log message is only printed if the log level is set to fatal.
|
||||||
|
*
|
||||||
|
* This call will also terminate the application.
|
||||||
|
*
|
||||||
|
* @param fmt printf format string
|
||||||
|
* @param ... Additional arguments according to the specified arguments in the
|
||||||
|
* printf format string
|
||||||
|
*/
|
||||||
|
#define log_fatal(...) \
|
||||||
|
do { \
|
||||||
|
_core_log_fatal_impl(LOG_MODULE, __VA_ARGS__); \
|
||||||
|
abort(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message and terminate the application if given condition fails
|
||||||
|
*
|
||||||
|
* Always use this interface in your application which hides the currently
|
||||||
|
* configured implementation.
|
||||||
|
*
|
||||||
|
* The macro is required to make things work with varargs.
|
||||||
|
*
|
||||||
|
* @param x Condition to evaluate. If false, the application terminates
|
||||||
|
*/
|
||||||
|
#define log_assert(x) \
|
||||||
|
do { \
|
||||||
|
if (!(x)) { \
|
||||||
|
_core_log_fatal_impl( \
|
||||||
|
"assert", \
|
||||||
|
"%s:%d: function `%s'", \
|
||||||
|
__FILE__, \
|
||||||
|
__LINE__, \
|
||||||
|
__FUNCTION__); \
|
||||||
|
abort(); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message in an exception handler
|
||||||
|
*
|
||||||
|
* Only use this function in an exception handler, e.g. for stack traces. It
|
||||||
|
* logs the message on fatal level but does not terminate.
|
||||||
|
*
|
||||||
|
* @param fmt printf format string
|
||||||
|
* @param ... Additional arguments according to the specified arguments in the
|
||||||
|
* printf format string
|
||||||
|
*/
|
||||||
|
#define log_exception_handler(...) \
|
||||||
|
_core_log_fatal_impl("exception", __VA_ARGS__)
|
||||||
|
|
||||||
|
typedef void (*core_log_message_t)(const char *module, const char *fmt, ...);
|
||||||
|
|
||||||
|
typedef void (*core_log_impl_set_t)(
|
||||||
|
core_log_message_t misc,
|
||||||
|
core_log_message_t info,
|
||||||
|
core_log_message_t warning,
|
||||||
|
core_log_message_t fatal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the log API implementations
|
||||||
|
*
|
||||||
|
* Advised to do this as early in your application/library module as possible
|
||||||
|
* as calls to the getter functions below will return the currently configured
|
||||||
|
* implementations.
|
||||||
|
*
|
||||||
|
* @param misc Pointer to a function implementing logging on misc level
|
||||||
|
* @param info Pointer to a function implementing logging on info level
|
||||||
|
* @param warning Pointer to a function implementing logging on warning level
|
||||||
|
* @param fatal Pointer to a function implementing logging on fatal level
|
||||||
|
*/
|
||||||
|
void core_log_impl_set(
|
||||||
|
core_log_message_t misc,
|
||||||
|
core_log_message_t info,
|
||||||
|
core_log_message_t warning,
|
||||||
|
core_log_message_t fatal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supporting function to inject/assign the currently set implementation
|
||||||
|
* with the given setter function.
|
||||||
|
*
|
||||||
|
* @param impl_set Setter function to call with the currently configured log
|
||||||
|
* function implementations
|
||||||
|
*/
|
||||||
|
void core_log_impl_assign(core_log_impl_set_t impl_set);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently configured implementation of the misc level log function
|
||||||
|
*
|
||||||
|
* @return Pointer to the currently configured implementation of the function
|
||||||
|
*/
|
||||||
|
core_log_message_t core_log_misc_impl_get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently configured implementation of the info level log function
|
||||||
|
*
|
||||||
|
* @return Pointer to the currently configured implementation of the function
|
||||||
|
*/
|
||||||
|
core_log_message_t core_log_info_impl_get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently configured implementation of the warning level log function
|
||||||
|
*
|
||||||
|
* @return Pointer to the currently configured implementation of the function
|
||||||
|
*/
|
||||||
|
core_log_message_t core_log_warning_impl_get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently configured implementation of the fatal level log function
|
||||||
|
*
|
||||||
|
* @return Pointer to the currently configured implementation of the function
|
||||||
|
*/
|
||||||
|
core_log_message_t core_log_fatal_impl_get();
|
||||||
|
|
||||||
|
// Do not use these directly.
|
||||||
|
// These are only here to allow usage in the macros above.
|
||||||
|
extern core_log_message_t _core_log_misc_impl;
|
||||||
|
extern core_log_message_t _core_log_info_impl;
|
||||||
|
extern core_log_message_t _core_log_warning_impl;
|
||||||
|
extern core_log_message_t _core_log_fatal_impl;
|
||||||
|
|
||||||
|
#endif
|
||||||
8
src/main/core/thread-crt-ext.c
Normal file
8
src/main/core/thread-crt-ext.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include "core/thread-crt.h"
|
||||||
|
#include "core/thread.h"
|
||||||
|
|
||||||
|
void core_thread_crt_ext_impl_set()
|
||||||
|
{
|
||||||
|
core_thread_impl_set(
|
||||||
|
core_thread_crt_create, core_thread_crt_join, core_thread_crt_destroy);
|
||||||
|
}
|
||||||
9
src/main/core/thread-crt-ext.h
Normal file
9
src/main/core/thread-crt-ext.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef CORE_THREAD_CRT_EXT_H
|
||||||
|
#define CORE_THREAD_CRT_EXT_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current thread API implementation to use the C runtime thread API
|
||||||
|
*/
|
||||||
|
void core_thread_crt_ext_impl_set();
|
||||||
|
|
||||||
|
#endif
|
||||||
62
src/main/core/thread-crt.c
Normal file
62
src/main/core/thread-crt.c
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#include <process.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "core/thread-crt.h"
|
||||||
|
#include "core/thread.h"
|
||||||
|
|
||||||
|
#include "util/defs.h"
|
||||||
|
|
||||||
|
struct shim_ctx {
|
||||||
|
HANDLE barrier;
|
||||||
|
int (*proc)(void *);
|
||||||
|
void *ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int STDCALL crt_thread_shim(void *outer_ctx)
|
||||||
|
{
|
||||||
|
struct shim_ctx *sctx = outer_ctx;
|
||||||
|
int (*proc)(void *);
|
||||||
|
void *inner_ctx;
|
||||||
|
|
||||||
|
proc = sctx->proc;
|
||||||
|
inner_ctx = sctx->ctx;
|
||||||
|
|
||||||
|
SetEvent(sctx->barrier);
|
||||||
|
|
||||||
|
return proc(inner_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int core_thread_crt_create(
|
||||||
|
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority)
|
||||||
|
{
|
||||||
|
struct shim_ctx sctx;
|
||||||
|
uintptr_t thread_id;
|
||||||
|
|
||||||
|
sctx.barrier = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
sctx.proc = proc;
|
||||||
|
sctx.ctx = ctx;
|
||||||
|
|
||||||
|
thread_id = _beginthreadex(NULL, stack_sz, crt_thread_shim, &sctx, 0, NULL);
|
||||||
|
|
||||||
|
WaitForSingleObject(sctx.barrier, INFINITE);
|
||||||
|
CloseHandle(sctx.barrier);
|
||||||
|
|
||||||
|
return (int) thread_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_thread_crt_destroy(int thread_id)
|
||||||
|
{
|
||||||
|
CloseHandle((HANDLE) (uintptr_t) thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_thread_crt_join(int thread_id, int *result)
|
||||||
|
{
|
||||||
|
WaitForSingleObject((HANDLE) (uintptr_t) thread_id, INFINITE);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
GetExitCodeThread((HANDLE) (uintptr_t) thread_id, (DWORD *) result);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/main/core/thread-crt.h
Normal file
15
src/main/core/thread-crt.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef CORE_THREAD_CRT_H
|
||||||
|
#define CORE_THREAD_CRT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread API implementation using the C runtime API
|
||||||
|
*/
|
||||||
|
|
||||||
|
int core_thread_crt_create(
|
||||||
|
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority);
|
||||||
|
void core_thread_crt_join(int thread_id, int *result);
|
||||||
|
void core_thread_crt_destroy(int thread_id);
|
||||||
|
|
||||||
|
#endif
|
||||||
78
src/main/core/thread.c
Normal file
78
src/main/core/thread.c
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core/log.h"
|
||||||
|
#include "core/thread.h"
|
||||||
|
|
||||||
|
core_thread_create_t core_thread_create_impl;
|
||||||
|
core_thread_join_t core_thread_join_impl;
|
||||||
|
core_thread_destroy_t core_thread_destroy_impl;
|
||||||
|
|
||||||
|
int core_thread_create(
|
||||||
|
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority)
|
||||||
|
{
|
||||||
|
log_assert(core_thread_create_impl);
|
||||||
|
|
||||||
|
return core_thread_create_impl(proc, ctx, stack_sz, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_thread_join(int thread_id, int *result)
|
||||||
|
{
|
||||||
|
log_assert(core_thread_join_impl);
|
||||||
|
|
||||||
|
core_thread_join_impl(thread_id, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_thread_destroy(int thread_id)
|
||||||
|
{
|
||||||
|
log_assert(core_thread_destroy_impl);
|
||||||
|
|
||||||
|
core_thread_destroy_impl(thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_thread_impl_set(
|
||||||
|
core_thread_create_t create,
|
||||||
|
core_thread_join_t join,
|
||||||
|
core_thread_destroy_t destroy)
|
||||||
|
{
|
||||||
|
if (create == NULL || join == NULL || destroy == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
core_thread_create_impl = create;
|
||||||
|
core_thread_join_impl = join;
|
||||||
|
core_thread_destroy_impl = destroy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_thread_impl_assign(core_thread_impl_set_t impl_set)
|
||||||
|
{
|
||||||
|
if (core_thread_create_impl == NULL || core_thread_join_impl == NULL ||
|
||||||
|
core_thread_destroy_impl == NULL) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_set(
|
||||||
|
core_thread_create_impl,
|
||||||
|
core_thread_join_impl,
|
||||||
|
core_thread_destroy_impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
core_thread_create_t core_thread_create_impl_get()
|
||||||
|
{
|
||||||
|
log_assert(core_thread_create_impl);
|
||||||
|
|
||||||
|
return core_thread_create_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_thread_join_t core_thread_join_impl_get()
|
||||||
|
{
|
||||||
|
log_assert(core_thread_join_impl);
|
||||||
|
|
||||||
|
return core_thread_join_impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_thread_destroy_t core_thread_destroy_impl_get()
|
||||||
|
{
|
||||||
|
log_assert(core_thread_destroy_impl);
|
||||||
|
|
||||||
|
return core_thread_destroy_impl;
|
||||||
|
}
|
||||||
117
src/main/core/thread.h
Normal file
117
src/main/core/thread.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#ifndef CORE_THREAD_H
|
||||||
|
#define CORE_THREAD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The core thread API of bemanitools.
|
||||||
|
*
|
||||||
|
* This essentially reflects the AVS threading API and allows for swapping out
|
||||||
|
* the backends with different implementations. Most games should have some
|
||||||
|
* version of the AVS API available while some (legacy) games do not. These
|
||||||
|
* can use a bemanitools private threading implementation by configuring it
|
||||||
|
* in the bootstrapping process.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a thread
|
||||||
|
*
|
||||||
|
* Always use this interface in your application which hides the currently
|
||||||
|
* configured implementation.
|
||||||
|
*
|
||||||
|
* @param proc The function to run in a separate thread
|
||||||
|
* @param ctx Additional data to pass to the function as a parameter
|
||||||
|
* @param stack_sz The stack size to allocate for the thread in bytes
|
||||||
|
* @param priority The thread's priority
|
||||||
|
* @return The ID of the thread once created and started
|
||||||
|
*/
|
||||||
|
int core_thread_create(
|
||||||
|
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for a thread to finish
|
||||||
|
*
|
||||||
|
* Always use this interface in your application which hides the currently
|
||||||
|
* configured implementation.
|
||||||
|
*
|
||||||
|
* The caller of this function blocks until the thread has finished executing.
|
||||||
|
*
|
||||||
|
* @param thread_id ID of the thread to wait for
|
||||||
|
* @param result Pointer to a variable to write the return value of the function
|
||||||
|
* the thread executed to
|
||||||
|
*/
|
||||||
|
void core_thread_join(int thread_id, int *result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a thread
|
||||||
|
*
|
||||||
|
* Always use this interface in your application which hides the currently
|
||||||
|
* configured implementation.
|
||||||
|
*
|
||||||
|
* The thread must have finished execution before calling this. It is advised
|
||||||
|
* to make threads terminate their execution flow, join them and destroy.
|
||||||
|
*
|
||||||
|
* @param thread_id The ID of the thread to destroy.
|
||||||
|
*/
|
||||||
|
void core_thread_destroy(int thread_id);
|
||||||
|
|
||||||
|
typedef int (*core_thread_create_t)(
|
||||||
|
int (*proc)(void *), void *ctx, uint32_t stack_sz, unsigned int priority);
|
||||||
|
typedef void (*core_thread_join_t)(int thread_id, int *result);
|
||||||
|
typedef void (*core_thread_destroy_t)(int thread_id);
|
||||||
|
|
||||||
|
typedef void (*core_thread_impl_set_t)(
|
||||||
|
core_thread_create_t create,
|
||||||
|
core_thread_join_t join,
|
||||||
|
core_thread_destroy_t destroy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the thread API implementations
|
||||||
|
*
|
||||||
|
* Advised to do this as early in your application/library module as possible
|
||||||
|
* as calls to the getter functions below will return the currently configured
|
||||||
|
* implementations.
|
||||||
|
*
|
||||||
|
* @param create Pointer to a function implementing thread creation
|
||||||
|
* @param join Pointer to a function implementing joining of a thread
|
||||||
|
* @param destroy Pointer to a function implementing destroying of a thread
|
||||||
|
*/
|
||||||
|
void core_thread_impl_set(
|
||||||
|
core_thread_create_t create,
|
||||||
|
core_thread_join_t join,
|
||||||
|
core_thread_destroy_t destroy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supporting function to inject/assign the currently set implementation
|
||||||
|
* with the given setter function.
|
||||||
|
*
|
||||||
|
* @param impl_set Setter function to call with the currently configured thread
|
||||||
|
* function implementations
|
||||||
|
*/
|
||||||
|
void core_thread_impl_assign(core_thread_impl_set_t impl_set);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently configured implementation for thread_create
|
||||||
|
*
|
||||||
|
* @return Pointer to the currently configured implementation of the
|
||||||
|
* thread_create function
|
||||||
|
*/
|
||||||
|
core_thread_create_t core_thread_create_impl_get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently configured implementation for thread_join
|
||||||
|
*
|
||||||
|
* @return Pointer to the currently configured implementation of the thread_join
|
||||||
|
* function
|
||||||
|
*/
|
||||||
|
core_thread_join_t core_thread_join_impl_get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently configured implementation for thread_destroy
|
||||||
|
*
|
||||||
|
* @return Pointer to the currently configured implementation of the
|
||||||
|
* thread_destroy function
|
||||||
|
*/
|
||||||
|
core_thread_destroy_t core_thread_destroy_impl_get();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -15,12 +15,21 @@ static const size_t apiset_prefix_len = sizeof(apiset_prefix) - 1;
|
|||||||
static void hook_table_apply_to_all(
|
static void hook_table_apply_to_all(
|
||||||
const char *depname, const struct hook_symbol *syms, size_t nsyms);
|
const char *depname, const struct hook_symbol *syms, size_t nsyms);
|
||||||
|
|
||||||
|
static void hook_table_revert_to_all(
|
||||||
|
const char *depname, const struct hook_symbol *syms, size_t nsyms);
|
||||||
|
|
||||||
static void hook_table_apply_to_iid(
|
static void hook_table_apply_to_iid(
|
||||||
HMODULE target,
|
HMODULE target,
|
||||||
const pe_iid_t *iid,
|
const pe_iid_t *iid,
|
||||||
const struct hook_symbol *syms,
|
const struct hook_symbol *syms,
|
||||||
size_t nsyms);
|
size_t nsyms);
|
||||||
|
|
||||||
|
static void hook_table_revert_to_iid(
|
||||||
|
HMODULE target,
|
||||||
|
const pe_iid_t *iid,
|
||||||
|
const struct hook_symbol *syms,
|
||||||
|
size_t nsyms);
|
||||||
|
|
||||||
static bool hook_table_match_module(
|
static bool hook_table_match_module(
|
||||||
HMODULE target, const char *iid_name, const char *depname);
|
HMODULE target, const char *iid_name, const char *depname);
|
||||||
|
|
||||||
@@ -44,6 +53,23 @@ static void hook_table_apply_to_all(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hook_table_revert_to_all(
|
||||||
|
const char *depname, const struct hook_symbol *syms, size_t nsyms)
|
||||||
|
{
|
||||||
|
const peb_dll_t *dll;
|
||||||
|
HMODULE pe;
|
||||||
|
|
||||||
|
for (dll = peb_dll_get_first(); dll != NULL; dll = peb_dll_get_next(dll)) {
|
||||||
|
pe = peb_dll_get_base(dll);
|
||||||
|
|
||||||
|
if (pe == NULL) {
|
||||||
|
continue; /* ?? Happens sometimes. */
|
||||||
|
}
|
||||||
|
|
||||||
|
hook_table_revert(pe, depname, syms, nsyms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void hook_table_apply(
|
void hook_table_apply(
|
||||||
HMODULE target,
|
HMODULE target,
|
||||||
const char *depname,
|
const char *depname,
|
||||||
@@ -73,6 +99,35 @@ void hook_table_apply(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hook_table_revert(
|
||||||
|
HMODULE target,
|
||||||
|
const char *depname,
|
||||||
|
const struct hook_symbol *syms,
|
||||||
|
size_t nsyms)
|
||||||
|
{
|
||||||
|
const pe_iid_t *iid;
|
||||||
|
const char *iid_name;
|
||||||
|
|
||||||
|
assert(depname != NULL);
|
||||||
|
assert(syms != NULL || nsyms == 0);
|
||||||
|
|
||||||
|
if (target == NULL) {
|
||||||
|
/* Call out, which will then call us back repeatedly. Awkward, but
|
||||||
|
viewed from the outside it's good for usability. */
|
||||||
|
|
||||||
|
hook_table_revert_to_all(depname, syms, nsyms);
|
||||||
|
} else {
|
||||||
|
for (iid = pe_iid_get_first(target); iid != NULL;
|
||||||
|
iid = pe_iid_get_next(target, iid)) {
|
||||||
|
iid_name = pe_iid_get_name(target, iid);
|
||||||
|
|
||||||
|
if (hook_table_match_module(target, iid_name, depname)) {
|
||||||
|
hook_table_revert_to_iid(target, iid, syms, nsyms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void hook_table_apply_to_iid(
|
static void hook_table_apply_to_iid(
|
||||||
HMODULE target,
|
HMODULE target,
|
||||||
const pe_iid_t *iid,
|
const pe_iid_t *iid,
|
||||||
@@ -101,6 +156,33 @@ static void hook_table_apply_to_iid(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hook_table_revert_to_iid(
|
||||||
|
HMODULE target,
|
||||||
|
const pe_iid_t *iid,
|
||||||
|
const struct hook_symbol *syms,
|
||||||
|
size_t nsyms)
|
||||||
|
{
|
||||||
|
struct pe_iat_entry iate;
|
||||||
|
size_t i;
|
||||||
|
size_t j;
|
||||||
|
const struct hook_symbol *sym;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while (pe_iid_get_iat_entry(target, iid, i++, &iate) == S_OK) {
|
||||||
|
for (j = 0; j < nsyms; j++) {
|
||||||
|
sym = &syms[j];
|
||||||
|
|
||||||
|
if (hook_table_match_proc(&iate, sym)) {
|
||||||
|
// Only revert-able if the original pointer was stored previously
|
||||||
|
if (sym->link != NULL && *sym->link != NULL) {
|
||||||
|
pe_patch(iate.ppointer, sym->link, sizeof(*sym->link));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool hook_table_match_module(
|
static bool hook_table_match_module(
|
||||||
HMODULE target, const char *iid_name, const char *depname)
|
HMODULE target, const char *iid_name, const char *depname)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user