123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- /*
- * Copyright (c) 2002-2003 ActiveState Corp.
- * Author: Trent Mick (TrentM@ActiveState.com)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- /* Console launch executable.
- *
- * This program exists solely to launch:
- * python <installdir>/<exename>.py <argv>
- * on Windows. "<exename>.py" must be in the same directory.
- *
- * Rationale:
- * - On some Windows flavours .py *can* be put on the PATHEXT to be
- * able to find "<exename>.py" if it is on the PATH. This is fine
- * until you need shell redirection to work. It does NOT for
- * extensions to PATHEXT. Redirection *does* work for "python
- * <script>.py" so we will try to do that.
- */
- #ifdef WIN32
- #include <windows.h>
- #include <process.h>
- #include <direct.h>
- #include <shlwapi.h>
- #else /* linux */
- #include <unistd.h>
- #endif /* WIN32 */
- #include <sys/stat.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
- //---- constants
- #define BUF_LENGTH 2048
- #define MAX_PYTHON_ARGS 50
- #define MAX_FILES 50
- #define MAXPATHLEN 1024
- #ifdef WIN32
- #define SEP '\\'
- #define ALTSEP '/'
- // path list element separator
- #define DELIM ';'
- #else /* linux */
- #define SEP '/'
- // path list element separator
- #define DELIM ':'
- #endif
- #ifdef WIN32
- #define spawnvp _spawnvp
- #if defined(_MSC_VER) && _MSC_VER < 1900
- #define snprintf _snprintf
- #define vsnprintf _vsnprintf
- #endif
- //NOTE: this is for the stat *call* and the stat *struct*
- #define stat _stat
- #endif
- //---- globals
- char* programName = NULL;
- char* programPath = NULL;
- #ifndef WIN32 /* i.e. linux */
- extern char **environ; // the user environment
- #endif /* linux */
- //---- error logging functions
- void _LogError(const char* format ...)
- {
- va_list ap;
- va_start(ap, format);
- #if defined(WIN32) && defined(_WINDOWS)
- // put up a MessageBox
- char caption[BUF_LENGTH+1];
- snprintf(caption, BUF_LENGTH, "Error in %s", programName);
- char msg[BUF_LENGTH+1];
- vsnprintf(msg, BUF_LENGTH, format, ap);
- va_end(ap);
- MessageBox(NULL, msg, caption, MB_OK | MB_ICONEXCLAMATION);
- #else
- fprintf(stderr, "%s: error: ", programName);
- vfprintf(stderr, format, ap);
- va_end(ap);
- #endif /* WIN32 && _WINDOWS */
- }
- void _LogWarning(const char* format ...)
- {
- va_list ap;
- va_start(ap, format);
- #if defined(WIN32) && defined(_WINDOWS)
- // put up a MessageBox
- char caption[BUF_LENGTH+1];
- snprintf(caption, BUF_LENGTH, "Warning in %s", programName);
- char msg[BUF_LENGTH+1];
- vsnprintf(msg, BUF_LENGTH, format, ap);
- va_end(ap);
- MessageBox(NULL, msg, caption, MB_OK | MB_ICONWARNING);
- #else
- fprintf(stderr, "%s: warning: ", programName);
- vfprintf(stderr, format, ap);
- va_end(ap);
- #endif /* WIN32 && _WINDOWS */
- }
- //---- utilities functions
- /* _IsDir: Is the given dirname an existing directory */
- static int _IsDir(char *dirname)
- {
- #ifdef WIN32
- DWORD dwAttrib;
- dwAttrib = GetFileAttributes(dirname);
- if (dwAttrib == -1) {
- return 0;
- }
- if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
- return 1;
- }
- return 0;
- #else /* i.e. linux */
- struct stat buf;
- if (stat(dirname, &buf) != 0)
- return 0;
- if (!S_ISDIR(buf.st_mode))
- return 0;
- return 1;
- #endif
- }
- /* _IsLink: Is the given filename a symbolic link */
- static int _IsLink(char *filename)
- {
- #ifdef WIN32
- return 0;
- #else /* i.e. linux */
- struct stat buf;
- if (lstat(filename, &buf) != 0)
- return 0;
- if (!S_ISLNK(buf.st_mode))
- return 0;
- return 1;
- #endif
- }
- /* Is executable file
- * On Linux: check 'x' permission. On Windows: just check existence.
- */
- static int _IsExecutableFile(char *filename)
- {
- #ifdef WIN32
- return (int)PathFileExists(filename);
- #else /* i.e. linux */
- struct stat buf;
- if (stat(filename, &buf) != 0)
- return 0;
- if (!S_ISREG(buf.st_mode))
- return 0;
- if ((buf.st_mode & 0111) == 0)
- return 0;
- return 1;
- #endif /* WIN32 */
- }
- /* _GetProgramPath: Determine the absolute path to the given program name.
- *
- * Takes into account the current working directory, etc.
- * The implementations require the global 'programName' to be set.
- */
- #ifdef WIN32
- static char* _GetProgramPath(void)
- {
- //XXX this is ugly but I didn't want to use malloc, no reason
- static char progPath[MAXPATHLEN+1];
- // get absolute path to module
- if (!GetModuleFileName(NULL, progPath, MAXPATHLEN)) {
- _LogError("could not get absolute program name from "\
- "GetModuleFileName\n");
- exit(1);
- }
- // just need dirname
- for (char* p = progPath+strlen(progPath);
- *p != SEP && *p != ALTSEP;
- --p)
- {
- *p = '\0';
- }
- *p = '\0'; // remove the trailing SEP as well
- return progPath;
- }
- #else
- /* _JoinPath requires that any buffer argument passed to it has at
- least MAXPATHLEN + 1 bytes allocated. If this requirement is met,
- it guarantees that it will never overflow the buffer. If stuff
- is too long, buffer will contain a truncated copy of stuff.
- */
- static void
- _JoinPath(char *buffer, char *stuff)
- {
- size_t n, k;
- if (stuff[0] == SEP)
- n = 0;
- else {
- n = strlen(buffer);
- if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN)
- buffer[n++] = SEP;
- }
- k = strlen(stuff);
- if (n + k > MAXPATHLEN)
- k = MAXPATHLEN - n;
- strncpy(buffer+n, stuff, k);
- buffer[n+k] = '\0';
- }
- static char*
- _GetProgramPath(void)
- {
- /* XXX this routine does *no* error checking */
- char* path = getenv("PATH");
- static char progPath[MAXPATHLEN+1];
- /* If there is no slash in the argv0 path, then we have to
- * assume the program is on the user's $PATH, since there's no
- * other way to find a directory to start the search from. If
- * $PATH isn't exported, you lose.
- */
- if (strchr(programName, SEP)) {
- strncpy(progPath, programName, MAXPATHLEN);
- }
- else if (path) {
- int bufspace = MAXPATHLEN;
- while (1) {
- char *delim = strchr(path, DELIM);
- if (delim) {
- size_t len = delim - path;
- if (len > bufspace) {
- len = bufspace;
- }
- strncpy(progPath, path, len);
- *(progPath + len) = '\0';
- bufspace -= len;
- }
- else {
- strncpy(progPath, path, bufspace);
- }
- _JoinPath(progPath, programName);
- if (_IsExecutableFile(progPath)) {
- break;
- }
- if (!delim) {
- progPath[0] = '\0';
- break;
- }
- path = delim + 1;
- }
- }
- else {
- progPath[0] = '\0';
- }
- // now we have to resolve a string of possible symlinks
- // - we'll just handle the simple case of a single level of
- // indirection
- //
- // XXX note this does not handle multiple levels of symlinks
- // here is pseudo-code for that (please implement it :):
- // while 1:
- // if islink(progPath):
- // linkText = readlink(progPath)
- // if isabsolute(linkText):
- // progPath = os.path.join(dirname(progPath), linkText)
- // else:
- // progPath = linkText
- // else:
- // break
- if (_IsLink(progPath)) {
- char newProgPath[MAXPATHLEN+1];
- readlink(progPath, newProgPath, MAXPATHLEN);
- strncpy(progPath, newProgPath, MAXPATHLEN);
- }
-
- // prefix with the current working directory if the path is
- // relative to conform with the Windows version of this
- if (strlen(progPath) != 0 && progPath[0] != SEP) {
- char cwd[MAXPATHLEN+1];
- char tmp[MAXPATHLEN+1];
- //XXX should check for failure retvals
- getcwd(cwd, MAXPATHLEN);
- snprintf(tmp, MAXPATHLEN, "%s%c%s", cwd, SEP, progPath);
- strncpy(progPath, tmp, MAXPATHLEN);
- }
-
- // 'progPath' now contains the full path to the program *and* the program
- // name. The latter is not desire.
- char* pLetter = progPath + strlen(progPath);
- for (;pLetter != progPath && *pLetter != SEP; --pLetter) {
- /* do nothing */
- }
- *pLetter = '\0';
- return progPath;
- }
- #endif /* WIN32 */
- //---- mainline
- int main(int argc, char** argv)
- {
- programName = argv[0];
- programPath = _GetProgramPath();
- // Determine the extension-less program basename.
- // XXX Will not always handle app names with '.' in them (other than
- // the '.' for the extension.
- char programNameNoExt[MAXPATHLEN+1];
- char *pStart, *pEnd;
- pStart = pEnd = programName + strlen(programName) - 1;
- while (pStart != programName && *(pStart-1) != SEP) {
- pStart--;
- }
- while (1) {
- if (pEnd == pStart) {
- pEnd = programName + strlen(programName) - 1;
- break;
- }
- pEnd--;
- if (*(pEnd+1) == '.') {
- break;
- }
- }
- strncpy(programNameNoExt, pStart, pEnd-pStart+1);
- *(programNameNoExt+(pEnd-pStart+1)) = '\0';
- // determine the full path to "<exename>.py"
- char pyFile[MAXPATHLEN+1];
- snprintf(pyFile, MAXPATHLEN, "%s%c%s.py", programPath, SEP,
- programNameNoExt);
-
- // Build the argument array for launching.
- char* pythonArgs[MAX_PYTHON_ARGS+1];
- int nPythonArgs = 0;
- pythonArgs[nPythonArgs++] = "python";
- pythonArgs[nPythonArgs++] = "-tt";
- pythonArgs[nPythonArgs++] = pyFile;
- for (int i = 1; i < argc; ++i) {
- pythonArgs[nPythonArgs++] = argv[i];
- }
- pythonArgs[nPythonArgs++] = NULL;
- return _spawnvp(_P_WAIT, pythonArgs[0], pythonArgs);
- }
- //---- mainline for win32 subsystem:windows app
- #ifdef WIN32
- int WINAPI WinMain(
- HINSTANCE hInstance, /* handle to current instance */
- HINSTANCE hPrevInstance, /* handle to previous instance */
- LPSTR lpCmdLine, /* pointer to command line */
- int nCmdShow /* show state of window */
- )
- {
- return main(__argc, __argv);
- }
- #endif
|