1#!/usr/bin/env python
2"""
3Create a C file for embedding one or more Cython source files.
4Requires Cython 0.11.2 (or perhaps newer).
5
6See Demos/freeze/README.txt for more details.
7"""
8
9import optparse
10from os.path import splitext, basename
11
12usage= '%prog [-o outfile] [-p] module [module ...]'
13description = 'Create a C file for embedding Cython modules.'
14p = optparse.OptionParser(usage=usage, description=description)
15p.add_option('-o', '--output', metavar='FILE',
16        help='write output to FILE instead of standard output')
17p.add_option('-p', '--pymain', action='store_true', default=False,
18        help='do not automatically run the first module as __main__')
19
20options, args = p.parse_args()
21
22if len(args) < 1:
23    p.print_help()
24    p.exit(1)
25
26if options.output:
27    import sys
28    old_stdout = sys.stdout
29    sys.stdout = open(options.output, 'w')
30
31modules = [basename(splitext(x)[0]).replace('.', '_') for x in args]
32
33print """\
34#include <Python.h>
35#include <locale.h>
36#include <stdio.h>
37#include <stdlib.h>
38
39#ifdef __FreeBSD__
40#include <floatingpoint.h>
41#endif
42
43#if PY_MAJOR_VERSION < 3
44# define MODINIT(name)  init ## name
45#else
46# define MODINIT(name)  PyInit_ ## name
47#endif
48"""
49
50for name in modules:
51    print "PyMODINIT_FUNC MODINIT(%s) (void);" % name
52
53print """
54static struct _inittab inittab[] = {"""
55
56for name in modules:
57    print '    {"%(name)s", MODINIT(%(name)s)},' % {'name' : name}
58
59print """    {NULL, NULL}
60};
61""",
62
63if not options.pymain:
64    print "\nextern int __pyx_module_is_main_%s;" % modules[0]
65
66print """
67#if PY_MAJOR_VERSION < 3
68int main(int argc, char** argv) {
69#elif defined(WIN32) || defined(MS_WINDOWS)
70int wmain(int argc, wchar_t **argv) {
71#else
72static int python_main(int argc, wchar_t **argv) {
73#endif
74""",
75if not options.pymain:
76    print """\
77    PyObject *m = NULL;
78    int r = 0;
79""",
80print """\
81    /* 754 requires that FP exceptions run in "no stop" mode by default,
82     * and until C vendors implement C99's ways to control FP exceptions,
83     * Python requires non-stop mode.  Alas, some platforms enable FP
84     * exceptions by default.  Here we disable them.
85     */
86#ifdef __FreeBSD__
87    fp_except_t m;
88
89    m = fpgetmask();
90    fpsetmask(m & ~FP_X_OFL);
91#endif
92    if (PyImport_ExtendInittab(inittab)) {
93        fprintf(stderr, "No memory\\n");
94        exit(1);
95    }
96""",
97if options.pymain:
98    print """\
99    return Py_Main(argc, argv);
100}
101"""
102else:
103    print """\
104    Py_SetProgramName(argv[0]);
105    Py_Initialize();
106    PySys_SetArgv(argc, argv);
107    __pyx_module_is_main_%(main)s = 1;
108    m = PyImport_ImportModule(inittab[0].name);
109    if (!m) {
110        r = 1;
111        PyErr_Print(); /* This exits with the right code if SystemExit. */
112#if PY_MAJOR_VERSION < 3
113        if (Py_FlushLine())
114            PyErr_Clear();
115#endif
116    }
117    Py_XDECREF(m);
118    Py_Finalize();
119    return r;
120}
121""" % {'main' : modules[0]},
122
123print r"""
124#if PY_MAJOR_VERSION >= 3 && !defined(WIN32) && !defined(MS_WINDOWS)
125static wchar_t*
126char2wchar(char* arg)
127{
128	wchar_t *res;
129#ifdef HAVE_BROKEN_MBSTOWCS
130	/* Some platforms have a broken implementation of
131	 * mbstowcs which does not count the characters that
132	 * would result from conversion.  Use an upper bound.
133	 */
134	size_t argsize = strlen(arg);
135#else
136	size_t argsize = mbstowcs(NULL, arg, 0);
137#endif
138	size_t count;
139	unsigned char *in;
140	wchar_t *out;
141#ifdef HAVE_MBRTOWC
142	mbstate_t mbs;
143#endif
144	if (argsize != (size_t)-1) {
145		res = (wchar_t *)malloc((argsize+1)*sizeof(wchar_t));
146		if (!res)
147			goto oom;
148		count = mbstowcs(res, arg, argsize+1);
149		if (count != (size_t)-1) {
150			wchar_t *tmp;
151			/* Only use the result if it contains no
152			   surrogate characters. */
153			for (tmp = res; *tmp != 0 &&
154				     (*tmp < 0xd800 || *tmp > 0xdfff); tmp++)
155				;
156			if (*tmp == 0)
157				return res;
158		}
159		free(res);
160	}
161	/* Conversion failed. Fall back to escaping with surrogateescape. */
162#ifdef HAVE_MBRTOWC
163	/* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */
164
165	/* Overallocate; as multi-byte characters are in the argument, the
166	   actual output could use less memory. */
167	argsize = strlen(arg) + 1;
168	res = malloc(argsize*sizeof(wchar_t));
169	if (!res) goto oom;
170	in = (unsigned char*)arg;
171	out = res;
172	memset(&mbs, 0, sizeof mbs);
173	while (argsize) {
174		size_t converted = mbrtowc(out, (char*)in, argsize, &mbs);
175		if (converted == 0)
176			/* Reached end of string; null char stored. */
177			break;
178		if (converted == (size_t)-2) {
179			/* Incomplete character. This should never happen,
180			   since we provide everything that we have -
181			   unless there is a bug in the C library, or I
182			   misunderstood how mbrtowc works. */
183			fprintf(stderr, "unexpected mbrtowc result -2\n");
184			return NULL;
185		}
186		if (converted == (size_t)-1) {
187			/* Conversion error. Escape as UTF-8b, and start over
188			   in the initial shift state. */
189			*out++ = 0xdc00 + *in++;
190			argsize--;
191			memset(&mbs, 0, sizeof mbs);
192			continue;
193		}
194		if (*out >= 0xd800 && *out <= 0xdfff) {
195			/* Surrogate character.  Escape the original
196			   byte sequence with surrogateescape. */
197			argsize -= converted;
198			while (converted--)
199				*out++ = 0xdc00 + *in++;
200			continue;
201		}
202		/* successfully converted some bytes */
203		in += converted;
204		argsize -= converted;
205		out++;
206	}
207#else
208	/* Cannot use C locale for escaping; manually escape as if charset
209	   is ASCII (i.e. escape all bytes > 128. This will still roundtrip
210	   correctly in the locale's charset, which must be an ASCII superset. */
211	res = malloc((strlen(arg)+1)*sizeof(wchar_t));
212	if (!res) goto oom;
213	in = (unsigned char*)arg;
214	out = res;
215	while(*in)
216		if(*in < 128)
217			*out++ = *in++;
218		else
219			*out++ = 0xdc00 + *in++;
220	*out = 0;
221#endif
222	return res;
223oom:
224	fprintf(stderr, "out of memory\n");
225	return NULL;
226}
227
228int
229main(int argc, char **argv)
230{
231	wchar_t **argv_copy = (wchar_t **)malloc(sizeof(wchar_t*)*argc);
232	/* We need a second copies, as Python might modify the first one. */
233	wchar_t **argv_copy2 = (wchar_t **)malloc(sizeof(wchar_t*)*argc);
234	int i, res;
235	char *oldloc;
236	if (!argv_copy || !argv_copy2) {
237		fprintf(stderr, "out of memory\n");
238		return 1;
239	}
240	oldloc = strdup(setlocale(LC_ALL, NULL));
241	setlocale(LC_ALL, "");
242	for (i = 0; i < argc; i++) {
243		argv_copy2[i] = argv_copy[i] = char2wchar(argv[i]);
244		if (!argv_copy[i])
245			return 1;
246	}
247	setlocale(LC_ALL, oldloc);
248	free(oldloc);
249	res = python_main(argc, argv_copy);
250	for (i = 0; i < argc; i++) {
251		free(argv_copy2[i]);
252	}
253	free(argv_copy);
254	free(argv_copy2);
255	return res;
256}
257#endif"""
258