~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_rio_pyx.pyx

  • Committer: mbp at sourcefrog
  • Date: 2005-03-24 00:44:18 UTC
  • Revision ID: mbp@sourcefrog.net-20050324004418-b4a050f656c07f5f
show space usage for various stores in the info command

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
"""Pyrex implementation of _read_stanza_*."""
18
 
 
19
 
#python2.4 support
20
 
cdef extern from "python-compat.h":
21
 
    pass
22
 
 
23
 
cdef extern from "malloc.h":
24
 
    void *malloc(int)
25
 
    void *realloc(void *, int)
26
 
    void free(void *)
27
 
 
28
 
cdef extern from "Python.h":
29
 
    ctypedef int Py_ssize_t # Required for older pyrex versions
30
 
    ctypedef int Py_UNICODE
31
 
    char *PyString_AS_STRING(object s)
32
 
    Py_ssize_t PyString_GET_SIZE(object t) except -1
33
 
    object PyUnicode_DecodeUTF8(char *string, Py_ssize_t length, char *errors)
34
 
    object PyString_FromStringAndSize(char *s, Py_ssize_t len)
35
 
    int PyString_CheckExact(object)
36
 
    int PyUnicode_CheckExact(object)
37
 
    object PyUnicode_Join(object, object)
38
 
    object PyUnicode_EncodeASCII(Py_UNICODE *, int, char *)
39
 
    Py_UNICODE *PyUnicode_AS_UNICODE(object)
40
 
    Py_UNICODE *PyUnicode_AsUnicode(object)
41
 
    Py_ssize_t PyUnicode_GET_SIZE(object) except -1
42
 
    int PyList_Append(object, object) except -1    
43
 
    int Py_UNICODE_ISLINEBREAK(Py_UNICODE)
44
 
    int Py_UNICODE_ISSPACE(Py_UNICODE)
45
 
    object PyUnicode_FromUnicode(Py_UNICODE *, int)
46
 
    void *Py_UNICODE_COPY(Py_UNICODE *, Py_UNICODE *, int)
47
 
 
48
 
from bzrlib.rio import Stanza
49
 
 
50
 
cdef int _valid_tag_char(char c):
51
 
    return (c == c'_' or c == c'-' or 
52
 
            (c >= c'a' and c <= c'z') or
53
 
            (c >= c'A' and c <= c'Z') or
54
 
            (c >= c'0' and c <= c'9'))
55
 
 
56
 
 
57
 
def _valid_tag(tag):
58
 
    cdef char *c_tag
59
 
    cdef Py_ssize_t c_len
60
 
    cdef int i
61
 
    if not PyString_CheckExact(tag):
62
 
        raise TypeError(tag)
63
 
    c_tag = PyString_AS_STRING(tag)
64
 
    c_len = PyString_GET_SIZE(tag)
65
 
    for i from 0 <= i < c_len:
66
 
        if not _valid_tag_char(c_tag[i]):
67
 
            return False
68
 
    return True
69
 
 
70
 
 
71
 
cdef object _split_first_line_utf8(char *line, int len, 
72
 
                                   Py_UNICODE *value, int *value_len):
73
 
    cdef int i
74
 
    for i from 0 <= i < len:
75
 
        if line[i] == c':':
76
 
            if line[i+1] != c' ':
77
 
                raise ValueError("invalid tag in line %r" % line)
78
 
            new_value = PyUnicode_DecodeUTF8(line+i+2, len-i-2, "strict")
79
 
            value_len[0] = PyUnicode_GET_SIZE(new_value)
80
 
            Py_UNICODE_COPY(value, PyUnicode_AS_UNICODE(new_value), 
81
 
                            value_len[0])
82
 
            return PyString_FromStringAndSize(line, i)
83
 
    raise ValueError('tag/value separator not found in line %r' % line)
84
 
 
85
 
 
86
 
cdef Py_UNICODE *colon
87
 
colon = PyUnicode_AsUnicode(unicode(":"))
88
 
 
89
 
cdef object _split_first_line_unicode(Py_UNICODE *line, int len, 
90
 
                                      Py_UNICODE *value, int *value_len):
91
 
    cdef int i
92
 
    for i from 0 <= i < len:
93
 
        if line[i] == colon[0]:
94
 
            if not Py_UNICODE_ISSPACE(line[i+1]):
95
 
                raise ValueError("invalid tag in line %r" %
96
 
                                 PyUnicode_FromUnicode(line, len))
97
 
            Py_UNICODE_COPY(value, line+(i+2) * sizeof(Py_UNICODE),
98
 
                            len-i-2)
99
 
            value_len[0] = len-i-2
100
 
            return PyUnicode_EncodeASCII(line, i, "strict")
101
 
    raise ValueError("tag/value separator not found in line %r" %
102
 
                     PyUnicode_FromUnicode(line, len))
103
 
 
104
 
 
105
 
def _read_stanza_utf8(line_iter):
106
 
    cdef char *c_line
107
 
    cdef Py_ssize_t c_len
108
 
    cdef Py_UNICODE *accum_value
109
 
    cdef int accum_len, accum_size
110
 
    pairs = []
111
 
    tag = None
112
 
    accum_len = 0
113
 
    accum_size = 4096
114
 
    accum_value = <Py_UNICODE *>malloc(accum_size*sizeof(Py_UNICODE))
115
 
    if accum_value == NULL:
116
 
        raise MemoryError
117
 
    try:
118
 
        # TODO: jam 20060922 This code should raise real errors rather than
119
 
        #       using 'assert' to process user input, or raising ValueError
120
 
        #       rather than a more specific error.
121
 
        for line in line_iter:
122
 
            if line is None:
123
 
                break # end of file
124
 
            if not PyString_CheckExact(line):
125
 
                raise TypeError("%r is not a plain string" % line)
126
 
            c_line = PyString_AS_STRING(line)
127
 
            c_len = PyString_GET_SIZE(line)
128
 
            if c_len < 1:
129
 
                break       # end of file
130
 
            if c_len == 1 and c_line[0] == c"\n":
131
 
                break       # end of stanza
132
 
            if accum_len + c_len > accum_size:
133
 
                accum_size = (accum_size * 3) / 2
134
 
                accum_value = <Py_UNICODE *>realloc(accum_value, 
135
 
                    accum_size*sizeof(Py_UNICODE))
136
 
                if accum_value == NULL:
137
 
                    raise MemoryError
138
 
            if c_line[0] == c'\t': # continues previous value
139
 
                if tag is None:
140
 
                    raise ValueError('invalid continuation line %r' % line)
141
 
                new_value = PyUnicode_DecodeUTF8(c_line+1, c_len-1, "strict")
142
 
            else: # new tag:value line
143
 
                if tag is not None:
144
 
                    PyList_Append(pairs, 
145
 
                        (tag, PyUnicode_FromUnicode(accum_value, accum_len-1)))
146
 
                tag = _split_first_line_utf8(c_line, c_len, accum_value, 
147
 
                                             &accum_len)
148
 
                if not _valid_tag(tag):
149
 
                    raise ValueError("invalid rio tag %r" % (tag,))
150
 
        if tag is not None: # add last tag-value
151
 
            PyList_Append(pairs, 
152
 
                (tag, PyUnicode_FromUnicode(accum_value, accum_len-1)))
153
 
            return Stanza.from_pairs(pairs)
154
 
        else:     # didn't see any content
155
 
            return None
156
 
    finally:
157
 
        free(accum_value)
158
 
 
159
 
 
160
 
def _read_stanza_unicode(unicode_iter):
161
 
    cdef Py_UNICODE *c_line
162
 
    cdef int c_len
163
 
    cdef Py_UNICODE *accum_value
164
 
    cdef int accum_len, accum_size
165
 
    pairs = []
166
 
    tag = None
167
 
    accum_len = 0
168
 
    accum_size = 4096
169
 
    accum_value = <Py_UNICODE *>malloc(accum_size*sizeof(Py_UNICODE))
170
 
    if accum_value == NULL:
171
 
        raise MemoryError
172
 
    try:
173
 
        # TODO: jam 20060922 This code should raise real errors rather than
174
 
        #       using 'assert' to process user input, or raising ValueError
175
 
        #       rather than a more specific error.
176
 
        for line in unicode_iter:
177
 
            if line is None:
178
 
                break       # end of file
179
 
            if not PyUnicode_CheckExact(line):
180
 
                raise TypeError("%r is not a unicode string" % line)
181
 
            c_line = PyUnicode_AS_UNICODE(line)
182
 
            c_len = PyUnicode_GET_SIZE(line)
183
 
            if c_len < 1:
184
 
                break        # end of file
185
 
            if Py_UNICODE_ISLINEBREAK(c_line[0]):
186
 
                break       # end of stanza
187
 
            if accum_len + c_len > accum_size:
188
 
                accum_size = (accum_size * 3) / 2
189
 
                accum_value = <Py_UNICODE *>realloc(accum_value, 
190
 
                    accum_size*sizeof(Py_UNICODE))
191
 
                if accum_value == NULL:
192
 
                    raise MemoryError
193
 
            if Py_UNICODE_ISSPACE(c_line[0]): # continues previous value,
194
 
                                            # strictly speaking this should be \t
195
 
                if tag is None:
196
 
                    raise ValueError('invalid continuation line %r' % line)
197
 
                Py_UNICODE_COPY(accum_value+accum_len*sizeof(Py_UNICODE),
198
 
                                c_line+1*sizeof(Py_UNICODE), c_len-1);
199
 
            else: # new tag:value line
200
 
                if tag is not None:
201
 
                    PyList_Append(pairs, (tag, PyUnicode_FromUnicode(accum_value, accum_len-1)))
202
 
                tag = _split_first_line_unicode(c_line, c_len, accum_value, 
203
 
                                                &accum_len)
204
 
                if not _valid_tag(tag):
205
 
                    raise ValueError("invalid rio tag %r" % (tag,))
206
 
        if tag is not None: # add last tag-value
207
 
            PyList_Append(pairs, (tag, PyUnicode_FromUnicode(accum_value, accum_len-1)))
208
 
            return Stanza.from_pairs(pairs)
209
 
        else:     # didn't see any content
210
 
            return None
211
 
    finally:
212
 
        free(accum_value)