root/masterdriverz/snakeoil/src/formatters.c @ masterdriverz%2540gentoo.org-20070901083026-s6u5sjdj5f1p5jyh

Revision masterdriverz%2540gentoo.org-20070901083026-s6u5sjdj5f1p5jyh, 25.3 kB (checked in by Charlie Shepherd <masterdriverz@…>, 16 months ago)

Set formatter.encoding to ascii if we can't do anything else, rather than just giving up

Line 
1#include "Python.h"
2#include <snakeoil/common.h>
3#include "structmember.h"
4
5/*
6 * Known bugs:
7 *   encoding isn't modifiable after the fact.  should be.
8 * optimizations:
9 *   PyUnicode_Find internally makes it's own objs when doing subranges- inline the lookup.
10 *   currently creates 2n strings on slicing; leftbit, remaining- use windowing instead, just
11 *   pullng the window as needed.
12 */
13
14
15
16/* Duplicating this is annoying, but we need to
17   access it from the C level, so we do. */
18static PyObject *StreamClosed = NULL;
19
20/* Stuff we keep a copy of */
21static PyObject *PTF_unic_space = NULL;
22static PyObject *ascii_str = NULL;
23
24/* PlainTextFormatter is abbreviated to PTF */
25
26typedef struct {
27    PyObject_HEAD
28
29    /* This is actually the write method of stream if it's not a file */
30    PyObject *stream_callable;
31    PyObject *first_prefix;
32    PyObject *later_prefix;
33
34    /* need these for TermInfoFormatter */
35
36    PyObject *reset;
37    PyObject *bold;
38    PyObject *underline;
39    PyObject *encoding;
40    int width;
41    int autoline;
42    int wrap;
43
44    PyObject *raw_stream;
45    int pos;
46    int in_first_line;
47    int wrote_something;
48
49} PTF_object;
50
51snakeoil_MUTABLE_ATTR_BOOL(PTF_object, "autoline", autoline, self->autoline,
52    self->autoline = 1, self->autoline = 0)
53snakeoil_MUTABLE_ATTR_BOOL(PTF_object, "wrap", wrap, self->wrap,
54    self->wrap = 1, self->wrap = 0)
55snakeoil_GET_ATTR(PTF_object, "first_prefix", first_prefix, self->first_prefix)
56snakeoil_GET_ATTR(PTF_object, "later_prefix", later_prefix, self->later_prefix)
57
58
59static int
60PTF_set_first_prefix(PTF_object *self, PyObject *value, void *closure)
61{
62    PyObject *tmp;
63    if(!value) {
64        PyErr_SetString(PyExc_TypeError, "first_prefix is not deletable");
65        return -1;
66    }
67
68    if(!PyList_CheckExact(value))
69        return PyList_SetSlice(self->first_prefix,
70            0, PyList_GET_SIZE(self->first_prefix),
71            value);
72    tmp = self->first_prefix;
73    Py_INCREF(value);
74    self->first_prefix = value;
75    Py_DECREF(tmp);
76    return 0;
77}
78
79static int
80PTF_set_later_prefix(PTF_object *self, PyObject *value, void *closure)
81{
82    PyObject *tmp;
83    if(!value) {
84        PyErr_SetString(PyExc_TypeError, "later_prefix is not deletable");
85        return -1;
86    }
87
88    if(!PyList_CheckExact(value))
89        return PyList_SetSlice(self->later_prefix,
90            0, PyList_GET_SIZE(self->later_prefix),
91            value);
92    tmp = self->later_prefix;
93    Py_INCREF(value);
94    self->later_prefix = value;
95    Py_DECREF(tmp);
96    return 0;
97}
98
99static PyObject *
100PTF_getstream(PTF_object *self, void *closure)
101{
102    Py_INCREF(self->raw_stream);
103    return self->raw_stream;
104}
105
106static int
107PTF_set_encoding(PTF_object *self, PyObject *value, void *closure)
108{
109    PyObject *tmp;
110    if(!value) {
111        PyErr_SetString(PyExc_TypeError, "encoding prefix is not deletable");
112        return -1;
113    } else if(!PyString_CheckExact(value)) {
114        PyErr_SetString(PyExc_TypeError, "encoding must be a string");
115        return -1;
116    }
117    tmp = self->encoding;
118    Py_INCREF(value);
119    self->encoding = value;
120    Py_DECREF(tmp);
121    return 0;
122}
123
124static PyObject *
125PTF_get_encoding(PTF_object *self, void *closure)
126{
127    PyObject *tmp = self->encoding;
128    if(!tmp) {
129        PyErr_SetString(PyExc_RuntimeError, "PTF instance has null encoding; this shouldn't be possible");
130    }
131    Py_XDECREF(tmp);
132    return tmp;
133}
134
135static int
136PTF_setstream(PTF_object *self, PyObject *value, void *closure)
137{
138    PyObject *tmp;
139    if (value == NULL) {
140        PyErr_SetString(PyExc_TypeError, "Cannot delete the stream attribute");
141        return -1;
142    }
143
144    if (PyFile_Check(value)) {
145        Py_CLEAR(self->stream_callable);
146    } else {
147        tmp = PyObject_GetAttrString(value, "write");
148        if (!tmp) {
149            if (!PyErr_Occurred())
150                PyErr_SetString(PyExc_TypeError, "stream has no write method");
151            return -1;
152        }
153        PyObject *tmp2 = self->stream_callable;
154        self->stream_callable = tmp;
155        Py_XDECREF(tmp2);
156    }
157
158    tmp = self->raw_stream;
159    Py_INCREF(value);
160    self->raw_stream = value;
161    Py_XDECREF(tmp);
162
163    return 0;
164}
165
166
167static int
168PTF_traverse(PTF_object *self, visitproc visit, void *arg)
169{
170    Py_VISIT(self->stream_callable);
171    Py_VISIT(self->raw_stream);
172    Py_VISIT(self->first_prefix);
173    Py_VISIT(self->later_prefix);
174    Py_VISIT(self->reset);
175    Py_VISIT(self->bold);
176    Py_VISIT(self->underline);
177    Py_VISIT(self->encoding);
178    return 0;
179}
180
181static int
182PTF_clear(PTF_object *self)
183{
184    Py_CLEAR(self->stream_callable);
185    Py_CLEAR(self->raw_stream);
186    Py_CLEAR(self->first_prefix);
187    Py_CLEAR(self->later_prefix);
188    Py_CLEAR(self->reset);
189    Py_CLEAR(self->bold);
190    Py_CLEAR(self->underline);
191    Py_CLEAR(self->encoding);
192    return 0;
193}
194
195static void
196PTF_dealloc(PTF_object *self) {
197    PTF_clear(self);
198    self->ob_type->tp_free((PyObject*)self);
199}
200
201static PyObject *
202PTF_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
203{
204    PTF_object *self;
205    self = (PTF_object *)type->tp_alloc(type, 0);
206    if(!self)
207        return NULL;
208
209    Py_INCREF(ascii_str);
210    self->encoding = ascii_str;
211    self->autoline = self->in_first_line = 1;
212    self->pos = self->wrap = self->wrote_something = 0;
213    self->first_prefix = self->later_prefix = self->bold = self->reset = self->underline = NULL;
214    self->raw_stream = self->stream_callable = NULL;
215
216    self->width = 79;
217     /* this should pick up on the system default but i'm lazy. */
218    if(!(self->first_prefix = PyList_New(0))) {
219        Py_DECREF(self);
220        return NULL;
221    }
222    if(!(self->later_prefix = PyList_New(0))) {
223        Py_DECREF(self);
224        return NULL;
225    }
226    if(!(self->bold = PyString_FromString(""))) {
227        Py_DECREF(self);
228        return NULL;
229    }
230    Py_INCREF(self->bold);
231    self->reset = self->bold;
232    Py_INCREF(self->bold);
233    self->underline = self->bold;
234    return (PyObject *)self;
235}
236
237static int
238PTF_init(PTF_object *self, PyObject *args, PyObject *kwds)
239{
240    PyObject *encoding = NULL, *tmp, *stream = NULL;
241    int width = 0;
242    static char *kwlist[] = {"stream", "width", "encoding", NULL};
243
244    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO", kwlist,
245        &stream, &width, &encoding))
246        return -1;
247
248    if(encoding == Py_None)
249        encoding = NULL;
250
251    if(encoding) {
252        if(!PyString_Check(encoding)) {
253            PyErr_SetString(PyExc_TypeError,
254                "encoding must be None, or a str object");
255            return -1;
256        }
257        Py_INCREF(encoding);
258    } else {
259        /* try to pull it from the stream, else from the current settings */
260        if(!(encoding = PyObject_GetAttrString(stream, "encoding"))) {
261            PyErr_Clear();
262        } else if (!PyString_Check(encoding)) {
263            Py_CLEAR(encoding);
264        }
265        if(!encoding) {
266            /* try system setting */
267            const char *p = PyUnicode_GetDefaultEncoding();
268            if(!p)
269                /* should check for locale error here instead of just wiping... */
270                PyErr_Clear();
271            else if(!(encoding = PyString_FromString(p)))
272                /* leave self->encoding as ascii. */
273                encoding = NULL;
274        }
275    }
276    if(encoding) {
277        tmp = self->encoding;
278        self->encoding = encoding;
279        Py_DECREF(tmp);
280    }
281    if(width > 0)
282        self->width = width;
283
284    return PTF_setstream(self, stream, NULL);
285}
286
287/* repeatedly reduce a callable invoking func(self), till it's no longer callable
288  steals the passed in ref, and returns a new reference.
289*/
290static PyObject *
291reduce_callable(PTF_object *self, PyObject *arg)
292{
293    PyObject *tmp;
294    while(PyCallable_Check(arg)) {
295        tmp = PyObject_CallFunctionObjArgs(arg, (PyObject *)self, NULL);
296        if(!tmp)
297            return tmp;
298        Py_DECREF(arg);
299        arg = tmp;
300    }
301    return arg;
302}
303
304static int
305_flush_newline(PTF_object *self)
306{
307    PyObject *tmp;
308    if (self->stream_callable) {
309        tmp = PyObject_CallFunction(self->stream_callable, "(s)", "\n");
310        if(!tmp)
311            return -1;
312        Py_DECREF(tmp);
313    } else {
314        if(PyFile_WriteString("\n", self->raw_stream))
315            return -1;
316    }
317    self->wrote_something = 0;
318    self->pos = 0;
319    return 0;
320}
321
322/* convert passed in object, stealing the reference, returning a new reference
323for the encoded version, else NULL with exception set */
324static inline PyObject *
325PTF_convert_encoding(PTF_object *self, PyObject *data)
326{
327    PyObject *tmp;
328    tmp = PyUnicode_AsEncodedString(data, PyString_AS_STRING(self->encoding),
329        "replace");
330    Py_DECREF(data);
331    return tmp;
332}
333
334static int
335_write_prefix(PTF_object *self, int wrap) {
336    PyObject *iter, *arg, *tmp;
337    Py_ssize_t len;
338    int ret;
339
340    iter = self->in_first_line ? self->first_prefix : self->later_prefix;
341    if(!(iter = PyObject_GetIter(iter)))
342        return -1;
343
344    while ((arg = PyIter_Next(iter))) {
345        if(!(arg = reduce_callable(self, arg))) {
346            Py_DECREF(iter);
347            return -1;
348        }
349
350        if (arg == Py_None) {
351            Py_DECREF(arg);
352            continue;
353        }
354
355        if (!PyString_Check(arg)) {
356            int is_unicode = PyUnicode_Check(arg);
357            if(!is_unicode) {
358                tmp = PyObject_Str(arg);
359                Py_DECREF(arg);
360                if(!tmp) {
361                    Py_DECREF(iter);
362                    return -1;
363                }
364                is_unicode = PyUnicode_Check(arg);
365            }
366            if(is_unicode) {
367                len = PyUnicode_GET_SIZE(arg);
368                if(!(arg = PTF_convert_encoding(self, arg))) {
369                    Py_DECREF(iter);
370                    return -1;
371                }
372            } else {
373                if(!(len = PyObject_Length(arg))) {
374                    Py_DECREF(iter);
375                    Py_DECREF(arg);
376                    return -1;
377                }
378            }
379        } else {
380            len = PyString_GET_SIZE(arg);
381        }
382
383        if (self->stream_callable) {
384            tmp = PyObject_CallFunctionObjArgs(self->stream_callable, arg, NULL);
385            Py_XDECREF(tmp);
386            ret = tmp == NULL;
387        } else {
388            ret = PyFile_WriteObject(arg, self->raw_stream, Py_PRINT_RAW);
389        }
390        Py_DECREF(arg);
391        if(ret) {
392            Py_DECREF(iter);
393            return -1;
394        }
395        // overflow potential.
396        self->pos += len;
397    }
398    if (wrap && (self->pos >= self->width))
399        self->pos = self->width-10;
400    Py_DECREF(iter);
401    return 0;
402}
403
404static PyObject *
405PTF_write(PTF_object *self, PyObject *args, PyObject *kwargs) {
406    PyObject *wrap=NULL, *autoline=NULL, *prefixes=NULL, *prefix=NULL;
407    PyObject *first_prefixes=NULL, *later_prefixes=NULL;
408    PyObject *first_prefix=NULL, *later_prefix=NULL;
409    PyObject *tmp=NULL, *arg=NULL;
410    PyObject *iterator=NULL, *e=NULL;
411
412    int maxlen, space, failed = 1;
413    int i_wrap = self->wrap;
414    int i_autoline = self->autoline;
415    Py_ssize_t first_prune = 0, later_prune = 0;
416    Py_ssize_t arg_len = 0;
417
418#define getitem(ptr) ptr = PyDict_GetItemString(kwargs, #ptr);     \
419        if (!ptr && PyErr_Occurred())                              \
420            return NULL;
421
422    if(kwargs) {
423        getitem(prefix);
424        getitem(first_prefix);
425        getitem(later_prefix);
426        getitem(prefixes);
427        getitem(first_prefixes);
428        getitem(later_prefixes);
429        getitem(wrap);
430        getitem(autoline);
431    }
432#undef getitem
433
434    if(autoline) {
435        if(-1 == (i_autoline = PyObject_IsTrue(autoline))) {
436            return NULL;
437        }
438    }
439
440    if(wrap) {
441        if(-1 == (i_wrap = PyObject_IsTrue(wrap))) {
442            return NULL;
443        }
444    }
445
446    if(prefixes) {
447        if (first_prefixes || later_prefixes) {
448            PyErr_SetString(PyExc_TypeError,
449                "do not pass first_prefixes or later_prefixes "
450                "if prefixes is passed");
451            return NULL;
452        }
453        first_prefixes = later_prefixes = prefixes;
454    }
455
456    if(prefix) {
457        if (first_prefix || later_prefix) {
458            PyErr_SetString(PyExc_TypeError,
459                "do not pass first_prefix or later_prefix with prefix");
460            return NULL;
461        }
462        first_prefix = later_prefix = prefix;
463    }
464
465    if (first_prefix) {
466        if (first_prefixes) {
467            PyErr_SetString(PyExc_TypeError,
468                "do not pass both first_prefix and first_prefixes");
469            return NULL;
470        }
471        if(PyList_Append(self->first_prefix, first_prefix))
472            return NULL;
473        first_prune = 1;
474    } else if (first_prefixes) {
475        first_prune = PyList_GET_SIZE(self->first_prefix);
476        if(!(tmp = _PyList_Extend((PyListObject *)self->first_prefix, first_prefixes)))
477            return NULL;
478        Py_DECREF(tmp);
479        first_prune = PyList_GET_SIZE(self->first_prefix) - first_prune;
480    }
481
482    if (later_prefix) {
483        if (later_prefixes) {
484            PyErr_SetString(PyExc_TypeError,
485                "do not pass both later_prefix and later_prefixes");
486            goto finally;
487        }
488        if(PyList_Append(self->later_prefix, later_prefix))
489            goto finally;
490        later_prune = 1;
491    } else if (later_prefixes) {
492        later_prune = PyList_GET_SIZE(self->later_prefix);
493        if(!(tmp = _PyList_Extend((PyListObject *)self->later_prefix, later_prefixes))) {
494            later_prune = 0;
495            goto finally;
496        }
497        Py_DECREF(tmp);
498        later_prune = PyList_GET_SIZE(self->later_prefix) - later_prune;
499    }
500
501    if(!(iterator = PyObject_GetIter(args)))
502        goto finally;
503
504    while ((arg = PyIter_Next(iterator))) {
505        /* If we're at the start of the line, write our prefix.
506         * There is a deficiency here: if neither our arg nor our
507         * prefix affect _pos (both are escape sequences or empty)
508         * we will write prefix more than once. This should not
509         * matter.
510         */
511
512        int is_unicode;
513        if (self->pos == 0)
514            if (_write_prefix(self, i_wrap))
515                goto finally;
516
517        if(!(arg = reduce_callable(self, arg)))
518            goto finally;
519
520        if (arg == Py_None) {
521            Py_CLEAR(arg);
522            continue;
523        }
524
525        if (!PyString_Check(arg)) {
526            is_unicode = PyUnicode_Check(arg);
527            if(!is_unicode) {
528                tmp = PyObject_Str(arg);
529                Py_CLEAR(arg);
530                if(!tmp)
531                    goto finally;
532                arg = tmp;
533                is_unicode = PyUnicode_Check(arg);
534            }
535            if(is_unicode) {
536                arg_len = PyUnicode_GET_SIZE(arg);
537            } else {
538                if(!(arg_len = PyObject_Length(arg)))
539                    goto finally;
540            }
541        } else {
542            arg_len = PyString_GET_SIZE(arg);
543            is_unicode = 0;
544        }
545
546        if(!arg_len) {
547            /* There's nothing to write, so skip this bit... */
548            Py_CLEAR(arg);
549            continue;
550        }
551
552        while (i_wrap && (arg_len > self->width - self->pos)) {
553            PyObject *bit = NULL;
554            /* We have to split. */
555            maxlen = self->width - self->pos;
556            // this should be wiped; it's added for the moment since I'm
557            // not so sure about the code flow following for when
558            // arg_len == max_len
559            int tmp_max = arg_len > maxlen ? maxlen : arg_len;
560            if(is_unicode) {
561                if(-2 == (space = PyUnicode_Find(arg, PTF_unic_space, 0, tmp_max, -1)))
562                    goto finally;
563            } else {
564                char *start, *p;
565                start = PyString_AS_STRING(arg);
566                p = start + tmp_max - 1;
567                while(p >= start && ' ' != *p)
568                    p--;
569                space = start > p ? -1 : p - start;
570            }
571
572            if (space == -1) {
573                /* No space to split on.
574
575                * If we are on the first line we can simply go to
576                * the next (this helps if the "later" prefix is
577                * shorter and should not really matter if not).
578
579                * If we are on the second line and have already
580                * written something we can also go to the next
581                * line.
582                */
583
584                if (self->in_first_line || self->wrote_something) {
585                    if(!(bit = PyString_FromString(""))) {
586                        goto finally;
587                    }
588                } else {
589                    /* Forcibly split this as far to the right as
590                     * possible.
591                     */
592                    if(!(bit = PySequence_GetSlice(arg, 0, tmp_max)))
593                        goto finally;
594                    tmp = PySequence_GetSlice(arg, tmp_max, arg_len);
595                    Py_CLEAR(arg);
596                    if (!tmp) {
597                        Py_DECREF(bit);
598                        goto finally;
599                    }
600                    arg_len -= tmp_max;
601                    arg = tmp;
602                }
603            } else {
604                /* Omit the space we split on.*/
605                if(!(bit = PySequence_GetSlice(arg, 0, space)))
606                    goto finally;
607                tmp = PySequence_GetSlice(arg, space+1, arg_len);
608                Py_CLEAR(arg);
609                if (!tmp) {
610                    Py_DECREF(bit);
611                    goto finally;
612                }
613                arg_len -= space + 1;
614                arg = tmp;
615            }
616
617            if(is_unicode && !(bit = PTF_convert_encoding(self, bit)))
618                goto finally;
619
620            int ret = 0;
621            if (self->stream_callable) {
622                tmp = PyObject_CallFunctionObjArgs(self->stream_callable, bit, NULL);
623                Py_XDECREF(tmp);
624                ret = tmp == NULL;
625            } else {
626                ret = PyFile_WriteObject(bit, self->raw_stream, Py_PRINT_RAW);
627            }
628            Py_DECREF(bit);
629            if(ret)
630                goto finally;
631            if(_flush_newline(self))
632                goto finally;
633
634            self->in_first_line = 0;
635            if(_write_prefix(self, i_wrap))
636                goto finally;
637
638        }
639
640        if(is_unicode && !(arg = PTF_convert_encoding(self, arg)))
641            goto finally;
642        if(self->stream_callable) {
643            tmp = PyObject_CallFunctionObjArgs(self->stream_callable, arg, NULL);
644            Py_XDECREF(tmp);
645            if(!tmp) {
646                goto finally;
647            }
648        } else {
649            if(PyFile_WriteObject(arg, self->raw_stream, Py_PRINT_RAW)) {
650                goto finally;
651            }
652        }
653        self->pos += arg_len;
654        self->wrote_something = 1;
655        Py_CLEAR(arg);
656    }
657
658    if (i_autoline) {
659        if(_flush_newline(self))
660            goto finally;
661        self->in_first_line = 1;
662    }
663
664    failed = 0;
665
666finally:
667    Py_XDECREF(iterator);
668    Py_XDECREF(arg);
669
670    if(first_prune) {
671        PyList_SetSlice(self->first_prefix, -first_prune, PyList_GET_SIZE(self->first_prefix), NULL);
672    }
673    if (later_prune) {
674        PyList_SetSlice(self->later_prefix, -later_prune, PyList_GET_SIZE(self->later_prefix), NULL);
675    }
676
677    e = PyErr_Occurred();
678    if (e) {
679        if (PyErr_ExceptionMatches(PyExc_IOError) &&
680            PyInt_AS_LONG(PyObject_GetAttrString(e, "errno")) == EPIPE)
681                PyErr_SetObject(e, StreamClosed);
682        return NULL;
683    }
684
685    if(failed)
686        return NULL;
687    Py_RETURN_NONE;
688}
689
690PyDoc_STRVAR(
691    PTF_write_doc,
692"Write something to the stream.\n\
693\n\
694Acceptable arguments are:\n\
695  - Strings are simply written to the stream.\n\
696  - C{None} is ignored.\n\
697  - Functions are called with the formatter as argument.\n\
698    Their return value is then used the same way as the other\n\
699    arguments.\n\
700  - Formatter subclasses might special-case certain objects.\n\
701\n\
702Accepts wrap and autoline as keyword arguments. Effect is\n\
703the same as setting them before the write call and resetting\n\
704them afterwards.\n\
705\n\
706Accepts first_prefixes and later_prefixes as keyword\n\
707arguments. They should be sequences that are temporarily\n\
708appended to the first_prefix and later_prefix attributes.\n\
709\n\
710Accepts prefixes as a keyword argument. Effect is the same as\n\
711setting first_prefixes and later_prefixes to the same value.\n\
712\n\
713Accepts first_prefix, later_prefix and prefix as keyword\n\
714argument. Effect is the same as setting first_prefixes,\n\
715later_prefixes or prefixes to a one-element tuple.\n\
716\n\
717The formatter has a couple of attributes that are useful as argument\n\
718to write.\n");
719
720static PyMethodDef PTF_methods[] = {
721    {"write", (PyCFunction)PTF_write, METH_VARARGS | METH_KEYWORDS,
722        PTF_write_doc
723    },
724    {NULL}  /* Sentinel */
725};
726
727static PyGetSetDef PTF_getseters[] = {
728    {"autoline", (getter)PTF_object_get_autoline,
729        (setter)PTF_object_set_autoline,
730        "boolean indicating we are in auto-newline mode "
731        "(defaults to on).", NULL},
732    {"wrap", (getter)PTF_object_get_wrap, (setter)PTF_object_set_wrap,
733        "boolean indicating we auto-linewrap (defaults to off).", NULL},
734    {"stream", (getter)PTF_getstream, (setter)PTF_setstream,
735        "stream to write to",NULL},
736    {"first_prefix", (getter)PTF_object_get_first_prefix,
737        (setter)PTF_set_first_prefix,
738        "a list of items to write on the first line.", NULL},
739    {"later_prefix", (getter)PTF_object_get_later_prefix,
740        (setter)PTF_set_later_prefix,
741        "a list of items to write on every line but the first.", NULL},
742    {"encoding", (getter)PTF_get_encoding, (setter)PTF_set_encoding,
743        "encoding", NULL},
744    {NULL} /* Sentinel */
745};
746
747#undef pyobj_struct
748
749static PyMemberDef PTF_members[] = {
750    {"width", T_INT, offsetof(PTF_object, width), 0,
751         "width to split at"},
752    {"_pos", T_INT, offsetof(PTF_object, pos), 0,
753         "current position"},
754    {"bold", T_OBJECT_EX, offsetof(PTF_object, bold), 0,
755        "object to use to get 'bold' semantics"},
756    {"reset", T_OBJECT_EX, offsetof(PTF_object, reset), 0,
757        "object to use to get 'reset' semantics"},
758    {"underline", T_OBJECT_EX, offsetof(PTF_object, underline), 0,
759        "object to use to get 'underline' semantics"},
760    {NULL}  /* Sentinel */
761};
762
763
764static PyTypeObject PTF_type = {
765        PyObject_HEAD_INIT(NULL)
766        0,                              /* ob_size */
767        "formatters.PlainTextFormatter",/* tp_name */
768        sizeof(PTF_object),             /* tp_basicsize */
769        0,                              /* tp_itemsize */
770        (destructor)PTF_dealloc,        /* tp_dealloc */
771        0,                              /* tp_print */
772        0,                              /* tp_getattr */
773        0,                              /* tp_setattr */
774        0,                              /* tp_compare */
775        0,                              /* tp_repr */
776        0,                              /* tp_as_number */
777        0,                              /* tp_as_sequence */
778        0,                              /* tp_as_mapping */
779        0,                              /* tp_hash */
780        0,                              /* tp_call */
781        0,                              /* tp_str */
782        0,                              /* tp_getattro */
783        0,                              /* tp_setattro */
784        0,                              /* tp_as_buffer */
785        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_CLASS | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
786        0,                              /* tp_doc */
787        (traverseproc)PTF_traverse,     /* tp_traverse */
788        (inquiry)PTF_clear,             /* tp_clear */
789        0,                              /* tp_richcompare */
790        0,                              /* tp_weaklistoffset */
791        0,                              /* tp_iter */
792        0,                              /* tp_iternext */
793        PTF_methods,                    /* tp_methods */
794        PTF_members,                    /* tp_members */
795        PTF_getseters,                  /* tp_getset */
796        0,                              /* tp_base */
797        0,                              /* tp_dict */
798        0,                              /* tp_descr_get */
799        0,                              /* tp_descr_set */
800        0,                              /* tp_dictoffset */
801        (initproc)PTF_init,             /* tp_init */
802        0,                              /* tp_alloc */
803        PTF_new,                        /* tp_new */
804};
805
806PyDoc_STRVAR(
807    formatters_module_doc,
808    "C implementation of snakeoil.formatters.PlainTextFormatter.\n");
809
810PyMODINIT_FUNC
811init_formatters()
812{
813    PyObject *tmp;
814    PyObject *m = Py_InitModule3("_formatters", NULL, formatters_module_doc);
815    if (!m)
816        return;
817
818    if(!StreamClosed) {
819        if(!(StreamClosed = PyErr_NewException("snakeoil._formatters.StreamClosed",
820            PyExc_KeyboardInterrupt, NULL)))
821            return;
822    }
823    Py_INCREF(StreamClosed);
824    if (PyModule_AddObject(m, "StreamClosed", StreamClosed))
825        return;
826
827    if(!PTF_unic_space) {
828        if(!(tmp = PyString_FromString(" ")))
829            return;
830        PTF_unic_space = PyUnicode_FromObject(tmp);
831        Py_DECREF(tmp);
832        if(!PTF_unic_space)
833            return;
834    }
835    if (!ascii_str)
836        if(!(ascii_str = PyString_FromString("ascii")))
837            return;
838
839
840    if (PyType_Ready(&PTF_type) < 0)
841        return;
842    Py_INCREF(&PTF_type);
843    if (PyModule_AddObject(m, "PlainTextFormatter", (PyObject *)&PTF_type) == -1)
844        return;
845}
Note: See TracBrowser for help on using the browser.