key.c: Complain about duplicate subkeys passed to `KeyDataStructured'.
[catacomb-python] / key.c
diff --git a/key.c b/key.c
index 0707edc..017c973 100644 (file)
--- a/key.c
+++ b/key.c
@@ -1015,46 +1015,48 @@ static const gmap_ops keydatastruct_gmops = {
   keydatastruct_gmdelentry
 };
 
+static int populate_struct(key_data *kd, PyObject *map)
+{
+  PyObject *it = 0, *name = 0, *val = 0;
+  const char *p;
+  int rc = -1;
+
+  if (!PyMapping_Check(map)) TYERR("subkeys must be an iterable mapping");
+  if ((it = PyObject_GetIter(map)) == 0) goto end;
+  while ((name = PyIter_Next(it)) != 0) {
+    if ((p = TEXT_STR(name)) == 0 ||
+       (val = PyObject_GetItem(map, name)) == 0)
+      goto end;
+    if (!KEYDATA_PYCHECK(val))
+      TYERR("subkey objects must be instances of KeyData");
+    if (key_structfind(kd, p)) VALERR("duplicate tag");
+    key_structset(kd, p, KEYDATA_KD(val));
+    Py_DECREF(name); name = 0;
+    Py_DECREF(val); val = 0;
+  }
+  if (PyErr_Occurred()) goto end;
+  rc = 0;
+end:
+  Py_XDECREF(it); Py_XDECREF(name); Py_XDECREF(val);
+  return (rc);
+}
+
 static PyObject *keydatastruct_pynew(PyTypeObject *ty,
                                     PyObject *arg, PyObject *kw)
 {
   PyObject *sub = 0;
-  PyObject *it = 0, *name = 0, *val = 0;
-  char *p;
   keydata_pyobj *me = 0;
   key_data *kd = 0;
-  static const char *const kwlist[] = { "subkeys", 0 };
 
-  Py_XINCREF(arg); Py_XINCREF(kw);
-  if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", KWLIST, &sub))
-    goto end;
+  if (!PyArg_ParseTuple(arg, "|O:new", &sub)) goto end;
   kd = key_newstruct();
-  if (sub) {
-    if (!PyMapping_Check(sub))
-      TYERR("subkeys must be an iterable mapping");
-    if ((it = PyObject_GetIter(sub)) == 0)
-      goto end;
-    while ((name = PyIter_Next(it)) != 0) {
-      if ((p = TEXT_STR(name)) == 0 ||
-         (val = PyObject_GetItem(sub, name)) == 0)
-       goto end;
-      if (!KEYDATA_PYCHECK(val))
-       TYERR("subkey objects must be subclasses of KeyData");
-      key_structset(kd, p, KEYDATA_KD(val));
-      Py_DECREF(name); name = 0;
-      Py_DECREF(val); val = 0;
-    }
-    if (PyErr_Occurred())
-      goto end;
-    Py_DECREF(it); it = 0;
-  }
+  if (sub && populate_struct(kd, sub)) goto end;
+  if (kw && populate_struct(kd, kw)) goto end;
   me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
   me->gmops = &keydatastruct_gmops;
-  me->kd = kd;
+  me->kd = kd; kd = 0;
 end:
-  if (kd && !me) key_drop(kd);
-  Py_XDECREF(name); Py_XDECREF(val); Py_XDECREF(it);
-  Py_XDECREF(arg); Py_XDECREF(kw);
+  if (kd) key_drop(kd);
   return ((PyObject *)me);
 }
 
@@ -1646,7 +1648,6 @@ static PyObject *keyfile_pynew(PyTypeObject *ty,
   keyfile_pyobj *rc = 0;
   static const char *const kwlist[] = { "file", "how", "report", 0 };
 
-  Py_XINCREF(arg); Py_XINCREF(kw);
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|iO:new", KWLIST,
                                   &file, &how, &ri.func))
     goto end;
@@ -1669,7 +1670,6 @@ end:
     rc = 0;
   }
 done:
-  Py_XDECREF(arg); Py_XDECREF(kw);
   return ((PyObject *)rc);
 }
 
@@ -1702,7 +1702,6 @@ static PyObject *kfmeth_mergeline(PyObject *me, PyObject *arg, PyObject *kw)
   int lno, rc;
   static const char *const kwlist[] = { "name", "lno", "line", "report", 0 };
 
-  Py_XINCREF(arg); Py_XINCREF(kw);
   if (!PyArg_ParseTupleAndKeywords(arg, kw, "sis|O:merge", KWLIST,
                                   &file, &lno, &line, &ri.func))
     goto end;
@@ -1713,11 +1712,9 @@ static PyObject *kfmeth_mergeline(PyObject *me, PyObject *arg, PyObject *kw)
     goto end;
   if (rc != 0)
     KEYERR(rc);
-  Py_XDECREF(arg); Py_XDECREF(kw);
   RETURN_ME;
 
 end:
-  Py_XDECREF(arg); Py_XDECREF(kw);
   return (0);
 }