1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2009 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 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 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 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 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 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 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 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