1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * Glenn Fowler <gsf@research.att.com> * 18*4887Schin * David Korn <dgk@research.att.com> * 19*4887Schin * Phong Vo <kpv@research.att.com> * 20*4887Schin * * 21*4887Schin ***********************************************************************/ 22*4887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide) 23*4887Schin __STDPP__directive pragma pp:hide getpagesize 24*4887Schin #else 25*4887Schin #define getpagesize ______getpagesize 26*4887Schin #endif 27*4887Schin 28*4887Schin #include "sfhdr.h" 29*4887Schin 30*4887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide) 31*4887Schin __STDPP__directive pragma pp:nohide getpagesize 32*4887Schin #else 33*4887Schin #undef getpagesize 34*4887Schin #endif 35*4887Schin 36*4887Schin #if _lib_getpagesize 37*4887Schin _BEGIN_EXTERNS_ 38*4887Schin extern int getpagesize _ARG_((void)); 39*4887Schin _END_EXTERNS_ 40*4887Schin #endif 41*4887Schin 42*4887Schin /* Set a (new) buffer for a stream. 43*4887Schin ** If size < 0, it is assigned a suitable value depending on the 44*4887Schin ** kind of stream. The actual buffer size allocated is dependent 45*4887Schin ** on how much memory is available. 46*4887Schin ** 47*4887Schin ** Written by Kiem-Phong Vo. 48*4887Schin */ 49*4887Schin 50*4887Schin #if !_sys_stat 51*4887Schin struct stat 52*4887Schin { int st_mode; 53*4887Schin int st_size; 54*4887Schin }; 55*4887Schin #undef sysfstatf 56*4887Schin #define sysfstatf(fd,st) (-1) 57*4887Schin #endif /*_sys_stat*/ 58*4887Schin 59*4887Schin static int setlinemode() 60*4887Schin { char* astsfio; 61*4887Schin char* endw; 62*4887Schin 63*4887Schin static int modes = -1; 64*4887Schin static const char sf_line[] = "SF_LINE"; 65*4887Schin static const char sf_wcwidth[] = "SF_WCWIDTH"; 66*4887Schin 67*4887Schin #define ISSEPAR(c) ((c) == ',' || (c) == ' ' || (c) == '\t') 68*4887Schin if (modes < 0) 69*4887Schin { modes = 0; 70*4887Schin if(astsfio = getenv("_AST_SFIO_OPTIONS")) 71*4887Schin { for(; *astsfio != 0; astsfio = endw) 72*4887Schin { while(ISSEPAR(*astsfio) ) 73*4887Schin *astsfio++; 74*4887Schin for(endw = astsfio; *endw && !ISSEPAR(*endw); ++endw) 75*4887Schin ; 76*4887Schin if((endw-astsfio) == (sizeof(sf_line)-1) && 77*4887Schin strncmp(astsfio,sf_line,endw-astsfio) == 0) 78*4887Schin { if ((modes |= SF_LINE) == (SF_LINE|SF_WCWIDTH)) 79*4887Schin break; 80*4887Schin } 81*4887Schin else if((endw-astsfio) == (sizeof(sf_wcwidth)-1) && 82*4887Schin strncmp(astsfio,sf_wcwidth,endw-astsfio) == 0) 83*4887Schin { if ((modes |= SF_WCWIDTH) == (SF_LINE|SF_WCWIDTH)) 84*4887Schin break; 85*4887Schin } 86*4887Schin } 87*4887Schin } 88*4887Schin } 89*4887Schin return modes; 90*4887Schin } 91*4887Schin 92*4887Schin #if __STD_C 93*4887Schin Void_t* sfsetbuf(reg Sfio_t* f, reg Void_t* buf, reg size_t size) 94*4887Schin #else 95*4887Schin Void_t* sfsetbuf(f,buf,size) 96*4887Schin reg Sfio_t* f; /* stream to be buffered */ 97*4887Schin reg Void_t* buf; /* new buffer */ 98*4887Schin reg size_t size; /* buffer size, -1 for default size */ 99*4887Schin #endif 100*4887Schin { 101*4887Schin int sf_malloc, oflags, init, okmmap, local; 102*4887Schin ssize_t bufsize, blksz; 103*4887Schin Sfdisc_t* disc; 104*4887Schin sfstat_t st; 105*4887Schin uchar* obuf = NIL(uchar*); 106*4887Schin ssize_t osize = 0; 107*4887Schin 108*4887Schin SFONCE(); 109*4887Schin 110*4887Schin SFMTXSTART(f,NIL(Void_t*)); 111*4887Schin 112*4887Schin GETLOCAL(f,local); 113*4887Schin 114*4887Schin if(size == 0 && buf) 115*4887Schin { /* special case to get buffer info */ 116*4887Schin _Sfi = f->val = (f->bits&SF_MMAP) ? (f->endb-f->data) : f->size; 117*4887Schin SFMTXRETURN(f, (Void_t*)f->data); 118*4887Schin } 119*4887Schin 120*4887Schin /* cleanup actions already done, don't allow write buffering any more */ 121*4887Schin if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE)) 122*4887Schin { buf = NIL(Void_t*); 123*4887Schin size = 0; 124*4887Schin } 125*4887Schin 126*4887Schin if((init = f->mode&SF_INIT) ) 127*4887Schin { if(!f->pool && _sfsetpool(f) < 0) 128*4887Schin SFMTXRETURN(f, NIL(Void_t*)); 129*4887Schin } 130*4887Schin else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0) 131*4887Schin SFMTXRETURN(f, NIL(Void_t*)); 132*4887Schin 133*4887Schin if(init) 134*4887Schin f->mode = (f->mode&SF_RDWR)|SF_LOCK; 135*4887Schin else 136*4887Schin { int rv; 137*4887Schin 138*4887Schin /* make sure there is no hidden read data */ 139*4887Schin if(f->proc && (f->flags&SF_READ) && (f->mode&SF_WRITE) && 140*4887Schin _sfmode(f,SF_READ,local) < 0) 141*4887Schin SFMTXRETURN(f, NIL(Void_t*)); 142*4887Schin 143*4887Schin /* synchronize first */ 144*4887Schin SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local); 145*4887Schin if(rv < 0) 146*4887Schin SFMTXRETURN(f, NIL(Void_t*)); 147*4887Schin 148*4887Schin /* turn off the SF_SYNCED bit because buffer is changing */ 149*4887Schin f->mode &= ~SF_SYNCED; 150*4887Schin } 151*4887Schin 152*4887Schin SFLOCK(f,local); 153*4887Schin 154*4887Schin if((Sfio_t*)buf != f) 155*4887Schin blksz = -1; 156*4887Schin else /* setting alignment size only */ 157*4887Schin { blksz = (ssize_t)size; 158*4887Schin 159*4887Schin if(!init) /* stream already initialized */ 160*4887Schin { obuf = f->data; 161*4887Schin osize = f->size; 162*4887Schin goto done; 163*4887Schin } 164*4887Schin else /* initialize stream as if in the default case */ 165*4887Schin { buf = NIL(Void_t*); 166*4887Schin size = (size_t)SF_UNBOUND; 167*4887Schin } 168*4887Schin } 169*4887Schin 170*4887Schin bufsize = 0; 171*4887Schin oflags = f->flags; 172*4887Schin 173*4887Schin /* see if memory mapping is possible (see sfwrite for SF_BOTH) */ 174*4887Schin okmmap = (buf || (f->flags&SF_STRING) || (f->flags&SF_RDWR) == SF_RDWR) ? 0 : 1; 175*4887Schin 176*4887Schin /* save old buffer info */ 177*4887Schin #ifdef MAP_TYPE 178*4887Schin if(f->bits&SF_MMAP) 179*4887Schin { if(f->data) 180*4887Schin { SFMUNMAP(f,f->data,f->endb-f->data); 181*4887Schin f->data = NIL(uchar*); 182*4887Schin } 183*4887Schin } else 184*4887Schin #endif 185*4887Schin if(f->data == f->tiny) 186*4887Schin { f->data = NIL(uchar*); 187*4887Schin f->size = 0; 188*4887Schin } 189*4887Schin obuf = f->data; 190*4887Schin osize = f->size; 191*4887Schin 192*4887Schin f->flags &= ~SF_MALLOC; 193*4887Schin f->bits &= ~SF_MMAP; 194*4887Schin 195*4887Schin /* pure read/string streams must have a valid string */ 196*4887Schin if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR && 197*4887Schin (size == (size_t)SF_UNBOUND || !buf)) 198*4887Schin size = 0; 199*4887Schin 200*4887Schin /* set disc to the first discipline with a seekf */ 201*4887Schin for(disc = f->disc; disc; disc = disc->disc) 202*4887Schin if(disc->seekf) 203*4887Schin break; 204*4887Schin 205*4887Schin if((init || local) && !(f->flags&SF_STRING)) 206*4887Schin { /* ASSERT(f->file >= 0) */ 207*4887Schin st.st_mode = 0; 208*4887Schin 209*4887Schin /* if has discipline, set size by discipline if possible */ 210*4887Schin if(!_sys_stat || disc) 211*4887Schin { if((f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,disc)) < 0) 212*4887Schin goto unseekable; 213*4887Schin else 214*4887Schin { Sfoff_t e; 215*4887Schin if((e = SFSK(f,(Sfoff_t)0,SEEK_END,disc)) >= 0) 216*4887Schin f->extent = e > f->here ? e : f->here; 217*4887Schin (void)SFSK(f,f->here,SEEK_SET,disc); 218*4887Schin goto setbuf; 219*4887Schin } 220*4887Schin } 221*4887Schin 222*4887Schin /* get file descriptor status */ 223*4887Schin if(sysfstatf((int)f->file,&st) < 0) 224*4887Schin f->here = -1; 225*4887Schin else 226*4887Schin { 227*4887Schin #if _sys_stat && _stat_blksize /* preferred io block size */ 228*4887Schin f->blksz = (size_t)st.st_blksize; 229*4887Schin #endif 230*4887Schin bufsize = 64 * 1024; 231*4887Schin if(S_ISDIR(st.st_mode) || (Sfoff_t)st.st_size < (Sfoff_t)SF_GRAIN) 232*4887Schin okmmap = 0; 233*4887Schin if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) 234*4887Schin f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,f->disc); 235*4887Schin else f->here = -1; 236*4887Schin 237*4887Schin #if O_TEXT /* no memory mapping with O_TEXT because read()/write() alter data stream */ 238*4887Schin if(okmmap && f->here >= 0 && 239*4887Schin (sysfcntlf((int)f->file,F_GETFL,0) & O_TEXT) ) 240*4887Schin okmmap = 0; 241*4887Schin #endif 242*4887Schin } 243*4887Schin 244*4887Schin if(init) 245*4887Schin f->flags |= setlinemode(); 246*4887Schin 247*4887Schin if(f->here >= 0) 248*4887Schin { f->extent = (Sfoff_t)st.st_size; 249*4887Schin 250*4887Schin /* seekable std-devices are share-public by default */ 251*4887Schin if(f == sfstdin || f == sfstdout || f == sfstderr) 252*4887Schin f->flags |= SF_SHARE|SF_PUBLIC; 253*4887Schin } 254*4887Schin else 255*4887Schin { 256*4887Schin unseekable: 257*4887Schin f->extent = -1; 258*4887Schin f->here = 0; 259*4887Schin 260*4887Schin if(init) 261*4887Schin { if(S_ISCHR(st.st_mode) ) 262*4887Schin { int oerrno = errno; 263*4887Schin 264*4887Schin bufsize = SF_GRAIN; 265*4887Schin 266*4887Schin /* set line mode for terminals */ 267*4887Schin if(!(f->flags&(SF_LINE|SF_WCWIDTH)) && isatty(f->file)) 268*4887Schin f->flags |= SF_LINE|SF_WCWIDTH; 269*4887Schin #if _sys_stat 270*4887Schin else /* special case /dev/null */ 271*4887Schin { reg int dev, ino; 272*4887Schin dev = (int)st.st_dev; 273*4887Schin ino = (int)st.st_ino; 274*4887Schin if(sysstatf(DEVNULL,&st) >= 0 && 275*4887Schin dev == (int)st.st_dev && 276*4887Schin ino == (int)st.st_ino) 277*4887Schin SFSETNULL(f); 278*4887Schin } 279*4887Schin #endif 280*4887Schin errno = oerrno; 281*4887Schin } 282*4887Schin 283*4887Schin /* initialize side buffer for r+w unseekable streams */ 284*4887Schin if(!f->proc && (f->bits&SF_BOTH) ) 285*4887Schin (void)_sfpopen(f,-1,-1,1); 286*4887Schin } 287*4887Schin } 288*4887Schin 289*4887Schin /* set page size, this is also the desired default buffer size */ 290*4887Schin if(_Sfpage <= 0) 291*4887Schin { 292*4887Schin #if _lib_getpagesize 293*4887Schin if((_Sfpage = (size_t)getpagesize()) <= 0) 294*4887Schin #endif 295*4887Schin _Sfpage = SF_PAGE; 296*4887Schin } 297*4887Schin } 298*4887Schin 299*4887Schin #ifdef MAP_TYPE 300*4887Schin if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 ) 301*4887Schin { /* see if we can try memory mapping */ 302*4887Schin if(!disc) 303*4887Schin for(disc = f->disc; disc; disc = disc->disc) 304*4887Schin if(disc->readf) 305*4887Schin break; 306*4887Schin if(!disc) 307*4887Schin { f->bits |= SF_MMAP; 308*4887Schin if(size == (size_t)SF_UNBOUND) 309*4887Schin { if(bufsize > _Sfpage) 310*4887Schin size = bufsize * SF_NMAP; 311*4887Schin else size = _Sfpage * SF_NMAP; 312*4887Schin if(size > 256*1024) 313*4887Schin size = 256*1024; 314*4887Schin } 315*4887Schin } 316*4887Schin } 317*4887Schin #endif 318*4887Schin 319*4887Schin /* get buffer space */ 320*4887Schin setbuf: 321*4887Schin if(size == (size_t)SF_UNBOUND) 322*4887Schin { /* define a default size suitable for block transfer */ 323*4887Schin if(init && osize > 0) 324*4887Schin size = osize; 325*4887Schin else if(f == sfstderr && (f->mode&SF_WRITE)) 326*4887Schin size = 0; 327*4887Schin else if(f->flags&SF_STRING ) 328*4887Schin size = SF_GRAIN; 329*4887Schin else if((f->flags&SF_READ) && !(f->bits&SF_BOTH) && 330*4887Schin f->extent > 0 && f->extent < (Sfoff_t)_Sfpage ) 331*4887Schin size = (((size_t)f->extent + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN; 332*4887Schin else if((ssize_t)(size = _Sfpage) < bufsize) 333*4887Schin size = bufsize; 334*4887Schin 335*4887Schin buf = NIL(Void_t*); 336*4887Schin } 337*4887Schin 338*4887Schin sf_malloc = 0; 339*4887Schin if(size > 0 && !buf && !(f->bits&SF_MMAP)) 340*4887Schin { /* try to allocate a buffer */ 341*4887Schin if(obuf && size == (size_t)osize && init) 342*4887Schin { buf = (Void_t*)obuf; 343*4887Schin obuf = NIL(uchar*); 344*4887Schin sf_malloc = (oflags&SF_MALLOC); 345*4887Schin } 346*4887Schin if(!buf) 347*4887Schin { /* do allocation */ 348*4887Schin while(!buf && size > 0) 349*4887Schin { if((buf = (Void_t*)malloc(size)) ) 350*4887Schin break; 351*4887Schin else size /= 2; 352*4887Schin } 353*4887Schin if(size > 0) 354*4887Schin sf_malloc = SF_MALLOC; 355*4887Schin } 356*4887Schin } 357*4887Schin 358*4887Schin if(size == 0 && !(f->flags&SF_STRING) && !(f->bits&SF_MMAP) && (f->mode&SF_READ)) 359*4887Schin { /* use the internal buffer */ 360*4887Schin size = sizeof(f->tiny); 361*4887Schin buf = (Void_t*)f->tiny; 362*4887Schin } 363*4887Schin 364*4887Schin /* set up new buffer */ 365*4887Schin f->size = size; 366*4887Schin f->next = f->data = f->endr = f->endw = (uchar*)buf; 367*4887Schin f->endb = (f->mode&SF_READ) ? f->data : f->data+size; 368*4887Schin if(f->flags&SF_STRING) 369*4887Schin { /* these fields are used to test actual size - see sfseek() */ 370*4887Schin f->extent = (!sf_malloc && 371*4887Schin ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ) ? size : 0; 372*4887Schin f->here = 0; 373*4887Schin 374*4887Schin /* read+string stream should have all data available */ 375*4887Schin if((f->mode&SF_READ) && !sf_malloc) 376*4887Schin f->endb = f->data+size; 377*4887Schin } 378*4887Schin 379*4887Schin f->flags = (f->flags & ~SF_MALLOC)|sf_malloc; 380*4887Schin 381*4887Schin if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC)) 382*4887Schin { free((Void_t*)obuf); 383*4887Schin obuf = NIL(uchar*); 384*4887Schin } 385*4887Schin 386*4887Schin done: 387*4887Schin _Sfi = f->val = obuf ? osize : 0; 388*4887Schin 389*4887Schin /* blksz is used for aligning disk block boundary while reading data to 390*4887Schin ** optimize data transfer from disk (eg, via direct I/O). blksz can be 391*4887Schin ** at most f->size/2 so that data movement in buffer can be optimized. 392*4887Schin ** blksz should also be a power-of-2 for optimal disk seeks. 393*4887Schin */ 394*4887Schin if(blksz <= 0 || (blksz & (blksz-1)) != 0 ) 395*4887Schin blksz = SF_GRAIN; 396*4887Schin while(blksz > f->size/2) 397*4887Schin blksz /= 2; 398*4887Schin f->blksz = blksz; 399*4887Schin 400*4887Schin SFOPEN(f,local); 401*4887Schin 402*4887Schin SFMTXRETURN(f, (Void_t*)obuf); 403*4887Schin } 404