/* See license.txt in the root of this project. */ # include # include # include "auxfile.h" # include "auxmemory.h" # ifdef _WIN32 # include # include # include # include # include LPWSTR aux_utf8_to_wide(const char *utf8str) { if (utf8str) { int length = MultiByteToWideChar(CP_UTF8, 0, utf8str, -1, NULL, 0); /* preroll */ LPWSTR wide = (LPWSTR) lmt_memory_malloc(sizeof(WCHAR) * length); MultiByteToWideChar(CP_UTF8, 0, utf8str, -1, wide, length); return wide; } else { return NULL; } } char *aux_utf8_from_wide(LPWSTR widestr) { if (widestr) { int length = WideCharToMultiByte(CP_UTF8, 0, widestr, -1, NULL, 0, NULL, NULL); char * utf8str = (char *) lmt_memory_malloc(sizeof(char) * length); WideCharToMultiByte(CP_UTF8, 0, widestr, -1, utf8str, length, NULL, NULL); return (char *) utf8str; } else { return NULL; } } FILE *aux_utf8_fopen(const char *path, const char *mode) { if (path && mode) { LPWSTR wpath = aux_utf8_to_wide(path); LPWSTR wmode = aux_utf8_to_wide(mode); FILE *f = _wfopen(wpath,wmode); lmt_memory_free(wpath); lmt_memory_free(wmode); return f; } else { return NULL; } } FILE *aux_utf8_popen(const char *path, const char *mode) { if (path && mode) { LPWSTR wpath = aux_utf8_to_wide(path); LPWSTR wmode = aux_utf8_to_wide(mode); FILE *f = _wpopen(wpath,wmode); lmt_memory_free(wpath); lmt_memory_free(wmode); return f; } else { return NULL; } } int aux_utf8_system(const char *cmd) { LPWSTR wcmd = aux_utf8_to_wide(cmd); int result = _wsystem(wcmd); lmt_memory_free(wcmd); return result; } int aux_utf8_remove(const char *name) { LPWSTR wname = aux_utf8_to_wide(name); int result = _wremove(wname); lmt_memory_free(wname); return result; } int aux_utf8_rename(const char *oldname, const char *newname) { LPWSTR woldname = aux_utf8_to_wide(oldname); LPWSTR wnewname = aux_utf8_to_wide(newname); int result = _wrename(woldname, wnewname); lmt_memory_free(woldname); lmt_memory_free(wnewname); return result; } int aux_utf8_setargv(char * **av, char **argv, int argc) { if (argv) { int c = 0; LPWSTR *l = CommandLineToArgvW(GetCommandLineW(), &c); if (l != NULL) { char **v = lmt_memory_malloc(sizeof(char *) * c); for (int i = 0; i < c; i++) { v[i] = aux_utf8_from_wide(l[i]); } *av = v; /*tex Let's be nice with path names: |c:\\foo\\etc| */ if (c > 1) { if ((strlen(v[c-1]) > 2) && isalpha(v[c-1][0]) && (v[c-1][1] == ':') && (v[c-1][2] == '\\')) { for (char *p = v[c-1]+2; *p; p++) { if (*p == '\\') { *p = '/'; } } } } } return c; } else { *av = NULL; return argc; } } char *aux_utf8_getownpath(const char *file) { if (file) { char *path = NULL; char buffer[MAX_PATH]; GetModuleFileName(NULL, buffer, sizeof(buffer)); path = lmt_memory_strdup(buffer); if (strlen(path) > 0) { for (size_t i = 0; i < strlen(path); i++) { if (path[i] == '\\') { path[i] = '/'; } } return path; } } return lmt_memory_strdup("."); } /*tex We alwways return a copy so that we're consistent with windows/unix. */ // # if defined(__MINGW64__) || defined(__MINGW32__) // extern DWORD GetFinalPathNameByHandleW(HANDLE hFile, LPWSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags); // # endif char *aux_utf8_readlink(const char *file) { LPWSTR wide = aux_utf8_to_wide(file); HANDLE handle = CreateFileW(wide, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); char *link = NULL; if (handle == INVALID_HANDLE_VALUE) { LPWSTR path = (LPWSTR) lmt_memory_malloc((MAX_PATH+1) * sizeof(WCHAR)); DWORD size = GetFinalPathNameByHandleW(handle, path, MAX_PATH, VOLUME_NAME_NT); if (size > 0 && size < MAX_PATH) { path[size] = '\0'; link = aux_utf8_from_wide(path); } lmt_memory_free(path); } CloseHandle(handle); lmt_memory_free(wide); return link ? link : lmt_memory_strdup(file); } # else # include # include # include int aux_utf8_setargv(char * **av, char **argv, int argc) { *av = argv; return argc; } char *aux_utf8_getownpath(const char *file) { if (strchr(file, '/')) { return lmt_memory_strdup(file); } else { const char *esp; size_t prefixlen = 0; size_t totallen = 0; size_t filelen = strlen(file); char *path = NULL; char *searchpath = lmt_memory_strdup(getenv("PATH")); const char *index = searchpath; if (index) { do { esp = strchr(index, ':'); if (esp) { prefixlen = (size_t) (esp - index); } else { prefixlen = strlen(index); } if (prefixlen == 0 || index[prefixlen - 1] == '/') { totallen = prefixlen + filelen; # ifdef PATH_MAX if (totallen >= PATH_MAX) { continue; } # endif path = lmt_memory_malloc(totallen + 1); memcpy(path, index, prefixlen); memcpy(path + prefixlen, file, filelen); } else { totallen = prefixlen + filelen + 1; # ifdef PATH_MAX if (totallen >= PATH_MAX) { continue; } # endif path = lmt_memory_malloc(totallen + 1); memcpy(path, index, prefixlen); path[prefixlen] = '/'; memcpy(path + prefixlen + 1, file, filelen); } path[totallen] = '\0'; if (access(path, X_OK) >= 0) { break; } lmt_memory_free(path); path = NULL; index = esp + 1; } while (esp); } lmt_memory_free(searchpath); if (path) { return path; } else { return lmt_memory_strdup("."); /* ok? */ } } } /*tex We alwways return a copy so that we're consistent with windows/unix. */ char *aux_utf8_readlink(const char *file) { int size = 256; while (1) { char *target = lmt_memory_malloc(size); if (! target) { break; } else { int tsize = readlink(file, target, size); if (tsize <= 0) { lmt_memory_free(target); break; } else if (tsize < size) { target[tsize] = '\0'; return target; } else { size *= 2; } } } return lmt_memory_strdup(file); } # endif # ifndef S_ISREG # define S_ISREG(mode) (mode & _S_IFREG) # endif # ifdef _WIN32 char *aux_basename(const char *name) { char base[256+1]; char suff[256+1]; _splitpath(name,NULL,NULL,base,suff); { size_t b = strlen((const char*)base); size_t s = strlen((const char*)suff); char *result = (char *) lmt_memory_malloc(sizeof(char) * (b+s+1)); if (result) { memcpy(&result[0], &base[0], b); memcpy(&result[b], &suff[0], s); result[b + s] = '\0'; } return result; } } char *aux_dirname(const char *name) { char driv[256 + 1]; char path[256 + 1]; _splitpath(name,driv,path,NULL,NULL); { size_t d = strlen((const char*)driv); size_t p = strlen((const char*)path); char *result = (char *) lmt_memory_malloc(sizeof(char) * (d+p+1)); if (result) { if (path[p - 1] == '/' || path[p - 1] == '\\') { --p; } memcpy(&result[0], &driv[0], d); memcpy(&result[d], &path[0], p); result[d + p] = '\0'; } return result; } } int aux_is_readable(const char *filename) { struct _stati64 info; LPWSTR w = aux_utf8_to_wide(filename); int r = _wstati64(w, &info); FILE *f; lmt_memory_free(w); return (r == 0) && (S_ISREG(info.st_mode)) && ((f = aux_utf8_fopen(filename, "r")) != NULL) && ! fclose(f); } # else # include int aux_is_readable(const char *filename) { struct stat finfo; FILE *f; return (stat(filename, &finfo) == 0) && S_ISREG(finfo.st_mode) && ((f = fopen(filename, "r")) != NULL) && ! fclose(f); } # endif