diff --git a/pyserpent.cpp b/pyserpent.cpp index fa323e2..626ef06 100644 --- a/pyserpent.cpp +++ b/pyserpent.cpp @@ -5,6 +5,12 @@ #include #include "funcs.h" +#if PY_MAJOR_VERSION >= 3 +#define PY_STRING_FORMAT "y#" +#else +#define PY_STRING_FORMAT "s#" +#endif + #define PYMETHOD(name, FROM, method, TO) \ static PyObject * name(PyObject *, PyObject *args) { \ try { \ @@ -32,7 +38,7 @@ #define FROMSTR(v) \ const char *command; \ int len; \ - if (!PyArg_ParseTuple(args, "s#", &command, &len)) \ + if (!PyArg_ParseTuple(args, PY_STRING_FORMAT, &command, &len)) \ return NULL; \ std::string v = std::string(command, len); \ @@ -41,7 +47,7 @@ int len1; \ const char *command2; \ int len2; \ - if (!PyArg_ParseTuple(args, "s#s#", &command1, &len1, &command2, &len2)) \ + if (!PyArg_ParseTuple(args, PY_STRING_FORMAT PY_STRING_FORMAT, &command1, &len1, &command2, &len2)) \ return NULL; \ std::string a1##v = std::string(command1, len1); \ std::string a2##v = std::string(command2, len2); \ @@ -61,7 +67,7 @@ // Convert metadata into python wrapper form [file, ln, ch] PyObject* pyifyMetadata(Metadata m) { PyObject* a = PyList_New(0); - PyList_Append(a, Py_BuildValue("s#", m.file.c_str(), m.file.length())); + PyList_Append(a, Py_BuildValue(PY_STRING_FORMAT, m.file.c_str(), m.file.length())); PyList_Append(a, Py_BuildValue("i", m.ln)); PyList_Append(a, Py_BuildValue("i", m.ch)); return a; @@ -72,7 +78,7 @@ PyObject* pyifyMetadata(Metadata m) { PyObject* pyifyNode(Node n) { PyObject* a = PyList_New(0); PyList_Append(a, Py_BuildValue("i", n.type == ASTNODE)); - PyList_Append(a, Py_BuildValue("s#", n.val.c_str(), n.val.length())); + PyList_Append(a, Py_BuildValue(PY_STRING_FORMAT, n.val.c_str(), n.val.length())); PyList_Append(a, pyifyMetadata(n.metadata)); for (unsigned i = 0; i < n.args.size(); i++) PyList_Append(a, pyifyNode(n.args[i])); @@ -81,7 +87,7 @@ PyObject* pyifyNode(Node n) { // Convert string into python wrapper form PyObject* pyifyString(std::string s) { - return Py_BuildValue("s#", s.c_str(), s.length()); + return Py_BuildValue(PY_STRING_FORMAT, s.c_str(), s.length()); } // Convert integer into python wrapper form @@ -108,8 +114,13 @@ int cppifyInt(PyObject* o) { // Convert pyobject string into normal form std::string cppifyString(PyObject* o) { const char *command; +#if PY_MAJOR_VERSION >= 3 + if (!PyArg_Parse(o, "y", &command)) + err("Argument should be bytes", Metadata()); +#else if (!PyArg_Parse(o, "s", &command)) err("Argument should be string", Metadata()); +#endif return std::string(command); } @@ -190,7 +201,23 @@ static PyMethodDef PyextMethods[] = { {NULL, NULL, 0, NULL} /* Sentinel */ }; +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef SerpentModule = { + PyModuleDef_HEAD_INIT, + "serpent_pyext", + "...", + -1, + PyextMethods +}; + +PyMODINIT_FUNC PyInit_serpent_pyext(void) { + return PyModule_Create(&SerpentModule); +} + +#else PyMODINIT_FUNC initserpent_pyext(void) { Py_InitModule( "serpent_pyext", PyextMethods ); } +#endif + diff --git a/serpent.py b/serpent.py index c7adfb2..b45d51d 100644 --- a/serpent.py +++ b/serpent.py @@ -1,8 +1,14 @@ import serpent_pyext as pyext import sys, re +import binascii VERSION = '1.8.0' +def strtobytes(x): + return x.encode('ascii') if isinstance(x, str) else x + +def bytestostr(x): + return x.decode('ascii') if isinstance(x, bytes) else x class Metadata(object): def __init__(self, li): @@ -23,7 +29,7 @@ def out(self): return [0, self.val, self.metadata.out()] def __repr__(self): - return str(self.val) + return str(bytestostr(self.val)) class Astnode(object): @@ -37,8 +43,8 @@ def out(self): return o def __repr__(self): - o = '(' + self.val - subs = map(repr, self.args) + o = '(' + bytestostr(self.val) + subs = list(map(bytestostr, map(repr, self.args))) k = 0 out = " " while k < len(subs) and o != "(seq": @@ -63,24 +69,28 @@ def node(li): def take(x): - return pyext.parse_lll(x) if isinstance(x, (str, unicode)) else x.out() - + if sys.version_info[0] < 3: + return pyext.parse_lll(x) if isinstance(x, (str, unicode)) else x.out() + else: + return pyext.parse_lll(x) if isinstance(x, (str, bytes)) else x.out() def takelist(x): - return map(take, parse(x).args if isinstance(x, (str, unicode)) else x) - - -compile = lambda x: pyext.compile(x) -compile_to_lll = lambda x: node(pyext.compile_to_lll(x)) -compile_lll = lambda x: pyext.compile_lll(take(x)) -parse = lambda x: node(pyext.parse(x)) -rewrite = lambda x: node(pyext.rewrite(take(x))) -pretty_compile = lambda x: map(node, pyext.pretty_compile(x)) -pretty_compile_lll = lambda x: map(node, pyext.pretty_compile_lll(take(x))) -serialize = lambda x: pyext.serialize(takelist(x)) -deserialize = lambda x: map(node, pyext.deserialize(x)) -mk_signature = lambda x: pyext.mk_signature(x) -mk_full_signature = lambda x: pyext.mk_full_signature(x) + if sys.version_info[0] < 3: + return map(take, parse(x).args if isinstance(x, (str, unicode)) else x) + else: + return map(take, parse(x).args if isinstance(x, (str, bytes)) else x) + +compile = lambda x: pyext.compile(strtobytes(x)) +compile_to_lll = lambda x: node(pyext.compile_to_lll(strtobytes(x))) +compile_lll = lambda x: pyext.compile_lll(take(strtobytes(x))) +parse = lambda x: node(pyext.parse(strtobytes(x))) +rewrite = lambda x: node(pyext.rewrite(take(strtobytes(x)))) +pretty_compile = lambda x: map(node, pyext.pretty_compile(strtobytes(x))) +pretty_compile_lll = lambda x: map(node, pyext.pretty_compile_lll(take(strtobytes(x)))) +serialize = lambda x: pyext.serialize(takelist(strtobytes(x))) +deserialize = lambda x: map(node, pyext.deserialize(strtobytes(x))) +mk_signature = lambda x: pyext.mk_signature(strtobytes(x)) +mk_full_signature = lambda x: pyext.mk_full_signature(strtobytes(x)) get_prefix = lambda x, y: pyext.get_prefix(x, y) % 2**32 is_numeric = lambda x: isinstance(x, (int, long)) @@ -168,13 +178,13 @@ def decode_abi(arr, *lens): def main(): if len(sys.argv) == 1: - print "serpent ..." + print("serpent ...") else: cmd = sys.argv[2] if sys.argv[1] == '-s' else sys.argv[1] if sys.argv[1] == '-s': args = [sys.stdin.read()] + sys.argv[3:] elif sys.argv[1] == '-v': - print VERSION + print(VERSION) sys.exit() else: cmd = sys.argv[1] @@ -186,8 +196,8 @@ def main(): kwargs['source'] = 'cmdline' o = globals()[cmd](*args, **kwargs) if isinstance(o, (Token, Astnode, list)): - print repr(o) + print(repr(o)) elif cmd in ['mk_signature', 'mk_full_signature', 'get_prefix']: - print o + print(o) else: - print o.encode('hex') + print(binascii.b2a_hex(o).decode('ascii'))