1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #include "sfdchdr.h"
23
24 /* Discipline to turn \r\n into \n.
25 ** This is useful to deal with DOS text files.
26 **
27 ** Written by David Korn (03/18/1998).
28 */
29
30 #define MINMAP 8
31 #define CHUNK 1024
32
33 struct map
34 {
35 Sfoff_t logical;
36 Sfoff_t physical;
37 };
38
39 typedef struct _dosdisc
40 {
41 Sfdisc_t disc;
42 struct map *maptable;
43 int mapsize;
44 int maptop;
45 Sfoff_t lhere;
46 Sfoff_t llast;
47 Sfoff_t lmax;
48 Sfoff_t pmax;
49 Sfoff_t phere;
50 Sfoff_t plast;
51 Sfoff_t begin;
52 int skip;
53 void *buff;
54 char last;
55 char extra;
56 int bsize;
57 } Dosdisc_t;
58
59 #if __STD_C
addmapping(register Dosdisc_t * dp)60 static void addmapping(register Dosdisc_t *dp)
61 #else
62 static void addmapping(dp)
63 register Dosdisc_t *dp;
64 #endif
65 {
66 register int n;
67 if((n=dp->maptop++)>=dp->mapsize)
68 {
69 dp->mapsize *= 2;
70 if(!(dp->maptable=(struct map*)realloc((void*)dp->maptable,(dp->mapsize+1)*sizeof(struct map))))
71 {
72 dp->maptop--;
73 dp->mapsize *= 2;
74 return;
75 }
76 }
77 dp->maptable[n].physical = dp->phere;
78 dp->maptable[n].logical = dp->lhere;
79 dp->maptable[dp->maptop].logical=0;
80 }
81
82 #if __STD_C
getmapping(Dosdisc_t * dp,Sfoff_t offset,register int whence)83 static struct map *getmapping(Dosdisc_t *dp, Sfoff_t offset, register int whence)
84 #else
85 static struct map *getmapping(dp, offset, whence)
86 Dosdisc_t *dp;
87 Sfoff_t offset;
88 register int whence;
89 #endif
90 {
91 register struct map *mp;
92 static struct map dummy;
93 if(offset <= dp->begin)
94 {
95 dummy.logical = dummy.physical = offset;
96 return(&dummy);
97 }
98 if(!(mp=dp->maptable))
99 {
100 dummy.logical = dp->begin;
101 dummy.physical = dummy.logical+1;
102 return(&dummy);
103 }
104 while((++mp)->logical && (whence==SEEK_CUR?mp->physical:mp->logical) <= offset);
105 return(mp-1);
106 }
107
108 #if __STD_C
dos_read(Sfio_t * iop,void * buff,size_t size,Sfdisc_t * disc)109 static ssize_t dos_read(Sfio_t *iop, void *buff, size_t size, Sfdisc_t* disc)
110 #else
111 static ssize_t dos_read(iop, buff, size, disc)
112 Sfio_t *iop;
113 void *buff;
114 size_t size;
115 Sfdisc_t* disc;
116 #endif
117 {
118 register Dosdisc_t *dp = (Dosdisc_t*)disc;
119 register char *cp = (char*)buff, *first, *cpmax;
120 register int n, count, m;
121 if(dp->extra)
122 {
123 dp->extra=0;
124 *cp = dp->last;
125 return(1);
126 }
127 while(1)
128 {
129 if((n = sfrd(iop,buff,size,disc)) <= 0)
130 return(n);
131 dp->plast=dp->phere;
132 dp->phere +=n;
133 dp->llast = dp->lhere;
134 cpmax = cp+n-1;
135 if(dp->last=='\r' && *cp!='\n')
136 {
137 /* should insert a '\r' */ ;
138 }
139 dp->last = *cpmax;
140 if(n>1)
141 break;
142 if(dp->last!='\r')
143 {
144 dp->lhere++;
145 return(1);
146 }
147 }
148 if(dp->last=='\r')
149 n--;
150 else if(dp->last!='\n' || cpmax[-1]!='\r')
151 *cpmax = '\r';
152 dp->lhere += n;
153 while(1)
154 {
155 while(*cp++ != '\r');
156 if(cp > cpmax || *cp=='\n')
157 break;
158 }
159 dp->skip = cp-1 - (char*)buff;
160 /* if not \r\n in buffer, just return */
161 if((count = cpmax+1-cp) <=0)
162 {
163 *cpmax = dp->last;
164 if(!dp->maptable)
165 dp->begin +=n;
166 dp->skip++;
167 count=0;
168 goto done;
169 }
170 if(!dp->maptable)
171 {
172 dp->begin += cp - (char*)buff-1;
173 if(dp->maptable=(struct map*)malloc((MINMAP+1)*sizeof(struct map)))
174 {
175 dp->mapsize = MINMAP;
176 dp->maptable[0].logical= dp->begin;
177 dp->maptable[0].physical = dp->maptable[0].logical+1;
178 dp->maptable[1].logical=0;
179 dp->maptop = 1;
180 }
181 }
182 /* save original discipline inside buffer */
183 if(count>dp->bsize)
184 {
185 if(dp->bsize==0)
186 dp->buff = malloc(count);
187 else
188 dp->buff = realloc(dp->buff,count);
189 dp->bsize = count;
190 if(!dp->buff)
191 return(-1);
192 }
193 memcpy(dp->buff, cp, count);
194 count=1;
195 while(1)
196 {
197 first=cp;
198 if(cp==cpmax)
199 cp++;
200 else
201 while(*cp++ != '\r');
202 if(cp<=cpmax && *cp!='\n')
203 continue;
204 if((m=(cp-first)-1) >0)
205 memcpy(first-count, first, m);
206 if(cp > cpmax)
207 break;
208 count++;
209 }
210 cpmax[-count] = dp->last;
211 dp->lhere -= count;
212 done:
213 if(dp->lhere>dp->lmax)
214 {
215 dp->lmax = dp->lhere;
216 dp->pmax = dp->phere;
217 if(dp->maptable && dp->lmax > dp->maptable[dp->maptop-1].logical+CHUNK)
218 addmapping(dp);
219 }
220 return(n-count);
221 }
222
223 /*
224 * returns the current offset
225 * <offset> must be in the current buffer
226 * if <whence> is SEEK_CUR, physical offset converted to logical offset
227 * otherwise, logical offset is converted to physical offset
228 */
229 #if __STD_C
cur_offset(Dosdisc_t * dp,Sfoff_t offset,Sfio_t * iop,register int whence)230 static Sfoff_t cur_offset(Dosdisc_t *dp, Sfoff_t offset,Sfio_t *iop,register int whence)
231 #else
232 static Sfoff_t cur_offset(dp, offset, iop, whence)
233 Dosdisc_t *dp;
234 Sfoff_t offset;
235 Sfio_t *iop;
236 register int whence;
237 #endif
238 {
239 register Sfoff_t n,m=0;
240 register char *cp;
241
242 if(whence==SEEK_CUR)
243 {
244 whence= -1;
245 n = offset - dp->plast;
246 iop->next = iop->data + n;
247 offset = dp->llast;
248 }
249 else
250 {
251 whence = 1;
252 n = offset - dp->llast;
253 offset = dp->plast;
254 }
255 offset +=n;
256 if((n -= dp->skip) > 0)
257 {
258 m=whence;
259 cp = (char*)dp->buff;
260 while(n--)
261 {
262 if(*cp++=='\r' && *cp=='\n')
263 {
264 m += whence;
265 if(whence>0)
266 n++;
267 }
268 }
269 }
270 if(whence<0)
271 iop->next += m;
272 return(offset+m);
273 }
274
275 #if __STD_C
dos_seek(Sfio_t * iop,Sfoff_t offset,register int whence,Sfdisc_t * disc)276 static Sfoff_t dos_seek(Sfio_t *iop, Sfoff_t offset, register int whence, Sfdisc_t* disc)
277 #else
278 static Sfoff_t dos_seek(iop, offset, whence, disc)
279 Sfio_t *iop;
280 Sfoff_t offset;
281 register int whence;
282 Sfdisc_t* disc;
283 #endif
284 {
285 register Dosdisc_t *dp = (Dosdisc_t*)disc;
286 struct map dummy, *mp=0;
287 Sfoff_t physical;
288 register int n,size;
289 retry:
290 switch(whence)
291 {
292 case SEEK_CUR:
293 offset = sfsk(iop, (Sfoff_t)0,SEEK_CUR,disc);
294 if(offset<=dp->begin)
295 return(offset);
296 /* check for seek outside buffer */
297 if(offset==dp->phere)
298 return(dp->lhere);
299 else if(offset==dp->plast)
300 return(dp->llast);
301 else if(offset<dp->plast || offset>dp->phere)
302 mp = getmapping(dp,offset,whence);
303 break;
304 case SEEK_SET:
305 /* check for seek outside buffer */
306 if(offset<dp->llast || offset > dp->lhere)
307 mp = getmapping(dp,offset,whence);
308 break;
309 case SEEK_END:
310 if(!dp->maptable)
311 return(sfsk(iop,offset,SEEK_END,disc));
312 mp = &dummy;
313 mp->physical = dp->plast;
314 mp->logical = dp->llast;
315 break;
316 }
317 if(sfsetbuf(iop,(char*)iop,0))
318 size = sfvalue(iop);
319 else
320 size = iop->endb-iop->data;
321 if(mp)
322 {
323 sfsk(iop,mp->physical,SEEK_SET,disc);
324 dp->phere = mp->physical;
325 dp->lhere = mp->logical;
326 if((*disc->readf)(iop,iop->data,size,disc)<0)
327 return(-1);
328 }
329 while(1)
330 {
331 if(whence==SEEK_CUR && dp->phere>=offset)
332 break;
333 if(whence==SEEK_SET && dp->lhere>=offset)
334 break;
335 n=(*disc->readf)(iop,iop->data,size,disc);
336 if(n < 0)
337 return(-1);
338 if(n==0)
339 {
340 if(whence==SEEK_END && offset<0)
341 {
342 offset = dp->lhere;
343 whence=SEEK_SET;
344 goto retry;
345 }
346 break;
347 }
348 }
349 if(whence==SEEK_END)
350 offset += dp->lhere;
351 else
352 {
353 physical = cur_offset(dp,offset,iop,whence);
354 if(whence==SEEK_SET)
355 {
356 sfsk(iop, physical ,SEEK_SET,disc);
357 dp->phere = physical;
358 dp->lhere = offset;
359 }
360 else
361 offset = physical;
362 }
363 return(offset);
364 }
365
366 #if __STD_C
dos_except(Sfio_t * iop,int type,void * arg,Sfdisc_t * disc)367 static int dos_except(Sfio_t *iop, int type, void *arg, Sfdisc_t *disc)
368 #else
369 static int dos_except(iop, type, arg, disc)
370 Sfio_t *iop;
371 int type;
372 void *arg;
373 Sfdisc_t *disc;
374 #endif
375 {
376 register Dosdisc_t *dp = (Dosdisc_t*)disc;
377 if(type==SF_DPOP || type==SF_FINAL)
378 {
379 if(dp->bsize>0)
380 free((void*)dp->buff);
381 if(dp->mapsize)
382 free((void*)dp->maptable);
383 free((void*)disc);
384 }
385 return(0);
386 }
387
388 #if __STD_C
sfdcdos(Sfio_t * f)389 int sfdcdos(Sfio_t *f)
390 #else
391 int sfdcdos(f)
392 Sfio_t *f;
393 #endif
394 {
395 Dosdisc_t *dos;
396
397 /* this is a readonly discipline */
398 if(sfset(f,0,0)&SF_WRITE)
399 return(-1);
400
401 if(!(dos = (Dosdisc_t*)malloc(sizeof(Dosdisc_t))) )
402 return -1;
403 memset(dos,'\0',sizeof(Dosdisc_t));
404
405 dos->disc.readf = dos_read;
406 dos->disc.writef = NIL(Sfwrite_f);
407 dos->disc.seekf = dos_seek;
408 dos->disc.exceptf = dos_except;
409
410 if(sfdisc(f,(Sfdisc_t*)dos) != (Sfdisc_t*)dos)
411 { free(dos);
412 return -1;
413 }
414
415 return(0);
416 }
417