source: trunk/ext/_syckmodule.c @ 5

Revision 5, 15.0 KB checked in by xi, 9 years ago (diff)

_syckmodule.c: Rename types and functions.

Line 
1
2#include <Python.h>
3#include <syck.h>
4
5/* Global objects. */
6
7static PyObject *PySyck_Error;
8
9static PyObject *PySyck_ScalarKind;
10static PyObject *PySyck_SeqKind;
11static PyObject *PySyck_MapKind;
12
13/* Node type. */
14
15typedef struct {
16    PyObject_HEAD
17    PyObject *kind;
18    PyObject *type_id;
19    PyObject *value;
20} PySyckNodeObject;
21
22static void
23PySyckNode_dealloc(PySyckNodeObject *self)
24{
25    Py_XDECREF(self->kind);
26    Py_XDECREF(self->type_id);
27    Py_XDECREF(self->value);
28    PyObject_Del(self);
29}
30
31static PyObject *
32PySyckNode_getattr(PySyckNodeObject *self, char *name)
33{
34    PyObject *value;
35
36    if (strcmp(name, "kind") == 0)
37        value = self->kind;
38    else if (strcmp(name, "type_id") == 0)
39        value = self->type_id;
40    else if (strcmp(name, "value") == 0)
41        value = self->value;
42    else {
43        PyErr_SetString(PyExc_AttributeError, name);
44        return NULL;
45    }
46
47    Py_INCREF(value);
48    return value;
49}
50
51static char PySyckNode_doc[] =
52    "Node object\n"
53    "\n"
54    "Attributes of the Node object:\n\n"
55    "kind -- 'scalar', 'seq', or 'map'.\n"
56    "type_id -- the tag of the node.\n"
57    "value -- the value of the node, a string, list or dict object.\n";
58
59static PyTypeObject PySyckNode_Type = {
60    PyObject_HEAD_INIT(NULL)
61    0,                                  /* ob_size */
62    "_syck.Node",                       /* tp_name */
63    sizeof(PySyckNodeObject),           /* tp_basicsize */
64    0,                                  /* tp_itemsize */
65    (destructor)PySyckNode_dealloc,     /* tp_dealloc */
66    0,                                  /* tp_print */
67    (getattrfunc)PySyckNode_getattr,    /* tp_getattr */
68    0,                                  /* tp_setattr */
69    0,                                  /* tp_compare */
70    0,                                  /* tp_repr */
71    0,                                  /* tp_as_number */
72    0,                                  /* tp_as_sequence */
73    0,                                  /* tp_as_mapping */
74    0,                                  /* tp_hash */
75    0,                                  /* tp_call */
76    0,                                  /* tp_str */
77    0,                                  /* tp_getattro */
78    0,                                  /* tp_setattro */
79    0,                                  /* tp_as_buffer */
80    Py_TPFLAGS_DEFAULT,                 /* tp_flags */
81    PySyckNode_doc,                     /* tp_doc */
82};
83
84static PyObject *
85PySyckNode_New(char *type_id, PyObject *value) /* Note: steals the reference to the value. */
86{
87    PySyckNodeObject *self;
88    PyObject *kind;
89
90    self = PyObject_NEW(PySyckNodeObject, &PySyckNode_Type);
91    if (!self) {
92        Py_XDECREF(value);
93        return NULL;
94    }
95
96    self->value = value;
97
98    if (PyList_Check(value))
99        kind = PySyck_SeqKind;
100    else if (PyDict_Check(value))
101        kind = PySyck_MapKind;
102    else
103        kind = PySyck_ScalarKind;
104    Py_INCREF(kind);
105    self->kind = kind;
106
107    if (type_id) {
108        self->type_id = PyString_FromString(type_id);
109        if (!self->type_id) {
110            Py_DECREF(self);
111            return NULL;
112        }
113    }
114    else {
115        Py_INCREF(Py_None);
116        self->type_id = Py_None;
117    }
118
119    return (PyObject *)self;
120}
121
122static PyObject *
123PySyck_Node(PyObject *self, PyObject *args)
124{
125    if (!PyArg_ParseTuple(args, ":_syck.Node"))
126        return NULL;
127
128    PyErr_SetString(PyExc_TypeError, "Node object cannot be created explicitly. Use _syck.Parser.parse() instead.");
129    return NULL;
130}
131
132static char PySyck_Node_doc[] =
133    "Node object cannot be created explicitly. Use _syck.Parser.parse() instead.";
134
135/* Parser type. */
136
137typedef struct {
138    PyObject_HEAD
139    PyObject *source;
140/*    PyObject *resolver;*/
141    PyObject *symbols;
142    SyckParser *syck;
143    int error;
144} PySyckParserObject;
145
146static PyObject *
147PySyckParser_parse(PySyckParserObject *parser, PyObject *args)
148{
149    SYMID index;
150    PyObject *value;
151
152    if (!PyArg_ParseTuple(args, ":parse"))
153        return NULL;
154
155    if (!parser->syck) {
156        PyErr_SetString(PyExc_TypeError, "Parser object is closed");
157        return NULL;
158    }
159
160    parser->symbols = PyList_New(0);
161    if (!parser->symbols) {
162        return NULL;
163    }
164
165    index = syck_parse(parser->syck);
166    if (!parser->error && !parser->syck->eof) {
167        value = PyList_GetItem(parser->symbols, index-1);
168    }
169
170    Py_DECREF(parser->symbols);
171
172    if (parser->error) {
173        parser->error = 0;
174        return NULL;
175    }
176
177    if (parser->syck->eof) {
178        Py_INCREF(Py_None);
179        return Py_None;
180    }
181   
182    return value;
183}
184
185static char PySyckParser_parse_doc[] =
186    "Parses the next document in the YAML stream, return the root Node object or None on EOF.";
187
188static PyObject *
189PySyckParser_parse_documents(PySyckParserObject *parser, PyObject *args)
190{
191    SYMID index;
192    PyObject *value = NULL;
193    PyObject *documents = NULL;
194
195    if (!PyArg_ParseTuple(args, ":parse_document"))
196        return NULL;
197
198    if (!parser->syck) {
199        PyErr_SetString(PyExc_TypeError, "Parser object is closed");
200        return NULL;
201    }
202
203    documents = PyList_New(0);
204    if (!documents) return NULL;
205
206    while (1) {
207
208        parser->symbols = PyList_New(0);
209        if (!parser->symbols) {
210            Py_DECREF(documents);
211            return NULL;
212        };
213
214        index = syck_parse(parser->syck);
215
216        if (!parser->error && !parser->syck->eof) {
217            value = PyList_GetItem(parser->symbols, index-1);
218            if (!value) {
219                Py_DECREF(parser->symbols);
220                Py_DECREF(documents);
221                return NULL;
222            }
223            if (PyList_Append(documents, value) < 0) {
224                Py_DECREF(parser->symbols);
225                Py_DECREF(value);
226                Py_DECREF(documents);
227                return NULL;
228            }
229            Py_DECREF(value);
230        }
231
232        Py_DECREF(parser->symbols);
233
234        if (parser->error) {
235            parser->error = 0;
236            Py_DECREF(documents);
237            return NULL;
238        }
239
240        if (parser->syck->eof) break;
241    }
242
243    return documents;
244}
245
246static char PySyckParser_parse_documents_doc[] =
247    "Parses the entire YAML stream and returns list of documents.";
248
249static PyObject *
250PySyckParser_close(PySyckParserObject *parser, PyObject *args)
251{
252    if (!PyArg_ParseTuple(args, ":close"))
253        return NULL;
254
255    Py_XDECREF(parser->source);
256    parser->source = NULL;
257
258    if (parser->syck) {
259        syck_free_parser(parser->syck);
260    }
261    parser->syck = NULL;
262
263    Py_INCREF(Py_None);
264    return Py_None;
265}
266
267static char PySyckParser_close_doc[] =
268    "Closes the parser and frees memory";
269
270static PyMethodDef PySyckParser_methods[] = {
271    {"parse",  (PyCFunction)PySyckParser_parse, METH_VARARGS, PySyckParser_parse_doc},
272    {"parse_documents",  (PyCFunction)PySyckParser_parse_documents, METH_VARARGS, PySyckParser_parse_documents_doc},
273    {"close",  (PyCFunction)PySyckParser_close, METH_VARARGS, PySyckParser_close_doc},
274    {NULL}  /* Sentinel */
275};
276
277static void
278PySyckParser_dealloc(PySyckParserObject *parser)
279{
280    Py_XDECREF(parser->source);
281    if (parser->syck) {
282        syck_free_parser(parser->syck);
283    }
284    PyObject_Del(parser);
285}
286
287static PyObject *
288PySyckParser_getattr(PySyckParserObject *parser, char *name)
289{
290    return Py_FindMethod(PySyckParser_methods, (PyObject *)parser, name);
291}
292
293static char PySyckParser_doc[] =
294    "_syck.Parser(yaml_string_or_file, implicit_typing=True, taguri_expansion=True) -> Parser object\n"
295    "\n"
296    "Methods of the Parser object:\n\n"
297    "parse() -- Parses the next document in the YAML stream, return the root Node object or None on EOF.\n"
298    "parse_documents() -- Parses the entire YAML stream and returns list of documents.\n"
299    "close() -- Closes the parser and frees memory.\n";
300
301static PyTypeObject PySyckParser_Type = {
302    PyObject_HEAD_INIT(NULL)
303    0,                                  /* ob_size */
304    "_syck.Parser",                     /* tp_name */
305    sizeof(PySyckParserObject),         /* tp_basicsize */
306    0,                                  /* tp_itemsize */
307    (destructor)PySyckParser_dealloc,   /* tp_dealloc */
308    0,                                  /* tp_print */
309    (getattrfunc)PySyckParser_getattr,  /* tp_getattr */
310    0,                                  /* tp_setattr */
311    0,                                  /* tp_compare */
312    0,                                  /* tp_repr */
313    0,                                  /* tp_as_number */
314    0,                                  /* tp_as_sequence */
315    0,                                  /* tp_as_mapping */
316    0,                                  /* tp_hash */
317    0,                                  /* tp_call */
318    0,                                  /* tp_str */
319    0,                                  /* tp_getattro */
320    0,                                  /* tp_setattro */
321    0,                                  /* tp_as_buffer */
322    Py_TPFLAGS_DEFAULT,                 /* tp_flags */
323    PySyckParser_doc,                   /* tp_doc */
324};
325
326static long
327PySyckParser_read_handler(char *buf, SyckIoFile *file, long max_size, long skip)
328{
329    PySyckParserObject *parser = (PySyckParserObject *)file->ptr;
330
331    PyObject *value;
332
333    char *str;
334    int length;
335
336    buf[skip] = '\0';
337
338    if (parser->error) {
339        return skip;
340    }
341   
342    max_size -= skip;
343
344    value = PyObject_CallMethod(parser->source, "read", "(i)", max_size);
345    if (!value) {
346        parser->error = 1;
347        return skip;
348    }
349
350    if (!PyString_Check(value)) {
351        Py_DECREF(value);
352        PyErr_SetString(PyExc_TypeError, "file-like object should return a string");
353        parser->error = 1;
354       
355        return skip;
356    }
357
358    str = PyString_AS_STRING(value);
359    length = PyString_GET_SIZE(value);
360    if (!length) {
361        Py_DECREF(value);
362        return skip;
363    }
364
365    if (length > max_size) {
366        Py_DECREF(value);
367        PyErr_SetString(PyExc_ValueError, "read returns an overly long string");
368        parser->error = 1;
369        return skip;
370    }
371
372    memcpy(buf+skip, str, length);
373    length += skip;
374    buf[length] = '\0';
375
376    Py_DECREF(value);
377
378    return length;
379}
380
381static SYMID
382PySyckParser_node_handler(SyckParser *syck, SyckNode *node)
383{
384    PySyckParserObject *parser = (PySyckParserObject *)syck->bonus;
385
386    SYMID index;
387    PyObject *object = NULL;
388
389    PyObject *key, *value, *item;
390    int k;
391
392    if (parser->error)
393        return 0;
394
395    switch (node->kind) {
396
397        case syck_str_kind:
398            object = PyString_FromStringAndSize(node->data.str->ptr,
399                    node->data.str->len);
400            if (!object) goto error;
401            break;
402
403        case syck_seq_kind:
404            object = PyList_New(node->data.list->idx);
405            if (!object) goto error;
406            for (k = 0; k < node->data.list->idx; k++) {
407                index = syck_seq_read(node, k);
408                item = PyList_GetItem(parser->symbols, index-1);
409                if (!item) goto error;
410                Py_INCREF(item);
411                PyList_SET_ITEM(object, k, item);
412            }
413            break;
414
415        case syck_map_kind:
416            object = PyDict_New();
417            if (!object) goto error;
418            for (k = 0; k < node->data.pairs->idx; k++)
419            {
420                index = syck_map_read(node, map_key, k);
421                key = PyList_GetItem(parser->symbols, index-1);
422                if (!key) goto error;
423                index = syck_map_read(node, map_value, k);
424                value = PyList_GetItem(parser->symbols, index-1);
425                if (!value) goto error;
426                if (PyDict_SetItem(object, key, value) < 0)
427                    goto error;
428            }
429            break;
430    }
431
432    object = PySyckNode_New(node->type_id, object);
433    if (!object) goto error;
434
435    if (PyList_Append(parser->symbols, object) < 0)
436        goto error;
437
438    index = PyList_Size(parser->symbols);
439    return index;
440
441error:
442    Py_XDECREF(object);
443    parser->error = 1;
444    return 0;
445}
446
447static void
448PySyckParser_error_handler(SyckParser *syck, char *str)
449{
450    PySyckParserObject *parser = (PySyckParserObject *)syck->bonus;
451    PyObject *value;
452
453    if (parser->error) return;
454
455    parser->error = 1;
456
457    value = Py_BuildValue("(sii)", str, syck->linect, syck->cursor-syck->lineptr);
458    if (value) {
459        PyErr_SetObject(PySyck_Error, value);
460    }
461}
462
463static PyObject *
464PySyck_Parser(PyObject *self, PyObject *args, PyObject *kwds)
465{
466    PySyckParserObject *parser;
467    PyObject *source;
468    int implicit_typing = 1;
469    int taguri_expansion = 1;
470
471    static char *kwdlist[] = {"source", "implicit_typing", "taguri_expansion", NULL};
472
473    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ii", kwdlist,
474                &source, &implicit_typing, &taguri_expansion))
475        return NULL;
476
477    parser = PyObject_NEW(PySyckParserObject, &PySyckParser_Type);
478    if (!parser)
479        return NULL;
480
481    Py_INCREF(source);
482    parser->source = source;
483    parser->error = 0;
484
485    parser->syck = syck_new_parser();
486    parser->syck->bonus = parser;
487
488    if (PyString_Check(source)) {
489        syck_parser_str(parser->syck, PyString_AS_STRING(source), PyString_GET_SIZE(source), NULL);
490    }
491    else {
492        syck_parser_file(parser->syck, (FILE *)parser, PySyckParser_read_handler);
493    }
494    syck_parser_implicit_typing(parser->syck, implicit_typing);
495    syck_parser_taguri_expansion(parser->syck, taguri_expansion);
496
497    syck_parser_handler(parser->syck, PySyckParser_node_handler);
498    syck_parser_error_handler(parser->syck, PySyckParser_error_handler);
499    /*
500    syck_parser_bad_anchor_handler(parser, _syck_Parser_bad_anchor_handler);
501    */
502
503    return (PyObject *)parser;
504}
505
506static char PySyck_Parser_doc[] =
507    "Creates a new Parser object.";
508
509/* The module definitions. */
510
511static PyMethodDef PySyck_methods[] = {
512    {"Node",  (PyCFunction)PySyck_Node, METH_VARARGS, PySyck_Node_doc},
513    {"Parser",  (PyCFunction)PySyck_Parser, METH_VARARGS|METH_KEYWORDS, PySyck_Parser_doc},
514    {NULL}  /* Sentinel */
515};
516
517static char PySyck_doc[] =
518    "This module provides low-level access to the Syck parser and emitter.\n"
519    "Do not use this module directly, use the package 'syck' instead.\n";
520
521PyMODINIT_FUNC
522init_syck(void)
523{
524    PyObject *m;
525
526    PySyckNode_Type.ob_type = &PyType_Type;
527    PySyckParser_Type.ob_type = &PyType_Type;
528
529    PySyck_Error = PyErr_NewException("_syck.error", NULL, NULL);
530    if (!PySyck_Error)
531        return;
532
533    PySyck_ScalarKind = PyString_FromString("scalar");
534    if (!PySyck_ScalarKind)
535        return;
536    PySyck_SeqKind = PyString_FromString("seq");
537    if (!PySyck_SeqKind)
538        return;
539    PySyck_MapKind = PyString_FromString("map");
540    if (!PySyck_MapKind)
541        return;
542
543    m = Py_InitModule3("_syck", PySyck_methods, PySyck_doc);
544
545    Py_INCREF(PySyck_Error);
546    if (!PyModule_AddObject(m, "error", PySyck_Error) < 0)
547        return;
548
549    Py_INCREF(&PySyckNode_Type);
550    if (PyModule_AddObject(m, "NodeType", (PyObject *)&PySyckNode_Type) < 0)
551        return;
552
553    Py_INCREF(&PySyckParser_Type);
554    if (PyModule_AddObject(m, "ParserType", (PyObject *)&PySyckParser_Type) < 0)
555        return;
556}
557
Note: See TracBrowser for help on using the repository browser.