Bumping manifests a=b2g-bump
[gecko.git] / python / which / launcher.cpp
blobae1d30708b2ef8183f5a1de3d6eb8d10a8bbf781
1 /*
2 * Copyright (c) 2002-2003 ActiveState Corp.
3 * Author: Trent Mick (TrentM@ActiveState.com)
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 /* Console launch executable.
27 * This program exists solely to launch:
28 * python <installdir>/<exename>.py <argv>
29 * on Windows. "<exename>.py" must be in the same directory.
31 * Rationale:
32 * - On some Windows flavours .py *can* be put on the PATHEXT to be
33 * able to find "<exename>.py" if it is on the PATH. This is fine
34 * until you need shell redirection to work. It does NOT for
35 * extensions to PATHEXT. Redirection *does* work for "python
36 * <script>.py" so we will try to do that.
39 #ifdef WIN32
40 #include <windows.h>
41 #include <process.h>
42 #include <direct.h>
43 #include <shlwapi.h>
44 #else /* linux */
45 #include <unistd.h>
46 #endif /* WIN32 */
47 #include <sys/stat.h>
48 #include <errno.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <stdarg.h>
54 //---- constants
56 #define BUF_LENGTH 2048
57 #define MAX_PYTHON_ARGS 50
58 #define MAX_FILES 50
59 #define MAXPATHLEN 1024
60 #ifdef WIN32
61 #define SEP '\\'
62 #define ALTSEP '/'
63 // path list element separator
64 #define DELIM ';'
65 #else /* linux */
66 #define SEP '/'
67 // path list element separator
68 #define DELIM ':'
69 #endif
71 #ifdef WIN32
72 #define spawnvp _spawnvp
73 #define snprintf _snprintf
74 #define vsnprintf _vsnprintf
75 //NOTE: this is for the stat *call* and the stat *struct*
76 #define stat _stat
77 #endif
80 //---- globals
82 char* programName = NULL;
83 char* programPath = NULL;
84 #ifndef WIN32 /* i.e. linux */
85 extern char **environ; // the user environment
86 #endif /* linux */
88 //---- error logging functions
90 void _LogError(const char* format ...)
92 va_list ap;
93 va_start(ap, format);
94 #if defined(WIN32) && defined(_WINDOWS)
95 // put up a MessageBox
96 char caption[BUF_LENGTH+1];
97 snprintf(caption, BUF_LENGTH, "Error in %s", programName);
98 char msg[BUF_LENGTH+1];
99 vsnprintf(msg, BUF_LENGTH, format, ap);
100 va_end(ap);
101 MessageBox(NULL, msg, caption, MB_OK | MB_ICONEXCLAMATION);
102 #else
103 fprintf(stderr, "%s: error: ", programName);
104 vfprintf(stderr, format, ap);
105 va_end(ap);
106 #endif /* WIN32 && _WINDOWS */
110 void _LogWarning(const char* format ...)
112 va_list ap;
113 va_start(ap, format);
114 #if defined(WIN32) && defined(_WINDOWS)
115 // put up a MessageBox
116 char caption[BUF_LENGTH+1];
117 snprintf(caption, BUF_LENGTH, "Warning in %s", programName);
118 char msg[BUF_LENGTH+1];
119 vsnprintf(msg, BUF_LENGTH, format, ap);
120 va_end(ap);
121 MessageBox(NULL, msg, caption, MB_OK | MB_ICONWARNING);
122 #else
123 fprintf(stderr, "%s: warning: ", programName);
124 vfprintf(stderr, format, ap);
125 va_end(ap);
126 #endif /* WIN32 && _WINDOWS */
131 //---- utilities functions
133 /* _IsDir: Is the given dirname an existing directory */
134 static int _IsDir(char *dirname)
136 #ifdef WIN32
137 DWORD dwAttrib;
138 dwAttrib = GetFileAttributes(dirname);
139 if (dwAttrib == -1) {
140 return 0;
142 if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
143 return 1;
145 return 0;
146 #else /* i.e. linux */
147 struct stat buf;
148 if (stat(dirname, &buf) != 0)
149 return 0;
150 if (!S_ISDIR(buf.st_mode))
151 return 0;
152 return 1;
153 #endif
157 /* _IsLink: Is the given filename a symbolic link */
158 static int _IsLink(char *filename)
160 #ifdef WIN32
161 return 0;
162 #else /* i.e. linux */
163 struct stat buf;
164 if (lstat(filename, &buf) != 0)
165 return 0;
166 if (!S_ISLNK(buf.st_mode))
167 return 0;
168 return 1;
169 #endif
173 /* Is executable file
174 * On Linux: check 'x' permission. On Windows: just check existence.
176 static int _IsExecutableFile(char *filename)
178 #ifdef WIN32
179 return (int)PathFileExists(filename);
180 #else /* i.e. linux */
181 struct stat buf;
182 if (stat(filename, &buf) != 0)
183 return 0;
184 if (!S_ISREG(buf.st_mode))
185 return 0;
186 if ((buf.st_mode & 0111) == 0)
187 return 0;
188 return 1;
189 #endif /* WIN32 */
193 /* _GetProgramPath: Determine the absolute path to the given program name.
195 * Takes into account the current working directory, etc.
196 * The implementations require the global 'programName' to be set.
198 #ifdef WIN32
199 static char* _GetProgramPath(void)
201 //XXX this is ugly but I didn't want to use malloc, no reason
202 static char progPath[MAXPATHLEN+1];
203 // get absolute path to module
204 if (!GetModuleFileName(NULL, progPath, MAXPATHLEN)) {
205 _LogError("could not get absolute program name from "\
206 "GetModuleFileName\n");
207 exit(1);
209 // just need dirname
210 for (char* p = progPath+strlen(progPath);
211 *p != SEP && *p != ALTSEP;
212 --p)
214 *p = '\0';
216 *p = '\0'; // remove the trailing SEP as well
218 return progPath;
220 #else
222 /* _JoinPath requires that any buffer argument passed to it has at
223 least MAXPATHLEN + 1 bytes allocated. If this requirement is met,
224 it guarantees that it will never overflow the buffer. If stuff
225 is too long, buffer will contain a truncated copy of stuff.
227 static void
228 _JoinPath(char *buffer, char *stuff)
230 size_t n, k;
231 if (stuff[0] == SEP)
232 n = 0;
233 else {
234 n = strlen(buffer);
235 if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN)
236 buffer[n++] = SEP;
238 k = strlen(stuff);
239 if (n + k > MAXPATHLEN)
240 k = MAXPATHLEN - n;
241 strncpy(buffer+n, stuff, k);
242 buffer[n+k] = '\0';
246 static char*
247 _GetProgramPath(void)
249 /* XXX this routine does *no* error checking */
250 char* path = getenv("PATH");
251 static char progPath[MAXPATHLEN+1];
253 /* If there is no slash in the argv0 path, then we have to
254 * assume the program is on the user's $PATH, since there's no
255 * other way to find a directory to start the search from. If
256 * $PATH isn't exported, you lose.
258 if (strchr(programName, SEP)) {
259 strncpy(progPath, programName, MAXPATHLEN);
261 else if (path) {
262 int bufspace = MAXPATHLEN;
263 while (1) {
264 char *delim = strchr(path, DELIM);
266 if (delim) {
267 size_t len = delim - path;
268 if (len > bufspace) {
269 len = bufspace;
271 strncpy(progPath, path, len);
272 *(progPath + len) = '\0';
273 bufspace -= len;
275 else {
276 strncpy(progPath, path, bufspace);
279 _JoinPath(progPath, programName);
280 if (_IsExecutableFile(progPath)) {
281 break;
284 if (!delim) {
285 progPath[0] = '\0';
286 break;
288 path = delim + 1;
291 else {
292 progPath[0] = '\0';
295 // now we have to resolve a string of possible symlinks
296 // - we'll just handle the simple case of a single level of
297 // indirection
299 // XXX note this does not handle multiple levels of symlinks
300 // here is pseudo-code for that (please implement it :):
301 // while 1:
302 // if islink(progPath):
303 // linkText = readlink(progPath)
304 // if isabsolute(linkText):
305 // progPath = os.path.join(dirname(progPath), linkText)
306 // else:
307 // progPath = linkText
308 // else:
309 // break
310 if (_IsLink(progPath)) {
311 char newProgPath[MAXPATHLEN+1];
312 readlink(progPath, newProgPath, MAXPATHLEN);
313 strncpy(progPath, newProgPath, MAXPATHLEN);
317 // prefix with the current working directory if the path is
318 // relative to conform with the Windows version of this
319 if (strlen(progPath) != 0 && progPath[0] != SEP) {
320 char cwd[MAXPATHLEN+1];
321 char tmp[MAXPATHLEN+1];
322 //XXX should check for failure retvals
323 getcwd(cwd, MAXPATHLEN);
324 snprintf(tmp, MAXPATHLEN, "%s%c%s", cwd, SEP, progPath);
325 strncpy(progPath, tmp, MAXPATHLEN);
328 // 'progPath' now contains the full path to the program *and* the program
329 // name. The latter is not desire.
330 char* pLetter = progPath + strlen(progPath);
331 for (;pLetter != progPath && *pLetter != SEP; --pLetter) {
332 /* do nothing */
334 *pLetter = '\0';
336 return progPath;
338 #endif /* WIN32 */
341 //---- mainline
343 int main(int argc, char** argv)
345 programName = argv[0];
346 programPath = _GetProgramPath();
348 // Determine the extension-less program basename.
349 // XXX Will not always handle app names with '.' in them (other than
350 // the '.' for the extension.
351 char programNameNoExt[MAXPATHLEN+1];
352 char *pStart, *pEnd;
353 pStart = pEnd = programName + strlen(programName) - 1;
354 while (pStart != programName && *(pStart-1) != SEP) {
355 pStart--;
357 while (1) {
358 if (pEnd == pStart) {
359 pEnd = programName + strlen(programName) - 1;
360 break;
362 pEnd--;
363 if (*(pEnd+1) == '.') {
364 break;
367 strncpy(programNameNoExt, pStart, pEnd-pStart+1);
368 *(programNameNoExt+(pEnd-pStart+1)) = '\0';
370 // determine the full path to "<exename>.py"
371 char pyFile[MAXPATHLEN+1];
372 snprintf(pyFile, MAXPATHLEN, "%s%c%s.py", programPath, SEP,
373 programNameNoExt);
375 // Build the argument array for launching.
376 char* pythonArgs[MAX_PYTHON_ARGS+1];
377 int nPythonArgs = 0;
378 pythonArgs[nPythonArgs++] = "python";
379 pythonArgs[nPythonArgs++] = "-tt";
380 pythonArgs[nPythonArgs++] = pyFile;
381 for (int i = 1; i < argc; ++i) {
382 pythonArgs[nPythonArgs++] = argv[i];
384 pythonArgs[nPythonArgs++] = NULL;
386 return _spawnvp(_P_WAIT, pythonArgs[0], pythonArgs);
390 //---- mainline for win32 subsystem:windows app
391 #ifdef WIN32
392 int WINAPI WinMain(
393 HINSTANCE hInstance, /* handle to current instance */
394 HINSTANCE hPrevInstance, /* handle to previous instance */
395 LPSTR lpCmdLine, /* pointer to command line */
396 int nCmdShow /* show state of window */
399 return main(__argc, __argv);
401 #endif