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
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>
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
);
52 win32_floor (double x
)
60 /* Ensure HOME and SHELL are defined. */
61 char *home
= get_home_directory();
63 putenv(concat("HOME=", home
));
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.
79 if ((p
= getenv("TEXMFTEMP")) != NULL
) {
80 putenv(concat("TEMP=", p
));
81 putenv(concat("TMP=", p
));
86 /* Returns the home directory, in external format */
88 get_home_directory (void)
90 char *found_home_directory
= NULL
;
92 if ((found_home_directory
= getenv("HOME")) != NULL
) {
94 /* In case it is %HOMEDRIVE%%HOMEPATH% */
95 if (ExpandEnvironmentStrings(found_home_directory
, q
, sizeof(q
)) == 0) {
97 found_home_directory
= NULL
;
100 found_home_directory
= xstrdup(q
);
106 char *homedrive
, *homepath
;
107 if ((homedrive
= getenv("HOMEDRIVE")) != NULL
&&
108 (homepath
= getenv("HOMEPATH")) != NULL
) {
109 found_home_directory
= concat(homedrive
, homepath
);
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 */
120 pSHGetSpecialFolderPathA p1
;
121 pGetDesktopWindow p2
;
124 if ((h
= LoadLibrary("user32.dll"))) {
125 if ((p2
= (pGetDesktopWindow
)GetProcAddress(h
, "GetDesktopWindow")))
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
);
137 if (found_home_directory
) goto done
;
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"
144 " This is probably incorrect.\n",
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.
171 normalize_filename (char *fp
, char path_sep
)
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') {
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
;
193 int len
= strlen(fp
+i
);
194 /* remove unneeded slashes, for the sake of win95 */
196 fprintf(stderr
, "moving %s to %s\n", fp
+ret
, fp
+i
);
198 memmove (fp
+ret
, fp
+i
, len
+1);
201 /* conditionnally rewrite to same path_sep, slash preferably */
203 for (p
= fp
; *p
; p
++)
209 fprintf(stderr
, "normalize_filename returned (%d) %s\n", ret
, fp
);
216 /* Destructively turn backslashes into slashes. */
219 dostounix_filename (char *p
)
221 normalize_filename (p
, '/');
225 /* Destructively turn slashes into backslashes. */
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.) */
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
;
245 while (buf
< endp
- 1)
251 if (*(++buf
) != 0x0a)
267 /* Parse the root part of file name, if present. Return length and
268 optionally store pointer to char after root. */
270 _parse_root (char * name
, char ** pPath
)
277 /* find the root name of the volume if given */
278 if (isalpha (name
[0]) && name
[1] == ':')
280 /* skip past drive specifier */
282 if (IS_DIR_SEP (name
[0]))
285 else if (IS_DIR_SEP (name
[0]) && IS_DIR_SEP (name
[1]))
291 if (IS_DIR_SEP (*name
) && --slashes
== 0)
296 if (IS_DIR_SEP (name
[0]))
306 /* Get long base name for name; name is assumed to be absolute. */
308 get_long_basename (char * name
, char * buf
, int size
)
310 WIN32_FIND_DATA find_data
;
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
--;
321 if (strchr (p
, '*') || strchr (p
, '?'))
323 if ((len
= strlen (p
)) < size
)
324 memcpy (buf
, p
, len
+ 1);
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);
338 FindClose (dir_handle
);
343 /* Get long name for file, if possible (assumed to be absolute). */
345 win32_get_long_filename (char * name
, char * buf
, int size
)
350 char full
[ MAX_PATH
];
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
);
370 p
= strchr (q
, '\\');
372 len
= get_long_basename (full
, o
, size
);
390 while (p
!= NULL
&& *p
);
395 /* special TeXLive Ghostscript */
397 static int is_dir (char *buff
)
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)
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")) {
417 nptr
= kpse_var_value("SELFAUTOPARENT");
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;");
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
);
435 xputenv("PATH", path
);
436 xputenv("GS_LIB", tlgslibdir
);
444 #endif /* __MINGW32__ */