~ubuntu-branches/ubuntu/natty/9base/natty

« back to all changes in this revision

Viewing changes to sam/buff.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2010-06-04 17:22:03 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20100604172203-ei85j0da495sr8ut
Tags: 1:6-1
* Adding Kai as co-maintainer.
* Merging upstream version 6.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "sam.h"
 
2
 
 
3
enum
 
4
{
 
5
        Slop = 100      /* room to grow with reallocation */
 
6
};
 
7
 
 
8
static
 
9
void
 
10
sizecache(Buffer *b, uint n)
 
11
{
 
12
        if(n <= b->cmax)
 
13
                return;
 
14
        b->cmax = n+Slop;
 
15
        b->c = runerealloc(b->c, b->cmax);
 
16
}
 
17
 
 
18
static
 
19
void
 
20
addblock(Buffer *b, uint i, uint n)
 
21
{
 
22
        if(i > b->nbl)
 
23
                panic("internal error: addblock");
 
24
 
 
25
        b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]);
 
26
        if(i < b->nbl)
 
27
                memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*));
 
28
        b->bl[i] = disknewblock(disk, n);
 
29
        b->nbl++;
 
30
}
 
31
 
 
32
 
 
33
static
 
34
void
 
35
delblock(Buffer *b, uint i)
 
36
{
 
37
        if(i >= b->nbl)
 
38
                panic("internal error: delblock");
 
39
 
 
40
        diskrelease(disk, b->bl[i]);
 
41
        b->nbl--;
 
42
        if(i < b->nbl)
 
43
                memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*));
 
44
        b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]);
 
45
}
 
46
 
 
47
/*
 
48
 * Move cache so b->cq <= q0 < b->cq+b->cnc.
 
49
 * If at very end, q0 will fall on end of cache block.
 
50
 */
 
51
 
 
52
static
 
53
void
 
54
flush(Buffer *b)
 
55
{
 
56
        if(b->cdirty || b->cnc==0){
 
57
                if(b->cnc == 0)
 
58
                        delblock(b, b->cbi);
 
59
                else
 
60
                        diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
 
61
                b->cdirty = FALSE;
 
62
        }
 
63
}
 
64
 
 
65
static
 
66
void
 
67
setcache(Buffer *b, uint q0)
 
68
{
 
69
        Block **blp, *bl;
 
70
        uint i, q;
 
71
 
 
72
        if(q0 > b->nc)
 
73
                panic("internal error: setcache");
 
74
        /*
 
75
         * flush and reload if q0 is not in cache.
 
76
         */
 
77
        if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc))
 
78
                return;
 
79
        /*
 
80
         * if q0 is at end of file and end of cache, continue to grow this block
 
81
         */
 
82
        if(q0==b->nc && q0==b->cq+b->cnc && b->cnc<=Maxblock)
 
83
                return;
 
84
        flush(b);
 
85
        /* find block */
 
86
        if(q0 < b->cq){
 
87
                q = 0;
 
88
                i = 0;
 
89
        }else{
 
90
                q = b->cq;
 
91
                i = b->cbi;
 
92
        }
 
93
        blp = &b->bl[i];
 
94
        while(q+(*blp)->u.n <= q0 && q+(*blp)->u.n < b->nc){
 
95
                q += (*blp)->u.n;
 
96
                i++;
 
97
                blp++;
 
98
                if(i >= b->nbl)
 
99
                        panic("block not found");
 
100
        }
 
101
        bl = *blp;
 
102
        /* remember position */
 
103
        b->cbi = i;
 
104
        b->cq = q;
 
105
        sizecache(b, bl->u.n);
 
106
        b->cnc = bl->u.n;
 
107
        /*read block*/
 
108
        diskread(disk, bl, b->c, b->cnc);
 
109
}
 
110
 
 
111
void
 
112
bufinsert(Buffer *b, uint q0, Rune *s, uint n)
 
113
{
 
114
        uint i, m, t, off;
 
115
 
 
116
        if(q0 > b->nc)
 
117
                panic("internal error: bufinsert");
 
118
 
 
119
        while(n > 0){
 
120
                setcache(b, q0);
 
121
                off = q0-b->cq;
 
122
                if(b->cnc+n <= Maxblock){
 
123
                        /* Everything fits in one block. */
 
124
                        t = b->cnc+n;
 
125
                        m = n;
 
126
                        if(b->bl == nil){       /* allocate */
 
127
                                if(b->cnc != 0)
 
128
                                        panic("internal error: bufinsert1 cnc!=0");
 
129
                                addblock(b, 0, t);
 
130
                                b->cbi = 0;
 
131
                        }
 
132
                        sizecache(b, t);
 
133
                        runemove(b->c+off+m, b->c+off, b->cnc-off);
 
134
                        runemove(b->c+off, s, m);
 
135
                        b->cnc = t;
 
136
                        goto Tail;
 
137
                }
 
138
                /*
 
139
                 * We must make a new block.  If q0 is at
 
140
                 * the very beginning or end of this block,
 
141
                 * just make a new block and fill it.
 
142
                 */
 
143
                if(q0==b->cq || q0==b->cq+b->cnc){
 
144
                        if(b->cdirty)
 
145
                                flush(b);
 
146
                        m = min(n, Maxblock);
 
147
                        if(b->bl == nil){       /* allocate */
 
148
                                if(b->cnc != 0)
 
149
                                        panic("internal error: bufinsert2 cnc!=0");
 
150
                                i = 0;
 
151
                        }else{
 
152
                                i = b->cbi;
 
153
                                if(q0 > b->cq)
 
154
                                        i++;
 
155
                        }
 
156
                        addblock(b, i, m);
 
157
                        sizecache(b, m);
 
158
                        runemove(b->c, s, m);
 
159
                        b->cq = q0;
 
160
                        b->cbi = i;
 
161
                        b->cnc = m;
 
162
                        goto Tail;
 
163
                }
 
164
                /*
 
165
                 * Split the block; cut off the right side and
 
166
                 * let go of it.
 
167
                 */
 
168
                m = b->cnc-off;
 
169
                if(m > 0){
 
170
                        i = b->cbi+1;
 
171
                        addblock(b, i, m);
 
172
                        diskwrite(disk, &b->bl[i], b->c+off, m);
 
173
                        b->cnc -= m;
 
174
                }
 
175
                /*
 
176
                 * Now at end of block.  Take as much input
 
177
                 * as possible and tack it on end of block.
 
178
                 */
 
179
                m = min(n, Maxblock-b->cnc);
 
180
                sizecache(b, b->cnc+m);
 
181
                runemove(b->c+b->cnc, s, m);
 
182
                b->cnc += m;
 
183
  Tail:
 
184
                b->nc += m;
 
185
                q0 += m;
 
186
                s += m;
 
187
                n -= m;
 
188
                b->cdirty = TRUE;
 
189
        }
 
190
}
 
191
 
 
192
void
 
193
bufdelete(Buffer *b, uint q0, uint q1)
 
194
{
 
195
        uint m, n, off;
 
196
 
 
197
        if(!(q0<=q1 && q0<=b->nc && q1<=b->nc))
 
198
                panic("internal error: bufdelete");
 
199
        while(q1 > q0){
 
200
                setcache(b, q0);
 
201
                off = q0-b->cq;
 
202
                if(q1 > b->cq+b->cnc)
 
203
                        n = b->cnc - off;
 
204
                else
 
205
                        n = q1-q0;
 
206
                m = b->cnc - (off+n);
 
207
                if(m > 0)
 
208
                        runemove(b->c+off, b->c+off+n, m);
 
209
                b->cnc -= n;
 
210
                b->cdirty = TRUE;
 
211
                q1 -= n;
 
212
                b->nc -= n;
 
213
        }
 
214
}
 
215
 
 
216
uint
 
217
bufload(Buffer *b, uint q0, int fd, int *nulls)
 
218
{
 
219
        char *p;
 
220
        Rune *r;
 
221
        int l, m, n, nb, nr;
 
222
        uint q1;
 
223
 
 
224
        if(q0 > b->nc)
 
225
                panic("internal error: bufload");
 
226
        p = malloc((Maxblock+UTFmax+1)*sizeof p[0]);
 
227
        if(p == nil)
 
228
                panic("bufload: malloc failed");
 
229
        r = runemalloc(Maxblock);
 
230
        m = 0;
 
231
        n = 1;
 
232
        q1 = q0;
 
233
        /*
 
234
         * At top of loop, may have m bytes left over from
 
235
         * last pass, possibly representing a partial rune.
 
236
         */
 
237
        while(n > 0){
 
238
                n = read(fd, p+m, Maxblock);
 
239
                if(n < 0){
 
240
                        error(Ebufload);
 
241
                        break;
 
242
                }
 
243
                m += n;
 
244
                p[m] = 0;
 
245
                l = m;
 
246
                if(n > 0)
 
247
                        l -= UTFmax;
 
248
                cvttorunes(p, l, r, &nb, &nr, nulls);
 
249
                memmove(p, p+nb, m-nb);
 
250
                m -= nb;
 
251
                bufinsert(b, q1, r, nr);
 
252
                q1 += nr;
 
253
        }
 
254
        free(p);
 
255
        free(r);
 
256
        return q1-q0;
 
257
}
 
258
 
 
259
void
 
260
bufread(Buffer *b, uint q0, Rune *s, uint n)
 
261
{
 
262
        uint m;
 
263
 
 
264
        if(!(q0<=b->nc && q0+n<=b->nc))
 
265
                panic("bufread: internal error");
 
266
 
 
267
        while(n > 0){
 
268
                setcache(b, q0);
 
269
                m = min(n, b->cnc-(q0-b->cq));
 
270
                runemove(s, b->c+(q0-b->cq), m);
 
271
                q0 += m;
 
272
                s += m;
 
273
                n -= m;
 
274
        }
 
275
}
 
276
 
 
277
void
 
278
bufreset(Buffer *b)
 
279
{
 
280
        int i;
 
281
 
 
282
        b->nc = 0;
 
283
        b->cnc = 0;
 
284
        b->cq = 0;
 
285
        b->cdirty = 0;
 
286
        b->cbi = 0;
 
287
        /* delete backwards to avoid n² behavior */
 
288
        for(i=b->nbl-1; --i>=0; )
 
289
                delblock(b, i);
 
290
}
 
291
 
 
292
void
 
293
bufclose(Buffer *b)
 
294
{
 
295
        bufreset(b);
 
296
        free(b->c);
 
297
        b->c = nil;
 
298
        b->cnc = 0;
 
299
        free(b->bl);
 
300
        b->bl = nil;
 
301
        b->nbl = 0;
 
302
}