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