~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_rio_pyx.pyx

  • Committer: Jelmer Vernooij
  • Date: 2009-05-14 15:42:42 UTC
  • mto: (4290.1.9 rio-serializer2)
  • mto: This revision was merged to the branch mainline in revision 4368.
  • Revision ID: jelmer@samba.org-20090514154242-n8bquw2crer2yur0
More work using C API's rather than Python objects.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
cdef extern from "Python.h":
24
24
    ctypedef int Py_ssize_t # Required for older pyrex versions
 
25
    struct _PyObject:
 
26
        pass
 
27
    ctypedef _PyObject PyObject
25
28
    char *PyString_AS_STRING(object s)
26
 
    Py_ssize_t PyString_GET_SIZE(object t)
 
29
    Py_ssize_t PyString_GET_SIZE(object t) except -1
 
30
    object PyUnicode_DecodeUTF8(char *string, Py_ssize_t length, char *errors)
 
31
    Py_ssize_t PyUnicode_GET_SIZE(object t) except -1
 
32
    int PyUnicode_Resize(PyObject **o, Py_ssize_t size) except -1
 
33
    object PyString_FromStringAndSize(char *s, Py_ssize_t len)
 
34
    int PyString_CheckExact(object)
 
35
    int PyUnicode_CheckExact(object)
 
36
    void Py_INCREF(object)
 
37
    void Py_DECREF(object)
 
38
    object PyList_GetItem(object, int)
 
39
    int PyList_SetItem(object, int, object)    except -1
 
40
    int PyList_Size(object) except -1
 
41
    object PyUnicode_Join(object, object)
 
42
    object PyUnicode_AsASCIIString(object)
27
43
 
28
44
cdef extern from "ctype.h":
29
45
     int isalnum(char c)
30
46
 
 
47
cdef extern from "string.h":
 
48
    char *strstr(char *a, char *b)
 
49
    int strcmp(char *a, char *b)
 
50
 
 
51
 
31
52
from bzrlib.rio import Stanza
32
53
 
33
54
def _valid_tag(tag):
34
55
    cdef char *c_tag
35
 
    cdef int c_len
 
56
    cdef Py_ssize_t c_len
 
57
    cdef int i
36
58
    c_tag = PyString_AS_STRING(tag)
37
59
    c_len = PyString_GET_SIZE(tag)
38
60
    for i from 0 <= i < c_len:
41
63
            return False
42
64
    return True
43
65
 
 
66
cdef object _join_utf8_strip(object entries):
 
67
    cdef PyObject *c_ret
 
68
    cdef Py_ssize_t size
 
69
    entries[-1] = entries[-1][:-1]
 
70
    return PyUnicode_Join(unicode(""), entries)
 
71
 
44
72
 
45
73
def _read_stanza_utf8(line_iter):
 
74
    cdef char *c_line, *colon
 
75
    cdef Py_ssize_t c_len
46
76
    pairs = []
47
77
    tag = None
48
78
    accum_value = []
51
81
    #       using 'assert' to process user input, or raising ValueError
52
82
    #       rather than a more specific error.
53
83
    for line in line_iter:
54
 
        if line is None or line == '':
 
84
        if line is None:
 
85
            break # end of file
 
86
        if not PyString_CheckExact(line):
 
87
            raise TypeError("%r is not a line" % line)
 
88
        c_line = PyString_AS_STRING(line)
 
89
        c_len = PyString_GET_SIZE(line)
 
90
        if strcmp(c_line, "") == 0:
55
91
            break       # end of file
56
 
        if line == '\n':
 
92
        if strcmp(c_line, "\n") == 0:
57
93
            break       # end of stanza
58
 
        if line[0] == '\t': # continues previous value
 
94
        if c_line[0] == c'\t': # continues previous value
59
95
            if tag is None:
60
96
                raise ValueError('invalid continuation line %r' % line)
61
 
            accum_value.append('\n' + line[1:-1])
 
97
            new_value = PyUnicode_DecodeUTF8(c_line+1, c_len-1, "strict")
62
98
        else: # new tag:value line
63
99
            if tag is not None:
64
 
                pairs.append((tag, ''.join(accum_value).decode('utf-8')))
65
 
            try:
66
 
                colon_index = line.index(': ')
67
 
            except ValueError:
 
100
                pairs.append((tag, _join_utf8_strip(accum_value)))
 
101
            colon = <char *>strstr(c_line, ": ")
 
102
            if colon == NULL:
68
103
                raise ValueError('tag/value separator not found in line %r'
69
104
                                 % line)
70
 
            tag = line[:colon_index]
71
 
            #if not _valid_tag(tag):
72
 
            #    raise ValueError("invalid rio tag %r" % (tag,))
73
 
            accum_value = [line[colon_index+2:-1]]
 
105
            tag = PyString_FromStringAndSize(c_line, colon-c_line)
 
106
            if not _valid_tag(tag):
 
107
                raise ValueError("invalid rio tag %r" % (tag,))
 
108
            accum_value = []
 
109
            new_value = PyUnicode_DecodeUTF8(colon+2, c_len-(colon-c_line+2),
 
110
                                             "strict")
 
111
        accum_value.append(new_value)
74
112
    if tag is not None: # add last tag-value
75
 
        pairs.append((tag, ''.join(accum_value).decode('utf-8')))
 
113
        pairs.append((tag, _join_utf8_strip(accum_value)))
76
114
        return Stanza.from_pairs(pairs)
77
115
    else:     # didn't see any content
78
116
        return None
79
117
 
80
118
 
81
119
def _read_stanza_unicode(unicode_iter):
 
120
    cdef int colon_index
82
121
    pairs = []
83
122
    tag = None
84
 
    accum_value = None
 
123
    accum_value = []
85
124
 
86
125
    # TODO: jam 20060922 This code should raise real errors rather than
87
126
    #       using 'assert' to process user input, or raising ValueError
88
127
    #       rather than a more specific error.
89
128
    for line in unicode_iter:
90
 
        if line is None or line == '':
 
129
        if line is None or line == unicode(''):
91
130
            break       # end of file
92
 
        if line == '\n':
 
131
        if line == unicode('\n'):
93
132
            break       # end of stanza
94
 
        real_l = line
95
 
        if line[0] == '\t': # continues previous value
 
133
        if line[0] == unicode('\t'): # continues previous value
96
134
            if tag is None:
97
 
                raise ValueError('invalid continuation line %r' % real_l)
98
 
            accum_value += '\n' + line[1:-1]
 
135
                raise ValueError('invalid continuation line %r' % line)
 
136
            accum_value.append(line[1:])
99
137
        else: # new tag:value line
100
138
            if tag is not None:
101
 
                pairs.append((tag, accum_value))
 
139
                pairs.append((tag, PyUnicode_Join(unicode(""), accum_value[:-1])))
102
140
            try:
103
 
                colon_index = line.index(': ')
 
141
                colon_index = line.index(unicode(': '))
104
142
            except ValueError:
105
143
                raise ValueError('tag/value separator not found in line %r'
106
 
                                 % real_l)
107
 
            tag = str(line[:colon_index])
108
 
            #if not _valid_tag(tag):
109
 
            #    raise ValueError("invalid rio tag %r" % (tag,))
110
 
            accum_value = line[colon_index+2:-1]
 
144
                                 % line)
 
145
            tag = PyUnicode_AsASCIIString(line[0:colon_index])
 
146
            if not _valid_tag(tag):
 
147
                raise ValueError("invalid rio tag %r" % (tag,))
 
148
            accum_value = [line[colon_index+2:]]
111
149
 
112
150
    if tag is not None: # add last tag-value
113
 
        pairs.append((tag, accum_value))
 
151
        pairs.append((tag, PyUnicode_Join(unicode(""), accum_value[:-1])))
114
152
        return Stanza.from_pairs(pairs)
115
153
    else:     # didn't see any content
116
154
        return None