Document of c-modernization-kit (funcman) 1.0.0

Loading...
Searching...
No Matches
get_lib_info.c
Go to the documentation of this file.
1
22
23#include <funcman.h>
24#if defined(_WIN32)
25 #define WIN32_LEAN_AND_MEAN
26 #include <stddef.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <windows.h>
31#else
32 #include <dlfcn.h>
33 #include <limits.h>
34 #include <stddef.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40#endif
41
47 typedef enum get_lib_info_status_t
48{
50 MYLIB_OK = 0,
52 MYLIB_EINVAL = -1,
54 MYLIB_ENOBUFS = -2,
56 MYLIB_EFAIL = -3
57} get_lib_info_status_t;
58
69 static get_lib_info_status_t copy_str(char *dst, size_t dst_sz, const char *src)
70{
71 size_t n;
72
73 if (!dst || dst_sz == 0 || !src)
74 return MYLIB_EINVAL;
75 n = strlen(src);
76 if (n + 1 > dst_sz)
77 {
78 if (dst_sz > 0)
79 dst[0] = '\0';
80 return MYLIB_ENOBUFS;
81 }
82 memcpy(dst, src, n + 1);
83 return MYLIB_OK;
84}
85
94 static const char *get_ilename_part(const char *path)
95{
96 const char *p;
97 const char *last = path;
98
99 if (!path)
100 return "";
101 for (p = path; *p; ++p)
102 {
103 if (*p == '/' || *p == '\\')
104 last = p + 1;
105 }
106 return last;
107}
108
120 static void strip_extension_inplace(char *s)
121{
122 char *dot;
123
124 if (!s)
125 return;
126
127#if !defined(_WIN32)
128 {
129 char *so_ver = strstr(s, ".so.");
130 if (so_ver)
131 {
132 *so_ver = '\0';
133 return;
134 }
135
136 {
137 size_t len = strlen(s);
138 if (len >= 3 && strcmp(s + (len - 3), ".so") == 0)
139 {
140 s[len - 3] = '\0';
141 return;
142 }
143 }
144
145 {
146 size_t len = strlen(s);
147 if (len >= 6 && strcmp(s + (len - 6), ".dylib") == 0)
148 {
149 s[len - 6] = '\0';
150 return;
151 }
152 }
153 }
154#endif
155
156 dot = strrchr(s, '.');
157 if (dot && dot != s)
158 {
159 *dot = '\0';
160 }
161}
162
163#if defined(_WIN32)
164
175 static get_lib_info_status_t narrow_utf8(const wchar_t *w, char *out_u8, size_t out_u8_sz)
176{
177 int need;
178 if (!w || !out_u8 || out_u8_sz == 0)
179 return MYLIB_EINVAL;
180
181 need = WideCharToMultiByte(CP_UTF8, 0, w, -1, NULL, 0, NULL, NULL);
182 if (need <= 0)
183 return MYLIB_EFAIL;
184 if ((size_t)need > out_u8_sz)
185 return MYLIB_ENOBUFS;
186
187 if (WideCharToMultiByte(CP_UTF8, 0, w, -1, out_u8, (int)out_u8_sz, NULL, NULL) <= 0)
188 return MYLIB_EFAIL;
189 return MYLIB_OK;
190}
191
202 static get_lib_info_status_t get_self_path_w(wchar_t *out_w, size_t out_w_cap, const void *func_addr)
203{
204 HMODULE hm = NULL;
205 wchar_t buf[MAX_PATH];
206 DWORD n;
207
208 if (!out_w || out_w_cap == 0 || !func_addr)
209 return MYLIB_EINVAL;
210
211 if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
212 (LPCWSTR)func_addr, &hm))
213 {
214 return MYLIB_EFAIL;
215 }
216
217 n = GetModuleFileNameW(hm, buf, (DWORD)(sizeof(buf) / sizeof(buf[0])));
218 if (n == 0 || n >= (DWORD)(sizeof(buf) / sizeof(buf[0])))
219 {
220 return MYLIB_EFAIL;
221 }
222 buf[n] = L'\0';
223
224 /* GetModuleFileNameW は通常フルパスを返しますが、念のため GetFullPathNameW で正規化します。 */
225 /* (失敗した場合は buf をそのまま返す) */
226 {
227 wchar_t full[MAX_PATH];
228 DWORD m = GetFullPathNameW(buf, (DWORD)(sizeof(full) / sizeof(full[0])), full, NULL);
229 if (m == 0 || m >= (DWORD)(sizeof(full) / sizeof(full[0])))
230 {
231 if (wcslen(buf) + 1 > out_w_cap)
232 return MYLIB_ENOBUFS;
233 wcscpy_s(out_w, out_w_cap, buf);
234 return MYLIB_OK;
235 }
236 if (wcslen(full) + 1 > out_w_cap)
237 return MYLIB_ENOBUFS;
238 wcscpy_s(out_w, out_w_cap, full);
239 return MYLIB_OK;
240 }
241}
242
243#else /* Linux/Unix */
244
258 static get_lib_info_status_t get_self_path_posix(char *out_path, size_t out_path_sz, const void *func_addr)
259{
260 Dl_info info;
261 const char *p;
262 char resolved[PATH_MAX];
263
264 if (!out_path || out_path_sz == 0 || !func_addr)
265 return MYLIB_EINVAL;
266
267 memset(&info, 0, sizeof(info));
268 if (dladdr(func_addr, &info) == 0)
269 {
270 return MYLIB_EFAIL;
271 }
272
273 p = info.dli_fname ? info.dli_fname : "";
274 if (p[0] == '\0')
275 return MYLIB_EFAIL;
276
277 /* realpath() は symlink 解決と絶対化を行います。 */
278 /* ロード後にファイルが移動/削除される等で失敗する場合があるため、その場合はフォールバックします。 */
279 if (realpath(p, resolved) != NULL)
280 {
281 return copy_str(out_path, out_path_sz, resolved);
282 }
283
284 /* すでに絶対パスならそのまま返す (正規化はできない) */
285 if (p[0] == '/')
286 {
287 return copy_str(out_path, out_path_sz, p);
288 }
289
290 /* 相対パスなら CWD と結合して絶対化を試みる */
291 {
292 char cwd[PATH_MAX];
293 char joined[PATH_MAX];
294
295 if (getcwd(cwd, sizeof(cwd)) == NULL)
296 return MYLIB_EFAIL;
297 if (snprintf(joined, sizeof(joined), "%s/%s", cwd, p) <= 0)
298 return MYLIB_EFAIL;
299
300 if (realpath(joined, resolved) != NULL)
301 {
302 return copy_str(out_path, out_path_sz, resolved);
303 }
304
305 /* 最後の手段: 結合した絶対パス文字列 (正規化なし) */
306 return copy_str(out_path, out_path_sz, joined);
307 }
308}
309
310#endif
311
312/* doxygen コメントは、ヘッダに記載 */
313 int get_lib_path(char *out_path, const size_t out_path_sz, const void *func_addr)
314{
315#if defined(_WIN32)
316 wchar_t wpath[MAX_PATH];
317 get_lib_info_status_t st = get_self_path_w(wpath, (size_t)(sizeof(wpath) / sizeof(wpath[0])), func_addr);
318 if (st != MYLIB_OK)
319 {
320 if (out_path && out_path_sz)
321 out_path[0] = '\0';
322 return st;
323 }
324 return (int)narrow_utf8(wpath, out_path, out_path_sz);
325#else
326 return (int)get_self_path_posix(out_path, out_path_sz, func_addr);
327#endif
328}
329
330/* doxygen コメントは、ヘッダに記載 */
331 int get_lib_basename(char *out_basename, const size_t out_basename_sz, const void *func_addr)
332{
333 get_lib_info_status_t st;
334 char path_buf[4096];
335 const char *fname;
336 char tmp[1024];
337
338 if (!out_basename || out_basename_sz == 0)
339 return MYLIB_EINVAL;
340
341 st = get_lib_path(path_buf, sizeof(path_buf), func_addr);
342 if (st != MYLIB_OK)
343 {
344 out_basename[0] = '\0';
345 return st;
346 }
347
348 fname = get_ilename_part(path_buf);
349 if (!fname || fname[0] == '\0')
350 {
351 out_basename[0] = '\0';
352 return MYLIB_EFAIL;
353 }
354
355 /* ファイル名のみをコピーして拡張子を除く */
356 st = copy_str(tmp, sizeof(tmp), fname);
357 if (st != MYLIB_OK)
358 {
359 out_basename[0] = '\0';
360 return st;
361 }
362
363 strip_extension_inplace(tmp);
364
365 return (int)copy_str(out_basename, out_basename_sz, tmp);
366}
funcman.h
関数動的呼び出し機構 (funcman) の公開 API ヘッダー。
get_lib_info_status_t
get_lib_info_status_t
内部関数の戻り値(ステータス)。
Definition get_lib_info.c:48
MYLIB_EINVAL
@ MYLIB_EINVAL
引数不正 (NULL、サイズ0など)
Definition get_lib_info.c:52
MYLIB_EFAIL
@ MYLIB_EFAIL
その他の失敗 (取得不能、OS API 失敗など)
Definition get_lib_info.c:56
MYLIB_OK
@ MYLIB_OK
成功
Definition get_lib_info.c:50
MYLIB_ENOBUFS
@ MYLIB_ENOBUFS
バッファ不足 (出力が収まらない)
Definition get_lib_info.c:54
get_lib_basename
int get_lib_basename(char *out_basename, const size_t out_basename_sz, const void *func_addr)
指定した関数が所属する共有ライブラリ (.so/.dll) の basename (パスなし・拡張子なし) を取得します。
Definition get_lib_info.c:331
get_self_path_posix
static get_lib_info_status_t get_self_path_posix(char *out_path, size_t out_path_sz, const void *func_addr)
.so 自身の絶対パスを取得します (Linux/Unix)。
Definition get_lib_info.c:258
strip_extension_inplace
static void strip_extension_inplace(char *s)
拡張子を取り除きます (その場で書き換え)。
Definition get_lib_info.c:120
copy_str
static get_lib_info_status_t copy_str(char *dst, size_t dst_sz, const char *src)
文字列を安全にコピーします (UTF-8 想定だが単なる byte 列として扱う)。
Definition get_lib_info.c:69
get_ilename_part
static const char * get_ilename_part(const char *path)
パス文字列からファイル名部分 (最後の区切り文字以降) を返します。
Definition get_lib_info.c:94
get_lib_path
int get_lib_path(char *out_path, const size_t out_path_sz, const void *func_addr)
指定した関数が所属する共有ライブラリ (.so/.dll) の絶対パスを取得します。
Definition get_lib_info.c:313