--- /dev/null
+/*
+ Copyright (C) 2012 Modelon AB
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the BSD style license.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ FMILIB_License.txt file for more details.
+
+ You should have received a copy of the FMILIB_License.txt file
+ along with this program. If not, contact Modelon AB <http://www.modelon.com>.
+*/\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <locale.h>\r
+#include <string.h>\r
+
+#include <fmilib_config.h>
+\r
+#include <JM/jm_types.h>\r
+#include <JM/jm_portability.h>\r
+\r
+static const char * module = "JMPRT";\r
+\r
+#ifdef WIN32\r
+#include <shlwapi.h>\r
+#include <direct.h>\r
+#define get_current_working_directory _getcwd\r
+#define set_current_working_directory _chdir \r
+#else\r
+#include <unistd.h>\r
+#define get_current_working_directory getcwd\r
+#define set_current_working_directory chdir\r
+#endif\r
+\r
+#define JM_PORTABILITY_DLL_ERROR_MESSAGE_SIZE 1000\r
+\r
+DLL_HANDLE jm_portability_load_dll_handle(const char* dll_file_path)\r
+{\r
+#ifdef WIN32\r
+ /* printf("Will try to load %s\n", dll_file_path); */\r
+ return LoadLibrary(dll_file_path);\r
+#else \r
+ return dlopen(dll_file_path, RTLD_NOW|RTLD_LOCAL);\r
+#endif\r
+}\r
+\r
+jm_status_enu_t jm_portability_free_dll_handle(DLL_HANDLE dll_handle)\r
+{ \r
+#ifdef WIN32 \r
+ if (FreeLibrary(dll_handle)==0) {\r
+ return jm_status_error;\r
+ } else {\r
+ return jm_status_success;\r
+ }\r
+#else \r
+ if (dlclose(dll_handle)==0) {\r
+ return jm_status_success; \r
+ } else {\r
+ return jm_status_error;\r
+ }\r
+#endif\r
+}\r
+\r
+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
+{\r
+#ifdef WIN32\r
+ *dll_function_ptrptr = (jm_dll_function_ptr)GetProcAddress(dll_handle, dll_function_name);\r
+#else\r
+ *dll_function_ptrptr = dlsym(dll_handle, dll_function_name);\r
+#endif\r
+\r
+ if (*dll_function_ptrptr == NULL) {\r
+ return jm_status_error;\r
+ } else {\r
+ return jm_status_success;\r
+ }\r
+}\r
+\r
+char* jm_portability_get_last_dll_error(void)\r
+{\r
+ static char err_str[JM_PORTABILITY_DLL_ERROR_MESSAGE_SIZE]; \r
+\r
+#ifdef WIN32\r
+ LPVOID lpMsgBuf;\r
+ 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
+ jm_snprintf(err_str, JM_PORTABILITY_DLL_ERROR_MESSAGE_SIZE, "%s", lpMsgBuf);\r
+#else\r
+ jm_snprintf(err_str, JM_PORTABILITY_DLL_ERROR_MESSAGE_SIZE, "%s", dlerror());\r
+#endif \r
+ return err_str;\r
+}\r
+\r
+\r
+jm_status_enu_t jm_portability_get_current_working_directory(char* buffer, size_t len)\r
+{\r
+ int ilen = (int)len;\r
+ if(ilen != len) ilen = FILENAME_MAX + 2;\r
+ setlocale(LC_CTYPE, "en_US.UTF-8"); /* just in case, does not seem to have an effect */\r
+ if (get_current_working_directory(buffer, ilen) == NULL) {\r
+ return jm_status_error;\r
+ } else {\r
+ return jm_status_success;\r
+ }\r
+}\r
+\r
+jm_status_enu_t jm_portability_set_current_working_directory(const char* cwd)\r
+{\r
+ if (set_current_working_directory(cwd) == 0) {\r
+ return jm_status_success;\r
+ } else {\r
+ return jm_status_error;\r
+ }\r
+}\r
+\r
+#ifdef WIN32\r
+#define MAX_TEMP_DIR_NAME_LENGTH 262\r
+TCHAR jm_temp_dir_buffer[MAX_TEMP_DIR_NAME_LENGTH];\r
+#endif\r
+\r
+const char* jm_get_system_temp_dir() {\r
+#ifdef WIN32\r
+ if(!GetTempPath(MAX_TEMP_DIR_NAME_LENGTH, jm_temp_dir_buffer)) return 0;\r
+ return jm_temp_dir_buffer;\r
+#else\r
+ return "/tmp/";\r
+#endif\r
+}\r
+\r
+#ifdef WIN32\r
+#include <io.h>\r
+#else\r
+#include <stdlib.h>
+#endif\r
+char *jm_mkdtemp(jm_callbacks *cb, char *tmplt)
+{
+#ifdef WIN32
+ /* Windows does not have mkdtemp, use mktemp + mkdir */
+
+ if(!_mktemp(tmplt)) {
+ jm_log_fatal(cb, module, "Could not create a unique temporary directory name");
+ return NULL;
+ }
+ if(jm_mkdir(cb, tmplt) != jm_status_success) {
+ return NULL;
+ }
+ return tmplt;
+
+#else
+ return mkdtemp(tmplt);
+#endif
+}\r
+\r
+#ifdef WIN32\r
+#include <direct.h>\r
+#define MKDIR(dir) _mkdir(dir)\r
+#else\r
+#include <errno.h>\r
+#include <sys/stat.h>\r
+#define MKDIR(dir) mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)\r
+#endif\r
+\r
+jm_status_enu_t jm_mkdir(jm_callbacks* cb, const char* dir) {\r
+ if(!cb) {
+ cb = jm_get_default_callbacks();
+ }
+ if(MKDIR(dir)) {\r
+ jm_log_fatal(cb,module,"Could not create directory %s", dir);\r
+ return jm_status_error;\r
+ }\r
+ else\r
+ return jm_status_success;\r
+}\r
+\r
+\r
+jm_status_enu_t jm_rmdir(jm_callbacks* cb, const char* dir) {\r
+#ifdef WIN32
+ const char* fmt_cmd = "rmdir /s /q %s";
+#else
+ const char* fmt_cmd = "rm -rf %s";
+#endif
+ char * buf = (char*)cb->calloc(sizeof(char), strlen(dir)+strlen(fmt_cmd)+1);
+ if(!cb) {
+ cb = jm_get_default_callbacks();
+ }
+ if(!buf) {
+ jm_log_error(cb,module,"Could not allocate memory");
+ return jm_status_error;
+ }
+ sprintf(buf, fmt_cmd, dir);/*safe*/
+#ifdef WIN32
+ {
+ char* ch = buf+strlen(fmt_cmd) - 2;
+ while(*ch) {
+ if(*ch == '/') *ch = '\\';
+ ch++;
+ }
+ }
+#endif
+ jm_log_verbose(cb,module,"Removing %s", dir);
+ if(system(buf)) {
+ jm_log_error(cb,module,"Error removing %s (%s)", dir, strerror(errno));
+ return jm_status_error;
+ }
+ cb->free(buf);
+ return jm_status_success;
+}
+
+char* jm_get_dir_abspath(jm_callbacks* cb, const char* dir, char* outPath, size_t len) {\r
+ char curDir[FILENAME_MAX + 2];\r
+\r
+ if(!cb) {
+ cb = jm_get_default_callbacks();
+ }
+ if( jm_portability_get_current_working_directory(curDir, FILENAME_MAX+1) != jm_status_success) {\r
+ jm_log_fatal(cb,module, "Could not get current working directory (%s)", strerror(errno));\r
+ return 0;\r
+ };\r
+\r
+ if(jm_portability_set_current_working_directory(dir) != jm_status_success) {\r
+ jm_log_fatal(cb,module, "Could not change to the directory %s", dir);\r
+ jm_portability_set_current_working_directory(curDir);\r
+ return 0;\r
+ };\r
+ if( jm_portability_get_current_working_directory(outPath, len) != jm_status_success) {\r
+ jm_log_fatal(cb,module, "Could not get absolute path for the directory (%s)", strerror(errno));\r
+ jm_portability_set_current_working_directory(curDir);\r
+ return 0;\r
+ };\r
+ jm_portability_set_current_working_directory(curDir);\r
+ return outPath;\r
+}\r
+
+
+char* jm_mk_temp_dir(jm_callbacks* cb, const char* systemTempDir, const char* tempPrefix)
+{\r
+ size_t len;\r
+\r
+ char tmpDir[FILENAME_MAX + 2];\r
+ char* tmpPath;\r
+\r
+ if(!cb) {
+ cb = jm_get_default_callbacks();
+ }
+ if(!systemTempDir) {\r
+ systemTempDir = jm_get_system_temp_dir();\r
+ if(!systemTempDir) systemTempDir = "./";\r
+ }\r
+ if(!tempPrefix) {\r
+ tempPrefix = "jm";\r
+ }\r
+ len = strlen(systemTempDir);\r
+\r
+ if(!jm_get_dir_abspath(cb, systemTempDir, tmpDir, FILENAME_MAX + 2)) {\r
+ return 0;\r
+ }\r
+\r
+ len = strlen(tmpDir);\r
+ if(tmpDir[len-1] != FMI_FILE_SEP[0]) {\r
+ tmpDir[len] = FMI_FILE_SEP[0]; \r
+ tmpDir[len+1] = 0;\r
+ len++;\r
+ }\r
+ len += strlen(tempPrefix) + 6;\r
+ if(len + 16 > FILENAME_MAX) {\r
+ 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
+ return 0;\r
+ }\r
+ tmpPath = (char*)cb->malloc(len + 7);\r
+ if(!tmpPath) {\r
+ jm_log_fatal(cb, module,"Could not allocate memory");\r
+ return 0;\r
+ }\r
+ sprintf(tmpPath,"%s%sXXXXXX",tmpDir,tempPrefix);/*safe*/\r
+\r
+ if (jm_mkdtemp(cb, tmpPath) == NULL) {
+ jm_log_fatal(cb, module,"Could not create a unique temporary directory");
+ }
+
+ return tmpPath;\r
+}\r
+\r
+char* jm_create_URL_from_abs_path(jm_callbacks* cb, const char* path) {\r
+ /* worst case: all symbols are 4-byte UTF-8 and need to be %-encoded */\r
+#define MAX_URL_LENGTH (FILENAME_MAX * 4 * 3 + 7)\r
+ char buffer[MAX_URL_LENGTH];\r
+ char* url;\r
+ size_t urllen;\r
+ if(!cb) {
+ cb = jm_get_default_callbacks();
+ }
+\r
+#if defined(_WIN32) || defined(WIN32)\r
+ {\r
+ DWORD pathLen = MAX_URL_LENGTH;\r
+ HRESULT code = UrlCreateFromPathA(\r
+ path,\r
+ buffer,\r
+ &pathLen,\r
+ 0);\r
+ if( (code != S_FALSE) && (code != S_OK)) {\r
+ jm_log_fatal(cb, module,"Could not constuct file URL from path %s", path);\r
+ return 0;\r
+ }\r
+ urllen = pathLen;\r
+ }\r
+#else\r
+ {\r
+ size_t i, len = strlen(path);\r
+ char *curBuf = buffer + 7;\r
+ unsigned char ch;\r
+ strcpy(buffer, "file://");\r
+ for( i = 0; i < len; i++) {\r
+ ch = (unsigned char)path[i];\r
+ if( (ch == '/') || ((ch >= 'A') && (ch <= 'Z')) \r
+ || ((ch >= 'a') && (ch <= 'z'))\r
+ || ((ch >= '0') && (ch <= '9'))\r
+ || (ch == '-') || (ch == '_') || (ch == '.') ||(ch == '~')) {\r
+ *curBuf = ch;\r
+ curBuf++;\r
+ continue;\r
+ }\r
+ sprintf(curBuf, "%%%2X", (int)ch);/*safe*/\r
+ curBuf+=3;\r
+ }\r
+ *curBuf = 0;\r
+ urllen = curBuf - buffer;\r
+ }\r
+#endif\r
+ url = (char*)cb->malloc(urllen+1);\r
+ if(!url) {\r
+ jm_log_fatal(cb, module,"Could not allocate memory");\r
+ return 0;\r
+ }\r
+ strcpy(url, buffer);\r
+ return url;\r
+}\r
+
+#ifndef HAVE_VSNPRINTF
+int jm_rpl_vsnprintf(char *, size_t, const char *, va_list);
+#endif
+
+int jm_vsnprintf(char * str, size_t size, const char * fmt, va_list al) {
+ return jm_rpl_vsnprintf(str, size, fmt, al);
+}
+
+int jm_snprintf(char * str, size_t size, const char * fmt, ...) {
+ va_list args;
+ int ret;
+ va_start (args, fmt);
+ ret = jm_vsnprintf(str, size, fmt, args);
+ va_end (args);
+ return ret;
+}