Implement new way to override libc functions from within shared as well as static...
[xbmc:xbmc-antiquated.git] / xbmc / lib / libPython / linux / wrapper_python.c
1 /*
2  *      Copyright (C) 2007-2010 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <pthread.h>
26 #include <dlfcn.h>
27 #include <limits.h>
28
29 /* The names of libc libraries for different systems */
30 #if defined(_WIN32)
31 #  define C_LIB "msvcr90.dll"
32 #elif defined(__APPLE__)
33 #  define C_LIB "libc.dylib"
34 #else
35 #  define C_LIB "libc.so.6"
36 #endif
37
38 /* These are attributes that enable xbmc_libc_init to be automatically called
39  * before entering main() or during library initilization.
40  * Idea for the MSVC declaration is from
41  * http://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/auxiliary/util/u_init.h
42  */
43 #if defined(_MSC_VER)
44 #  define XBMC_LIBC_INIT \
45    static void __cdecl xbmc_libc_init(void); \
46    __declspec(allocate(".CRT$XCU")) void (__cdecl* xbmc_libc_init__xcu)(void) = xbmc_libc_init; \
47    static void __cdecl xbmc_libc_init(void)
48 #elif defined(__GNUC__)
49 #  define XBMC_LIBC_INIT __attribute__((constructor)) static void xbmc_libc_init(void)
50 #else
51 #  define XBMC_LIBC_INIT void xbmc_libc_init(void)
52 #endif
53
54 /* Global dlopen handle */
55 static void *dlopen_handle;
56
57 /* Global dlsym handles */
58 static char *(*libc_getcwd)(char*,size_t);
59 static int (*libc_chdir)(const char*);
60 static FILE *(*libc_fopen64)(const char*, const char*);
61
62 /* Function prototypes of overridden libc functions */
63 char *getcwd(char *buf, size_t size);
64 int chdir(const char *path);
65
66 /* Function to initialize dlopen and dlsym handles. It should be called before
67  * using any overridden libc function.
68  */
69 XBMC_LIBC_INIT
70 {
71   dlopen_handle = dlopen(C_LIB, RTLD_LOCAL | RTLD_LAZY);
72   libc_getcwd = dlsym(dlopen_handle, "getcwd");
73   libc_chdir = dlsym(dlopen_handle, "chdir");
74   libc_fopen64 = dlsym(dlopen_handle, "fopen64");
75 }
76
77 #ifdef __APPLE__
78 /* Use pthread's built-in support for TLS, it's more portable. */
79 static pthread_once_t keyOnce = PTHREAD_ONCE_INIT;
80 static pthread_key_t  tWorkingDir = 0;
81
82 /* Called once and only once. */
83 static void MakeTlsKeys()
84 {
85   pthread_key_create(&tWorkingDir, free);
86 }
87
88 #define xbp_cw_dir (char*)pthread_getspecific(tWorkingDir)
89
90 #else
91 __thread char xbp_cw_dir[PATH_MAX] = "";
92 #endif
93
94 /* Overridden functions */
95 char *getcwd(char *buf, size_t size)
96 {
97 #ifdef __APPLE__
98   // Initialize thread local storage and local thread pointer.
99   pthread_once(&keyOnce, MakeTlsKeys);
100   if (xbp_cw_dir == 0)
101   {
102     printf("Initializing Python path...\n");
103     char* path = (char* )malloc(PATH_MAX);
104     strcpy(path, _P("special://xbmc/system/python").c_str());
105     pthread_setspecific(tWorkingDir, (void*)path);
106   }
107 #endif
108
109   if (buf == NULL) buf = (char *)malloc(size);
110   strcpy(buf, xbp_cw_dir);
111   return buf;
112 }
113
114 int chdir(const char *dirname)
115 {
116 #ifdef __APPLE__
117   // Initialize thread local storage and local thread pointer.
118   pthread_once(&keyOnce, MakeTlsKeys);
119
120   if (xbp_cw_dir == 0)
121   {
122     char* path = (char* )malloc(PATH_MAX);
123     strcpy(path, _P("special://xbmc/system/python").c_str());
124     pthread_setspecific(tWorkingDir, (void*)path);
125   }
126 #endif
127
128   if (strlen(dirname) > PATH_MAX) return -1;
129   strcpy(xbp_cw_dir, dirname);
130   return 0;
131 }
132
133 FILE* fopen64(const char *filename, const char *mode)
134 {
135 #ifdef __APPLE__
136   return fopen(filename, mode);
137 #else
138   return (*libc_fopen64)(filename, mode);
139 #endif
140 }