6 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7 * Copyright (C) 2009, 2012, MinGW Project
10 * Implementation of helper function to identify the root directory
11 * of the mingw-get installation tree, and to map sub-directory path
12 * names relative to this tree.
15 * This is free software. Permission is granted to copy, modify and
16 * redistribute this software, under the provisions of the GNU General
17 * Public License, Version 3, (or, at your option, any later version),
18 * as published by the Free Software Foundation; see the file COPYING
19 * for licensing details.
21 * Note, in particular, that this software is provided "as is", in the
22 * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
23 * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
24 * PARTICULAR PURPOSE. Under no circumstances will the author, or the
25 * MinGW Project, accept liability for any damages, however caused,
26 * arising from the use of this software.
29 #define WIN32_LEAN_AND_MEAN
37 #define wcscasecmp _wcsicmp
39 wchar_t *AppPathNameW( const wchar_t *relpath )
41 /* UTF-16LE implementation; NOT thread safe...
43 * Map "relpath" into the file system hierarchy with logical root
44 * at the prefix where the application suite is installed, such that
45 * it becomes "d:\prefix\relpath".
47 * If the application's executables are installed in a directory called
48 * "bin" or "sbin", then this final directory is excluded from the mapped
49 * prefix, (i.e. a program installed as "d:\prefix\bin\prog.exe" returns
50 * the mapped path as "d:\prefix\relpath", rather than as the inclusive
51 * path "d:\prefix\bin\relpath"). Additionally, if the absolute path to
52 * the program executable includes a directory called "libexec", at any
53 * level within the path, then the absolute path to the parent of this is
54 * taken as the effective prefix. In any other case, the prefix is taken
55 * as the path to the directory in which the program file is installed,
56 * (i.e. a program installed as "d:\prefix\foo\prog.exe" returns the
57 * mapped path as "d:\prefix\foo\relpath".
59 * Note that, in all cases, the returned path name is normalised, such
60 * that only "\" is used as the directory name separator; this ensures
61 * that it may be safely passed to functions such as LoadLibrary(),
62 * which are known to reject "/" as the separator.
65 * Mapped path is returned in this static buffer...
67 static wchar_t retpath[PATH_MAX], *tail = NULL;
71 /* First time initialisation...
73 * Fill in the static local buffer, with the appropriate "prefix"
74 * string, marking the point at which "relpath" is to be appended.
76 * On subsequent calls, we reuse this static buffer, leaving the
77 * "prefix" element unchanged, but simply overwriting the "relpath"
78 * element from any prior call; this is NOT thread safe!
80 wchar_t bindir[] = L"bin", *bindir_p = bindir;
81 wchar_t *mark, *scan = mark = tail = retpath;
83 /* Ascertain the installation path of the calling executable.
85 int chk = GetModuleFileNameW( NULL, retpath, PATH_MAX );
87 /* Validate it; reject any result which doesn't fit in "retpath".
89 if( (chk == 0) || ((chk == PATH_MAX) && (retpath[--chk] != L'\0')) )
92 /* Parse it, to locate the end of the effective "prefix" string...
94 do { if( (*scan == L'/') || (*scan == L'\\') )
96 /* We found the start of a new path name component directory,
97 * (or maybe the file name, at the end); mark it as a possible
98 * final element of the path name, leaving "tail" pointing to
99 * the previously marked element.
105 /* The final name element is not empty; temporarily mark
106 * it as "end-of-string", the check if it represents the
107 * "libexec" directory name...
110 if( wcscasecmp( tail, L"\\libexec" ) == 0 )
112 /* ...and when it does, we back up to mark its parent
113 * directory as the last in the "prefix" path name...
119 /* ...otherwise we append a directory separator, before
120 * cycling around to append the next entity name from the
121 * module path name string.
126 } while( (*++scan) != L'\0' );
128 if( *(scan = tail) == L'\\' )
130 /* When we get to here, "mark" should point to the last directory
131 * separator, immediately preceeding the executable file name, while
132 * "tail" should point to the directory separator preceeding the last
133 * sub-directory name in the path; we now check, without regard to
134 * case, if this final sub-directory name is "bin" or "sbin"...
137 if( towlower( *++scan ) == L's' )
139 * Might be "sbin"; skip the initial "s", and check for "bin"...
143 if( wcscasecmp( scan, L"bin" ) == 0 )
145 * The final sub-directory is either "bin" or "sbin"; prune it...
150 /* ...but when it doesn't match either of these, just adjust the
151 * "tail" pointer, so we leave the final sub-directory name as
152 * part of the "prefix".
158 if( relpath == NULL )
160 * No "relpath" argument given; simply truncate, to return only
161 * the effective "prefix" string...
166 { /* We have a "relpath" argument to append; first ensure that the
167 * prefix ends with a directory name separator...
169 wchar_t *append = tail;
170 if( (*relpath != L'/') && (*relpath != L'\\') )
173 do { /* ...then append the specified path to the application's root,
174 * again, taking care to use "\" as the separator character...
176 *append++ = (*relpath == L'/') ? L'\\' : *relpath;
177 } while( *relpath++ && ((append - retpath) < PATH_MAX) );
179 if( *--append != L'\0' )
181 * Abort, if we didn't properly terminate the return string.
188 /* $RCSfile$: end of file */