1/*
2 * Workaround to make NSAppicationMain more usable from Python.
3 */
4#include <Python.h>
5#include "pyobjc-api.h"
6
7#import <AppKit/AppKit.h>
8
9static PyObject*
10objc_NSApplicationMain(
11	PyObject* self __attribute__((__unused__)),
12	PyObject* args,
13	PyObject* kwds)
14{
15static	char* keywords[] = { "argv", NULL };
16	char** argv = NULL;
17	int    argc;
18	PyObject* arglist;
19	int       i;
20	PyObject* v;
21	int       res;
22
23	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:NSApplicationMain",
24			keywords, &arglist)) {
25		return NULL;
26	}
27
28	if (!PySequence_Check(arglist)) {
29		PyErr_SetString(PyExc_TypeError,
30			"NSApplicationMain: need list of strings as argument");
31		return NULL;
32	}
33
34	argc = PySequence_Size(arglist);
35	argv = calloc((argc + 1), sizeof(char**));
36	if (argv == NULL) {
37		PyErr_SetString(PyExc_MemoryError,
38			"Out of memory");
39		return NULL;
40	}
41
42	for  (i = 0; i < argc; i++) {
43		v = PySequence_GetItem(arglist, i);
44		if (v == NULL) {
45			goto error_cleanup;
46		}
47		if (!PyString_Check(v)) {
48			PyErr_SetString(PyExc_TypeError,
49				"NSApplicationMain: need list of strings "
50				"as argument");
51			goto error_cleanup;
52		}
53
54		argv[i] = strdup(PyString_AsString(v));
55		if (argv[i] == NULL) {
56			PyErr_SetString(PyExc_MemoryError,
57				"Out of memory");
58			goto error_cleanup;
59		}
60	}
61
62	argv[argc] = NULL;
63
64#if 0
65	/*
66	 * NSApplicationMain on MacOS X completely ignores its arguments and
67	 * reads the argv from the shared NSProcessInfo. We *HACK* around this
68	 * by setting a (private) instance variable of the object.
69	 *
70	 * This code is evil. Look away if you're easily scared.
71	 *
72	 * This doesn't work in 64-bit mode however. Therefore this code
73	 * is now disabled. This shouldn't make a difference when using
74	 * py2app or Xcode's PyObjC templates.
75	 */
76	{
77		typedef struct {
78			@defs(NSProcessInfo)
79		} NSProcessInfoStruct;
80
81		NSMutableArray *newarglist = [[NSMutableArray alloc] init];
82		NSProcessInfo *processInfo = [NSProcessInfo processInfo];
83		char **anArg = argv;
84
85		while(*anArg) {
86			[newarglist addObject:
87				[NSString stringWithUTF8String: *anArg]];
88			anArg++;
89		}
90
91		/* Don't release the orignal arguments, because we don't know
92		 * if the list is owned by the processInfo object.
93		 *
94		 *[((NSProcessInfoStruct *)processInfo)->arguments release];
95		 */
96		((NSProcessInfoStruct *)processInfo)->arguments = newarglist;
97	}
98#endif
99
100	PyObjC_DURING
101		res = NSApplicationMain(argc, (const char**)argv);
102	PyObjC_HANDLER
103		PyObjCErr_FromObjC(localException);
104		res = -1;
105	PyObjC_ENDHANDLER
106
107	for (i = 0; i < argc; i++) {
108		free(argv[i]);
109	}
110	free(argv);
111
112	if (res == -1 && PyErr_Occurred())
113		return NULL;
114	return PyInt_FromLong(res);
115
116error_cleanup:
117	if (argv != NULL) {
118		for (i = 0; i < argc; i++) {
119			if (argv[i] != NULL) {
120				free(argv[i]);
121				argv[i] = NULL;
122			}
123		}
124		free(argv);
125		argv = NULL;
126	}
127
128	return NULL;
129}
130
131
132static PyMethodDef mod_methods[] = {
133	{
134		"NSApplicationMain",
135		(PyCFunction)objc_NSApplicationMain,
136		METH_VARARGS|METH_KEYWORDS,
137		"int NSApplicationMain(int argc, const char *argv[]);"
138	},
139	{ 0, 0, 0, 0 } /* sentinel */
140};
141
142void init_appmain(void);
143void init_appmain(void)
144{
145	PyObject* m = Py_InitModule4("_appmain", mod_methods, "", NULL,
146			PYTHON_API_VERSION);
147
148	PyObjC_ImportAPI(m);
149}
150