int main(int argc, char * *argv, char * const *envp) { int rval = 0; char exec_path[PATH_MAX+1]; char resolved_path[PATH_MAX+1]; uint32_t exec_path_size = sizeof(exec_path); CFStringRef argv0_string; CFURLRef argv0_url; char *argv0 = NULL; char *root = NULL; if (bind_CoreFoundation()) { fprintf(stderr, "CoreFoundation not found or functions missing\n"); return -1; } if (_NSGetExecutablePath(exec_path, &exec_path_size) != 0) { fprintf(stderr, "_NSGetExecutablePath failed to find current executable\n"); return -1; } exec_path[exec_path_size] = '\0'; realpath(exec_path, resolved_path); root = dirname(dirname(dirname(resolved_path))); argv0_url = py2app_CFURLCreateFromFileSystemRepresentation( NULL, (uint8_t *)root, strlen(root), true ); if (!argv0_url) { fprintf(stderr, "Could not cast '%s' to CFURL!\n", root); return -1; } py2app_main_bundle = py2app_CFBundleCreate(NULL, argv0_url); if (!py2app_main_bundle) { fprintf(stderr, "Not bundled, exiting\n"); return -1; } py2app_pool = py2app_CFArrayCreateMutable(NULL, 0, py2app_kCFTypeArrayCallBacks); if (!py2app_pool) { fprintf(stderr, "Couldn't create global pool\n"); return -1; } rval = py2app_main(argc, argv, envp); py2app_CFRelease(py2app_pool); py2app_CFRelease(py2app_main_bundle); py2app_CFRelease(argv0_url); // py2app_CFRelease(argv0_string); // free(argv0); return rval; }
static CFStringRef getMainScript(void) { CFMutableArrayRef possibleMains; CFBundleRef bndl; CFStringRef e_py, e_pyc, e_pyo, path; int i, cnt; possibleMains = py2app_CFArrayCreateMutable(NULL, 0, py2app_kCFTypeArrayCallBacks); CFArrayRef firstMains = py2app_getKey("PyMainFileNames"); if (firstMains) { CFRange rng; rng.location = 0; rng.length = py2app_CFArrayGetCount(firstMains); py2app_CFArrayAppendArray(possibleMains, firstMains, rng); } py2app_CFArrayAppendValue(possibleMains, py2app_CFSTR("__main__")); py2app_CFArrayAppendValue(possibleMains, py2app_CFSTR("__realmain__")); py2app_CFArrayAppendValue(possibleMains, py2app_CFSTR("Main")); e_py = py2app_CFSTR("py"); e_pyc = py2app_CFSTR("pyc"); e_pyo = py2app_CFSTR("pyo"); cnt = py2app_CFArrayGetCount(possibleMains); bndl = CFBundleGetMainBundle(); path = NULL; for (i = 0; i < cnt; i++) { CFStringRef base; CFURLRef resURL; base = py2app_CFArrayGetValueAtIndex(possibleMains, i); resURL = py2app_CFBundleCopyResourceURL(bndl, base, e_py, NULL); if (resURL == NULL) { resURL = py2app_CFBundleCopyResourceURL(bndl, base, e_pyc, NULL); } if (resURL == NULL) { resURL = py2app_CFBundleCopyResourceURL(bndl, base, e_pyo, NULL); } if (resURL != NULL) { path = pathFromURL(resURL); py2app_CFRelease(resURL); break; } } py2app_CFRelease(possibleMains); return path; }
static CFStringRef getErrorScript(void) { CFMutableArrayRef errorScripts; CFBundleRef bndl; CFStringRef path; int i, cnt; errorScripts = py2app_CFArrayCreateMutable(NULL, 0, py2app_kCFTypeArrayCallBacks); CFArrayRef firstErrorScripts = py2app_getKey("PyErrorScripts"); if (firstErrorScripts) { CFRange rng; rng.location = 0; rng.length = py2app_CFArrayGetCount(firstErrorScripts); py2app_CFArrayAppendArray(errorScripts, firstErrorScripts, rng); } py2app_CFArrayAppendValue(errorScripts, py2app_CFSTR("__error__")); py2app_CFArrayAppendValue(errorScripts, py2app_CFSTR("__error__.py")); py2app_CFArrayAppendValue(errorScripts, py2app_CFSTR("__error__.pyc")); py2app_CFArrayAppendValue(errorScripts, py2app_CFSTR("__error__.pyo")); py2app_CFArrayAppendValue(errorScripts, py2app_CFSTR("__error__.sh")); cnt = py2app_CFArrayGetCount(errorScripts); bndl = CFBundleGetMainBundle(); path = NULL; for (i = 0; i < cnt; i++) { CFStringRef base; CFURLRef resURL; base = py2app_CFArrayGetValueAtIndex(errorScripts, i); resURL = py2app_CFBundleCopyResourceURL(bndl, base, NULL, NULL); if (resURL) { path = pathFromURL(resURL); py2app_CFRelease(resURL); break; } } py2app_CFRelease(errorScripts); return path; }
static CFMutableArrayRef get_trimmed_lines(CFStringRef output) { CFMutableArrayRef lines; CFArrayRef tmp; CFRange rng; lines = py2app_CFArrayCreateMutable(NULL, 0, py2app_kCFTypeArrayCallBacks); tmp = py2app_CFStringCreateArrayBySeparatingStrings( NULL, output, py2app_CFSTR("\n")); rng.location = 0; rng.length = py2app_CFArrayGetCount(tmp); py2app_CFArrayAppendArray(lines, tmp, rng); while (true) { CFIndex cnt = py2app_CFArrayGetCount(lines); CFStringRef last; /* Nothing on stdout means pass silently */ if (cnt <= 0) { py2app_CFRelease(lines); return NULL; } last = py2app_CFArrayGetValueAtIndex(lines, cnt - 1); if (py2app_CFStringGetLength(last) > 0) break; py2app_CFArrayRemoveValueAtIndex(lines, cnt - 1); } return lines; }
static int report_script_error(const char *msg) { CFStringRef errorScript; CFMutableArrayRef lines; CFRange foundRange; CFStringRef lastLine; CFStringRef output = NULL; CFIndex lineCount; CFURLRef buttonURL = NULL; CFStringRef buttonString = NULL; CFStringRef title = NULL; CFStringRef errmsg = NULL; id releasePool; int errBinding; int status = 0; errorScript = getErrorScript(); if (!errorScript) return report_error(msg); errBinding = bind_objc_Cocoa_ApplicationServices(); if (!errBinding) { id task, stdoutPipe, taskData; CFMutableArrayRef argv; releasePool = ((id(*)(id, SEL))py2app_objc_msgSend)( ((id(*)(id, SEL))py2app_objc_msgSend)( py2app_objc_getClass("NSAutoreleasePool"), py2app_sel_getUid("alloc")), py2app_sel_getUid("init")); task = ((id(*)(id, SEL))py2app_objc_msgSend)( ((id(*)(id, SEL))py2app_objc_msgSend)( py2app_objc_getClass("NSTask"), py2app_sel_getUid("alloc")), py2app_sel_getUid("init")); stdoutPipe = ((id(*)(id, SEL))py2app_objc_msgSend)(py2app_objc_getClass("NSPipe"), py2app_sel_getUid("pipe")); ((void(*)(id, SEL, id))py2app_objc_msgSend)(task, py2app_sel_getUid("setLaunchPath:"), py2app_CFSTR("/bin/sh")); ((void(*)(id, SEL, id))py2app_objc_msgSend)(task, py2app_sel_getUid("setStandardOutput:"), stdoutPipe); argv = py2app_CFArrayCreateMutable(NULL, 0, py2app_kCFTypeArrayCallBacks); py2app_CFArrayAppendValue(argv, errorScript); py2app_CFArrayAppendValue(argv, py2app_getApplicationName()); ((void(*)(id, SEL, id))py2app_objc_msgSend)(task, py2app_sel_getUid("setArguments:"), argv); /* This could throw, in theory, but /bin/sh should prevent that */ ((void(*)(id, SEL))py2app_objc_msgSend)(task, py2app_sel_getUid("launch")); ((void(*)(id, SEL))py2app_objc_msgSend)(task, py2app_sel_getUid("waitUntilExit")); taskData = ((id(*)(id, SEL))py2app_objc_msgSend)( ((id(*)(id, SEL))py2app_objc_msgSend)(stdoutPipe, py2app_sel_getUid("fileHandleForReading")), py2app_sel_getUid("readDataToEndOfFile")); py2app_CFRelease(argv); status = ((int(*)(id, SEL))py2app_objc_msgSend)(task, py2app_sel_getUid("terminationStatus")); py2app_CFRelease(task); if (!status && taskData) { output = py2app_CFStringCreateFromExternalRepresentation( NULL, taskData, kCFStringEncodingUTF8); } ((void(*)(id, SEL))py2app_objc_msgSend)(releasePool, py2app_sel_getUid("release")); } py2app_CFRelease(errorScript); if (status || !output) return report_error(msg); lines = get_trimmed_lines(output); py2app_CFRelease(output); /* Nothing on stdout means pass silently */ if (!lines) return -1; lineCount = py2app_CFArrayGetCount(lines); lastLine = py2app_CFArrayGetValueAtIndex(lines, lineCount - 1); foundRange = py2app_CFStringFind(lastLine, py2app_CFSTR("ERRORURL: "), 0); if (foundRange.location != kCFNotFound && foundRange.length != 0) { CFMutableArrayRef buttonArr; CFArrayRef tmp; CFRange rng; buttonArr = py2app_CFArrayCreateMutable(NULL, 0, py2app_kCFTypeArrayCallBacks); tmp = py2app_CFStringCreateArrayBySeparatingStrings( NULL, lastLine, py2app_CFSTR(" ")); lineCount -= 1; py2app_CFArrayRemoveValueAtIndex(lines, lineCount); rng.location = 1; rng.length = py2app_CFArrayGetCount(tmp) - 1; py2app_CFArrayAppendArray(buttonArr, tmp, rng); py2app_CFRelease(tmp); while (true) { CFStringRef tmpstr; if (py2app_CFArrayGetCount(buttonArr) <= 0) break; tmpstr = py2app_CFArrayGetValueAtIndex(buttonArr, 0); if (py2app_CFStringGetLength(tmpstr) == 0) { py2app_CFArrayRemoveValueAtIndex(buttonArr, 0); } else { break; } } buttonURL = py2app_CFURLCreateWithString( NULL, py2app_CFArrayGetValueAtIndex(buttonArr, 0), NULL); if (buttonURL) { py2app_CFArrayRemoveValueAtIndex(buttonArr, 0); while (true) { CFStringRef tmpstr; if (py2app_CFArrayGetCount(buttonArr) <= 0) break; tmpstr = py2app_CFArrayGetValueAtIndex(buttonArr, 0); if (py2app_CFStringGetLength(tmpstr) == 0) { py2app_CFArrayRemoveValueAtIndex(buttonArr, 0); } else { break; } } if (py2app_CFArrayGetCount(buttonArr) > 0) { buttonString = py2app_CFStringCreateByCombiningStrings( NULL, buttonArr, py2app_CFSTR(" ")); } if (!buttonString) buttonString = py2app_CFSTR(ERR_DEFAULTURLTITLE); } py2app_CFRelease(buttonArr); } if (lineCount <= 0 || errBinding) { py2app_CFRelease(lines); return report_error(msg); } releasePool = ((id(*)(id, SEL))py2app_objc_msgSend)( ((id(*)(id, SEL))py2app_objc_msgSend)( py2app_objc_getClass("NSAutoreleasePool"), py2app_sel_getUid("alloc")), py2app_sel_getUid("init")); title = py2app_CFArrayGetValueAtIndex(lines, 0); py2app_CFRetain(title); (void)AUTORELEASE(title); lineCount -= 1; py2app_CFArrayRemoveValueAtIndex(lines, lineCount); py2app_NSLog(py2app_CFSTR("%@"), title); if (lineCount > 0) { CFStringRef showerr; errmsg = py2app_CFStringCreateByCombiningStrings( NULL, lines, py2app_CFSTR("\r")); (void)AUTORELEASE(errmsg); showerr = ((id(*)(id, SEL, id))py2app_objc_msgSend)( ((id(*)(id, SEL, id))py2app_objc_msgSend)(errmsg, py2app_sel_getUid("componentsSeparatedByString:"), py2app_CFSTR("\r")), py2app_sel_getUid("componentsJoinedByString:"), py2app_CFSTR("\n")); py2app_NSLog(py2app_CFSTR("%@"), showerr); } else { errmsg = py2app_CFSTR(""); } ensureGUI(); if (!buttonURL) { int choice = py2app_NSRunAlertPanel( title, py2app_CFSTR("%@"), py2app_CFSTR(ERR_TERMINATE), py2app_CFSTR(ERR_CONSOLEAPPTITLE), NULL, errmsg); if (choice == NSAlertAlternateReturn) py2app_openConsole(); } else { int choice = py2app_NSRunAlertPanel( title, py2app_CFSTR("%@"), py2app_CFSTR(ERR_TERMINATE), buttonString, NULL, errmsg); if (choice == NSAlertAlternateReturn) { id ws = ((id(*)(id, SEL))py2app_objc_msgSend)(py2app_objc_getClass("NSWorkspace"), py2app_sel_getUid("sharedWorkspace")); ((void(*)(id, SEL, id))py2app_objc_msgSend)(ws, py2app_sel_getUid("openURL:"), buttonURL); } } ((void(*)(id, SEL))py2app_objc_msgSend)(releasePool, py2app_sel_getUid("release")); py2app_CFRelease(lines); return -1; }
static void py2app_setPythonPath(void) { CFMutableArrayRef paths; CFURLRef resDir; CFStringRef resPath; CFArrayRef resPackages; CFDictionaryRef options; paths = py2app_CFArrayCreateMutable(NULL, 0, py2app_kCFTypeArrayCallBacks); resDir = py2app_CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); resPath = pathFromURL(resDir); py2app_CFArrayAppendValue(paths, resPath); py2app_CFRelease(resPath); resPackages = py2app_getKey("PyResourcePackages"); if (resPackages) { int i; int cnt = py2app_CFArrayGetCount(resPackages); for (i = 0; i < cnt; i++) { resPath = tildeExpand(py2app_CFArrayGetValueAtIndex(resPackages, i)); if (py2app_CFStringGetLength(resPath)) { if (py2app_CFStringGetCharacterAtIndex(resPath, 0) != '/') { CFURLRef absURL = py2app_CFURLCreateWithString( NULL, resPath, resDir); py2app_CFRelease(resPath); resPath = pathFromURL(absURL); py2app_CFRelease(absURL); } py2app_CFArrayAppendValue(paths, resPath); } py2app_CFRelease(resPath); } } py2app_CFRelease(resDir); options = py2app_getKey("PyOptions"); if (options) { CFBooleanRef use_pythonpath; CFNumberRef optimize; use_pythonpath = py2app_CFDictionaryGetValue( options, py2app_CFSTR("use_pythonpath")); if (use_pythonpath && py2app_CFBooleanGetValue(use_pythonpath)) { char *ppath = getenv("PYTHONPATH"); if (ppath) { CFArrayRef oldPath; oldPath = py2app_CFStringCreateArrayBySeparatingStrings( NULL, py2app_CFSTR(ppath), py2app_CFSTR(":")); if (oldPath) { CFRange rng; rng.location = 0; rng.length = py2app_CFArrayGetCount(oldPath); py2app_CFArrayAppendArray(paths, oldPath, rng); py2app_CFRelease(oldPath); } } } optimize = py2app_CFDictionaryGetValue( options, py2app_CFSTR("optimize")); if (optimize) { int v = 0; char buf[32]; py2app_CFNumberGetValue(optimize, kCFNumberIntType, &v); snprintf(buf, 31, "%d", v); setenv("PYTHONOPTIMIZE", buf, 1); } } if (py2app_CFArrayGetCount(paths)) { resPath = py2app_CFStringCreateByCombiningStrings(NULL, paths, py2app_CFSTR(":")); setcfenv("PYTHONPATH", resPath); py2app_CFRelease(resPath); } else { if (getenv("PYTHONPATH") != NULL) { unsetenv("PYTHONPATH"); } } py2app_CFRelease(paths); }
int main(int argc, char * const *argv, char * const *envp) { int rval; #ifndef PY2APP_SECONDARY /* Running as a GUI app started by launch * services, try to redirect stdout/stderr * to ASL. * * NOTE: Detecting application bundles on OSX 10.9 * is annoyingly hard, the devnull trick is the least * worst option I've found yet. */ struct stat st; struct utsname uts; int is_app_bundle = 1; if (uname(&uts) != -1) { if (strcmp(uts.release, "13.") <= 0) { /* OSX 10.8 or earlier */ if (!have_psn_arg(argc, argv)) { is_app_bundle = 0; } } else { /* OSX 10.9 or later */ if (fstat(1, &st) != -1) { if (!S_ISCHR(st.st_mode) || major(st.st_dev) != 3 || minor(st.st_dev) != 2) { /* We appear to be launched from the * command-line after all. */ is_app_bundle = st.st_dev; } } } } if (is_app_bundle) { const char *bname; setenv("_PY2APP_LAUNCHED_", "1", 1); bname = strrchr(argv[0], '/'); if (bname == NULL) { bname = argv[0]; } else { bname++; } setup_asl(bname); } #endif /* !PY2APP_SECONDARY */ if (bind_CoreFoundation()) { fprintf(stderr, "CoreFoundation not found or functions missing\n"); return -1; } if (!CFBundleGetMainBundle()) { fprintf(stderr, "Not bundled, exiting\n"); return -1; } py2app_pool = py2app_CFArrayCreateMutable(NULL, 0, py2app_kCFTypeArrayCallBacks); if (!py2app_pool) { fprintf(stderr, "Couldn't create global pool\n"); return -1; } rval = py2app_main(argc, argv, envp); py2app_CFRelease(py2app_pool); return rval; }