diff options
Diffstat (limited to 'Build/source/texk/kpathsea/mingw32.c')
-rw-r--r-- | Build/source/texk/kpathsea/mingw32.c | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/Build/source/texk/kpathsea/mingw32.c b/Build/source/texk/kpathsea/mingw32.c new file mode 100644 index 00000000000..a795a3a27a2 --- /dev/null +++ b/Build/source/texk/kpathsea/mingw32.c @@ -0,0 +1,458 @@ +/* mingw32.c: bits and pieces for mingw32 + + Copyright 2009-2017 Taco Hoekwater <taco@luatex.org>. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* Original sources lifted from the distribution of XEmacs for Windows NT, + Copyright 1994-1996 Free Software Foundation, later adapted to + fpTeX 0.4 (2000) by Fabrice Popineau <Fabrice.Popineau@supelec.fr>, + then simplified and re-adapted to TeXLive (2009) by Taco Hoekwater + <taco@luatex.org>. +*/ + +#ifdef __MINGW32__ + +#include <kpathsea/config.h> +#include <kpathsea/c-pathch.h> +#include <kpathsea/c-proto.h> +#include <kpathsea/mingw32.h> +#include <kpathsea/lib.h> +#include <kpathsea/concatn.h> +#include <kpathsea/variable.h> +#include <kpathsea/c-stat.h> +#include <shlobj.h> +#include <errno.h> + +/* Emulate getpwuid, getpwnam and others. */ + +typedef HWND (WINAPI *pGetDesktopWindow)(void); + +typedef HRESULT (WINAPI * pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL); + +extern int __cdecl _set_osfhnd (int fd, long h); +extern int __cdecl _free_osfhnd (int fd); + +static char *get_home_directory (void); +static int _parse_root (char * name, char ** pPath); + +double +win32_floor (double x) +{ + return floor (x); +} + +void +init_user_info (void) +{ + /* Ensure HOME and SHELL are defined. */ + char *home = get_home_directory(); + if (home) { + putenv(concat("HOME=", home)); + } + else { + putenv ("HOME=c:/"); + } + if (getenv ("SHELL") == NULL) + putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd"); + + { + /* Win2K problem : we need a specific TEMP directory with + full access rights so that any user building a format file + or a font file will build it with full access rights. The installer + takes care of defining TEXMFTEMP=$SELFAUTOPARENT/tmp in the environment. + If it is defined, then use it as the TEMP and TMP variables. + */ + char *p; + if ((p = getenv("TEXMFTEMP")) != NULL) { + putenv(concat("TEMP=", p)); + putenv(concat("TMP=", p)); + } + } +} + +/* Returns the home directory, in external format */ +static char * +get_home_directory (void) +{ + char *found_home_directory = NULL; + + if ((found_home_directory = getenv("HOME")) != NULL) { + char q[MAXPATHLEN]; + /* In case it is %HOMEDRIVE%%HOMEPATH% */ + if (ExpandEnvironmentStrings(found_home_directory, q, sizeof(q)) == 0) { + /* Error */ + found_home_directory = NULL; + } + else { + found_home_directory = xstrdup(q); + goto done; + } + } + + { + char *homedrive, *homepath; + if ((homedrive = getenv("HOMEDRIVE")) != NULL && + (homepath = getenv("HOMEPATH")) != NULL) { + found_home_directory = concat(homedrive, homepath); + goto done; + } + } + + /* This method is the prefered one because even if it requires a more recent shell32.dll, + it does not need to call SHMalloc()->Free() */ + { + /* This will probably give the wrong value */ + char q [MAXPATHLEN]; + HINSTANCE h; + pSHGetSpecialFolderPathA p1; + pGetDesktopWindow p2; + HWND hwnd = NULL; + + if ((h = LoadLibrary("user32.dll"))) { + if ((p2 = (pGetDesktopWindow)GetProcAddress(h, "GetDesktopWindow"))) + hwnd = (*p2)(); + FreeLibrary(h); + } + + if (hwnd && (h = LoadLibrary("shell32.dll"))) { + if ((p1 = (pSHGetSpecialFolderPathA)GetProcAddress(h, "SHGetSpecialFolderPathA"))) + if ((*p1)(hwnd, q, CSIDL_PERSONAL, TRUE)) { + found_home_directory = xstrdup(q); + } + FreeLibrary(h); + } + if (found_home_directory) goto done; + } + + if (1) { + fprintf(stderr, "kpathsea has been unable to determine a good value for the user's $HOME\n" + " directory, and will be using the value:\n" + " %s\n" + " This is probably incorrect.\n", + found_home_directory + ); + } + done: + return found_home_directory; +} + + +/* Consider cached volume information to be stale if older than 10s, + at least for non-local drives. Info for fixed drives is never stale. */ +#define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' ) +#define VOLINFO_STILL_VALID( root_dir, info ) \ + ( ( isalpha (root_dir[0]) ) \ + || GetTickCount () - info->timestamp < 10000 ) + + +/* Normalize filename by converting all path separators to + the specified separator. Also conditionally convert upper + case path name components to lower case. + Returns the index of the first meaningful char in the path + past any drive specifier of unc name specifier. + Remove any multiple path separators after a leading + drive specifier or double path separator. +*/ + +static int +normalize_filename (char *fp, char path_sep) +{ + char *p; + int ret, i; + + /* Always lower-case drive letters a-z, even if the filesystem + preserves case in filenames. + This is so filenames can be compared by string comparison + functions that are case-sensitive. Even case-preserving filesystems + do not distinguish case in drive letters. */ + if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z') { + *fp += 'a' - 'A'; + } + + /* Remove unneeded double slashes */ + ret = (IS_UNC_NAME(fp) ? 2 : + NAME_BEGINS_WITH_DEVICE(fp) ? + (IS_DIR_SEP(*(fp+2)) ? 3 : 2) : IS_DIR_SEP(*fp) ? 1 : 0); + for (i = ret, p = fp+i; + IS_DIR_SEP(*p); + i++, p++); + if (i > ret) { + int len = strlen(fp+i); + /* remove unneeded slashes, for the sake of win95 */ +#if 0 + fprintf(stderr, "moving %s to %s\n", fp+ret, fp+i); +#endif + memmove (fp+ret, fp+i, len+1); + } + + /* conditionnally rewrite to same path_sep, slash preferably */ + if (path_sep) { + for (p = fp; *p; p++) + if (IS_DIR_SEP(*p)) + *p = path_sep; + } + +#if 0 + fprintf(stderr, "normalize_filename returned (%d) %s\n", ret, fp); +#endif + + return ret; +} + + +/* Destructively turn backslashes into slashes. */ +#if 0 /* unused */ +static void +dostounix_filename (char *p) +{ + normalize_filename (p, '/'); +} +#endif + +/* Destructively turn slashes into backslashes. */ +static void +unixtodos_filename (char *p) +{ + normalize_filename (p, '\\'); +} + +/* Remove all CR's that are followed by a LF. + (From msdos.c...probably should figure out a way to share it, + although this code isn't going to ever change.) */ +#if 0 /* unused */ +static int +crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count) +{ + unsigned char *np = buf; + unsigned char *startp = buf; + unsigned char *endp = buf + n; + + if (n == 0) + return n; + while (buf < endp - 1) + { + if (*buf == 0x0a) + (*lf_count)++; + if (*buf == 0x0d) + { + if (*(++buf) != 0x0a) + *np++ = 0x0d; + } + else + *np++ = *buf++; + } + if (buf < endp) + { + if (*buf == 0x0a) + (*lf_count)++; + *np++ = *buf++; + } + return np - startp; +} +#endif + +/* Parse the root part of file name, if present. Return length and + optionally store pointer to char after root. */ +static int +_parse_root (char * name, char ** pPath) +{ + char * start = name; + + if (name == NULL) + return 0; + + /* find the root name of the volume if given */ + if (isalpha (name[0]) && name[1] == ':') + { + /* skip past drive specifier */ + name += 2; + if (IS_DIR_SEP (name[0])) + name++; + } + else if (IS_DIR_SEP (name[0]) && IS_DIR_SEP (name[1])) + { + int slashes = 2; + name += 2; + do + { + if (IS_DIR_SEP (*name) && --slashes == 0) + break; + name++; + } + while ( *name ); + if (IS_DIR_SEP (name[0])) + name++; + } + + if (pPath) + *pPath = name; + + return name - start; +} + +/* Get long base name for name; name is assumed to be absolute. */ +static int +get_long_basename (char * name, char * buf, int size) +{ + WIN32_FIND_DATA find_data; + HANDLE dir_handle; + int len = 0; +#ifdef PIGSFLY + char *p; + + /* If the last component of NAME has a wildcard character, + return it as the basename. */ + p = name + strlen (name); + while (*p != '\\' && *p != ':' && p > name) p--; + if (p > name) p++; + if (strchr (p, '*') || strchr (p, '?')) + { + if ((len = strlen (p)) < size) + memcpy (buf, p, len + 1); + else + len = 0; + return len; + } +#endif + + dir_handle = FindFirstFile (name, &find_data); + if (dir_handle != INVALID_HANDLE_VALUE) + { + if ((len = strlen (find_data.cFileName)) < size) + memcpy (buf, find_data.cFileName, len + 1); + else + len = 0; + FindClose (dir_handle); + } + return len; +} + +/* Get long name for file, if possible (assumed to be absolute). */ +BOOL +win32_get_long_filename (char * name, char * buf, int size) +{ + char * o = buf; + char * p; + char * q; + char full[ MAX_PATH ]; + int len; + + len = strlen (name); + if (len >= MAX_PATH) + return FALSE; + + /* Use local copy for destructive modification. */ + memcpy (full, name, len+1); + unixtodos_filename (full); + + /* Copy root part verbatim. */ + len = _parse_root (full, &p); + memcpy (o, full, len); + o += len; + size -= len; + + do + { + q = p; + p = strchr (q, '\\'); + if (p) *p = '\0'; + len = get_long_basename (full, o, size); + if (len > 0) + { + o += len; + size -= len; + if (p != NULL) + { + *p++ = '\\'; + if (size < 2) + return FALSE; + *o++ = '\\'; + size--; + *o = '\0'; + } + } + else + return FALSE; + } + while (p != NULL && *p); + + return TRUE; +} + +/* special TeXLive Ghostscript */ + +static int is_dir (char *buff) +{ + struct stat stats; + + return stat (buff, &stats) == 0 && S_ISDIR (stats.st_mode); +} + +/* + TeXlive uses its own gs in + $SELFAUTOPARENT/tlpkg/tlgs +*/ +void texlive_gs_init(void) +{ + char *nptr, *path; + char tlgsbindir[512]; + char tlgslibdir[512]; + char resourcedir[512]; + nptr = kpse_var_value("TEXLIVE_WINDOWS_EXTERNAL_GS"); + if (nptr == NULL || *nptr == '0' || *nptr == 'n' || *nptr == 'f') { + if (nptr) + free (nptr); + nptr = kpse_var_value("SELFAUTOPARENT"); + if (nptr) { + strcpy(tlgsbindir, nptr); + strcat(tlgsbindir,"/tlpkg/tlgs"); + strcpy(resourcedir, tlgsbindir); + strcat(resourcedir, "/Resource"); + if(is_dir(tlgsbindir)) { + strcpy(tlgslibdir, tlgsbindir); + strcat(tlgslibdir, "/lib;"); + if(is_dir(resourcedir)) { + strcat(tlgslibdir, tlgsbindir); + strcat(tlgslibdir, "/fonts;"); + strcat(tlgslibdir, tlgsbindir); + strcat(tlgslibdir, "/Resource/Init;"); + strcat(tlgslibdir, tlgsbindir); + strcat(tlgslibdir, "/Resource;"); + strcat(tlgslibdir, tlgsbindir); + strcat(tlgslibdir, "/kanji"); + } else { + strcat(tlgslibdir, tlgsbindir); + strcat(tlgslibdir, "/fonts"); + } + strcat(tlgsbindir, "/bin;"); + free(nptr); + for(nptr = tlgsbindir; *nptr; nptr++) { + if(*nptr == '/') *nptr = '\\'; + } + nptr = getenv("PATH"); + path = (char *)malloc(strlen(nptr) + strlen(tlgsbindir) + 6); + strcpy(path, tlgsbindir); + strcat(path, nptr); + xputenv("PATH", path); + xputenv("GS_LIB", tlgslibdir); + } + } + } else { + free (nptr); + } +} + +#endif /* __MINGW32__ */ |