/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1985-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * David Korn * * Phong Vo * * * ***********************************************************************/ #include "sfdchdr.h" /* Discipline to turn \r\n into \n. ** This is useful to deal with DOS text files. ** ** Written by David Korn (03/18/1998). */ #define MINMAP 8 #define CHUNK 1024 struct map { Sfoff_t logical; Sfoff_t physical; }; typedef struct _dosdisc { Sfdisc_t disc; struct map *maptable; int mapsize; int maptop; Sfoff_t lhere; Sfoff_t llast; Sfoff_t lmax; Sfoff_t pmax; Sfoff_t phere; Sfoff_t plast; Sfoff_t begin; int skip; void *buff; char last; char extra; int bsize; } Dosdisc_t; #if __STD_C static void addmapping(register Dosdisc_t *dp) #else static void addmapping(dp) register Dosdisc_t *dp; #endif { register int n; if((n=dp->maptop++)>=dp->mapsize) { dp->mapsize *= 2; if(!(dp->maptable=(struct map*)realloc((void*)dp->maptable,(dp->mapsize+1)*sizeof(struct map)))) { dp->maptop--; dp->mapsize *= 2; return; } } dp->maptable[n].physical = dp->phere; dp->maptable[n].logical = dp->lhere; dp->maptable[dp->maptop].logical=0; } #if __STD_C static struct map *getmapping(Dosdisc_t *dp, Sfoff_t offset, register int whence) #else static struct map *getmapping(dp, offset, whence) Dosdisc_t *dp; Sfoff_t offset; register int whence; #endif { register struct map *mp; static struct map dummy; if(offset <= dp->begin) { dummy.logical = dummy.physical = offset; return(&dummy); } if(!(mp=dp->maptable)) { dummy.logical = dp->begin; dummy.physical = dummy.logical+1; return(&dummy); } while((++mp)->logical && (whence==SEEK_CUR?mp->physical:mp->logical) <= offset); return(mp-1); } #if __STD_C static ssize_t dos_read(Sfio_t *iop, void *buff, size_t size, Sfdisc_t* disc) #else static ssize_t dos_read(iop, buff, size, disc) Sfio_t *iop; void *buff; size_t size; Sfdisc_t* disc; #endif { register Dosdisc_t *dp = (Dosdisc_t*)disc; register char *cp = (char*)buff, *first, *cpmax; register int n, count, m; if(dp->extra) { dp->extra=0; *cp = dp->last; return(1); } while(1) { if((n = sfrd(iop,buff,size,disc)) <= 0) return(n); dp->plast=dp->phere; dp->phere +=n; dp->llast = dp->lhere; cpmax = cp+n-1; if(dp->last=='\r' && *cp!='\n') { /* should insert a '\r' */ ; } dp->last = *cpmax; if(n>1) break; if(dp->last!='\r') { dp->lhere++; return(1); } } if(dp->last=='\r') n--; else if(dp->last!='\n' || cpmax[-1]!='\r') *cpmax = '\r'; dp->lhere += n; while(1) { while(*cp++ != '\r'); if(cp > cpmax || *cp=='\n') break; } dp->skip = cp-1 - (char*)buff; /* if not \r\n in buffer, just return */ if((count = cpmax+1-cp) <=0) { *cpmax = dp->last; if(!dp->maptable) dp->begin +=n; dp->skip++; count=0; goto done; } if(!dp->maptable) { dp->begin += cp - (char*)buff-1; if(dp->maptable=(struct map*)malloc((MINMAP+1)*sizeof(struct map))) { dp->mapsize = MINMAP; dp->maptable[0].logical= dp->begin; dp->maptable[0].physical = dp->maptable[0].logical+1; dp->maptable[1].logical=0; dp->maptop = 1; } } /* save original discipline inside buffer */ if(count>dp->bsize) { if(dp->bsize==0) dp->buff = malloc(count); else dp->buff = realloc(dp->buff,count); dp->bsize = count; if(!dp->buff) return(-1); } memcpy(dp->buff, cp, count); count=1; while(1) { first=cp; if(cp==cpmax) cp++; else while(*cp++ != '\r'); if(cp<=cpmax && *cp!='\n') continue; if((m=(cp-first)-1) >0) memcpy(first-count, first, m); if(cp > cpmax) break; count++; } cpmax[-count] = dp->last; dp->lhere -= count; done: if(dp->lhere>dp->lmax) { dp->lmax = dp->lhere; dp->pmax = dp->phere; if(dp->maptable && dp->lmax > dp->maptable[dp->maptop-1].logical+CHUNK) addmapping(dp); } return(n-count); } /* * returns the current offset * must be in the current buffer * if is SEEK_CUR, physical offset converted to logical offset * otherwise, logical offset is converted to physical offset */ #if __STD_C static Sfoff_t cur_offset(Dosdisc_t *dp, Sfoff_t offset,Sfio_t *iop,register int whence) #else static Sfoff_t cur_offset(dp, offset, iop, whence) Dosdisc_t *dp; Sfoff_t offset; Sfio_t *iop; register int whence; #endif { register Sfoff_t n,m=0; register char *cp; if(whence==SEEK_CUR) { whence= -1; n = offset - dp->plast; iop->next = iop->data + n; offset = dp->llast; } else { whence = 1; n = offset - dp->llast; offset = dp->plast; } offset +=n; if((n -= dp->skip) > 0) { m=whence; cp = (char*)dp->buff; while(n--) { if(*cp++=='\r' && *cp=='\n') { m += whence; if(whence>0) n++; } } } if(whence<0) iop->next += m; return(offset+m); } #if __STD_C static Sfoff_t dos_seek(Sfio_t *iop, Sfoff_t offset, register int whence, Sfdisc_t* disc) #else static Sfoff_t dos_seek(iop, offset, whence, disc) Sfio_t *iop; Sfoff_t offset; register int whence; Sfdisc_t* disc; #endif { register Dosdisc_t *dp = (Dosdisc_t*)disc; struct map dummy, *mp=0; Sfoff_t physical; register int n,size; retry: switch(whence) { case SEEK_CUR: offset = sfsk(iop, (Sfoff_t)0,SEEK_CUR,disc); if(offset<=dp->begin) return(offset); /* check for seek outside buffer */ if(offset==dp->phere) return(dp->lhere); else if(offset==dp->plast) return(dp->llast); else if(offsetplast || offset>dp->phere) mp = getmapping(dp,offset,whence); break; case SEEK_SET: /* check for seek outside buffer */ if(offsetllast || offset > dp->lhere) mp = getmapping(dp,offset,whence); break; case SEEK_END: if(!dp->maptable) return(sfsk(iop,offset,SEEK_END,disc)); mp = &dummy; mp->physical = dp->plast; mp->logical = dp->llast; break; } if(sfsetbuf(iop,(char*)iop,0)) size = sfvalue(iop); else size = iop->endb-iop->data; if(mp) { sfsk(iop,mp->physical,SEEK_SET,disc); dp->phere = mp->physical; dp->lhere = mp->logical; if((*disc->readf)(iop,iop->data,size,disc)<0) return(-1); } while(1) { if(whence==SEEK_CUR && dp->phere>=offset) break; if(whence==SEEK_SET && dp->lhere>=offset) break; n=(*disc->readf)(iop,iop->data,size,disc); if(n < 0) return(-1); if(n==0) { if(whence==SEEK_END && offset<0) { offset = dp->lhere; whence=SEEK_SET; goto retry; } break; } } if(whence==SEEK_END) offset += dp->lhere; else { physical = cur_offset(dp,offset,iop,whence); if(whence==SEEK_SET) { sfsk(iop, physical ,SEEK_SET,disc); dp->phere = physical; dp->lhere = offset; } else offset = physical; } return(offset); } #if __STD_C static int dos_except(Sfio_t *iop, int type, void *arg, Sfdisc_t *disc) #else static int dos_except(iop, type, arg, disc) Sfio_t *iop; int type; void *arg; Sfdisc_t *disc; #endif { register Dosdisc_t *dp = (Dosdisc_t*)disc; if(type==SF_DPOP || type==SF_FINAL) { if(dp->bsize>0) free((void*)dp->buff); if(dp->mapsize) free((void*)dp->maptable); free((void*)disc); } return(0); } #if __STD_C int sfdcdos(Sfio_t *f) #else int sfdcdos(f) Sfio_t *f; #endif { Dosdisc_t *dos; /* this is a readonly discipline */ if(sfset(f,0,0)&SF_WRITE) return(-1); if(!(dos = (Dosdisc_t*)malloc(sizeof(Dosdisc_t))) ) return -1; memset(dos,'\0',sizeof(Dosdisc_t)); dos->disc.readf = dos_read; dos->disc.writef = NIL(Sfwrite_f); dos->disc.seekf = dos_seek; dos->disc.exceptf = dos_except; if(sfdisc(f,(Sfdisc_t*)dos) != (Sfdisc_t*)dos) { free(dos); return -1; } return(0); }