beta-0.89.2
[luatex.git] / source / texk / kpathsea / mingw32.c
blob32c23e75d704053b82ba624a1a41f63b97a6ce1c
1 /* mingw32.c: bits and pieces for mingw32
3 Copyright 2009-2013 Taco Hoekwater <taco@luatex.org>.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library 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 GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this library; if not, see <http://www.gnu.org/licenses/>.
19 /* Original sources lifted from the distribution of XEmacs for Windows NT,
20 Copyright 1994-1996 Free Software Foundation, later adapted to
21 fpTeX 0.4 (2000) by Fabrice Popineau <Fabrice.Popineau@supelec.fr>,
22 then simplified and re-adapted to TeXLive (2009) by Taco Hoekwater
23 <taco@luatex.org>.
26 #ifdef __MINGW32__
28 #include <kpathsea/config.h>
29 #include <kpathsea/c-pathch.h>
30 #include <kpathsea/c-proto.h>
31 #include <kpathsea/mingw32.h>
32 #include <kpathsea/lib.h>
33 #include <kpathsea/concatn.h>
34 #include <kpathsea/variable.h>
35 #include <kpathsea/c-stat.h>
36 #include <shlobj.h>
37 #include <errno.h>
39 /* Emulate getpwuid, getpwnam and others. */
41 typedef HWND (WINAPI *pGetDesktopWindow)(void);
43 typedef HRESULT (WINAPI * pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
45 extern int __cdecl _set_osfhnd (int fd, long h);
46 extern int __cdecl _free_osfhnd (int fd);
48 static char *get_home_directory (void);
49 static int _parse_root (char * name, char ** pPath);
51 double
52 win32_floor (double x)
54 return floor (x);
57 void
58 init_user_info (void)
60 /* Ensure HOME and SHELL are defined. */
61 char *home = get_home_directory();
62 if (home) {
63 putenv(concat("HOME=", home));
65 else {
66 putenv ("HOME=c:/");
68 if (getenv ("SHELL") == NULL)
69 putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
72 /* Win2K problem : we need a specific TEMP directory with
73 full access rights so that any user building a format file
74 or a font file will build it with full access rights. The installer
75 takes care of defining TEXMFTEMP=$SELFAUTOPARENT/tmp in the environment.
76 If it is defined, then use it as the TEMP and TMP variables.
78 char *p;
79 if ((p = getenv("TEXMFTEMP")) != NULL) {
80 putenv(concat("TEMP=", p));
81 putenv(concat("TMP=", p));
86 /* Returns the home directory, in external format */
87 static char *
88 get_home_directory (void)
90 char *found_home_directory = NULL;
92 if ((found_home_directory = getenv("HOME")) != NULL) {
93 char q[MAXPATHLEN];
94 /* In case it is %HOMEDRIVE%%HOMEPATH% */
95 if (ExpandEnvironmentStrings(found_home_directory, q, sizeof(q)) == 0) {
96 /* Error */
97 found_home_directory = NULL;
99 else {
100 found_home_directory = xstrdup(q);
101 goto done;
106 char *homedrive, *homepath;
107 if ((homedrive = getenv("HOMEDRIVE")) != NULL &&
108 (homepath = getenv("HOMEPATH")) != NULL) {
109 found_home_directory = concat(homedrive, homepath);
110 goto done;
114 /* This method is the prefered one because even if it requires a more recent shell32.dll,
115 it does not need to call SHMalloc()->Free() */
117 /* This will probably give the wrong value */
118 char q [MAXPATHLEN];
119 HINSTANCE h;
120 pSHGetSpecialFolderPathA p1;
121 pGetDesktopWindow p2;
122 HWND hwnd = NULL;
124 if ((h = LoadLibrary("user32.dll"))) {
125 if ((p2 = (pGetDesktopWindow)GetProcAddress(h, "GetDesktopWindow")))
126 hwnd = (*p2)();
127 FreeLibrary(h);
130 if (hwnd && (h = LoadLibrary("shell32.dll"))) {
131 if ((p1 = (pSHGetSpecialFolderPathA)GetProcAddress(h, "SHGetSpecialFolderPathA")))
132 if ((*p1)(hwnd, q, CSIDL_PERSONAL, TRUE)) {
133 found_home_directory = xstrdup(q);
135 FreeLibrary(h);
137 if (found_home_directory) goto done;
140 if (1) {
141 fprintf(stderr, "kpathsea has been unable to determine a good value for the user's $HOME\n"
142 " directory, and will be using the value:\n"
143 " %s\n"
144 " This is probably incorrect.\n",
145 found_home_directory
148 done:
149 return found_home_directory;
153 /* Consider cached volume information to be stale if older than 10s,
154 at least for non-local drives. Info for fixed drives is never stale. */
155 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
156 #define VOLINFO_STILL_VALID( root_dir, info ) \
157 ( ( isalpha (root_dir[0]) ) \
158 || GetTickCount () - info->timestamp < 10000 )
161 /* Normalize filename by converting all path separators to
162 the specified separator. Also conditionally convert upper
163 case path name components to lower case.
164 Returns the index of the first meaningful char in the path
165 past any drive specifier of unc name specifier.
166 Remove any multiple path separators after a leading
167 drive specifier or double path separator.
170 static int
171 normalize_filename (char *fp, char path_sep)
173 char *p;
174 int ret, i;
176 /* Always lower-case drive letters a-z, even if the filesystem
177 preserves case in filenames.
178 This is so filenames can be compared by string comparison
179 functions that are case-sensitive. Even case-preserving filesystems
180 do not distinguish case in drive letters. */
181 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z') {
182 *fp += 'a' - 'A';
185 /* Remove unneeded double slashes */
186 ret = (IS_UNC_NAME(fp) ? 2 :
187 NAME_BEGINS_WITH_DEVICE(fp) ?
188 (IS_DIR_SEP(*(fp+2)) ? 3 : 2) : IS_DIR_SEP(*fp) ? 1 : 0);
189 for (i = ret, p = fp+i;
190 IS_DIR_SEP(*p);
191 i++, p++);
192 if (i > ret) {
193 int len = strlen(fp+i);
194 /* remove unneeded slashes, for the sake of win95 */
195 #if 0
196 fprintf(stderr, "moving %s to %s\n", fp+ret, fp+i);
197 #endif
198 memmove (fp+ret, fp+i, len+1);
201 /* conditionnally rewrite to same path_sep, slash preferably */
202 if (path_sep) {
203 for (p = fp; *p; p++)
204 if (IS_DIR_SEP(*p))
205 *p = path_sep;
208 #if 0
209 fprintf(stderr, "normalize_filename returned (%d) %s\n", ret, fp);
210 #endif
212 return ret;
216 /* Destructively turn backslashes into slashes. */
217 #if 0 /* unused */
218 static void
219 dostounix_filename (char *p)
221 normalize_filename (p, '/');
223 #endif
225 /* Destructively turn slashes into backslashes. */
226 static void
227 unixtodos_filename (char *p)
229 normalize_filename (p, '\\');
232 /* Remove all CR's that are followed by a LF.
233 (From msdos.c...probably should figure out a way to share it,
234 although this code isn't going to ever change.) */
235 #if 0 /* unused */
236 static int
237 crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count)
239 unsigned char *np = buf;
240 unsigned char *startp = buf;
241 unsigned char *endp = buf + n;
243 if (n == 0)
244 return n;
245 while (buf < endp - 1)
247 if (*buf == 0x0a)
248 (*lf_count)++;
249 if (*buf == 0x0d)
251 if (*(++buf) != 0x0a)
252 *np++ = 0x0d;
254 else
255 *np++ = *buf++;
257 if (buf < endp)
259 if (*buf == 0x0a)
260 (*lf_count)++;
261 *np++ = *buf++;
263 return np - startp;
265 #endif
267 /* Parse the root part of file name, if present. Return length and
268 optionally store pointer to char after root. */
269 static int
270 _parse_root (char * name, char ** pPath)
272 char * start = name;
274 if (name == NULL)
275 return 0;
277 /* find the root name of the volume if given */
278 if (isalpha (name[0]) && name[1] == ':')
280 /* skip past drive specifier */
281 name += 2;
282 if (IS_DIR_SEP (name[0]))
283 name++;
285 else if (IS_DIR_SEP (name[0]) && IS_DIR_SEP (name[1]))
287 int slashes = 2;
288 name += 2;
291 if (IS_DIR_SEP (*name) && --slashes == 0)
292 break;
293 name++;
295 while ( *name );
296 if (IS_DIR_SEP (name[0]))
297 name++;
300 if (pPath)
301 *pPath = name;
303 return name - start;
306 /* Get long base name for name; name is assumed to be absolute. */
307 static int
308 get_long_basename (char * name, char * buf, int size)
310 WIN32_FIND_DATA find_data;
311 HANDLE dir_handle;
312 int len = 0;
313 #ifdef PIGSFLY
314 char *p;
316 /* If the last component of NAME has a wildcard character,
317 return it as the basename. */
318 p = name + strlen (name);
319 while (*p != '\\' && *p != ':' && p > name) p--;
320 if (p > name) p++;
321 if (strchr (p, '*') || strchr (p, '?'))
323 if ((len = strlen (p)) < size)
324 memcpy (buf, p, len + 1);
325 else
326 len = 0;
327 return len;
329 #endif
331 dir_handle = FindFirstFile (name, &find_data);
332 if (dir_handle != INVALID_HANDLE_VALUE)
334 if ((len = strlen (find_data.cFileName)) < size)
335 memcpy (buf, find_data.cFileName, len + 1);
336 else
337 len = 0;
338 FindClose (dir_handle);
340 return len;
343 /* Get long name for file, if possible (assumed to be absolute). */
344 BOOL
345 win32_get_long_filename (char * name, char * buf, int size)
347 char * o = buf;
348 char * p;
349 char * q;
350 char full[ MAX_PATH ];
351 int len;
353 len = strlen (name);
354 if (len >= MAX_PATH)
355 return FALSE;
357 /* Use local copy for destructive modification. */
358 memcpy (full, name, len+1);
359 unixtodos_filename (full);
361 /* Copy root part verbatim. */
362 len = _parse_root (full, &p);
363 memcpy (o, full, len);
364 o += len;
365 size -= len;
369 q = p;
370 p = strchr (q, '\\');
371 if (p) *p = '\0';
372 len = get_long_basename (full, o, size);
373 if (len > 0)
375 o += len;
376 size -= len;
377 if (p != NULL)
379 *p++ = '\\';
380 if (size < 2)
381 return FALSE;
382 *o++ = '\\';
383 size--;
384 *o = '\0';
387 else
388 return FALSE;
390 while (p != NULL && *p);
392 return TRUE;
395 /* special TeXLive Ghostscript */
397 static int is_dir (char *buff)
399 struct stat stats;
401 return stat (buff, &stats) == 0 && S_ISDIR (stats.st_mode);
405 TeXlive uses its own gs in
406 $SELFAUTOPARENT/tlpkg/tlgs
408 void texlive_gs_init(void)
410 char *nptr, *path;
411 char tlgsbindir[512];
412 char tlgslibdir[512];
413 nptr = kpse_var_value("TEXLIVE_WINDOWS_EXTERNAL_GS");
414 if (nptr == NULL || !strcmp(nptr, "0") || !strcmp(nptr, "n") || !strcmp(nptr, "f")) {
415 if (nptr)
416 free (nptr);
417 nptr = kpse_var_value("SELFAUTOPARENT");
418 if (nptr) {
419 strcpy(tlgsbindir, nptr);
420 strcat(tlgsbindir,"/tlpkg/tlgs");
421 if(is_dir(tlgsbindir)) {
422 strcpy(tlgslibdir, tlgsbindir);
423 strcat(tlgslibdir, "/lib;");
424 strcat(tlgslibdir, tlgsbindir);
425 strcat(tlgslibdir, "/fonts");
426 strcat(tlgsbindir, "/bin;");
427 free(nptr);
428 for(nptr = tlgsbindir; *nptr; nptr++) {
429 if(*nptr == '/') *nptr = '\\';
431 nptr = getenv("PATH");
432 path = (char *)malloc(strlen(nptr) + strlen(tlgsbindir) + 6);
433 strcpy(path, tlgsbindir);
434 strcat(path, nptr);
435 xputenv("PATH", path);
436 xputenv("GS_LIB", tlgslibdir);
439 } else {
440 free (nptr);
444 #endif /* __MINGW32__ */