Add progress bars to mergeinfo generation code.
[jelmer/subvertpy.git] / editor.c
1 /* Copyright © 2008 Jelmer Vernooij <jelmer@samba.org>
2  * -*- coding: utf-8 -*-
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 #include <stdbool.h>
19 #include <Python.h>
20 #include <apr_general.h>
21 #include <svn_types.h>
22 #include <svn_delta.h>
23
24 #include "editor.h"
25 #include "util.h"
26
27 typedef struct {
28         PyObject_HEAD
29         const svn_delta_editor_t *editor;
30         void *baton;
31         apr_pool_t *pool;
32         void (*done_cb) (void *baton);
33         void *done_baton;
34 } EditorObject;
35
36 PyObject *new_editor_object(const svn_delta_editor_t *editor, void *baton, apr_pool_t *pool, PyTypeObject *type, void (*done_cb) (void *), void *done_baton)
37 {
38         EditorObject *obj = PyObject_New(EditorObject, type);
39         if (obj == NULL)
40                 return NULL;
41         obj->editor = editor;
42         obj->baton = baton;
43         obj->pool = pool;
44         obj->done_cb = done_cb;
45         obj->done_baton = done_baton;
46         return (PyObject *)obj;
47 }
48
49 static void py_editor_dealloc(PyObject *self)
50 {
51         EditorObject *editor = (EditorObject *)self;
52         apr_pool_destroy(editor->pool);
53         PyObject_Del(self);
54 }
55
56 /* paranoia check */
57 #if defined(SIZEOF_SIZE_T) && SIZEOF_SIZE_T != SIZEOF_LONG
58 #error "Unable to determine PyArg_Parse format for size_t"
59 #endif
60
61 /* svn_filesize_t is always 64 bits */
62 #if SIZEOF_LONG == 8
63 #define SVN_FILESIZE_T_PYFMT "k"
64 #elif SIZEOF_LONG_LONG == 8
65 #define SVN_FILESIZE_T_PYFMT "K"
66 #else
67 #error "Unable to determine PyArg_Parse format for size_t"
68 #endif
69
70 static PyObject *txdelta_call(PyObject *self, PyObject *args, PyObject *kwargs)
71 {
72         char *kwnames[] = { "window", NULL };
73         svn_txdelta_window_t window;
74         TxDeltaWindowHandlerObject *obj = (TxDeltaWindowHandlerObject *)self;
75         PyObject *py_window, *py_ops, *py_new_data;
76         int i;
77         svn_string_t new_data;
78         svn_error_t *error;
79         svn_txdelta_op_t *ops;
80
81         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_window))
82                 return NULL;
83
84         if (py_window == Py_None) {
85                 RUN_SVN(obj->txdelta_handler(NULL, obj->txdelta_baton));
86                 Py_RETURN_NONE;
87         }
88
89         if (!PyArg_ParseTuple(py_window, SVN_FILESIZE_T_PYFMT "kkiOO", &window.sview_offset, &window.sview_len, 
90                                                                                         &window.tview_len, &window.src_ops, &py_ops, &py_new_data))
91                 return NULL;
92
93         if (py_new_data == Py_None) {
94                 window.new_data = NULL;
95         } else {
96                 new_data.data = PyString_AsString(py_new_data);
97                 new_data.len = PyString_Size(py_new_data);
98                 window.new_data = &new_data;
99         }
100
101         if (!PyList_Check(py_ops)) {
102                 PyErr_SetString(PyExc_TypeError, "ops not a list");
103                 return NULL;
104         }
105
106         window.num_ops = PyList_Size(py_ops);
107
108         window.ops = ops = malloc(sizeof(svn_txdelta_op_t) * window.num_ops);
109
110         for (i = 0; i < window.num_ops; i++) {
111                 PyObject *windowitem = PyList_GetItem(py_ops, i);
112                 if (!PyArg_ParseTuple(windowitem, "ikk", &ops[i].action_code, 
113                                                           &ops[i].offset, &ops[i].length)) {
114                         free(ops);
115                         return NULL;
116                 }
117         }
118
119         Py_BEGIN_ALLOW_THREADS
120         error = obj->txdelta_handler(&window, obj->txdelta_baton);
121         Py_END_ALLOW_THREADS
122         if (!check_error(error)) {
123                 free(ops);
124                 return NULL;
125         }
126
127         free(ops);
128
129         Py_RETURN_NONE;
130 }
131
132 PyTypeObject TxDeltaWindowHandler_Type = {
133         PyObject_HEAD_INIT(NULL) 0,
134         "ra.TxDeltaWindowHandler", /*   const char *tp_name;  For printing, in format "<module>.<name>" */
135         sizeof(TxDeltaWindowHandlerObject), 
136         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
137         
138         /* Methods to implement standard operations */
139         
140         (destructor)PyObject_Del, /*    destructor tp_dealloc;  */
141         NULL, /*        printfunc tp_print;     */
142         NULL, /*        getattrfunc tp_getattr; */
143         NULL, /*        setattrfunc tp_setattr; */
144         NULL, /*        cmpfunc tp_compare;     */
145         NULL, /*        reprfunc tp_repr;       */
146         
147         /* Method suites for standard classes */
148         
149         NULL, /*        PyNumberMethods *tp_as_number;  */
150         NULL, /*        PySequenceMethods *tp_as_sequence;      */
151         NULL, /*        PyMappingMethods *tp_as_mapping;        */
152         
153         /* More standard operations (here for binary compatibility) */
154         
155         NULL, /*        hashfunc tp_hash;       */
156         txdelta_call, /*        ternaryfunc tp_call;    */
157         
158 };
159
160 static PyObject *py_file_editor_apply_textdelta(PyObject *self, PyObject *args)
161 {
162         EditorObject *editor = (EditorObject *)self;
163         char *c_base_checksum = NULL;
164         svn_txdelta_window_handler_t txdelta_handler;
165         void *txdelta_baton;
166         TxDeltaWindowHandlerObject *py_txdelta;
167
168         if (!FileEditor_Check(self)) {
169                 PyErr_BadArgument();
170                 return NULL;
171         }
172
173         if (!PyArg_ParseTuple(args, "|z", &c_base_checksum))
174                 return NULL;
175         RUN_SVN(editor->editor->apply_textdelta(editor->baton,
176                                 c_base_checksum, editor->pool, 
177                                 &txdelta_handler, &txdelta_baton));
178         py_txdelta = PyObject_New(TxDeltaWindowHandlerObject, &TxDeltaWindowHandler_Type);
179         py_txdelta->txdelta_handler = txdelta_handler;
180         py_txdelta->txdelta_baton = txdelta_baton;
181         return (PyObject *)py_txdelta;
182 }
183
184 static PyObject *py_file_editor_change_prop(PyObject *self, PyObject *args)
185 {
186         EditorObject *editor = (EditorObject *)self;
187         char *name;
188         svn_string_t c_value;
189         int vallen;
190
191         if (!FileEditor_Check(self)) {
192                 PyErr_BadArgument();
193                 return NULL;
194         }
195
196         if (!PyArg_ParseTuple(args, "sz#", &name, &c_value.data, &vallen))
197                 return NULL;
198
199         c_value.len = vallen;
200
201         RUN_SVN(editor->editor->change_file_prop(editor->baton, name, 
202                                 &c_value, editor->pool));
203         Py_RETURN_NONE;
204 }
205
206 static PyObject *py_file_editor_close(PyObject *self, PyObject *args)
207 {
208         EditorObject *editor = (EditorObject *)self;
209         char *c_checksum = NULL;
210
211         if (!FileEditor_Check(self)) {
212                 PyErr_BadArgument();
213                 return NULL;
214         }
215
216         if (!PyArg_ParseTuple(args, "|z", &c_checksum))
217                 return NULL;
218         RUN_SVN(editor->editor->close_file(editor->baton, c_checksum, 
219                                         editor->pool));
220         Py_RETURN_NONE;
221 }
222
223 static PyMethodDef py_file_editor_methods[] = {
224         { "change_prop", py_file_editor_change_prop, METH_VARARGS, NULL },
225         { "close", py_file_editor_close, METH_VARARGS, NULL },
226         { "apply_textdelta", py_file_editor_apply_textdelta, METH_VARARGS, NULL },
227         { NULL }
228 };
229
230 PyTypeObject FileEditor_Type = { 
231         PyObject_HEAD_INIT(NULL) 0, 
232         "ra.FileEditor", /*     const char *tp_name;  For printing, in format "<module>.<name>" */
233         sizeof(EditorObject), 
234         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
235         
236         /* Methods to implement standard operations */
237         
238         (destructor)PyObject_Del, /*    destructor tp_dealloc;  */
239         NULL, /*        printfunc tp_print;     */
240         NULL, /*        getattrfunc tp_getattr; */
241         NULL, /*        setattrfunc tp_setattr; */
242         NULL, /*        cmpfunc tp_compare;     */
243         NULL, /*        reprfunc tp_repr;       */
244         
245         /* Method suites for standard classes */
246         
247         NULL, /*        PyNumberMethods *tp_as_number;  */
248         NULL, /*        PySequenceMethods *tp_as_sequence;      */
249         NULL, /*        PyMappingMethods *tp_as_mapping;        */
250         
251         /* More standard operations (here for binary compatibility) */
252         
253         NULL, /*        hashfunc tp_hash;       */
254         NULL, /*        ternaryfunc tp_call;    */
255         NULL, /*        reprfunc tp_str;        */
256         NULL, /*        getattrofunc tp_getattro;       */
257         NULL, /*        setattrofunc tp_setattro;       */
258         
259         /* Functions to access object as input/output buffer */
260         NULL, /*        PyBufferProcs *tp_as_buffer;    */
261         
262         /* Flags to define presence of optional/expanded features */
263         0, /*   long tp_flags;  */
264         
265         NULL, /*        const char *tp_doc;  Documentation string */
266         
267         /* Assigned meaning in release 2.0 */
268         /* call function for all accessible objects */
269         NULL, /*        traverseproc tp_traverse;       */
270         
271         /* delete references to contained objects */
272         NULL, /*        inquiry tp_clear;       */
273         
274         /* Assigned meaning in release 2.1 */
275         /* rich comparisons */
276         NULL, /*        richcmpfunc tp_richcompare;     */
277         
278         /* weak reference enabler */
279         0, /*   Py_ssize_t tp_weaklistoffset;   */
280         
281         /* Added in release 2.2 */
282         /* Iterators */
283         NULL, /*        getiterfunc tp_iter;    */
284         NULL, /*        iternextfunc tp_iternext;       */
285         
286         /* Attribute descriptor and subclassing stuff */
287         py_file_editor_methods, /*      struct PyMethodDef *tp_methods; */
288 };
289
290 static PyObject *py_dir_editor_delete_entry(PyObject *self, PyObject *args)
291 {
292         EditorObject *editor = (EditorObject *)self;
293         char *path; 
294         svn_revnum_t revision = -1;
295
296         if (!DirectoryEditor_Check(self)) {
297                 PyErr_BadArgument();
298                 return NULL;
299         }
300
301         if (!PyArg_ParseTuple(args, "s|l", &path, &revision))
302                 return NULL;
303
304         RUN_SVN(editor->editor->delete_entry(path, revision, editor->baton,
305                                                                                          editor->pool));
306
307         Py_RETURN_NONE;
308 }
309
310 static PyObject *py_dir_editor_add_directory(PyObject *self, PyObject *args)
311 {
312         char *path;
313         char *copyfrom_path=NULL; 
314         int copyfrom_rev=-1;
315         void *child_baton;
316         EditorObject *editor = (EditorObject *)self;
317
318         if (!DirectoryEditor_Check(self)) {
319                 PyErr_BadArgument();
320                 return NULL;
321         }
322
323         if (!PyArg_ParseTuple(args, "s|zl", &path, &copyfrom_path, &copyfrom_rev))
324                 return NULL;
325
326         RUN_SVN(editor->editor->add_directory(path, editor->baton,
327                                         copyfrom_path, copyfrom_rev, editor->pool, &child_baton));
328
329         return new_editor_object(editor->editor, child_baton, editor->pool, 
330                                                          &DirectoryEditor_Type, NULL, NULL);
331 }
332
333 static PyObject *py_dir_editor_open_directory(PyObject *self, PyObject *args)
334 {
335         char *path;
336         EditorObject *editor = (EditorObject *)self;
337         int base_revision=-1;
338         void *child_baton;
339
340         if (!DirectoryEditor_Check(self)) {
341                 PyErr_BadArgument();
342                 return NULL;
343         }
344
345         if (!PyArg_ParseTuple(args, "s|l", &path, &base_revision))
346                 return NULL;
347
348         RUN_SVN(editor->editor->open_directory(path, editor->baton,
349                                         base_revision, editor->pool, &child_baton));
350
351         return new_editor_object(editor->editor, child_baton, editor->pool, 
352                                                          &DirectoryEditor_Type, NULL, NULL);
353 }
354
355 static PyObject *py_dir_editor_change_prop(PyObject *self, PyObject *args)
356 {
357         char *name;
358         svn_string_t c_value;
359         EditorObject *editor = (EditorObject *)self;
360         int vallen;
361
362         if (!DirectoryEditor_Check(self)) {
363                 PyErr_BadArgument();
364                 return NULL;
365         }
366
367         if (!PyArg_ParseTuple(args, "sz#", &name, &c_value.data, &vallen))
368                 return NULL;
369
370         c_value.len = vallen;
371
372         RUN_SVN(editor->editor->change_dir_prop(editor->baton, name, 
373                                         &c_value, editor->pool));
374
375         Py_RETURN_NONE;
376 }
377
378 static PyObject *py_dir_editor_close(PyObject *self)
379 {
380         EditorObject *editor = (EditorObject *)self;
381
382         if (!DirectoryEditor_Check(self)) {
383                 PyErr_BadArgument();
384                 return NULL;
385         }
386
387         RUN_SVN(editor->editor->close_directory(editor->baton, editor->pool));
388
389         Py_RETURN_NONE;
390 }
391
392 static PyObject *py_dir_editor_absent_directory(PyObject *self, PyObject *args)
393 {
394         char *path;
395         EditorObject *editor = (EditorObject *)self;
396
397         if (!Editor_Check(self)) {
398                 PyErr_BadArgument();
399                 return NULL;
400         }
401
402
403         if (!PyArg_ParseTuple(args, "s", &path))
404                 return NULL;
405         
406         RUN_SVN(editor->editor->absent_directory(path, editor->baton, editor->pool));
407
408         Py_RETURN_NONE;
409 }
410
411 static PyObject *py_dir_editor_add_file(PyObject *self, PyObject *args)
412 {
413         char *path, *copy_path=NULL;
414         svn_revnum_t copy_rev=-1;
415         void *file_baton = NULL;
416         EditorObject *editor = (EditorObject *)self;
417
418         if (!DirectoryEditor_Check(self)) {
419                 PyErr_BadArgument();
420                 return NULL;
421         }
422
423         if (!PyArg_ParseTuple(args, "s|zl", &path, &copy_path, &copy_rev))
424                 return NULL;
425
426         RUN_SVN(editor->editor->add_file(path, editor->baton, copy_path,
427                                         copy_rev, editor->pool, &file_baton));
428
429         return new_editor_object(editor->editor, file_baton, editor->pool,
430                                                          &FileEditor_Type, NULL, NULL);
431 }
432
433 static PyObject *py_dir_editor_open_file(PyObject *self, PyObject *args)
434 {
435         char *path;
436         int base_revision=-1;
437         void *file_baton;
438         EditorObject *editor = (EditorObject *)self;
439
440         if (!DirectoryEditor_Check(self)) {
441                 PyErr_BadArgument();
442                 return NULL;
443         }
444
445         if (!PyArg_ParseTuple(args, "s|l", &path, &base_revision))
446                 return NULL;
447
448         RUN_SVN(editor->editor->open_file(path, editor->baton, 
449                                         base_revision, editor->pool, &file_baton));
450
451         return new_editor_object(editor->editor, file_baton, editor->pool,
452                                                          &FileEditor_Type, NULL, NULL);
453 }
454
455 static PyObject *py_dir_editor_absent_file(PyObject *self, PyObject *args)
456 {
457         char *path;
458         EditorObject *editor = (EditorObject *)self;
459
460         if (!DirectoryEditor_Check(self)) {
461                 PyErr_BadArgument();
462                 return NULL;
463         }
464
465         if (!PyArg_ParseTuple(args, "s", &path))
466                 return NULL;
467
468         RUN_SVN(editor->editor->absent_file(path, editor->baton, editor->pool));
469
470         Py_RETURN_NONE;
471 }
472
473 static PyMethodDef py_dir_editor_methods[] = {
474         { "absent_file", py_dir_editor_absent_file, METH_VARARGS, NULL },
475         { "absent_directory", py_dir_editor_absent_directory, METH_VARARGS, NULL },
476         { "delete_entry", py_dir_editor_delete_entry, METH_VARARGS, NULL },
477         { "add_file", py_dir_editor_add_file, METH_VARARGS, NULL },
478         { "open_file", py_dir_editor_open_file, METH_VARARGS, NULL },
479         { "add_directory", py_dir_editor_add_directory, METH_VARARGS, NULL },
480         { "open_directory", py_dir_editor_open_directory, METH_VARARGS, NULL },
481         { "close", (PyCFunction)py_dir_editor_close, METH_NOARGS, NULL },
482         { "change_prop", py_dir_editor_change_prop, METH_VARARGS, NULL },
483
484         { NULL, }
485 };
486
487 PyTypeObject DirectoryEditor_Type = { 
488         PyObject_HEAD_INIT(NULL) 0,
489         "ra.DirEditor", /*      const char *tp_name;  For printing, in format "<module>.<name>" */
490         sizeof(EditorObject), 
491         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
492         
493         /* Methods to implement standard operations */
494         
495         (destructor)PyObject_Del, /*    destructor tp_dealloc;  */
496         NULL, /*        printfunc tp_print;     */
497         NULL, /*        getattrfunc tp_getattr; */
498         NULL, /*        setattrfunc tp_setattr; */
499         NULL, /*        cmpfunc tp_compare;     */
500         NULL, /*        reprfunc tp_repr;       */
501         
502         /* Method suites for standard classes */
503         
504         NULL, /*        PyNumberMethods *tp_as_number;  */
505         NULL, /*        PySequenceMethods *tp_as_sequence;      */
506         NULL, /*        PyMappingMethods *tp_as_mapping;        */
507         
508         /* More standard operations (here for binary compatibility) */
509         
510         NULL, /*        hashfunc tp_hash;       */
511         NULL, /*        ternaryfunc tp_call;    */
512         NULL, /*        reprfunc tp_str;        */
513         NULL, /*        getattrofunc tp_getattro;       */
514         NULL, /*        setattrofunc tp_setattro;       */
515         
516         /* Functions to access object as input/output buffer */
517         NULL, /*        PyBufferProcs *tp_as_buffer;    */
518         
519         /* Flags to define presence of optional/expanded features */
520         0, /*   long tp_flags;  */
521         
522         NULL, /*        const char *tp_doc;  Documentation string */
523         
524         /* Assigned meaning in release 2.0 */
525         /* call function for all accessible objects */
526         NULL, /*        traverseproc tp_traverse;       */
527         
528         /* delete references to contained objects */
529         NULL, /*        inquiry tp_clear;       */
530         
531         /* Assigned meaning in release 2.1 */
532         /* rich comparisons */
533         NULL, /*        richcmpfunc tp_richcompare;     */
534         
535         /* weak reference enabler */
536         0, /*   Py_ssize_t tp_weaklistoffset;   */
537         
538         /* Added in release 2.2 */
539         /* Iterators */
540         NULL, /*        getiterfunc tp_iter;    */
541         NULL, /*        iternextfunc tp_iternext;       */
542         
543         /* Attribute descriptor and subclassing stuff */
544         py_dir_editor_methods, /*       struct PyMethodDef *tp_methods; */
545         
546 };
547
548 static PyObject *py_editor_set_target_revision(PyObject *self, PyObject *args)
549 {
550         int target_revision;
551         EditorObject *editor = (EditorObject *)self;
552
553         if (!Editor_Check(self)) {
554                 PyErr_BadArgument();
555                 return NULL;
556         }
557
558         if (!PyArg_ParseTuple(args, "i", &target_revision))
559                 return NULL;
560
561         RUN_SVN(editor->editor->set_target_revision(editor->baton,
562                                         target_revision, editor->pool));
563
564         Py_RETURN_NONE;
565 }
566         
567 static PyObject *py_editor_open_root(PyObject *self, PyObject *args)
568 {
569         svn_revnum_t base_revision=-1;
570         void *root_baton;
571         EditorObject *editor = (EditorObject *)self;
572
573         if (!Editor_Check(self)) {
574                 PyErr_BadArgument();
575                 return NULL;
576         }
577
578         if (!PyArg_ParseTuple(args, "|l:open_root", &base_revision))
579                 return NULL;
580
581         RUN_SVN(editor->editor->open_root(editor->baton, base_revision,
582                                         editor->pool, &root_baton));
583
584         return new_editor_object(editor->editor, root_baton, editor->pool,
585                                                          &DirectoryEditor_Type, NULL, NULL);
586 }
587
588 static PyObject *py_editor_close(PyObject *self)
589 {
590         EditorObject *editor = (EditorObject *)self;
591
592         if (!Editor_Check(self)) {
593                 PyErr_BadArgument();
594                 return NULL;
595         }
596
597         RUN_SVN(editor->editor->close_edit(editor->baton, editor->pool));
598
599         if (editor->done_cb != NULL)
600                 editor->done_cb(editor->done_baton);
601
602         Py_RETURN_NONE;
603 }
604
605 static PyObject *py_editor_abort(PyObject *self)
606 {
607         EditorObject *editor = (EditorObject *)self;
608
609         if (!Editor_Check(self)) {
610                 PyErr_BadArgument();
611                 return NULL;
612         }
613
614         RUN_SVN(editor->editor->abort_edit(editor->baton, editor->pool));
615
616         if (editor->done_cb != NULL)
617                 editor->done_cb(editor->done_baton);
618         
619         Py_RETURN_NONE;
620 }
621
622 static PyMethodDef py_editor_methods[] = { 
623         { "abort", (PyCFunction)py_editor_abort, METH_NOARGS, NULL },
624         { "close", (PyCFunction)py_editor_close, METH_NOARGS, NULL },
625         { "open_root", py_editor_open_root, METH_VARARGS, NULL },
626         { "set_target_revision", py_editor_set_target_revision, METH_VARARGS, NULL },
627         { NULL, }
628 };
629
630 PyTypeObject Editor_Type = { 
631         PyObject_HEAD_INIT(NULL) 0,
632         "ra.Editor", /* const char *tp_name;  For printing, in format "<module>.<name>" */
633         sizeof(EditorObject), 
634         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
635         
636         /* Methods to implement standard operations */
637         
638         py_editor_dealloc, /*   destructor tp_dealloc;  */
639         NULL, /*        printfunc tp_print;     */
640         NULL, /*        getattrfunc tp_getattr; */
641         NULL, /*        setattrfunc tp_setattr; */
642         NULL, /*        cmpfunc tp_compare;     */
643         NULL, /*        reprfunc tp_repr;       */
644         
645         /* Method suites for standard classes */
646         
647         NULL, /*        PyNumberMethods *tp_as_number;  */
648         NULL, /*        PySequenceMethods *tp_as_sequence;      */
649         NULL, /*        PyMappingMethods *tp_as_mapping;        */
650         
651         /* More standard operations (here for binary compatibility) */
652         
653         NULL, /*        hashfunc tp_hash;       */
654         NULL, /*        ternaryfunc tp_call;    */
655         NULL, /*        reprfunc tp_str;        */
656         NULL, /*        getattrofunc tp_getattro;       */
657         NULL, /*        setattrofunc tp_setattro;       */
658         
659         /* Functions to access object as input/output buffer */
660         NULL, /*        PyBufferProcs *tp_as_buffer;    */
661         
662         /* Flags to define presence of optional/expanded features */
663         0, /*   long tp_flags;  */
664         
665         NULL, /*        const char *tp_doc;  Documentation string */
666         
667         /* Assigned meaning in release 2.0 */
668         /* call function for all accessible objects */
669         NULL, /*        traverseproc tp_traverse;       */
670         
671         /* delete references to contained objects */
672         NULL, /*        inquiry tp_clear;       */
673         
674         /* Assigned meaning in release 2.1 */
675         /* rich comparisons */
676         NULL, /*        richcmpfunc tp_richcompare;     */
677         
678         /* weak reference enabler */
679         0, /*   Py_ssize_t tp_weaklistoffset;   */
680         
681         /* Added in release 2.2 */
682         /* Iterators */
683         NULL, /*        getiterfunc tp_iter;    */
684         NULL, /*        iternextfunc tp_iternext;       */
685         
686         /* Attribute descriptor and subclassing stuff */
687         py_editor_methods, /*   struct PyMethodDef *tp_methods; */
688 };
689
690