2 * Copyright (c) 2002-2003 ActiveState Corp.
3 * Author: Trent Mick (TrentM@ActiveState.com)
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.
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.
56 #define BUF_LENGTH 2048
57 #define MAX_PYTHON_ARGS 50
59 #define MAXPATHLEN 1024
63 // path list element separator
67 // path list element separator
72 #define spawnvp _spawnvp
73 #define snprintf _snprintf
74 #define vsnprintf _vsnprintf
75 //NOTE: this is for the stat *call* and the stat *struct*
82 char* programName
= NULL
;
83 char* programPath
= NULL
;
84 #ifndef WIN32 /* i.e. linux */
85 extern char **environ
; // the user environment
88 //---- error logging functions
90 void _LogError(const char* 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
);
101 MessageBox(NULL
, msg
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
103 fprintf(stderr
, "%s: error: ", programName
);
104 vfprintf(stderr
, format
, ap
);
106 #endif /* WIN32 && _WINDOWS */
110 void _LogWarning(const char* format
...)
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
);
121 MessageBox(NULL
, msg
, caption
, MB_OK
| MB_ICONWARNING
);
123 fprintf(stderr
, "%s: warning: ", programName
);
124 vfprintf(stderr
, format
, ap
);
126 #endif /* WIN32 && _WINDOWS */
131 //---- utilities functions
133 /* _IsDir: Is the given dirname an existing directory */
134 static int _IsDir(char *dirname
)
138 dwAttrib
= GetFileAttributes(dirname
);
139 if (dwAttrib
== -1) {
142 if (dwAttrib
& FILE_ATTRIBUTE_DIRECTORY
) {
146 #else /* i.e. linux */
148 if (stat(dirname
, &buf
) != 0)
150 if (!S_ISDIR(buf
.st_mode
))
157 /* _IsLink: Is the given filename a symbolic link */
158 static int _IsLink(char *filename
)
162 #else /* i.e. linux */
164 if (lstat(filename
, &buf
) != 0)
166 if (!S_ISLNK(buf
.st_mode
))
173 /* Is executable file
174 * On Linux: check 'x' permission. On Windows: just check existence.
176 static int _IsExecutableFile(char *filename
)
179 return (int)PathFileExists(filename
);
180 #else /* i.e. linux */
182 if (stat(filename
, &buf
) != 0)
184 if (!S_ISREG(buf
.st_mode
))
186 if ((buf
.st_mode
& 0111) == 0)
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.
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");
210 for (char* p
= progPath
+strlen(progPath
);
211 *p
!= SEP
&& *p
!= ALTSEP
;
216 *p
= '\0'; // remove the trailing SEP as well
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.
228 _JoinPath(char *buffer
, char *stuff
)
235 if (n
> 0 && buffer
[n
-1] != SEP
&& n
< MAXPATHLEN
)
239 if (n
+ k
> MAXPATHLEN
)
241 strncpy(buffer
+n
, stuff
, k
);
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
);
262 int bufspace
= MAXPATHLEN
;
264 char *delim
= strchr(path
, DELIM
);
267 size_t len
= delim
- path
;
268 if (len
> bufspace
) {
271 strncpy(progPath
, path
, len
);
272 *(progPath
+ len
) = '\0';
276 strncpy(progPath
, path
, bufspace
);
279 _JoinPath(progPath
, programName
);
280 if (_IsExecutableFile(progPath
)) {
295 // now we have to resolve a string of possible symlinks
296 // - we'll just handle the simple case of a single level of
299 // XXX note this does not handle multiple levels of symlinks
300 // here is pseudo-code for that (please implement it :):
302 // if islink(progPath):
303 // linkText = readlink(progPath)
304 // if isabsolute(linkText):
305 // progPath = os.path.join(dirname(progPath), linkText)
307 // progPath = linkText
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
) {
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];
353 pStart
= pEnd
= programName
+ strlen(programName
) - 1;
354 while (pStart
!= programName
&& *(pStart
-1) != SEP
) {
358 if (pEnd
== pStart
) {
359 pEnd
= programName
+ strlen(programName
) - 1;
363 if (*(pEnd
+1) == '.') {
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
,
375 // Build the argument array for launching.
376 char* pythonArgs
[MAX_PYTHON_ARGS
+1];
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
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
);