]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMILibrary/src/Util/src/JM/jm_portability.c
Switch to full JavaSE-11+ compatibility
[simantics/fmil.git] / org.simantics.fmil.core / native / FMILibrary / src / Util / src / JM / jm_portability.c
1 /*
2     Copyright (C) 2012 Modelon AB
3
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the BSD style license.
6
7      This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10     FMILIB_License.txt file for more details.
11
12     You should have received a copy of the FMILIB_License.txt file
13     along with this program. If not, contact Modelon AB <http://www.modelon.com>.
14 */\r
15 \r
16 #include <stdlib.h>\r
17 #include <stdio.h>\r
18 #include <locale.h>\r
19 #include <string.h>\r
20
21 #include <fmilib_config.h>
22 \r
23 #include <JM/jm_types.h>\r
24 #include <JM/jm_portability.h>\r
25 \r
26 static const char * module = "JMPRT";\r
27 \r
28 #ifdef WIN32\r
29 #include <shlwapi.h>\r
30 #include <direct.h>\r
31 #define get_current_working_directory _getcwd\r
32 #define set_current_working_directory _chdir    \r
33 #else\r
34 #include <unistd.h>\r
35 #define get_current_working_directory getcwd\r
36 #define set_current_working_directory chdir\r
37 #endif\r
38 \r
39 #define JM_PORTABILITY_DLL_ERROR_MESSAGE_SIZE 1000\r
40 \r
41 DLL_HANDLE jm_portability_load_dll_handle(const char* dll_file_path)\r
42 {\r
43 #ifdef WIN32\r
44         /* printf("Will try to load %s\n", dll_file_path); */\r
45         return LoadLibrary(dll_file_path);\r
46 #else   \r
47         return dlopen(dll_file_path, RTLD_NOW|RTLD_LOCAL);\r
48 #endif\r
49 }\r
50 \r
51 jm_status_enu_t jm_portability_free_dll_handle(DLL_HANDLE dll_handle)\r
52 {       \r
53 #ifdef WIN32            \r
54         if (FreeLibrary(dll_handle)==0) {\r
55                 return jm_status_error;\r
56         } else {\r
57                 return jm_status_success;\r
58         }\r
59 #else           \r
60         if (dlclose(dll_handle)==0) {\r
61                 return jm_status_success;                       \r
62         } else {\r
63                 return jm_status_error;\r
64         }\r
65 #endif\r
66 }\r
67 \r
68 jm_status_enu_t jm_portability_load_dll_function(DLL_HANDLE dll_handle, char* dll_function_name, jm_dll_function_ptr* dll_function_ptrptr)\r
69 {\r
70 #ifdef WIN32\r
71         *dll_function_ptrptr = (jm_dll_function_ptr)GetProcAddress(dll_handle, dll_function_name);\r
72 #else\r
73         *dll_function_ptrptr = dlsym(dll_handle, dll_function_name);\r
74 #endif\r
75 \r
76         if (*dll_function_ptrptr == NULL) {\r
77                 return jm_status_error;\r
78         } else {\r
79                 return jm_status_success;\r
80         }\r
81 }\r
82 \r
83 char* jm_portability_get_last_dll_error(void)\r
84 {\r
85         static char err_str[JM_PORTABILITY_DLL_ERROR_MESSAGE_SIZE]; \r
86 \r
87 #ifdef WIN32\r
88         LPVOID lpMsgBuf;\r
89         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);\r
90         jm_snprintf(err_str, JM_PORTABILITY_DLL_ERROR_MESSAGE_SIZE, "%s", lpMsgBuf);\r
91 #else\r
92         jm_snprintf(err_str, JM_PORTABILITY_DLL_ERROR_MESSAGE_SIZE, "%s", dlerror());\r
93 #endif  \r
94         return err_str;\r
95 }\r
96 \r
97 \r
98 jm_status_enu_t jm_portability_get_current_working_directory(char* buffer, size_t len)\r
99 {\r
100         int ilen = (int)len;\r
101         if(ilen != len) ilen = FILENAME_MAX + 2;\r
102         setlocale(LC_CTYPE, "en_US.UTF-8"); /* just in case, does not seem to have an effect */\r
103         if (get_current_working_directory(buffer, ilen) == NULL) {\r
104                 return jm_status_error;\r
105         } else {\r
106                 return jm_status_success;\r
107         }\r
108 }\r
109 \r
110 jm_status_enu_t jm_portability_set_current_working_directory(const char* cwd)\r
111 {\r
112         if (set_current_working_directory(cwd) == 0) {\r
113                 return jm_status_success;\r
114         } else {\r
115                 return jm_status_error;\r
116         }\r
117 }\r
118 \r
119 #ifdef WIN32\r
120 #define MAX_TEMP_DIR_NAME_LENGTH 262\r
121 TCHAR jm_temp_dir_buffer[MAX_TEMP_DIR_NAME_LENGTH];\r
122 #endif\r
123 \r
124 const char* jm_get_system_temp_dir() {\r
125 #ifdef WIN32\r
126         if(!GetTempPath(MAX_TEMP_DIR_NAME_LENGTH, jm_temp_dir_buffer)) return 0;\r
127         return jm_temp_dir_buffer;\r
128 #else\r
129         return "/tmp/";\r
130 #endif\r
131 }\r
132 \r
133 #ifdef WIN32\r
134 #include <io.h>\r
135 #else\r
136 #include <stdlib.h>
137 #endif\r
138 char *jm_mkdtemp(jm_callbacks *cb, char *tmplt)
139 {
140 #ifdef WIN32
141     /* Windows does not have mkdtemp, use mktemp + mkdir */
142
143     if(!_mktemp(tmplt)) {
144         jm_log_fatal(cb, module, "Could not create a unique temporary directory name");
145         return NULL;
146     }
147     if(jm_mkdir(cb, tmplt) != jm_status_success) {
148         return NULL;
149     }
150     return tmplt;
151
152 #else
153     return mkdtemp(tmplt);
154 #endif
155 }\r
156 \r
157 #ifdef WIN32\r
158 #include <direct.h>\r
159 #define MKDIR(dir) _mkdir(dir)\r
160 #else\r
161 #include <errno.h>\r
162 #include <sys/stat.h>\r
163 #define MKDIR(dir) mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)\r
164 #endif\r
165 \r
166 jm_status_enu_t jm_mkdir(jm_callbacks* cb, const char* dir) {\r
167         if(!cb) {
168                 cb = jm_get_default_callbacks();
169         }
170         if(MKDIR(dir)) {\r
171                 jm_log_fatal(cb,module,"Could not create directory %s", dir);\r
172                 return jm_status_error;\r
173         }\r
174         else\r
175                 return jm_status_success;\r
176 }\r
177 \r
178 \r
179 jm_status_enu_t jm_rmdir(jm_callbacks* cb, const char* dir) {\r
180 #ifdef WIN32
181         const char* fmt_cmd = "rmdir /s /q %s";
182 #else
183     const char* fmt_cmd = "rm -rf %s";
184 #endif
185     char * buf = (char*)cb->calloc(sizeof(char), strlen(dir)+strlen(fmt_cmd)+1);
186         if(!cb) {
187                 cb = jm_get_default_callbacks();
188         }
189         if(!buf) {
190             jm_log_error(cb,module,"Could not allocate memory");
191                 return jm_status_error;
192         }
193     sprintf(buf, fmt_cmd, dir);/*safe*/
194 #ifdef WIN32
195         {
196                 char* ch = buf+strlen(fmt_cmd) - 2;
197                 while(*ch) {
198                         if(*ch == '/') *ch = '\\';
199                         ch++;
200                 }
201         }
202 #endif
203     jm_log_verbose(cb,module,"Removing %s", dir);
204     if(system(buf)) {
205             jm_log_error(cb,module,"Error removing %s (%s)", dir, strerror(errno));
206                 return jm_status_error;
207         }
208     cb->free(buf);
209         return jm_status_success;
210 }
211
212 char* jm_get_dir_abspath(jm_callbacks* cb, const char* dir, char* outPath, size_t len) {\r
213         char curDir[FILENAME_MAX + 2];\r
214 \r
215         if(!cb) {
216                 cb = jm_get_default_callbacks();
217         }
218         if( jm_portability_get_current_working_directory(curDir, FILENAME_MAX+1) != jm_status_success) {\r
219                 jm_log_fatal(cb,module, "Could not get current working directory (%s)", strerror(errno));\r
220                 return 0;\r
221         };\r
222 \r
223         if(jm_portability_set_current_working_directory(dir) != jm_status_success) {\r
224                 jm_log_fatal(cb,module, "Could not change to the directory %s", dir);\r
225                 jm_portability_set_current_working_directory(curDir);\r
226                 return 0;\r
227         };\r
228         if( jm_portability_get_current_working_directory(outPath, len) != jm_status_success) {\r
229                 jm_log_fatal(cb,module, "Could not get absolute path for the directory (%s)", strerror(errno));\r
230                 jm_portability_set_current_working_directory(curDir);\r
231                 return 0;\r
232         };\r
233         jm_portability_set_current_working_directory(curDir);\r
234         return outPath;\r
235 }\r
236
237
238 char* jm_mk_temp_dir(jm_callbacks* cb, const char* systemTempDir, const char* tempPrefix)
239 {\r
240         size_t len;\r
241 \r
242         char tmpDir[FILENAME_MAX + 2];\r
243         char* tmpPath;\r
244 \r
245         if(!cb) {
246                 cb = jm_get_default_callbacks();
247         }
248         if(!systemTempDir) {\r
249                 systemTempDir = jm_get_system_temp_dir();\r
250                 if(!systemTempDir) systemTempDir = "./";\r
251         }\r
252         if(!tempPrefix) {\r
253                 tempPrefix = "jm";\r
254         }\r
255         len = strlen(systemTempDir);\r
256 \r
257         if(!jm_get_dir_abspath(cb, systemTempDir, tmpDir, FILENAME_MAX + 2)) {\r
258                 return 0;\r
259         }\r
260 \r
261         len = strlen(tmpDir);\r
262         if(tmpDir[len-1] != FMI_FILE_SEP[0]) {\r
263                 tmpDir[len] = FMI_FILE_SEP[0]; \r
264                 tmpDir[len+1] = 0;\r
265                 len++;\r
266         }\r
267         len += strlen(tempPrefix) + 6;\r
268         if(len + 16 > FILENAME_MAX) {\r
269                 jm_log_fatal(cb,module, "Canonical name for the temporary files directory is too long (system limit for path length is %d)", FILENAME_MAX);\r
270                 return 0;\r
271         }\r
272         tmpPath = (char*)cb->malloc(len + 7);\r
273         if(!tmpPath) {\r
274                 jm_log_fatal(cb, module,"Could not allocate memory");\r
275                 return 0;\r
276         }\r
277         sprintf(tmpPath,"%s%sXXXXXX",tmpDir,tempPrefix);/*safe*/\r
278 \r
279     if (jm_mkdtemp(cb, tmpPath) == NULL) {
280         jm_log_fatal(cb, module,"Could not create a unique temporary directory");
281     }
282
283         return tmpPath;\r
284 }\r
285 \r
286 char* jm_create_URL_from_abs_path(jm_callbacks* cb, const char* path) {\r
287         /* worst case: all symbols are 4-byte UTF-8 and need to be %-encoded */\r
288 #define MAX_URL_LENGTH  (FILENAME_MAX * 4 * 3 + 7)\r
289         char buffer[MAX_URL_LENGTH];\r
290         char* url;\r
291         size_t urllen;\r
292         if(!cb) {
293                 cb = jm_get_default_callbacks();
294         }
295 \r
296 #if defined(_WIN32) || defined(WIN32)\r
297         {\r
298                 DWORD pathLen = MAX_URL_LENGTH;\r
299                 HRESULT code = UrlCreateFromPathA(\r
300                         path,\r
301                         buffer,\r
302                         &pathLen,\r
303                         0);\r
304                 if( (code != S_FALSE) && (code != S_OK)) {\r
305                         jm_log_fatal(cb, module,"Could not constuct file URL from path %s", path);\r
306                         return 0;\r
307                 }\r
308                 urllen = pathLen;\r
309         }\r
310 #else\r
311         {\r
312                 size_t i, len = strlen(path);\r
313                 char *curBuf = buffer + 7;\r
314                 unsigned char ch;\r
315                 strcpy(buffer, "file://");\r
316                 for( i = 0; i < len; i++) {\r
317                         ch = (unsigned char)path[i];\r
318                         if( (ch == '/') || ((ch >= 'A') && (ch <= 'Z')) \r
319                                 || ((ch >= 'a') && (ch <= 'z'))\r
320                                 || ((ch >= '0') && (ch <= '9'))\r
321                                 || (ch == '-') || (ch == '_') || (ch == '.') ||(ch == '~')) {\r
322                                         *curBuf = ch;\r
323                                         curBuf++;\r
324                                         continue;\r
325                         }\r
326                         sprintf(curBuf, "%%%2X", (int)ch);/*safe*/\r
327                         curBuf+=3;\r
328                 }\r
329                 *curBuf = 0;\r
330                 urllen = curBuf - buffer;\r
331         }\r
332 #endif\r
333         url = (char*)cb->malloc(urllen+1);\r
334         if(!url) {\r
335                 jm_log_fatal(cb, module,"Could not allocate memory");\r
336                 return 0;\r
337         }\r
338         strcpy(url, buffer);\r
339         return url;\r
340 }\r
341
342 #ifndef HAVE_VSNPRINTF
343 int jm_rpl_vsnprintf(char *, size_t, const char *, va_list);
344 #endif
345
346 int jm_vsnprintf(char * str, size_t size, const char * fmt, va_list al) {
347     return jm_rpl_vsnprintf(str, size, fmt, al);
348 }
349
350 int jm_snprintf(char * str, size_t size, const char * fmt, ...) {
351     va_list args;
352     int ret;
353     va_start (args, fmt);
354     ret = jm_vsnprintf(str, size, fmt, args);
355     va_end (args);
356     return ret;
357 }