else:
raise AssertionError("die didn't exit")
- def test_mdwopt(me):
- mo = M.MdwOpt()
- print(list(mo))
+###--------------------------------------------------------------------------
+class TestMdwOpt (U.TestCase):
+
+ def test_argv_default(me):
+ old_argv = SYS.argv
+ try:
+ SYS.argv = ["just", "another", "Python", "hacker"]
+ mo = M.MdwOpt()
+ me.assertEqual(mo.argv, SYS.argv)
+ finally:
+ SYS.argv = old_argv
+
+ def test_basic(me):
+ mo = M.MdwOpt(argv = ["example",
+ "one",
+ "-abcarg",
+ "--opt",
+ "+de",
+ "two",
+ "--no-thing",
+ "-f", "alpha",
+ "--foo", "beta",
+ "--switch", "--frob", "--toggle", "--no-frob",
+ "three"],
+ shortopt = "abc:d+e+f:",
+ longopt = [("opt", "o"),
+ ("thing", "t", M.OPTF_NEGATE),
+ ("foo", None, M.OPTF_ARGREQ, "foo"),
+ ("switch", 1, M.OPTF_SWITCH, "flags"),
+ ("frob", 2, M.OPTF_SWITCH | M.OPTF_NEGATE,
+ "flags"),
+ ("toggle", 4, M.OPTF_SWITCH, "flags")],
+ flags = M.OPTF_NEGATION)
+ me.assertEqual(list(mo), [("a", None, 0),
+ ("b", None, 0),
+ ("c", "arg", 0),
+ ("o", None, 0),
+ ("d", None, M.OPTF_NEGATED),
+ ("e", None, M.OPTF_NEGATED),
+ ("t", None, M.OPTF_NEGATED),
+ ("f", "alpha", 0)])
+ me.assertEqual(mo.argv[mo.ind:], ["one", "two", "three"])
+ me.assertEqual(mo.state.foo, "beta")
+ me.assertEqual(mo.state.flags, 5)
###----- That's all, folks --------------------------------------------------
/*----- Option parser -----------------------------------------------------*/
+typedef struct {
+ PyObject_HEAD
+ PyObject *attrs;
+} optstate_pyobj;
+static PyTypeObject *optstate_pytype;
+
+static PyObject *optstate_pywrap(PyTypeObject *ty)
+{
+ optstate_pyobj *me = 0;
+
+ me = (optstate_pyobj *)ty->tp_alloc(ty, 0); if (!me) goto fail;
+ me->attrs = PyDict_New(); if (!me->attrs) goto fail;
+ return ((PyObject *)me);
+
+fail:
+ if (me) {
+ Py_XDECREF(me->attrs);
+ Py_DECREF(me);
+ }
+ return (0);
+}
+
+static PyObject *optstate_pynew(PyTypeObject *ty,
+ PyObject *arg, PyObject *kw)
+{
+ static const char *const kwlist[] = { 0 };
+ PyObject *me = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", KWLIST)) goto end;
+ me = optstate_pywrap(ty);
+end:
+ return (me);
+}
+
+static void optstate_pydealloc(PyObject *me)
+{
+ optstate_pyobj *st = (optstate_pyobj *)me;
+ Py_DECREF(st->attrs);
+ FREEOBJ(me);
+}
+
+static const PyTypeObject optstate_pytype_skel = {
+ PyVarObject_HEAD_INIT(0, 0) /* Header */
+ "OptState", /* @tp_name@ */
+ sizeof(optstate_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ optstate_pydealloc, /* @tp_dealloc@ */
+ 0, /* @tp_print@ */
+ 0, /* @tp_getattr@ */
+ 0, /* @tp_setattr@ */
+ 0, /* @tp_compare@ */
+ 0, /* @tp_repr@ */
+ 0, /* @tp_as_number@ */
+ 0, /* @tp_as_sequence@ */
+ 0, /* @tp_as_mapping@ */
+ 0, /* @tp_hash@ */
+ 0, /* @tp_call@ */
+ 0, /* @tp_str@ */
+ 0, /* @tp_getattro@ */
+ 0, /* @tp_setattro@ */
+ 0, /* @tp_as_buffer@ */
+ Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
+ Py_TPFLAGS_BASETYPE,
+
+ /* @tp_doc@ */
+ "OptState()\n"
+ "\n"
+ "A passive and generic container for arbitrary object attributes.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ 0, /* @tp_methods@ */
+ 0, /* @tp_members@ */
+ 0, /* @tp_getset@ */
+ 0, /* @tp_base@ */
+ 0, /* @tp_dict@ */
+ 0, /* @tp_descr_get@ */
+ 0, /* @tp_descr_set@ */
+ offsetof(optstate_pyobj, attrs), /* @tp_dictoffset@ */
+ 0, /* @tp_init@ */
+ PyType_GenericAlloc, /* @tp_alloc@ */
+ optstate_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
struct optextra {
PyObject *tag;
PyObject *attr;
#define MDWOPT_OPT(o) (&((mdwopt_pyobj *)(o))->opt)
#define MDWOPT_ARGV(o) (((mdwopt_pyobj *)(o))->argv)
#define MDWOPT_SHORT(o) (((mdwopt_pyobj *)(o))->stringdata)
-#define MDWOPT_LONG(o) (((mdwopt_pyobj *)(o))->longopt)
+#define MDWOPT_LONG(o) stativ(((mdwopt_pyobj *)(o))->longopt)
#define IXTAG(ix) (((ix)&0xff) | (((ix)&~0xff) << 2) | 0x200)
#define TAGIX(tag) (((tag)&0xff) | (((tag)&~0x3ff) >> 2))
opt_v opt; /* options */
extra_v extra; /* option extra data */
};
-#define OPTBUILD_INIT { DSTR_INIT, 0, DA_INIT, DA_INIT }
+#define OPTBUILD_INIT { DSTR_INIT, 0, DA_INIT, DA_INIT, DA_INIT }
-static PyObject *mdwopt_pynew(PyTypeObject *cls, PyObject *arg, PyObject *kw)
+static PyObject *mdwopt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
{
PyObject *argvobj = 0, *longoptobj = 0;
PyObject *it = 0, *t = 0, *u = 0;
if (n < 3)
opt->has_arg = 0;
else {
- u = PySequence_GetItem(t, 0); if (!u) goto end;
- if (convint(u, &opt->has_arg)) goto end;
+ u = PySequence_GetItem(t, 2); if (!u) goto end;
+ if (!convint(u, &opt->has_arg)) goto end;
Py_DECREF(u); u = 0;
}
}
/* Allocate the state value. */
- t = PyBaseObject_Type.tp_alloc(&PyBaseObject_Type, 0);
- if (!t) goto end;
+ t = optstate_pywrap(optstate_pytype); if (!t) goto end;
/* Allocate our return value. */
- me = (mdwopt_pyobj *)cls->tp_alloc(cls, 0);
+ me = (mdwopt_pyobj *)ty->tp_alloc(ty, 0);
me->state = t; t = 0;
me->flags = flags;
me->narg = build.narg;
COPYTAB(extra, DA(&build.extra), DA_LEN(&build.extra));
/* Fill in the `argv' vector. */
- me->argv = xmalloc(build.narg*sizeof(*me->argv));
+ me->argv = xmalloc((build.narg + 1)*sizeof(*me->argv));
for (i = 0; i < build.narg; i++)
- me->argv[i] = me->stringdata + DA(&build.off)[i + 1];
+ me->argv[i] = me->stringdata + DA(&build.off)[i];
me->argv[build.narg] = 0;
/* Fix up the string pointers and values in the long-options table. */
for (i = 0; i < me->nlong; i++) {
me->longopt[i].name =
- me->stringdata + DA(&build.off)[i + build.narg + 1];
+ me->stringdata + DA(&build.off)[i + build.narg];
me->longopt[i].val = IXTAG(i);
}
} else {
if (m->extra[ix].attr == Py_None)
{ val = m->extra[ix].tag; Py_INCREF(val); }
- else if (m->longopt[ix].has_arg&OPTF_SWITCH) {
- t = PyObject_GetAttr(m->state, m->extra[ix].attr);
- if (!t && PyErr_ExceptionMatches(PyExc_AttributeError)) {
- PyErr_Clear();
- t = PyInt_FromLong(0); if (!t) goto end;
+ else {
+ if (m->longopt[ix].has_arg&OPTF_SWITCH) {
+ t = PyObject_GetAttr(m->state, m->extra[ix].attr);
+ if (!t && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ t = PyInt_FromLong(0); if (!t) goto end;
+ }
+ if (!f)
+ { v = PyNumber_Or(t, m->extra[ix].tag); if (!v) goto end; }
+ else {
+ u = PyNumber_Invert(m->extra[ix].tag); if (!u) goto end;
+ v = PyNumber_And(t, u); if (!v) goto end;
+ }
+ if (PyObject_SetAttr(m->state, m->extra[ix].attr, v)) goto end;
+ Py_DECREF(t); t = 0;
+ Py_XDECREF(u); u = 0;
+ Py_DECREF(v); v = 0;
+ } else {
+ if (PyObject_SetAttr(m->state, m->extra[ix].attr,
+ f ?
+ Py_None :
+ m->longopt[ix].has_arg&OPTF_ARG ?
+ arg : m->extra[ix].tag))
+ goto end;
}
- if (!f)
- { v = PyNumber_Or(t, m->extra[ix].tag); if (!v) goto end; }
- else {
- u = PyNumber_Invert(m->extra[ix].tag); if (!u) goto end;
- v = PyNumber_And(t, u); if (!v) goto end;
- }
- if (PyObject_SetAttr(m->state, m->extra[ix].attr, v)) goto end;
- Py_DECREF(t); Py_XDECREF(u); Py_DECREF(v);
- } else {
- if (PyObject_SetAttr(m->state, m->extra[ix].attr,
- f ?
- Py_None :
- m->longopt[ix].has_arg&OPTF_ARG ?
- arg : m->extra[ix].tag))
- goto end;
+ Py_DECREF(arg); arg = 0;
+ goto again;
}
- Py_DECREF(arg);
- goto again;
}
rc = Py_BuildValue("(OOi)", val, arg, f);
/*----- Main code ---------------------------------------------------------*/
+static const struct nameval consts[] = {
+ CONST(OPTF_NOARG), CONST(OPTF_ARGREQ), CONST(OPTF_ARGOPT), CONST(OPTF_ARG),
+ CONST(OPTF_SWITCH), CONST(OPTF_NEGATE),
+ CONST(OPTF_NOLONGS), CONST(OPTF_NOSHORTS), CONST(OPTF_NUMBERS),
+ CONST(OPTF_NEGATION), CONST(OPTF_ENVVAR), CONST(OPTF_NOPROGNAME),
+ CONST(OPTF_NEGNUMBER),
+ CONST(OPTF_NEGATED)
+};
+
static const PyMethodDef methods[] = {
#define METHNAME(name) meth_##name
METH (ego, "ego(PROG): set program name")
void ui_pyinit(void)
{
+ INITTYPE(optstate, root);
INITTYPE(mdwopt, root);
addmethods(methods);
}
void ui_pyinsert(PyObject *mod)
{
+ INSERT("OptState", optstate_pytype);
INSERT("MdwOpt", mdwopt_pytype);
+ setconstants(mod, consts);
}
int ui_pyready(void) { return (set_program_name()); }