source: trunk/ext/_syckmodule.c @ 17

Revision 17, 65.3 KB checked in by xi, 9 years ago (diff)

Add _syck.Emitter (finally closes #19).

Line 
1
2#include <Python.h>
3#include <syck.h>
4
5/****************************************************************************
6 * Python 2.2 compatibility.
7 ****************************************************************************/
8
9#ifndef PyDoc_STR
10#define PyDoc_VAR(name)         static char name[]
11#define PyDoc_STR(str)          (str)
12#define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str)
13#endif
14
15#ifndef PyMODINIT_FUNC
16#define PyMODINIT_FUNC  void
17#endif
18
19/****************************************************************************
20 * Global objects: _syck.error, 'scalar', 'seq', 'map',
21 * '1quote', '2quote', 'fold', 'literal', 'plain', '+', '-'.
22 ****************************************************************************/
23
24static PyObject *PySyck_Error;
25
26static PyObject *PySyck_ScalarKind;
27static PyObject *PySyck_SeqKind;
28static PyObject *PySyck_MapKind;
29
30static PyObject *PySyck_1QuoteStyle;
31static PyObject *PySyck_2QuoteStyle;
32static PyObject *PySyck_FoldStyle;
33static PyObject *PySyck_LiteralStyle;
34static PyObject *PySyck_PlainStyle;
35
36static PyObject *PySyck_StripChomp;
37static PyObject *PySyck_KeepChomp;
38
39/****************************************************************************
40 * The type _syck.Node.
41 ****************************************************************************/
42
43PyDoc_STRVAR(PySyckNode_doc,
44    "_syck.Node() -> TypeError\n\n"
45    "_syck.Node is an abstract type. It is a base type for _syck.Scalar,\n"
46    "_syck.Seq, and _syck.Map. You cannot create an instance of _syck.Node\n"
47    "directly. You may use _syck.Node for type checking or subclassing.\n");
48
49typedef struct {
50    PyObject_HEAD
51    /* Common fields for all Node types: */
52    PyObject *value;    /* always an object */
53    PyObject *tag;      /* a string object or NULL */
54    PyObject *anchor;   /* a string object or NULL */
55} PySyckNodeObject;
56
57
58static int
59PySyckNode_clear(PySyckNodeObject *self)
60{
61    PyObject *tmp;
62
63    tmp = self->value;
64    self->value = NULL;
65    Py_XDECREF(tmp);
66
67    tmp = self->tag;
68    self->tag = NULL;
69    Py_XDECREF(tmp);
70
71    tmp = self->anchor;
72    self->value = NULL;
73    Py_XDECREF(tmp);
74
75    return 0;
76}
77
78static int
79PySyckNode_traverse(PySyckNodeObject *self, visitproc visit, void *arg)
80{
81    int ret;
82
83    if (self->value)
84        if ((ret = visit(self->value, arg)) != 0)
85            return ret;
86
87    if (self->tag)
88        if ((ret = visit(self->tag, arg)) != 0)
89            return ret;
90
91    if (self->anchor)
92        if ((ret = visit(self->anchor, arg)) != 0)
93            return ret;
94
95    return 0;
96}
97
98static void
99PySyckNode_dealloc(PySyckNodeObject *self)
100{
101    PySyckNode_clear(self);
102    self->ob_type->tp_free((PyObject *)self);
103}
104
105static PyObject *
106PySyckNode_getkind(PySyckNodeObject *self, PyObject **closure)
107{
108    Py_INCREF(*closure);
109    return *closure;
110}
111
112static PyObject *
113PySyckNode_getvalue(PySyckNodeObject *self, void *closure)
114{
115    Py_INCREF(self->value);
116    return self->value;
117}
118
119static PyObject *
120PySyckNode_gettag(PySyckNodeObject *self, void *closure)
121{
122    PyObject *value = self->tag ? self->tag : Py_None;
123    Py_INCREF(value);
124    return value;
125}
126
127static int
128PySyckNode_settag(PySyckNodeObject *self, PyObject *value, void *closure)
129{
130    if (!value) {
131        PyErr_SetString(PyExc_TypeError, "cannot delete 'tag'");
132        return -1;
133    }
134
135    if (value == Py_None) {
136        Py_XDECREF(self->tag);
137        self->tag = NULL;
138        return 0;
139    }
140
141    if (!PyString_Check(value)) {
142        PyErr_SetString(PyExc_TypeError, "'tag' must be a string");
143        return -1;
144    }
145
146    Py_XDECREF(self->tag);
147    Py_INCREF(value);
148    self->tag = value;
149
150    return 0;
151}
152
153static PyObject *
154PySyckNode_getanchor(PySyckNodeObject *self, void *closure)
155{
156    PyObject *value = self->anchor ? self->anchor : Py_None;
157    Py_INCREF(value);
158    return value;
159}
160
161static int
162PySyckNode_setanchor(PySyckNodeObject *self, PyObject *value, void *closure)
163{
164    if (!value) {
165        PyErr_SetString(PyExc_TypeError, "cannot delete 'anchor'");
166        return -1;
167    }
168
169    if (value == Py_None) {
170        Py_XDECREF(self->anchor);
171        self->anchor = NULL;
172        return 0;
173    }
174
175    if (!PyString_Check(value)) {
176        PyErr_SetString(PyExc_TypeError, "'anchor' must be a string");
177        return -1;
178    }
179
180    Py_XDECREF(self->anchor);
181    Py_INCREF(value);
182    self->anchor = value;
183
184    return 0;
185}
186
187static PyTypeObject PySyckNode_Type = {
188    PyObject_HEAD_INIT(NULL)
189    0,                                          /* ob_size */
190    "_syck.Node",                               /* tp_name */
191    sizeof(PySyckNodeObject),                   /* tp_basicsize */
192    0,                                          /* tp_itemsize */
193    (destructor)PySyckNode_dealloc,             /* tp_dealloc */
194    0,                                          /* tp_print */
195    0,                                          /* tp_getattr */
196    0,                                          /* tp_setattr */
197    0,                                          /* tp_compare */
198    0,                                          /* tp_repr */
199    0,                                          /* tp_as_number */
200    0,                                          /* tp_as_sequence */
201    0,                                          /* tp_as_mapping */
202    0,                                          /* tp_hash */
203    0,                                          /* tp_call */
204    0,                                          /* tp_str */
205    0,                                          /* tp_getattro */
206    0,                                          /* tp_setattro */
207    0,                                          /* tp_as_buffer */
208    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,  /* tp_flags */
209    PySyckNode_doc,                             /* tp_doc */
210    (traverseproc)PySyckNode_traverse,          /* tp_traverse */
211    (inquiry)PySyckNode_clear,                  /* tp_clear */
212};
213
214/****************************************************************************
215 * The type _syck.Scalar.
216 ****************************************************************************/
217
218PyDoc_STRVAR(PySyckScalar_doc,
219    "Scalar(value='', tag=None, style=None, indent=0, width=0, chomp=None)\n"
220    "      -> a Scalar node\n\n"
221    "_syck.Scalar represents a scalar node in Syck parser and emitter\n"
222    "graphs. A scalar node points to a single string value.\n");
223
224typedef struct {
225    PyObject_HEAD
226    /* Common fields for all Node types: */
227    PyObject *value;    /* always a string object */
228    PyObject *tag;      /* a string object or NULL */
229    PyObject *anchor;   /* a string object or NULL */
230    /* Scalar-specific fields: */
231    enum scalar_style style;
232    int indent;
233    int width;
234    char chomp;
235} PySyckScalarObject;
236
237static PyObject *
238PySyckScalar_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
239{
240    PySyckScalarObject *self;
241
242    self = (PySyckScalarObject *)type->tp_alloc(type, 0);
243    if (!self) return NULL;
244
245    self->value = PyString_FromString("");
246    if (!self->value) {
247        Py_DECREF(self);
248        return NULL;
249    }
250
251    self->tag = NULL;
252    self->anchor = NULL;
253    self->style = scalar_none;
254    self->indent = 0;
255    self->width = 0;
256    self->chomp = 0;
257
258    return (PyObject *)self;
259}
260
261static int
262PySyckScalar_setvalue(PySyckScalarObject *self, PyObject *value, void *closure)
263{
264    if (!value) {
265        PyErr_SetString(PyExc_TypeError, "cannot delete 'value'");
266        return -1;
267    }
268    if (!PyString_Check(value)) {
269        PyErr_SetString(PyExc_TypeError, "'value' must be a string");
270        return -1;
271    }
272
273    Py_DECREF(self->value);
274    Py_INCREF(value);
275    self->value = value;
276
277    return 0;
278}
279
280static PyObject *
281PySyckScalar_getstyle(PySyckScalarObject *self, void *closure)
282{
283    PyObject *value;
284
285    switch (self->style) {
286        case scalar_1quote: value = PySyck_1QuoteStyle; break;
287        case scalar_2quote: value = PySyck_2QuoteStyle; break;
288        case scalar_fold: value = PySyck_FoldStyle; break;
289        case scalar_literal: value = PySyck_LiteralStyle; break;
290        case scalar_plain: value = PySyck_PlainStyle; break;
291        default: value = Py_None;
292    }
293
294    Py_INCREF(value);
295    return value;
296}
297
298static int
299PySyckScalar_setstyle(PySyckScalarObject *self, PyObject *value, void *closure)
300{
301    char *str;
302
303    if (!value) {
304        PyErr_SetString(PyExc_TypeError, "cannot delete 'style'");
305        return -1;
306    }
307
308    if (value == Py_None) {
309        self->style = scalar_none;
310        return 0;
311    }
312
313    if (!PyString_Check(value)) {
314        PyErr_SetString(PyExc_TypeError, "'style' must be a string or None");
315        return -1;
316    }
317
318    str = PyString_AsString(value);
319    if (!str) return -1;
320
321    if (strcmp(str, "1quote") == 0)
322        self->style = scalar_1quote;
323    else if (strcmp(str, "2quote") == 0)
324        self->style = scalar_2quote;
325    else if (strcmp(str, "fold") == 0)
326        self->style = scalar_fold;
327    else if (strcmp(str, "literal") == 0)
328        self->style = scalar_literal;
329    else if (strcmp(str, "plain") == 0)
330        self->style = scalar_plain;
331    else {
332        PyErr_SetString(PyExc_ValueError, "unknown 'style'");
333        return -1;
334    }
335
336    return 0;
337}
338
339static PyObject *
340PySyckScalar_getindent(PySyckScalarObject *self, void *closure)
341{
342    return PyInt_FromLong(self->indent);
343}
344
345static int
346PySyckScalar_setindent(PySyckScalarObject *self, PyObject *value, void *closure)
347{
348    if (!value) {
349        PyErr_SetString(PyExc_TypeError, "cannot delete 'indent'");
350        return -1;
351    }
352
353    if (!PyInt_Check(value)) {
354        PyErr_SetString(PyExc_TypeError, "'indent' must be an integer");
355        return -1;
356    }
357
358    self->indent = PyInt_AS_LONG(value);
359
360    return 0;
361}
362
363static PyObject *
364PySyckScalar_getwidth(PySyckScalarObject *self, void *closure)
365{
366    return PyInt_FromLong(self->width);
367}
368
369static int
370PySyckScalar_setwidth(PySyckScalarObject *self, PyObject *value, void *closure)
371{
372    if (!value) {
373        PyErr_SetString(PyExc_TypeError, "cannot delete 'width'");
374        return -1;
375    }
376
377    if (!PyInt_Check(value)) {
378        PyErr_SetString(PyExc_TypeError, "'width' must be an integer");
379        return -1;
380    }
381
382    self->width = PyInt_AS_LONG(value);
383
384    return 0;
385}
386
387static PyObject *
388PySyckScalar_getchomp(PySyckScalarObject *self, void *closure)
389{
390    PyObject *value;
391
392    switch (self->chomp) {
393        case NL_CHOMP: value = PySyck_StripChomp; break;
394        case NL_KEEP: value = PySyck_KeepChomp; break;
395        default: value = Py_None;
396    }
397
398    Py_INCREF(value);
399    return value;
400}
401
402static int
403PySyckScalar_setchomp(PySyckScalarObject *self, PyObject *value, void *closure)
404{
405    char *str;
406
407    if (!value) {
408        PyErr_SetString(PyExc_TypeError, "cannot delete 'chomp'");
409        return -1;
410    }
411
412    if (value == Py_None) {
413        self->chomp = 0;
414        return 0;
415    }
416
417    if (!PyString_Check(value)) {
418        PyErr_SetString(PyExc_TypeError, "'chomp' must be '+', '-', or None");
419        return -1;
420    }
421
422    str = PyString_AsString(value);
423    if (!str) return -1;
424
425    if (strcmp(str, "-") == 0)
426        self->chomp = NL_CHOMP;
427    else if (strcmp(str, "+") == 0)
428        self->chomp = NL_KEEP;
429    else {
430        PyErr_SetString(PyExc_TypeError, "'chomp' must be '+', '-', or None");
431        return -1;
432    }
433
434    return 0;
435}
436
437static int
438PySyckScalar_init(PySyckScalarObject *self, PyObject *args, PyObject *kwds)
439{
440    PyObject *value = NULL;
441    PyObject *tag = NULL;
442    PyObject *anchor = NULL;
443    PyObject *style = NULL;
444    PyObject *indent = NULL;
445    PyObject *width = NULL;
446    PyObject *chomp = NULL;
447
448    static char *kwdlist[] = {"value", "tag", "anchor",
449        "style", "indent", "width", "chomp", NULL};
450
451    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOOO", kwdlist,
452                &value, &tag, &anchor, &style, &indent, &width, &chomp))
453        return -1;
454
455    if (value && PySyckScalar_setvalue(self, value, NULL) < 0)
456        return -1;
457
458    if (tag && PySyckNode_settag((PySyckNodeObject *)self, tag, NULL) < 0)
459        return -1;
460
461    if (anchor && PySyckNode_setanchor((PySyckNodeObject *)self, anchor, NULL) < 0)
462        return -1;
463
464    if (style && PySyckScalar_setstyle(self, style, NULL) < 0)
465        return -1;
466
467    if (indent && PySyckScalar_setindent(self, indent, NULL) < 0)
468        return -1;
469
470    if (width && PySyckScalar_setwidth(self, width, NULL) < 0)
471        return -1;
472
473    if (chomp && PySyckScalar_setchomp(self, chomp, NULL) < 0)
474        return -1;
475
476    return 0;
477}
478
479static PyGetSetDef PySyckScalar_getsetters[] = {
480    {"kind", (getter)PySyckNode_getkind, NULL,
481        PyDoc_STR("the node kind, always 'scalar', read-only"),
482        &PySyck_ScalarKind},
483    {"value", (getter)PySyckNode_getvalue, (setter)PySyckScalar_setvalue,
484        PyDoc_STR("the node value, a string"), NULL},
485    {"tag", (getter)PySyckNode_gettag, (setter)PySyckNode_settag,
486        PyDoc_STR("the node tag, a string or None"), NULL},
487    {"anchor", (getter)PySyckNode_getanchor, (setter)PySyckNode_setanchor,
488        PyDoc_STR("the node anchor, a string or None"), NULL},
489    {"style", (getter)PySyckScalar_getstyle, (setter)PySyckScalar_setstyle,
490        PyDoc_STR("the node style, values: None (means literal or plain),\n"
491            "'1quote', '2quote', 'fold', 'literal', 'plain'"), NULL},
492    {"indent", (getter)PySyckScalar_getindent, (setter)PySyckScalar_setindent,
493        PyDoc_STR("the node indentation, an integer"), NULL},
494    {"width", (getter)PySyckScalar_getwidth, (setter)PySyckScalar_setwidth,
495        PyDoc_STR("the node width, an integer"), NULL},
496    {"chomp", (getter)PySyckScalar_getchomp, (setter)PySyckScalar_setchomp,
497        PyDoc_STR("the chomping method,\n"
498            "values: None (clip), '-' (strip), or '+' (keep)"), NULL},
499    {NULL}  /* Sentinel */
500};
501
502static PyTypeObject PySyckScalar_Type = {
503    PyObject_HEAD_INIT(NULL)
504    0,                                          /* ob_size */
505    "_syck.Scalar",                             /* tp_name */
506    sizeof(PySyckScalarObject),                 /* tp_basicsize */
507    0,                                          /* tp_itemsize */
508    0,                                          /* tp_dealloc */
509    0,                                          /* tp_print */
510    0,                                          /* tp_getattr */
511    0,                                          /* tp_setattr */
512    0,                                          /* tp_compare */
513    0,                                          /* tp_repr */
514    0,                                          /* tp_as_number */
515    0,                                          /* tp_as_sequence */
516    0,                                          /* tp_as_mapping */
517    0,                                          /* tp_hash */
518    0,                                          /* tp_call */
519    0,                                          /* tp_str */
520    0,                                          /* tp_getattro */
521    0,                                          /* tp_setattro */
522    0,                                          /* tp_as_buffer */
523    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,     /* tp_flags */
524    PySyckScalar_doc,                           /* tp_doc */
525    0,                                          /* tp_traverse */
526    0,                                          /* tp_clear */
527    0,                                          /* tp_richcompare */
528    0,                                          /* tp_weaklistoffset */
529    0,                                          /* tp_iter */
530    0,                                          /* tp_iternext */
531    0,                                          /* tp_methods */
532    0,                                          /* tp_members */
533    PySyckScalar_getsetters,                    /* tp_getset */
534    &PySyckNode_Type,                           /* tp_base */
535    0,                                          /* tp_dict */
536    0,                                          /* tp_descr_get */
537    0,                                          /* tp_descr_set */
538    0,                                          /* tp_dictoffset */
539    (initproc)PySyckScalar_init,                /* tp_init */
540    0,                                          /* tp_alloc */
541    PySyckScalar_new,                           /* tp_new */
542};
543
544/****************************************************************************
545 * The type _syck.Seq.
546 ****************************************************************************/
547
548PyDoc_STRVAR(PySyckSeq_doc,
549    "Seq(value=[], tag=None, inline=False) -> a Seq node\n\n"
550    "_syck.Seq represents a sequence node in Syck parser and emitter\n"
551    "graphs. A sequence node points to an ordered set of subnodes.\n");
552
553typedef struct {
554    PyObject_HEAD
555    /* Common fields for all Node types: */
556    PyObject *value;    /* always an object */
557    PyObject *tag;      /* a string object or NULL */
558    PyObject *anchor;   /* a string object or NULL */
559    /* Seq-specific fields: */
560    enum seq_style style;
561} PySyckSeqObject;
562
563static PyObject *
564PySyckSeq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
565{
566    PySyckSeqObject *self;
567
568    self = (PySyckSeqObject *)type->tp_alloc(type, 0);
569    if (!self) return NULL;
570
571    self->value = PyList_New(0);
572    if (!self->value) {
573        Py_DECREF(self);
574        return NULL;
575    }
576
577    self->tag = NULL;
578    self->anchor = NULL;
579    self->style = seq_none;
580
581    return (PyObject *)self;
582}
583
584static int
585PySyckSeq_setvalue(PySyckSeqObject *self, PyObject *value, void *closure)
586{
587    if (!value) {
588        PyErr_SetString(PyExc_TypeError, "cannot delete 'value'");
589        return -1;
590    }
591    if (!PyList_Check(value)) {
592        PyErr_SetString(PyExc_TypeError, "'value' must be a list");
593        return -1;
594    }
595
596    Py_DECREF(self->value);
597    Py_INCREF(value);
598    self->value = value;
599
600    return 0;
601}
602
603static PyObject *
604PySyckSeq_getinline(PySyckSeqObject *self, void *closure)
605{
606    PyObject *value = (self->style == seq_inline) ? Py_True : Py_False;
607
608    Py_INCREF(value);
609    return value;
610}
611
612static int
613PySyckSeq_setinline(PySyckSeqObject *self, PyObject *value, void *closure)
614{
615    if (!value) {
616        PyErr_SetString(PyExc_TypeError, "cannot delete 'inline'");
617        return -1;
618    }
619
620    if (!PyInt_Check(value)) {
621        PyErr_SetString(PyExc_TypeError, "'inline' must be a Boolean object");
622        return -1;
623    }
624
625    self->style = PyInt_AS_LONG(value) ? seq_inline : seq_none;
626
627    return 0;
628}
629
630static int
631PySyckSeq_init(PySyckSeqObject *self, PyObject *args, PyObject *kwds)
632{
633    PyObject *value = NULL;
634    PyObject *tag = NULL;
635    PyObject *anchor = NULL;
636    PyObject *inline_ = NULL;
637
638    static char *kwdlist[] = {"value", "tag", "anchor", "inline", NULL};
639
640    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwdlist,
641                &value, &tag, &anchor, &inline_))
642        return -1;
643
644    if (value && PySyckSeq_setvalue(self, value, NULL) < 0)
645        return -1;
646
647    if (tag && PySyckNode_settag((PySyckNodeObject *)self, tag, NULL) < 0)
648        return -1;
649
650    if (anchor && PySyckNode_setanchor((PySyckNodeObject *)self, anchor, NULL) < 0)
651        return -1;
652
653    if (inline_ && PySyckSeq_setinline(self, inline_, NULL) < 0)
654        return -1;
655
656    return 0;
657}
658
659static PyGetSetDef PySyckSeq_getsetters[] = {
660    {"kind", (getter)PySyckNode_getkind, NULL,
661        PyDoc_STR("the node kind, always 'seq', read-only"), &PySyck_SeqKind},
662    {"value", (getter)PySyckNode_getvalue, (setter)PySyckSeq_setvalue,
663        PyDoc_STR("the node value, a sequence"), NULL},
664    {"tag", (getter)PySyckNode_gettag, (setter)PySyckNode_settag,
665        PyDoc_STR("the node tag, a string or None"), NULL},
666    {"anchor", (getter)PySyckNode_getanchor, (setter)PySyckNode_setanchor,
667        PyDoc_STR("the node anchor, a string or None"), NULL},
668    {"inline", (getter)PySyckSeq_getinline, (setter)PySyckSeq_setinline,
669        PyDoc_STR("the block/flow flag"), NULL},
670    {NULL}  /* Sentinel */
671};
672
673static PyTypeObject PySyckSeq_Type = {
674    PyObject_HEAD_INIT(NULL)
675    0,                                          /* ob_size */
676    "_syck.Seq",                                /* tp_name */
677    sizeof(PySyckSeqObject),                    /* tp_basicsize */
678    0,                                          /* tp_itemsize */
679    0,                                          /* tp_dealloc */
680    0,                                          /* tp_print */
681    0,                                          /* tp_getattr */
682    0,                                          /* tp_setattr */
683    0,                                          /* tp_compare */
684    0,                                          /* tp_repr */
685    0,                                          /* tp_as_number */
686    0,                                          /* tp_as_sequence */
687    0,                                          /* tp_as_mapping */
688    0,                                          /* tp_hash */
689    0,                                          /* tp_call */
690    0,                                          /* tp_str */
691    0,                                          /* tp_getattro */
692    0,                                          /* tp_setattro */
693    0,                                          /* tp_as_buffer */
694    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,  /* tp_flags */
695    PySyckSeq_doc,                              /* tp_doc */
696    (traverseproc)PySyckNode_traverse,          /* tp_traverse */
697    (inquiry)PySyckNode_clear,                  /* tp_clear */
698    0,                                          /* tp_richcompare */
699    0,                                          /* tp_weaklistoffset */
700    0,                                          /* tp_iter */
701    0,                                          /* tp_iternext */
702    0,                                          /* tp_methods */
703    0,                                          /* tp_members */
704    PySyckSeq_getsetters,                       /* tp_getset */
705    &PySyckNode_Type,                           /* tp_base */
706    0,                                          /* tp_dict */
707    0,                                          /* tp_descr_get */
708    0,                                          /* tp_descr_set */
709    0,                                          /* tp_dictoffset */
710    (initproc)PySyckSeq_init,                   /* tp_init */
711    0,                                          /* tp_alloc */
712    PySyckSeq_new,                              /* tp_new */
713};
714
715/****************************************************************************
716 * The type _syck.Map.
717 ****************************************************************************/
718
719PyDoc_STRVAR(PySyckMap_doc,
720    "Map(value='', tag=None, inline=False) -> a Map node\n\n"
721    "_syck.Map represents a mapping node in Syck parser and emitter\n"
722    "graphs. A mapping node points to an unordered collections of pairs.\n");
723
724typedef struct {
725    PyObject_HEAD
726    /* Common fields for all Node types: */
727    PyObject *value;    /* always an object */
728    PyObject *tag;      /* a string object or NULL */
729    PyObject *anchor;   /* a string object or NULL */
730    /* Map-specific fields: */
731    enum map_style style;
732} PySyckMapObject;
733
734static PyObject *
735PySyckMap_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
736{
737    PySyckMapObject *self;
738
739    self = (PySyckMapObject *)type->tp_alloc(type, 0);
740    if (!self) return NULL;
741
742    self->value = PyDict_New();
743    if (!self->value) {
744        Py_DECREF(self);
745        return NULL;
746    }
747
748    self->tag = NULL;
749    self->anchor = NULL;
750    self->style = seq_none;
751
752    return (PyObject *)self;
753}
754
755static int
756PySyckMap_setvalue(PySyckMapObject *self, PyObject *value, void *closure)
757{
758    if (!value) {
759        PyErr_SetString(PyExc_TypeError, "cannot delete 'value'");
760        return -1;
761    }
762    if (!PyDict_Check(value) && !PyList_Check(value)) {
763        PyErr_SetString(PyExc_TypeError,
764                "'value' must be a list of pairs or a dictionary");
765        return -1;
766    }
767
768    Py_DECREF(self->value);
769    Py_INCREF(value);
770    self->value = value;
771
772    return 0;
773}
774
775static PyObject *
776PySyckMap_getinline(PySyckMapObject *self, void *closure)
777{
778    PyObject *value = (self->style == map_inline) ? Py_True : Py_False;
779
780    Py_INCREF(value);
781    return value;
782}
783
784static int
785PySyckMap_setinline(PySyckMapObject *self, PyObject *value, void *closure)
786{
787    if (!value) {
788        PyErr_SetString(PyExc_TypeError, "cannot delete 'inline'");
789        return -1;
790    }
791
792    if (!PyInt_Check(value)) {
793        PyErr_SetString(PyExc_TypeError, "'inline' must be a Boolean object");
794        return -1;
795    }
796
797    self->style = PyInt_AS_LONG(value) ? map_inline : map_none;
798
799    return 0;
800}
801
802static int
803PySyckMap_init(PySyckMapObject *self, PyObject *args, PyObject *kwds)
804{
805    PyObject *value = NULL;
806    PyObject *tag = NULL;
807    PyObject *anchor = NULL;
808    PyObject *inline_ = NULL;
809
810    static char *kwdlist[] = {"value", "tag", "anchor", "inline", NULL};
811
812    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwdlist,
813                &value, &tag, &anchor, &inline_))
814        return -1;
815
816    if (value && PySyckMap_setvalue(self, value, NULL) < 0)
817        return -1;
818
819    if (tag && PySyckNode_settag((PySyckNodeObject *)self, tag, NULL) < 0)
820        return -1;
821
822    if (anchor && PySyckNode_setanchor((PySyckNodeObject *)self, anchor, NULL) < 0)
823        return -1;
824
825    if (inline_ && PySyckMap_setinline(self, inline_, NULL) < 0)
826        return -1;
827
828    return 0;
829}
830
831static PyGetSetDef PySyckMap_getsetters[] = {
832    {"kind", (getter)PySyckNode_getkind, NULL,
833        PyDoc_STR("the node kind, always 'map', read-only"), &PySyck_MapKind},
834    {"value", (getter)PySyckNode_getvalue, (setter)PySyckMap_setvalue,
835        PyDoc_STR("the node value, a mapping"), NULL},
836    {"tag", (getter)PySyckNode_gettag, (setter)PySyckNode_settag,
837        PyDoc_STR("the node tag, a string or None"), NULL},
838    {"anchor", (getter)PySyckNode_getanchor, (setter)PySyckNode_setanchor,
839        PyDoc_STR("the node anchor, a string or None"), NULL},
840    {"inline", (getter)PySyckMap_getinline, (setter)PySyckMap_setinline,
841        PyDoc_STR("the block/flow flag"), NULL},
842    {NULL}  /* Sentinel */
843};
844
845static PyTypeObject PySyckMap_Type = {
846    PyObject_HEAD_INIT(NULL)
847    0,                                          /* ob_size */
848    "_syck.Map",                                /* tp_name */
849    sizeof(PySyckMapObject),                    /* tp_basicsize */
850    0,                                          /* tp_itemsize */
851    0,                                          /* tp_dealloc */
852    0,                                          /* tp_print */
853    0,                                          /* tp_getattr */
854    0,                                          /* tp_setattr */
855    0,                                          /* tp_compare */
856    0,                                          /* tp_repr */
857    0,                                          /* tp_as_number */
858    0,                                          /* tp_as_sequence */
859    0,                                          /* tp_as_mapping */
860    0,                                          /* tp_hash */
861    0,                                          /* tp_call */
862    0,                                          /* tp_str */
863    0,                                          /* tp_getattro */
864    0,                                          /* tp_setattro */
865    0,                                          /* tp_as_buffer */
866    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,  /* tp_flags */
867    PySyckMap_doc,                              /* tp_doc */
868    (traverseproc)PySyckNode_traverse,          /* tp_traverse */
869    (inquiry)PySyckNode_clear,                  /* tp_clear */
870    0,                                          /* tp_richcompare */
871    0,                                          /* tp_weaklistoffset */
872    0,                                          /* tp_iter */
873    0,                                          /* tp_iternext */
874    0,                                          /* tp_methods */
875    0,                                          /* tp_members */
876    PySyckMap_getsetters,                       /* tp_getset */
877    &PySyckNode_Type,                           /* tp_base */
878    0,                                          /* tp_dict */
879    0,                                          /* tp_descr_get */
880    0,                                          /* tp_descr_set */
881    0,                                          /* tp_dictoffset */
882    (initproc)PySyckMap_init,                   /* tp_init */
883    0,                                          /* tp_alloc */
884    PySyckMap_new,                              /* tp_new */
885};
886
887/****************************************************************************
888 * The type _syck.Parser.
889 ****************************************************************************/
890
891PyDoc_STRVAR(PySyckParser_doc,
892    "Parser(source, implicit_typing=True, taguri_expansion=True)\n"
893    "      -> a Parser object\n\n"
894    "_syck.Parser is a low-lever wrapper of the Syck parser. It parses\n"
895    "a YAML stream and produces a graph of Nodes.\n");
896
897typedef struct {
898    PyObject_HEAD
899    /* Attributes: */
900    PyObject *source;       /* a string or file-like object */
901    int implicit_typing;
902    int taguri_expansion;
903    /* Internal fields: */
904    PyObject *symbols;      /* symbol table, a list, NULL outside parse() */
905    SyckParser *parser;
906    int parsing;
907    int halt;
908} PySyckParserObject;
909
910static PyObject *
911PySyckParser_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
912{
913    PySyckParserObject *self;
914
915    self = (PySyckParserObject *)type->tp_alloc(type, 0);
916    if (!self) return NULL;
917
918    self->source = NULL;
919    self->implicit_typing = 0;
920    self->taguri_expansion = 0;
921    self->symbols = NULL;
922    self->parser = NULL;
923    self->parsing = 0;
924    self->halt = 1;
925
926    /*
927    self->symbols = PyList_New(0);
928    if (!self->symbols) {
929        Py_DECREF(self);
930        return NULL;
931    }
932    */
933
934    return (PyObject *)self;
935}
936
937static int
938PySyckParser_clear(PySyckParserObject *self)
939{
940    PyObject *tmp;
941
942    if (self->parser) {
943        syck_free_parser(self->parser);
944        self->parser = NULL;
945    }
946
947    tmp = self->source;
948    self->source = NULL;
949    Py_XDECREF(tmp);
950
951    tmp = self->symbols;
952    self->symbols = NULL;
953    Py_XDECREF(tmp);
954
955    return 0;
956}
957
958static int
959PySyckParser_traverse(PySyckParserObject *self, visitproc visit, void *arg)
960{
961    int ret;
962
963    if (self->source)
964        if ((ret = visit(self->source, arg)) != 0)
965            return ret;
966
967    if (self->symbols)
968        if ((ret = visit(self->symbols, arg)) != 0)
969            return ret;
970
971    return 0;
972}
973
974static void
975PySyckParser_dealloc(PySyckParserObject *self)
976{
977    PySyckParser_clear(self);
978    self->ob_type->tp_free((PyObject *)self);
979}
980
981static PyObject *
982PySyckParser_getsource(PySyckParserObject *self, void *closure)
983{
984    PyObject *value = self->source ? self->source : Py_None;
985
986    Py_INCREF(value);
987    return value;
988}
989
990static PyObject *
991PySyckParser_getimplicit_typing(PySyckParserObject *self, void *closure)
992{
993    PyObject *value = self->implicit_typing ? Py_True : Py_False;
994
995    Py_INCREF(value);
996    return value;
997}
998
999static PyObject *
1000PySyckParser_gettaguri_expansion(PySyckParserObject *self, void *closure)
1001{
1002    PyObject *value = self->taguri_expansion ? Py_True : Py_False;
1003
1004    Py_INCREF(value);
1005    return value;
1006}
1007
1008static PyObject *
1009PySyckParser_geteof(PySyckParserObject *self, void *closure)
1010{
1011    PyObject *value = self->halt ? Py_True : Py_False;
1012
1013    Py_INCREF(value);
1014    return value;
1015}
1016
1017static PyGetSetDef PySyckParser_getsetters[] = {
1018    {"source", (getter)PySyckParser_getsource, NULL,
1019        PyDoc_STR("IO source, a string or file-like object"), NULL},
1020    {"implicit_typing", (getter)PySyckParser_getimplicit_typing, NULL,
1021        PyDoc_STR("implicit typing of builtin YAML types"), NULL},
1022    {"taguri_expansion", (getter)PySyckParser_gettaguri_expansion, NULL,
1023        PyDoc_STR("expansion of types in full taguri"), NULL},
1024    {"eof", (getter)PySyckParser_geteof, NULL,
1025        PyDoc_STR("EOF flag"), NULL},
1026    {NULL}  /* Sentinel */
1027};
1028
1029static SYMID
1030PySyckParser_node_handler(SyckParser *parser, SyckNode *node)
1031{
1032    PySyckParserObject *self = (PySyckParserObject *)parser->bonus;
1033
1034    SYMID index;
1035    PySyckNodeObject *object = NULL;
1036
1037    PyObject *key, *value;
1038    int k;
1039
1040    if (self->halt)
1041        return -1;
1042
1043    switch (node->kind) {
1044
1045        case syck_str_kind:
1046            object = (PySyckNodeObject *)
1047                PySyckScalar_new(&PySyckScalar_Type, NULL, NULL);
1048            if (!object) goto error;
1049            value = PyString_FromStringAndSize(node->data.str->ptr,
1050                    node->data.str->len);
1051            if (!value) goto error;
1052            Py_DECREF(object->value);
1053            object->value = value;
1054            break;
1055
1056        case syck_seq_kind:
1057            object = (PySyckNodeObject *)
1058                PySyckSeq_new(&PySyckSeq_Type, NULL, NULL);
1059            if (!object) goto error;
1060            for (k = 0; k < node->data.list->idx; k++) {
1061                index = syck_seq_read(node, k);
1062                value = PyList_GetItem(self->symbols, index);
1063                if (!value) goto error;
1064                if (PyList_Append(object->value, value) < 0)
1065                    goto error;
1066            }
1067            break;
1068
1069        case syck_map_kind:
1070            object = (PySyckNodeObject *)
1071                PySyckMap_new(&PySyckMap_Type, NULL, NULL);
1072            if (!object) goto error;
1073            for (k = 0; k < node->data.pairs->idx; k++)
1074            {
1075                index = syck_map_read(node, map_key, k);
1076                key = PyList_GetItem(self->symbols, index);
1077                if (!key) goto error;
1078                index = syck_map_read(node, map_value, k);
1079                value = PyList_GetItem(self->symbols, index);
1080                if (!value) goto error;
1081                if (PyDict_SetItem(object->value, key, value) < 0)
1082                    goto error;
1083            }
1084            break;
1085    }
1086
1087    if (node->type_id) {
1088        object->tag = PyString_FromString(node->type_id);
1089        if (!object->tag) goto error;
1090    }
1091
1092    if (node->anchor) {
1093        object->anchor = PyString_FromString(node->anchor);
1094        if (!object->anchor) goto error;
1095    }
1096
1097    if (PyList_Append(self->symbols, (PyObject *)object) < 0)
1098        goto error;
1099
1100    index = PyList_GET_SIZE(self->symbols)-1;
1101    return index;
1102
1103error:
1104    Py_XDECREF(object);
1105    self->halt = 1;
1106    return -1;
1107}
1108
1109static void
1110PySyckParser_error_handler(SyckParser *parser, char *str)
1111{
1112    PySyckParserObject *self = (PySyckParserObject *)parser->bonus;
1113    PyObject *value;
1114
1115    if (self->halt) return;
1116
1117    self->halt = 1;
1118
1119    value = Py_BuildValue("(sii)", str,
1120            parser->linect, parser->cursor - parser->lineptr);
1121    if (value) {
1122        PyErr_SetObject(PySyck_Error, value);
1123    }
1124}
1125
1126SyckNode *
1127PySyckParser_bad_anchor_handler(SyckParser *parser, char *anchor)
1128{
1129    PySyckParserObject *self = (PySyckParserObject *)parser->bonus;
1130
1131    if (!self->halt) {
1132        self->halt = 1;
1133        PyErr_SetString(PyExc_TypeError, "recursive anchors are not implemented");
1134    }
1135
1136    return syck_alloc_str();
1137}
1138
1139static long
1140PySyckParser_read_handler(char *buf, SyckIoFile *file, long max_size, long skip)
1141{
1142    PySyckParserObject *self = (PySyckParserObject *)file->ptr;
1143
1144    PyObject *value;
1145
1146    char *str;
1147    int length;
1148
1149    buf[skip] = '\0';
1150
1151    if (self->halt) {
1152        return skip;
1153    }
1154   
1155    max_size -= skip;
1156
1157    value = PyObject_CallMethod(self->source, "read", "(i)", max_size);
1158    if (!value) {
1159        self->halt = 1;
1160        return skip;
1161    }
1162
1163    if (!PyString_CheckExact(value)) {
1164        Py_DECREF(value);
1165        PyErr_SetString(PyExc_TypeError, "file-like object should return a string");
1166        self->halt = 1;
1167       
1168        return skip;
1169    }
1170
1171    str = PyString_AS_STRING(value);
1172    length = PyString_GET_SIZE(value);
1173    if (!length) {
1174        Py_DECREF(value);
1175        return skip;
1176    }
1177
1178    if (length > max_size) {
1179        Py_DECREF(value);
1180        PyErr_SetString(PyExc_ValueError, "read returns an overly long string");
1181        self->halt = 1;
1182        return skip;
1183    }
1184
1185    memcpy(buf+skip, str, length);
1186    length += skip;
1187    buf[length] = '\0';
1188
1189    Py_DECREF(value);
1190
1191    return length;
1192}
1193
1194static int
1195PySyckParser_init(PySyckParserObject *self, PyObject *args, PyObject *kwds)
1196{
1197    PyObject *source = NULL;
1198    int implicit_typing = 1;
1199    int taguri_expansion = 1;
1200
1201    static char *kwdlist[] = {"source", "implicit_typing", "taguri_expansion",
1202        NULL};
1203
1204    PySyckParser_clear(self);
1205
1206    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ii", kwdlist,
1207                &source, &implicit_typing, &taguri_expansion))
1208        return -1;
1209
1210    Py_INCREF(source);
1211    self->source = source;
1212
1213    self->implicit_typing = implicit_typing;
1214    self->taguri_expansion = taguri_expansion;
1215
1216    self->parser = syck_new_parser();
1217    self->parser->bonus = self;
1218
1219    if (PyString_CheckExact(self->source)) {
1220        syck_parser_str(self->parser,
1221                PyString_AS_STRING(self->source),
1222                PyString_GET_SIZE(self->source), NULL);
1223    }
1224    /*
1225    else if (PyUnicode_CheckExact(self->source)) {
1226        syck_parser_str(self->parser,
1227                PyUnicode_AS_DATA(self->source),
1228                PyString_GET_DATA_SIZE(self->source), NULL);
1229    }
1230    */
1231    else {
1232        syck_parser_file(self->parser, (FILE *)self, PySyckParser_read_handler);
1233    }
1234
1235    syck_parser_implicit_typing(self->parser, self->implicit_typing);
1236    syck_parser_taguri_expansion(self->parser, self->taguri_expansion);
1237
1238    syck_parser_handler(self->parser, PySyckParser_node_handler);
1239    syck_parser_error_handler(self->parser, PySyckParser_error_handler);
1240    syck_parser_bad_anchor_handler(self->parser, PySyckParser_bad_anchor_handler);
1241
1242    self->parsing = 0;
1243    self->halt = 0;
1244
1245    return 0;
1246}
1247
1248static PyObject *
1249PySyckParser_parse(PySyckParserObject *self)
1250{
1251    SYMID index;
1252    PyObject *value;
1253
1254    if (self->parsing) {
1255        PyErr_SetString(PyExc_RuntimeError, "do not call Parser.parse while it is already parsing");
1256        return NULL;
1257    }
1258
1259    if (self->halt) {
1260        Py_INCREF(Py_None);
1261        return Py_None;
1262    }
1263
1264    self->symbols = PyList_New(0);
1265    if (!self->symbols) {
1266        return NULL;
1267    }
1268
1269    self->parsing = 1;
1270    index = syck_parse(self->parser);
1271    self->parsing = 0;
1272
1273    if (self->halt || self->parser->eof) {
1274        Py_DECREF(self->symbols);
1275        self->symbols = NULL;
1276
1277        if (self->halt) return NULL;
1278
1279        self->halt = 1;
1280        Py_INCREF(Py_None);
1281        return Py_None;
1282    }
1283
1284    value = PyList_GetItem(self->symbols, index);
1285
1286    Py_DECREF(self->symbols);
1287    self->symbols = NULL;
1288
1289    return value;
1290}
1291
1292PyDoc_STRVAR(PySyckParser_parse_doc,
1293    "parse() -> the root Node object\n\n"
1294    "Parses the source and returns the next document. On EOF, returns None\n"
1295    "and sets the 'eof' attribute on.\n");
1296
1297static PyMethodDef PySyckParser_methods[] = {
1298    {"parse",  (PyCFunction)PySyckParser_parse,
1299        METH_NOARGS, PySyckParser_parse_doc},
1300    {NULL}  /* Sentinel */
1301};
1302
1303static PyTypeObject PySyckParser_Type = {
1304    PyObject_HEAD_INIT(NULL)
1305    0,                                          /* ob_size */
1306    "_syck.Parser",                             /* tp_name */
1307    sizeof(PySyckParserObject),                 /* tp_basicsize */
1308    0,                                          /* tp_itemsize */
1309    (destructor)PySyckParser_dealloc,           /* tp_dealloc */
1310    0,                                          /* tp_print */
1311    0,                                          /* tp_getattr */
1312    0,                                          /* tp_setattr */
1313    0,                                          /* tp_compare */
1314    0,                                          /* tp_repr */
1315    0,                                          /* tp_as_number */
1316    0,                                          /* tp_as_sequence */
1317    0,                                          /* tp_as_mapping */
1318    0,                                          /* tp_hash */
1319    0,                                          /* tp_call */
1320    0,                                          /* tp_str */
1321    0,                                          /* tp_getattro */
1322    0,                                          /* tp_setattro */
1323    0,                                          /* tp_as_buffer */
1324    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,  /* tp_flags */
1325    PySyckParser_doc,                           /* tp_doc */
1326    (traverseproc)PySyckParser_traverse,        /* tp_traverse */
1327    (inquiry)PySyckParser_clear,                /* tp_clear */
1328    0,                                          /* tp_richcompare */
1329    0,                                          /* tp_weaklistoffset */
1330    0,                                          /* tp_iter */
1331    0,                                          /* tp_iternext */
1332    PySyckParser_methods,                       /* tp_methods */
1333    0,                                          /* tp_members */
1334    PySyckParser_getsetters,                    /* tp_getset */
1335    0,                                          /* tp_base */
1336    0,                                          /* tp_dict */
1337    0,                                          /* tp_descr_get */
1338    0,                                          /* tp_descr_set */
1339    0,                                          /* tp_dictoffset */
1340    (initproc)PySyckParser_init,                /* tp_init */
1341    0,                                          /* tp_alloc */
1342    PySyckParser_new,                           /* tp_new */
1343};
1344
1345/****************************************************************************
1346 * The type _syck.Emitter.
1347 ****************************************************************************/
1348
1349PyDoc_STRVAR(PySyckEmitter_doc,
1350    "Emitter(output, headless=False, use_header=True, explicit_typing=True,"
1351    "        style=None, best_width=80, indent=2) -> an Emitter object\n\n"
1352    "_syck.Emitter is a low-lever wrapper of the Syck emitter. It emit\n"
1353    "a tree of Nodes into a YAML stream.\n");
1354
1355typedef struct {
1356    PyObject_HEAD
1357    /* Attributes: */
1358    PyObject *output;       /* a file-like object */
1359    int headless;
1360    int use_header;
1361    int use_version;
1362    int explicit_typing;
1363    enum scalar_style style;
1364    int best_width;
1365    int indent;
1366    /* Internal fields: */
1367    PyObject *symbols;      /* symbol table, a list, NULL outside emit() */
1368    PyObject *nodes;        /* node -> symbol, a dict, NULL outside emit() */
1369    SyckEmitter *emitter;
1370    int emitting;
1371    int halt;
1372} PySyckEmitterObject;
1373
1374static PyObject *
1375PySyckEmitter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1376{
1377    PySyckEmitterObject *self;
1378
1379    self = (PySyckEmitterObject *)type->tp_alloc(type, 0);
1380    if (!self) return NULL;
1381
1382    self->output = NULL;
1383    self->headless = 0;
1384    self->use_header = 0;
1385    self->use_version = 0;
1386    self->explicit_typing = 0;
1387    self->style = scalar_none;
1388    self->best_width = 0;
1389    self->indent = 0;
1390    self->symbols = NULL;
1391    self->nodes = NULL;
1392    self->emitter = NULL;
1393    self->emitting = 0;
1394    self->halt = 1;
1395
1396    return (PyObject *)self;
1397}
1398
1399static int
1400PySyckEmitter_clear(PySyckEmitterObject *self)
1401{
1402    PyObject *tmp;
1403
1404    if (self->emitter) {
1405        syck_free_emitter(self->emitter);
1406        self->emitter = NULL;
1407    }
1408
1409    tmp = self->output;
1410    self->output = NULL;
1411    Py_XDECREF(tmp);
1412
1413    tmp = self->symbols;
1414    self->symbols = NULL;
1415    Py_XDECREF(tmp);
1416
1417    tmp = self->nodes;
1418    self->nodes = NULL;
1419    Py_XDECREF(tmp);
1420
1421    return 0;
1422}
1423
1424static int
1425PySyckEmitter_traverse(PySyckEmitterObject *self, visitproc visit, void *arg)
1426{
1427    int ret;
1428
1429    if (self->output)
1430        if ((ret = visit(self->output, arg)) != 0)
1431            return ret;
1432
1433    if (self->symbols)
1434        if ((ret = visit(self->symbols, arg)) != 0)
1435            return ret;
1436
1437    if (self->nodes)
1438        if ((ret = visit(self->nodes, arg)) != 0)
1439            return ret;
1440
1441    return 0;
1442}
1443
1444static void
1445PySyckEmitter_dealloc(PySyckEmitterObject *self)
1446{
1447    PySyckEmitter_clear(self);
1448    self->ob_type->tp_free((PyObject *)self);
1449}
1450
1451static PyObject *
1452PySyckEmitter_getoutput(PySyckEmitterObject *self, void *closure)
1453{
1454    PyObject *value = self->output ? self->output : Py_None;
1455
1456    Py_INCREF(value);
1457    return value;
1458}
1459
1460static PyObject *
1461PySyckEmitter_getheadless(PySyckEmitterObject *self, void *closure)
1462{
1463    PyObject *value = self->headless ? Py_True : Py_False;
1464
1465    Py_INCREF(value);
1466    return value;
1467}
1468
1469static PyObject *
1470PySyckEmitter_getuse_header(PySyckEmitterObject *self, void *closure)
1471{
1472    PyObject *value = self->use_header ? Py_True : Py_False;
1473
1474    Py_INCREF(value);
1475    return value;
1476}
1477
1478static PyObject *
1479PySyckEmitter_getuse_version(PySyckEmitterObject *self, void *closure)
1480{
1481    PyObject *value = self->use_version ? Py_True : Py_False;
1482
1483    Py_INCREF(value);
1484    return value;
1485}
1486
1487static PyObject *
1488PySyckEmitter_getexplicit_typing(PySyckEmitterObject *self, void *closure)
1489{
1490    PyObject *value = self->explicit_typing ? Py_True : Py_False;
1491
1492    Py_INCREF(value);
1493    return value;
1494}
1495
1496static PyObject *
1497PySyckEmitter_getstyle(PySyckEmitterObject *self, void *closure)
1498{
1499    PyObject *value;
1500
1501    switch (self->style) {
1502        case scalar_1quote: value = PySyck_1QuoteStyle; break;
1503        case scalar_2quote: value = PySyck_2QuoteStyle; break;
1504        case scalar_fold: value = PySyck_FoldStyle; break;
1505        case scalar_literal: value = PySyck_LiteralStyle; break;
1506        case scalar_plain: value = PySyck_PlainStyle; break;
1507        default: value = Py_None;
1508    }
1509
1510    Py_INCREF(value);
1511    return value;
1512}
1513
1514static PyObject *
1515PySyckEmitter_getbest_width(PySyckEmitterObject *self, void *closure)
1516{
1517    return PyInt_FromLong(self->best_width);
1518}
1519
1520static PyObject *
1521PySyckEmitter_getindent(PySyckEmitterObject *self, void *closure)
1522{
1523    return PyInt_FromLong(self->indent);
1524}
1525
1526static PyGetSetDef PySyckEmitter_getsetters[] = {
1527    {"output", (getter)PySyckEmitter_getoutput, NULL,
1528        PyDoc_STR("output stream, a file-like object"), NULL},
1529    {"headless", (getter)PySyckEmitter_getheadless, NULL,
1530        PyDoc_STR("headerless document flag"), NULL},
1531    {"use_header", (getter)PySyckEmitter_getuse_header, NULL,
1532        PyDoc_STR("force header"), NULL},
1533    {"use_version", (getter)PySyckEmitter_getuse_version, NULL,
1534        PyDoc_STR("force version"), NULL},
1535    {"explicit_typing", (getter)PySyckEmitter_getexplicit_typing, NULL,
1536        PyDoc_STR("explicit typing for all collections"), NULL},
1537    {"style", (getter)PySyckEmitter_getstyle, NULL,
1538        PyDoc_STR("use literal or folded blocks on all text"), NULL},
1539    {"best_width", (getter)PySyckEmitter_getbest_width, NULL,
1540        PyDoc_STR("best width for folded scalars"), NULL},
1541    {"indent", (getter)PySyckEmitter_getindent, NULL,
1542        PyDoc_STR("default indentation"), NULL},
1543    {NULL}  /* Sentinel */
1544};
1545
1546static void
1547PySyckEmitter_node_handler(SyckEmitter *emitter, st_data_t id)
1548{
1549    PySyckEmitterObject *self = (PySyckEmitterObject *)emitter->bonus;
1550
1551    PySyckNodeObject *node;
1552    char *tag = NULL;
1553    PyObject *index;
1554    PyObject *key, *value, *item, *pair;
1555    int j, k, l;
1556    char *str;
1557    int len;
1558    int dict_pos;
1559
1560    if (self->halt) return;
1561
1562    node = (PySyckNodeObject *)PyList_GetItem(self->symbols, id);
1563    if (!node) {
1564        PyErr_SetString(PyExc_RuntimeError, "unknown data id");
1565        self->halt = 1;
1566        return;
1567    }
1568
1569    if (node->tag) {
1570        tag = PyString_AsString(node->tag);
1571        if (!tag) {
1572            self->halt = 1;
1573            return;
1574        }
1575    }
1576
1577    if (PyObject_TypeCheck((PyObject *)node, &PySyckSeq_Type)) {
1578
1579        syck_emit_seq(emitter, tag, ((PySyckSeqObject *)node)->style);
1580
1581        if (!PyList_Check(node->value)) {
1582            PyErr_SetString(PyExc_TypeError, "value of _syck.Seq must be a list");
1583            self->halt = 1;
1584            return;
1585        }
1586        l = PyList_GET_SIZE(node->value);
1587        for (k = 0; k < l; k ++) {
1588            item = PyList_GET_ITEM(node->value, k);
1589            if ((index = PyDict_GetItem(self->nodes, item))) {
1590                syck_emit_item(emitter, PyInt_AS_LONG(index));
1591                if (self->halt) return;
1592            }
1593            else {
1594                PyErr_SetString(PyExc_RuntimeError, "sequence item is not marked");
1595                self->halt = 1;
1596                return;
1597            }
1598        }
1599        syck_emit_end(emitter);
1600    }
1601
1602    else if (PyObject_TypeCheck((PyObject *)node, &PySyckMap_Type)) {
1603
1604        syck_emit_map(emitter, tag, ((PySyckMapObject *)node)->style);
1605       
1606        if (PyList_Check(node->value)) {
1607            l = PyList_GET_SIZE(node->value);
1608            for (k = 0; k < l; k ++) {
1609                pair = PyList_GET_ITEM(node->value, k);
1610                if (!PyTuple_Check(pair) || PyTuple_GET_SIZE(pair) != 2) {
1611                    PyErr_SetString(PyExc_TypeError,
1612                            "value of _syck.Map must be a list of pairs or a dictionary");
1613                    self->halt = 1;
1614                    return;
1615                }
1616                for (j = 0; j < 2; j++) {
1617                    item = PyTuple_GET_ITEM(pair, j);
1618                    if ((index = PyDict_GetItem(self->nodes, item))) {
1619                        syck_emit_item(emitter, PyInt_AS_LONG(index));
1620                        if (self->halt) return;
1621                    }
1622                    else {
1623                        PyErr_SetString(PyExc_RuntimeError, "mapping item is not marked");
1624                        self->halt = 1;
1625                        return;
1626                    }
1627                }
1628            }
1629        }
1630        else if (PyDict_Check(node->value)) {
1631            dict_pos = 0;
1632            while (PyDict_Next(node->value, &dict_pos, &key, &value)) {
1633                for (j = 0; j < 2; j++) {
1634                    item = j ? value : key;
1635                    if ((index = PyDict_GetItem(self->nodes, item))) {
1636                        syck_emit_item(emitter, PyInt_AS_LONG(index));
1637                        if (self->halt) return;
1638                    }
1639                    else {
1640                        PyErr_SetString(PyExc_RuntimeError, "mapping item is not marked");
1641                        self->halt = 1;
1642                        return;
1643                    }
1644                }
1645            }
1646        }
1647        else {
1648            PyErr_SetString(PyExc_TypeError,
1649                    "value of _syck.Map must be a list of pairs or a dictionary");
1650            self->halt = 1;
1651            return;
1652        }
1653
1654        syck_emit_end(emitter);
1655    }
1656
1657    else if (PyObject_TypeCheck((PyObject *)node, &PySyckScalar_Type)) {
1658        if (PyString_AsStringAndSize(node->value, &str, &len) < 0) {
1659            self->halt = 1;
1660            return;
1661        }
1662        syck_emit_scalar(emitter, tag, ((PySyckScalarObject *)node)->style,
1663                ((PySyckScalarObject *)node)->indent,
1664                ((PySyckScalarObject *)node)->width,
1665                ((PySyckScalarObject *)node)->chomp, str, len);
1666    }
1667
1668    else {
1669        PyErr_SetString(PyExc_TypeError, "Node instance is required");
1670        self->halt = 1;
1671        return;
1672    }   
1673}
1674static void
1675PySyckEmitter_write_handler(SyckEmitter *emitter, char *buf, long len)
1676{
1677    PySyckEmitterObject *self = (PySyckEmitterObject *)emitter->bonus;
1678
1679    if (!PyObject_CallMethod(self->output, "write", "(s#)", buf, len))
1680        self->halt = 1;
1681}
1682
1683static int
1684PySyckEmitter_init(PySyckEmitterObject *self, PyObject *args, PyObject *kwds)
1685{
1686    PyObject *output = NULL;
1687    int headless = 0;
1688    int use_header = 0;
1689    int use_version = 0;
1690    int explicit_typing = 0;
1691    PyObject *style = NULL;
1692    int best_width = 80;
1693    int indent = 2;
1694
1695    char *str;
1696
1697    static char *kwdlist[] = {"output", "headless", "use_header",
1698        "use_version", "explicit_typing", "style",
1699        "best_width", "indent", NULL};
1700
1701    PySyckEmitter_clear(self);
1702
1703    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiiiOii", kwdlist,
1704                &output, &headless, &use_header, &use_version,
1705                &explicit_typing, &style, &best_width, &indent))
1706        return -1;
1707
1708    if (best_width <= 0) {
1709        PyErr_SetString(PyExc_ValueError, "'best_width' must be positive");
1710        return -1;
1711    }
1712    if (indent <= 0) {
1713        PyErr_SetString(PyExc_ValueError, "'indent' must be positive");
1714        return -1;
1715    }
1716
1717    if (!style || style == Py_None) {
1718        self->style = scalar_none;
1719    }
1720    else {
1721        if (!PyString_Check(style)) {
1722            PyErr_SetString(PyExc_TypeError, "'style' must be a string or None");
1723            return -1;
1724        }
1725
1726        str = PyString_AsString(style);
1727        if (!str) return -1;
1728
1729        if (strcmp(str, "1quote") == 0)
1730            self->style = scalar_1quote;
1731        else if (strcmp(str, "2quote") == 0)
1732            self->style = scalar_2quote;
1733        else if (strcmp(str, "fold") == 0)
1734            self->style = scalar_fold;
1735        else if (strcmp(str, "literal") == 0)
1736            self->style = scalar_literal;
1737        else if (strcmp(str, "plain") == 0)
1738            self->style = scalar_plain;
1739        else {
1740            PyErr_SetString(PyExc_ValueError, "unknown 'style'");
1741            return -1;
1742        }
1743    }
1744
1745    self->headless = headless;
1746    self->use_header = use_header;
1747    self->use_version = use_version;
1748    self->explicit_typing = explicit_typing;
1749    self->best_width = best_width;
1750    self->indent = indent;
1751
1752    Py_INCREF(output);
1753    self->output = output;
1754
1755/*
1756    self->emitter = syck_new_emitter();
1757    self->emitter->bonus = self;
1758    self->emitter->headless = self->headless;
1759    self->emitter->use_header = use_header;
1760    self->emitter->use_version = use_version;
1761    self->emitter->explicit_typing = explicit_typing;
1762    self->emitter->style = self->style;
1763    self->emitter->best_width = self->best_width;
1764    self->emitter->indent = self->indent;
1765
1766    syck_emitter_handler(self->emitter, PySyckEmitter_node_handler);
1767    syck_output_handler(self->emitter, PySyckEmitter_write_handler);
1768*/
1769
1770    self->emitting = 0;
1771    self->halt = 0;
1772
1773    return 0;
1774}
1775
1776static int
1777PySyckEmitter_mark(PySyckEmitterObject *self, PyObject *root_node)
1778{
1779    int current, last;
1780    int j, k, l;
1781    PySyckNodeObject *node;
1782    PyObject *item, *key, *value, *pair;
1783    PyObject *index;
1784    int dict_pos;
1785
1786    last = 0;
1787    syck_emitter_mark_node(self->emitter, last);
1788    if (PyList_Append(self->symbols, root_node) < 0)
1789        return -1;
1790    index = PyInt_FromLong(last);
1791    if (!index) return -1;
1792    if (PyDict_SetItem(self->nodes, root_node, index) < 0) {
1793        Py_DECREF(index);
1794        return -1;
1795    }
1796    Py_DECREF(index);
1797
1798    for (current = 0; current < PyList_GET_SIZE(self->symbols); current++) {
1799
1800        node = (PySyckNodeObject *)PyList_GET_ITEM(self->symbols, current);
1801
1802        if (PyObject_TypeCheck((PyObject *)node, &PySyckSeq_Type)) {
1803            if (!PyList_Check(node->value)) {
1804                PyErr_SetString(PyExc_TypeError, "value of _syck.Seq must be a list");
1805                return -1;
1806            }
1807            l = PyList_GET_SIZE(node->value);
1808            for (k = 0; k < l; k ++) {
1809                item = PyList_GET_ITEM(node->value, k);
1810                if ((index = PyDict_GetItem(self->nodes, item))) {
1811                    syck_emitter_mark_node(self->emitter, PyInt_AS_LONG(index));
1812                }
1813                else {
1814                    syck_emitter_mark_node(self->emitter, ++last);
1815                    if (PyList_Append(self->symbols, item) < 0)
1816                        return -1;
1817                    index = PyInt_FromLong(last);
1818                    if (!index) return -1;
1819                    if (PyDict_SetItem(self->nodes, item, index) < 0) {
1820                        Py_DECREF(index);
1821                        return -1;
1822                    }
1823                    Py_DECREF(index);
1824                }
1825            }
1826        }
1827
1828        else if (PyObject_TypeCheck((PyObject *)node, &PySyckMap_Type)) {
1829           
1830            if (PyList_Check(node->value)) {
1831                l = PyList_GET_SIZE(node->value);
1832                for (k = 0; k < l; k ++) {
1833                    pair = PyList_GET_ITEM(node->value, k);
1834                    if (!PyTuple_Check(pair) || PyTuple_GET_SIZE(pair) != 2) {
1835                        PyErr_SetString(PyExc_TypeError,
1836                                "value of _syck.Map must be a list of pairs or a dictionary");
1837                        return -1;
1838                    }
1839                    for (j = 0; j < 2; j++) {
1840                        item = PyTuple_GET_ITEM(pair, j);
1841                        if ((index = PyDict_GetItem(self->nodes, item))) {
1842                            syck_emitter_mark_node(self->emitter, PyInt_AS_LONG(index));
1843                        }
1844                        else {
1845                            syck_emitter_mark_node(self->emitter, ++last);
1846                            if (PyList_Append(self->symbols, item) < 0)
1847                                return -1;
1848                            index = PyInt_FromLong(last);
1849                            if (!index) return -1;
1850                            if (PyDict_SetItem(self->nodes, item, index) < 0) {
1851                                Py_DECREF(index);
1852                                return -1;
1853                            }
1854                            Py_DECREF(index);
1855                        }
1856                    }
1857                }
1858               
1859            }
1860            else if (PyDict_Check(node->value)) {
1861                dict_pos = 0;
1862                while (PyDict_Next(node->value, &dict_pos, &key, &value)) {
1863                    for (j = 0; j < 2; j++) {
1864                        item = j ? value : key;
1865                        if ((index = PyDict_GetItem(self->nodes, item))) {
1866                            syck_emitter_mark_node(self->emitter, PyInt_AS_LONG(index));
1867                        }
1868                        else {
1869                            syck_emitter_mark_node(self->emitter, ++last);
1870                            if (PyList_Append(self->symbols, item) < 0)
1871                                return -1;
1872                            index = PyInt_FromLong(last);
1873                            if (!index) return -1;
1874                            if (PyDict_SetItem(self->nodes, item, index) < 0) {
1875                                Py_DECREF(index);
1876                                return -1;
1877                            }
1878                            Py_DECREF(index);
1879                        }
1880                    }
1881                }
1882            }
1883            else {
1884                PyErr_SetString(PyExc_TypeError,
1885                        "value of _syck.Map must be a list of pairs or a dictionary");
1886                return -1;
1887            }
1888        }
1889
1890        else if (!PyObject_TypeCheck((PyObject *)node, &PySyckScalar_Type)) {
1891            PyErr_SetString(PyExc_TypeError, "Node instance is required");
1892            return -1;
1893        }   
1894    }
1895    return 0;
1896}
1897
1898static PyObject *
1899PySyckEmitter_emit(PySyckEmitterObject *self, PyObject *args)
1900{
1901    PyObject *node;
1902
1903    if (self->emitting) {
1904        PyErr_SetString(PyExc_RuntimeError, "do not call Emitter.emit while it is already emitting");
1905        return NULL;
1906    }
1907
1908    if (self->halt) {
1909        Py_INCREF(Py_None);
1910        return Py_None;
1911    }
1912
1913    if (!PyArg_ParseTuple(args, "O", &node))
1914        return NULL;
1915
1916    self->emitting = 1;
1917
1918
1919    self->symbols = PyList_New(0);
1920    if (!self->symbols) {
1921        return NULL;
1922    }
1923    self->nodes = PyDict_New();
1924    if (!self->nodes) {
1925        Py_DECREF(self->symbols);
1926        self->symbols = NULL;
1927        return NULL;
1928    }
1929
1930    self->emitter = syck_new_emitter();
1931    self->emitter->bonus = self;
1932    self->emitter->headless = self->headless;
1933    self->emitter->use_header = self->use_header;
1934    self->emitter->use_version = self->use_version;
1935    self->emitter->explicit_typing = self->explicit_typing;
1936    self->emitter->style = self->style;
1937    self->emitter->best_width = self->best_width;
1938    self->emitter->indent = self->indent;
1939
1940    syck_emitter_handler(self->emitter, PySyckEmitter_node_handler);
1941    syck_output_handler(self->emitter, PySyckEmitter_write_handler);
1942
1943    if (PySyckEmitter_mark(self, node) < 0) {
1944        Py_DECREF(self->symbols);
1945        self->symbols = NULL;
1946        Py_DECREF(self->nodes);
1947        self->nodes = NULL;
1948        self->emitting = 0;
1949        self->halt = 1;
1950        syck_free_emitter(self->emitter);
1951        self->emitter = NULL;
1952        return NULL;
1953    }
1954
1955    syck_emit(self->emitter, 0);
1956    syck_emitter_flush(self->emitter, 0);
1957
1958    syck_free_emitter(self->emitter);
1959    self->emitter = NULL;
1960
1961    self->emitting = 0;
1962
1963    Py_DECREF(self->symbols);
1964    self->symbols = NULL;
1965    Py_DECREF(self->nodes);
1966    self->nodes = NULL;
1967
1968    if (self->halt) return NULL;
1969
1970    Py_INCREF(Py_None);
1971    return Py_None;
1972}
1973
1974PyDoc_STRVAR(PySyckEmitter_emit_doc,
1975    "emit(root_node) -> None\n\n"
1976    "Emit the Node tree to the output.\n");
1977
1978static PyMethodDef PySyckEmitter_methods[] = {
1979    {"emit",  (PyCFunction)PySyckEmitter_emit,
1980        METH_VARARGS, PySyckEmitter_emit_doc},
1981    {NULL}  /* Sentinel */
1982};
1983
1984static PyTypeObject PySyckEmitter_Type = {
1985    PyObject_HEAD_INIT(NULL)
1986    0,                                          /* ob_size */
1987    "_syck.Emitter",                            /* tp_name */
1988    sizeof(PySyckEmitterObject),                /* tp_basicsize */
1989    0,                                          /* tp_itemsize */
1990    (destructor)PySyckEmitter_dealloc,          /* tp_dealloc */
1991    0,                                          /* tp_print */
1992    0,                                          /* tp_getattr */
1993    0,                                          /* tp_setattr */
1994    0,                                          /* tp_compare */
1995    0,                                          /* tp_repr */
1996    0,                                          /* tp_as_number */
1997    0,                                          /* tp_as_sequence */
1998    0,                                          /* tp_as_mapping */
1999    0,                                          /* tp_hash */
2000    0,                                          /* tp_call */
2001    0,                                          /* tp_str */
2002    0,                                          /* tp_getattro */
2003    0,                                          /* tp_setattro */
2004    0,                                          /* tp_as_buffer */
2005    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,  /* tp_flags */
2006    PySyckEmitter_doc,                          /* tp_doc */
2007    (traverseproc)PySyckEmitter_traverse,       /* tp_traverse */
2008    (inquiry)PySyckEmitter_clear,               /* tp_clear */
2009    0,                                          /* tp_richcompare */
2010    0,                                          /* tp_weaklistoffset */
2011    0,                                          /* tp_iter */
2012    0,                                          /* tp_iternext */
2013    PySyckEmitter_methods,                      /* tp_methods */
2014    0,                                          /* tp_members */
2015    PySyckEmitter_getsetters,                   /* tp_getset */
2016    0,                                          /* tp_base */
2017    0,                                          /* tp_dict */
2018    0,                                          /* tp_descr_get */
2019    0,                                          /* tp_descr_set */
2020    0,                                          /* tp_dictoffset */
2021    (initproc)PySyckEmitter_init,               /* tp_init */
2022    0,                                          /* tp_alloc */
2023    PySyckEmitter_new,                          /* tp_new */
2024};
2025
2026/****************************************************************************
2027 * The module _syck.
2028 ****************************************************************************/
2029
2030static PyMethodDef PySyck_methods[] = {
2031    {NULL}  /* Sentinel */
2032};
2033
2034PyDoc_STRVAR(PySyck_doc,
2035    "low-level wrapper for the Syck YAML parser and emitter");
2036
2037PyMODINIT_FUNC
2038init_syck(void)
2039{
2040    PyObject *m;
2041
2042    if (PyType_Ready(&PySyckNode_Type) < 0)
2043        return;
2044    if (PyType_Ready(&PySyckScalar_Type) < 0)
2045        return;
2046    if (PyType_Ready(&PySyckSeq_Type) < 0)
2047        return;
2048    if (PyType_Ready(&PySyckMap_Type) < 0)
2049        return;
2050    if (PyType_Ready(&PySyckParser_Type) < 0)
2051        return;
2052    if (PyType_Ready(&PySyckEmitter_Type) < 0)
2053        return;
2054   
2055    PySyck_Error = PyErr_NewException("_syck.error", NULL, NULL);
2056    if (!PySyck_Error) return;
2057
2058    PySyck_ScalarKind = PyString_FromString("scalar");
2059    if (!PySyck_ScalarKind) return;
2060    PySyck_SeqKind = PyString_FromString("seq");
2061    if (!PySyck_SeqKind) return;
2062    PySyck_MapKind = PyString_FromString("map");
2063    if (!PySyck_MapKind) return;
2064
2065    PySyck_1QuoteStyle = PyString_FromString("1quote");
2066    if (!PySyck_1QuoteStyle) return;
2067    PySyck_2QuoteStyle = PyString_FromString("2quote");
2068    if (!PySyck_2QuoteStyle) return;
2069    PySyck_FoldStyle = PyString_FromString("fold");
2070    if (!PySyck_FoldStyle) return;
2071    PySyck_LiteralStyle = PyString_FromString("literal");
2072    if (!PySyck_LiteralStyle) return;
2073    PySyck_PlainStyle = PyString_FromString("plain");
2074    if (!PySyck_PlainStyle) return;
2075
2076    PySyck_StripChomp = PyString_FromString("-");
2077    if (!PySyck_StripChomp) return;
2078    PySyck_KeepChomp = PyString_FromString("+");
2079    if (!PySyck_KeepChomp) return;
2080
2081    m = Py_InitModule3("_syck", PySyck_methods, PySyck_doc);
2082
2083    Py_INCREF(PySyck_Error);
2084    if (PyModule_AddObject(m, "error", (PyObject *)PySyck_Error) < 0)
2085        return;
2086    Py_INCREF(&PySyckNode_Type);
2087    if (PyModule_AddObject(m, "Node", (PyObject *)&PySyckNode_Type) < 0)
2088        return;
2089    Py_INCREF(&PySyckScalar_Type);
2090    if (PyModule_AddObject(m, "Scalar", (PyObject *)&PySyckScalar_Type) < 0)
2091        return;
2092    Py_INCREF(&PySyckSeq_Type);
2093    if (PyModule_AddObject(m, "Seq", (PyObject *)&PySyckSeq_Type) < 0)
2094        return;
2095    Py_INCREF(&PySyckMap_Type);
2096    if (PyModule_AddObject(m, "Map", (PyObject *)&PySyckMap_Type) < 0)
2097        return;
2098    Py_INCREF(&PySyckParser_Type);
2099    if (PyModule_AddObject(m, "Parser", (PyObject *)&PySyckParser_Type) < 0)
2100        return;
2101    Py_INCREF(&PySyckEmitter_Type);
2102    if (PyModule_AddObject(m, "Emitter", (PyObject *)&PySyckEmitter_Type) < 0)
2103        return;
2104}
2105
Note: See TracBrowser for help on using the repository browser.