1 /*
2 Copyright (C) 2000 Masanao Izumo <mo@goice.co.jp>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #ifndef NO_STRING_H
23 #include <string.h>
24 #else
25 #include <strings.h>
26 #endif
27
28 #include "libarc/url.h"
29
30 #define URL_BUFF_SIZE (8*1024)
31 #define BASESIZE (URL_BUFF_SIZE * 2)
32 #define BASEMASK (BASESIZE-1)
33
34 typedef struct _URL_buff
35 {
36 char common[sizeof(struct _URL)];
37 URL reader;
38 unsigned char buffer[BASESIZE + URL_BUFF_SIZE]; /* ring buffer */
39 int wp; /* write pointer to the buffer */
40 int rp; /* read pointer from the buffer */
41 long pos, posofs; /* position */
42 int weof;
43 int eof;
44 int autoclose;
45 } URL_buff;
46
47 static long url_buff_read(URL url, void *buff, long n);
48 static char *url_buff_gets(URL url, char *buff, int n);
49 static int url_buff_fgetc(URL url);
50 static long url_buff_seek(URL url, long offset, int whence);
51 static long url_buff_tell(URL url);
52 static void url_buff_close(URL url);
53
url_buff_open(URL url,int autoclose)54 URL url_buff_open(URL url, int autoclose)
55 {
56 URL_buff *urlp;
57
58 if((urlp = (URL_buff *)alloc_url(sizeof(URL_buff))) == NULL)
59 {
60 if(autoclose)
61 url_close(url);
62 return NULL;
63 }
64
65 /* common members */
66 URLm(urlp, type) = URL_buff_t;
67 URLm(urlp, url_read) = url_buff_read;
68 URLm(urlp, url_gets) = url_buff_gets;
69 URLm(urlp, url_fgetc) = url_buff_fgetc;
70 URLm(urlp, url_seek) = url_buff_seek;
71 URLm(urlp, url_tell) = url_buff_tell;
72 URLm(urlp, url_close) = url_buff_close;
73
74 /* private members */
75 urlp->reader = url;
76 memset(urlp->buffer, 0, sizeof(urlp->buffer));
77 urlp->wp = 0;
78 urlp->rp = 0;
79 if((urlp->posofs = url_tell(url)) == -1)
80 urlp->posofs = 0;
81 urlp->pos = 0;
82 urlp->eof = 0;
83 urlp->autoclose = autoclose;
84
85 return (URL)urlp;
86 }
87
prefetch(URL_buff * urlp)88 static void prefetch(URL_buff *urlp)
89 {
90 long i, n;
91
92 n = url_safe_read(urlp->reader, urlp->buffer + urlp->wp, URL_BUFF_SIZE);
93 if(n <= 0)
94 return;
95 urlp->wp += n;
96 if(urlp->wp < BASESIZE)
97 return;
98 if(urlp->wp == BASESIZE)
99 {
100 urlp->wp = 0;
101 return;
102 }
103
104 /* urlp->wp > BASESIZE */
105 i = urlp->wp - BASESIZE;
106 memcpy(urlp->buffer, urlp->buffer + BASESIZE, i);
107 urlp->wp = i;
108 }
109
url_buff_fgetc(URL url)110 static int url_buff_fgetc(URL url)
111 {
112 URL_buff *urlp = (URL_buff *)url;
113 int c, r;
114
115 if(urlp->eof)
116 return EOF;
117
118 r = urlp->rp;
119 if(r == urlp->wp)
120 {
121 prefetch(urlp);
122 if(r == urlp->wp)
123 {
124 urlp->eof = 1;
125 return EOF;
126 }
127 }
128 c = urlp->buffer[r];
129 urlp->rp = ((r + 1) & BASEMASK);
130 urlp->pos++;
131 return c;
132 }
133
url_buff_read(URL url,void * buff,long n)134 static long url_buff_read(URL url, void *buff, long n)
135 {
136 URL_buff *urlp = (URL_buff *)url;
137 char *s = (char *)buff;
138 int r, i, j;
139
140 if(urlp->eof)
141 return 0;
142
143 r = urlp->rp;
144 if(r == urlp->wp)
145 {
146 prefetch(urlp);
147 if(r == urlp->wp)
148 {
149 urlp->eof = 1;
150 return EOF;
151 }
152 }
153
154 /* first fragment */
155 i = urlp->wp - r;
156 if(i < 0)
157 i = BASESIZE - r;
158 if(i > n)
159 i = n;
160 memcpy(s, urlp->buffer + r, i);
161 r = ((r + i) & BASEMASK);
162
163 if(i == n || r == urlp->wp || r != 0)
164 {
165 urlp->rp = r;
166 urlp->pos += i;
167 return i;
168 }
169
170 /* second fragment */
171 j = urlp->wp;
172 n -= i;
173 s += i;
174 if(j > n)
175 j = n;
176 memcpy(s, urlp->buffer, j);
177 urlp->rp = j;
178 urlp->pos += i + j;
179
180 return i + j;
181 }
182
url_buff_tell(URL url)183 static long url_buff_tell(URL url)
184 {
185 URL_buff *urlp = (URL_buff *)url;
186
187 return urlp->pos + urlp->posofs;
188 }
189
url_buff_gets(URL url,char * buff,int maxsiz)190 static char *url_buff_gets(URL url, char *buff, int maxsiz)
191 {
192 URL_buff *urlp = (URL_buff *)url;
193 int c, r, w;
194 long len, maxlen;
195 int newline = url_newline_code;
196 unsigned char *bp;
197
198 if(urlp->eof)
199 return NULL;
200
201 maxlen = maxsiz - 1;
202 if(maxlen == 0)
203 *buff = '\0';
204 if(maxlen <= 0)
205 return buff;
206 len = 0;
207 r = urlp->rp;
208 w = urlp->wp;
209 bp = urlp->buffer;
210
211 do
212 {
213 if(r == w)
214 {
215 urlp->wp = w;
216 prefetch(urlp);
217 w = urlp->wp;
218 if(r == w)
219 {
220 urlp->eof = 1;
221 if(len == 0)
222 return NULL;
223 buff[len] = '\0';
224 urlp->pos += len;
225 urlp->rp = r;
226 return buff;
227 }
228 }
229 c = bp[r];
230 buff[len++] = c;
231 r = ((r + 1) & BASEMASK);
232 } while(c != newline && len < maxlen);
233 buff[len] = '\0';
234 urlp->pos += len;
235 urlp->rp = r;
236 return buff;
237 }
238
url_buff_seek(URL url,long offset,int whence)239 static long url_buff_seek(URL url, long offset, int whence)
240 {
241 URL_buff *urlp = (URL_buff *)url;
242 long ret, diff, n;
243 int r, w, filled, i;
244
245 ret = urlp->pos + urlp->posofs;
246 switch(whence)
247 {
248 case SEEK_SET:
249 diff = offset - ret;
250 break;
251 case SEEK_CUR:
252 diff = offset;
253 break;
254 case SEEK_END:
255 if(!urlp->eof)
256 while(url_buff_fgetc(url) != EOF)
257 ;
258 diff = offset;
259 break;
260 default:
261 url_errno = errno = EPERM;
262 return -1;
263 }
264
265 if(diff == 0)
266 {
267 urlp->eof = 0; /* To be more read */
268 return ret;
269 }
270
271 n = 0; /* number of bytes to move */
272 r = urlp->rp; /* read pointer */
273 w = urlp->wp; /* write pointer */
274
275 if(diff > 0)
276 {
277 while(diff > 0)
278 {
279 if(r == w)
280 {
281 urlp->wp = w;
282 prefetch(urlp);
283 w = urlp->wp;
284 if(r == w)
285 {
286 urlp->eof = 1;
287 urlp->pos += n;
288 urlp->rp = r;
289 return ret;
290 }
291 }
292
293 i = w - r;
294 if(i < 0)
295 i = BASESIZE - r;
296 if(i > diff)
297 i = diff;
298 n += i;
299 diff -= i;
300 r = ((r + i) & BASEMASK);
301 }
302 urlp->pos += n;
303 urlp->rp = r;
304 urlp->eof = 0; /* To be more read */
305 return ret;
306 }
307
308 /* diff < 0 */
309
310 diff = -diff;
311 filled = r - w;
312 if(filled <= 0)
313 filled = BASEMASK + filled;
314 filled--;
315 if(filled > urlp->pos)
316 filled = urlp->pos;
317
318 if(filled < diff)
319 {
320 url_errno = errno = EPERM;
321 return -1;
322 }
323
324 /* back `rp' by `diff' */
325 r -= diff;
326 if(r < 0)
327 r += BASESIZE;
328 urlp->rp = r;
329 urlp->pos -= diff;
330 urlp->eof = 0; /* To be more read */
331 return ret;
332 }
333
url_buff_close(URL url)334 static void url_buff_close(URL url)
335 {
336 URL_buff *urlp = (URL_buff *)url;
337 if(urlp->autoclose)
338 url_close(urlp->reader);
339 free(url);
340 }
341