]> ruderich.org/simon Gitweb - coloredstderr/coloredstderr.git/blob - src/hookmacros.h
hookmacros.h: Reduce duplication in HOOK_VOID1().
[coloredstderr/coloredstderr.git] / src / hookmacros.h
1 /*
2  * Macros to hook functions.
3  *
4  * Copyright (C) 2013  Simon Ruderich
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifndef MACROS_H
21 #define MACROS_H 1
22
23 /* Hook the function by creating a function with the same name. With
24  * LD_PRELOAD our function will be preferred. The original function is stored
25  * in a static variable (real_*). */
26
27 #define _HOOK_PRE(type, name) \
28         int handle; \
29         DLSYM_FUNCTION(real_ ## name, #name);
30 #define _HOOK_PRE_FD(type, name, fd) \
31         type result; \
32         _HOOK_PRE_FD_(type, name, fd)
33 #define _HOOK_PRE_FD_(type, name, fd) \
34         _HOOK_PRE(type, name) \
35         handle = check_handle_fd(fd); \
36         if (handle) { \
37             handle_fd_pre(fd, handle); \
38         }
39 #define _HOOK_PRE_FILE(type, name, file) \
40         type result; \
41         _HOOK_PRE(type, name) \
42         handle = check_handle_fd(fileno(file)); \
43         if (handle) { \
44             handle_file_pre(file, handle); \
45         }
46 /* Save and restore the errno to make sure we return the errno of the original
47  * function call. */
48 #define _HOOK_POST_FD_(fd) \
49         if (handle) { \
50             int saved_errno = errno; \
51             handle_fd_post(fd, handle); \
52             errno = saved_errno; \
53         }
54 #define _HOOK_POST_FD(fd) \
55         _HOOK_POST_FD_(fd) \
56         return result;
57 #define _HOOK_POST_FILE(file) \
58         if (handle) { \
59             int saved_errno = errno; \
60             handle_file_post(file, handle); \
61             errno = saved_errno; \
62         } \
63         return result;
64
65
66 #define HOOK_VOID1(type, name, fd, type1, arg1) \
67     static type (*real_ ## name)(type1); \
68     type name(type1 arg1) { \
69         _HOOK_PRE_FD_(type, name, fd) \
70         real_ ## name(arg1); \
71         _HOOK_POST_FD_(fd) \
72     }
73
74 #define HOOK_FD3(type, name, fd, type1, arg1, type2, arg2, type3, arg3) \
75     static type (*real_ ## name)(type1, type2, type3); \
76     type name(type1 arg1, type2 arg2, type3 arg3) { \
77         _HOOK_PRE_FD(type, name, fd) \
78         result = real_ ## name(arg1, arg2, arg3); \
79         _HOOK_POST_FD(fd) \
80     }
81
82 #define HOOK_FILE1(type, name, file, type1, arg1) \
83     static type (*real_ ## name)(type1); \
84     type name(type1 arg1) { \
85         _HOOK_PRE_FILE(type, name, file) \
86         result = real_ ## name(arg1); \
87         _HOOK_POST_FILE(file) \
88     }
89 #define HOOK_FILE2(type, name, file, type1, arg1, type2, arg2) \
90     static type (*real_ ## name)(type1, type2); \
91     type name(type1 arg1, type2 arg2) { \
92         _HOOK_PRE_FILE(type, name, file) \
93         result = real_ ## name(arg1, arg2); \
94         _HOOK_POST_FILE(file) \
95     }
96 #define HOOK_FILE3(type, name, file, type1, arg1, type2, arg2, type3, arg3) \
97     static type (*real_ ## name)(type1, type2, type3); \
98     type name(type1 arg1, type2 arg2, type3 arg3) { \
99         _HOOK_PRE_FILE(type, name, file) \
100         result = real_ ## name(arg1, arg2, arg3); \
101         _HOOK_POST_FILE(file) \
102     }
103 #define HOOK_FILE4(type, name, file, type1, arg1, type2, arg2, type3, arg3, type4, arg4) \
104     static type (*real_ ## name)(type1, type2, type3, type4); \
105     type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
106         _HOOK_PRE_FILE(type, name, file) \
107         result = real_ ## name(arg1, arg2, arg3, arg4); \
108         _HOOK_POST_FILE(file) \
109     }
110
111 #define HOOK_VAR_FILE1(type, name, file, func, type1, arg1) \
112     static type (*real_ ## func)(type1, va_list); \
113     type name(type1 arg1, ...) { \
114         va_list ap; \
115         _HOOK_PRE_FILE(type, func, file) \
116         va_start(ap, arg1); \
117         result = real_ ## func(arg1, ap); \
118         va_end(ap); \
119         _HOOK_POST_FILE(file) \
120     }
121 #define HOOK_VAR_FILE2(type, name, file, func, type1, arg1, type2, arg2) \
122     static type (*real_ ## func)(type1, type2, va_list); \
123     type name(type1 arg1, type2 arg2, ...) { \
124         va_list ap; \
125         _HOOK_PRE_FILE(type, func, file) \
126         va_start(ap, arg2); \
127         result = real_ ## func(arg1, arg2, ap); \
128         va_end(ap); \
129         _HOOK_POST_FILE(file) \
130     }
131 #define HOOK_VAR_FILE3(type, name, file, func, type1, arg1, type2, arg2, type3, arg3) \
132     static type (*real_ ## func)(type1, type2, type3, va_list); \
133     type name(type1 arg1, type2 arg2, type3 arg3, ...) \
134     { \
135         va_list ap; \
136         _HOOK_PRE_FILE(type, func, file) \
137         va_start(ap, arg3); \
138         result = real_ ## func(arg1, arg2, arg3, ap); \
139         va_end(ap); \
140         _HOOK_POST_FILE(file) \
141     }
142
143 #endif