6 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7 * Copyright (C) 2009, 2010, MinGW Project
10 * Initiation stub for command line invocation of mingw-get
13 * This is free software. Permission is granted to copy, modify and
14 * redistribute this software, under the provisions of the GNU General
15 * Public License, Version 3, (or, at your option, any later version),
16 * as published by the Free Software Foundation; see the file COPYING
17 * for licensing details.
19 * Note, in particular, that this software is provided "as is", in the
20 * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
21 * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
22 * PARTICULAR PURPOSE. Under no circumstances will the author, or the
23 * MinGW Project, accept liability for any damages, however caused,
24 * arising from the use of this software.
27 #define _WIN32_WINNT 0x500
28 #define WIN32_LEAN_AND_MEAN
30 #define MINGW_GET_DLL L"libexec/mingw-get/mingw-get-0.dll"
31 #define MINGW_GET_GUI L"libexec/mingw-get/gui.exe"
40 #define EXIT_FATAL EXIT_FAILURE + 1
42 wchar_t *AppPathNameW( const wchar_t *relpath )
44 /* UTF-16LE implementation; NOT thread safe...
46 * Map "relpath" into the file system hierarchy with logical root
47 * at the prefix where the application suite is installed, such that
48 * it becomes "d:\prefix\relpath".
50 * If the application's executables are installed in a directory called
51 * "bin" or "sbin", then this final directory is excluded from the mapped
52 * prefix, (i.e. a program installed as "d:\prefix\bin\prog.exe" returns
53 * the mapped path as "d:\prefix\relpath", rather than as the inclusive
54 * path "d:\prefix\bin\relpath"); 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 * Mapped path is returned in this static buffer...
61 static wchar_t retpath[MAX_PATH], *tail = NULL;
65 /* First time initialisation...
67 * Fill in the static local buffer, with the appropriate "prefix"
68 * string, marking the point at which "relpath" is to be appended.
70 * On subsequent calls, we reuse this static buffer, leaving the
71 * "prefix" element unchanged, but simply overwriting the "relpath"
72 * element from any prior call; this is NOT thread safe!
75 wchar_t bindir[] = L"bin", *bindir_p = bindir;
76 wchar_t *mark, *scan = mark = tail = retpath;
78 /* Ascertain the installation path of the calling executable.
80 int chk = GetModuleFileNameW( NULL, retpath, MAX_PATH );
82 /* Validate it; reject any result which doesn't fit in "retpath".
84 if( (chk == 0) || ((chk == MAX_PATH) && (retpath[--chk] != L'\0')) )
87 /* Parse it, to locate the end of the effective "prefix" string...
89 do { if( *scan == L'/' )
91 * This is a sanity check; it should not be necessary, but...
93 * Enforce use of "\" rather than "/" as path component separator;
94 * ( "LoadLibrary" may be broken, since it seems to care! )
98 if( *scan && (prev == L'\\') )
100 /* We found the start a new path name component directory,
101 * (or maybe the file name, at the end); mark it as a possible
102 * final element of the path name, leaving "tail" pointing to
103 * the previously marked element.
108 } while( (prev = *scan++) != L'\0' );
110 /* When we get to here, "mark" should point to the executable file name,
111 * at the end of the path name string, while "tail" should point to the
112 * last directory in the installation path; we now check, without regard
113 * to case, if this final directory name is "bin" or "sbin"...
115 if( (*(scan = tail) == L's') || (*scan == L'S') )
117 * Might be "sbin"; skip the initial "s", and check for "bin"...
121 while( *bindir_p && ((*scan++ | L'\x20') == *bindir_p++) )
123 * ...could still match "bin"...
125 if( *bindir_p || (*scan != L'\\') )
127 * No, it didn't match; adjust "tail", so we leave the final
128 * directory name as part of "prefix".
133 if( relpath == NULL )
135 * No "relpath" argument given; simply truncate, to return only
136 * the effective "prefix" string...
141 { wchar_t *append = tail;
143 * Append the specified path to the application's root,
144 * again, taking care to use "\" as the separator character...
146 *append++ = (*relpath == L'/') ? L'\\' : *relpath;
147 } while( *relpath++ && ((append - retpath) < MAX_PATH) );
149 if( *--append != L'\0' )
151 * Abort, if we didn't properly terminate the return string.
158 extern const char *version_identification;
160 int main( int argc, char **argv )
162 wchar_t *approot; /* where this application is installed */
166 /* The user specified arguments on the command line...
167 * Interpret any which specify processing options for this application,
168 * (these are all specified in GNU `long only' style).
170 struct option options[] =
172 /* Option Name Argument Category Store To Return Value
173 * ---------------------- ------------------ -------- ------------
175 { "version", no_argument, NULL, 'V' },
177 /* This list must be terminated by a null definition...
183 while( (opt = getopt_long_only( argc, argv, "V", options, &offset )) != -1 )
187 /* This is a request to display the version of the application;
188 * emit the requisite informational message, and quit.
190 printf( version_identification );
194 /* User specified an invalid or unsupported option...
197 fprintf( stderr, "%s: option '-%s' not yet supported\n",
198 basename( *argv ), options[offset].name
204 /* Establish the installation path for the mingw-get application...
206 if( (approot = AppPathNameW( NULL )) != NULL )
208 /* ...and set up the APPROOT environment variable to refer to
209 * the associated installation prefix...
211 char approot_setup[1 + snprintf( NULL, 0, "APPROOT=%S", approot )];
212 snprintf( approot_setup, sizeof( approot_setup ), "APPROOT=%S", approot );
213 putenv( approot_setup );
218 /* The user specified arguments on the command line...
219 * we load the supporting DLL into the current process context,
220 * then, remaining in command line mode, we jump to its main
221 * command line processing routine...
223 typedef int (*dll_entry)( int, char ** );
224 HMODULE my_dll = LoadLibraryW( AppPathNameW( MINGW_GET_DLL ) );
225 dll_entry climain = (dll_entry)(GetProcAddress( my_dll, "climain" ));
226 if( climain == NULL )
228 /* ...bailing out, on failure to load the DLL.
230 fprintf( stderr, "%s: %S: shared library load failed\n",
231 basename( *argv ), MINGW_GET_DLL
235 return climain( argc, argv );
239 { /* No arguments were specified on the command line...
240 * we interpret this as a request to start up in GUI mode...
242 wchar_t *libexec_path = AppPathNameW( MINGW_GET_GUI );
243 char gui_program[1 + snprintf( NULL, 0, "%S", libexec_path )];
244 snprintf( gui_program, sizeof( gui_program ), "%S", libexec_path );
245 int status = execv( gui_program, (const char* const*)(argv) );
247 /* If we get to here, then the GUI could not be started...
248 * Issue a diagnostic message, before abnormal termination.
250 fprintf( stderr, "%s: %S: unable to start application; status = %d\n",
251 basename( *argv ), MINGW_GET_GUI, status
257 /* $RCSfile$: end of file */