1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
22 #if defined(__STDPP__directive) && defined(__STDPP__hide)
23 __STDPP__directive pragma pp
:hide getpagesize
25 #define getpagesize ______getpagesize
30 #if defined(__STDPP__directive) && defined(__STDPP__hide)
31 __STDPP__directive pragma pp
:nohide getpagesize
38 extern int getpagesize
_ARG_((void));
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.
47 ** Written by Kiem-Phong Vo.
56 #define sysfstatf(fd,st) (-1)
59 static int setlinemode()
63 static int modes
= -1;
64 static const char sf_line
[] = "SF_LINE";
65 static const char sf_wcwidth
[] = "SF_WCWIDTH";
67 #define ISSEPAR(c) ((c) == ',' || (c) == ' ' || (c) == '\t')
70 if(astsfio
= getenv("_AST_SFIO_OPTIONS"))
71 { for(; *astsfio
!= 0; astsfio
= endw
)
72 { while(ISSEPAR(*astsfio
) )
74 for(endw
= astsfio
; *endw
&& !ISSEPAR(*endw
); ++endw
)
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
))
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
))
93 Void_t
* sfsetbuf(Sfio_t
* f
, Void_t
* buf
, size_t size
)
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 */
101 int sf_malloc
, oflags
, init
, okmmap
, local
;
102 ssize_t bufsize
, blksz
;
105 uchar
* obuf
= NIL(uchar
*);
111 SFMTXENTER(f
,NIL(Void_t
*));
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
);
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
*);
127 if((init
= f
->mode
&SF_INIT
) )
128 { if(!f
->pool
&& _sfsetpool(f
) < 0)
129 SFMTXRETURN(f
, NIL(Void_t
*));
131 else if((f
->mode
&SF_RDWR
) != SFMODE(f
,local
) && _sfmode(f
,0,local
) < 0)
132 SFMTXRETURN(f
, NIL(Void_t
*));
135 f
->mode
= (f
->mode
&SF_RDWR
)|SF_LOCK
;
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
*));
144 /* synchronize first */
145 SFLOCK(f
,local
); rv
= SFSYNC(f
); SFOPEN(f
,local
);
147 SFMTXRETURN(f
, NIL(Void_t
*));
149 /* turn off the SF_SYNCED bit because buffer is changing */
150 f
->mode
&= ~SF_SYNCED
;
155 if((Sfio_t
*)buf
!= f
)
157 else /* setting alignment size only */
158 { blksz
= (ssize_t
)size
;
160 if(!init
) /* stream already initialized */
165 else /* initialize stream as if in the default case */
166 { buf
= NIL(Void_t
*);
167 size
= (size_t)SF_UNBOUND
;
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;
177 /* save old buffer info */
181 { SFMUNMAP(f
,f
->data
,f
->endb
-f
->data
);
182 f
->data
= NIL(uchar
*);
186 if(f
->data
== f
->tiny
)
187 { f
->data
= NIL(uchar
*);
193 f
->flags
&= ~SF_MALLOC
;
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
))
201 /* set disc to the first discipline with a seekf */
202 for(disc
= f
->disc
; disc
; disc
= disc
->disc
)
206 if((init
|| local
) && !(f
->flags
&SF_STRING
))
207 { /* ASSERT(f->file >= 0) */
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)
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
);
223 /* get file descriptor status */
224 if(sysfstatf((int)f
->file
,&st
) < 0)
228 #if _sys_stat && _stat_blksize /* preferred io block size */
229 f
->blksz
= (size_t)st
.st_blksize
;
232 if(S_ISDIR(st
.st_mode
) || (Sfoff_t
)st
.st_size
< (Sfoff_t
)SF_GRAIN
)
234 if(S_ISREG(st
.st_mode
) || S_ISDIR(st
.st_mode
))
235 f
->here
= SFSK(f
,(Sfoff_t
)0,SEEK_CUR
,f
->disc
);
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
) )
246 f
->flags
|= setlinemode();
249 { f
->extent
= (Sfoff_t
)st
.st_size
;
251 /* seekable std-devices are share-public by default */
252 if(f
== sfstdin
|| f
== sfstdout
|| f
== sfstderr
)
253 f
->flags
|= SF_SHARE
|SF_PUBLIC
;
262 { if(S_ISCHR(st
.st_mode
) )
263 { int oerrno
= errno
;
267 /* set line mode for terminals */
268 if(!(f
->flags
&(SF_LINE
|SF_WCWIDTH
)) && isatty(f
->file
))
269 f
->flags
|= SF_LINE
|SF_WCWIDTH
;
271 else /* special case /dev/null */
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
)
284 /* initialize side buffer for r+w unseekable streams */
285 if(!f
->proc
&& (f
->bits
&SF_BOTH
) )
286 (void)_sfpopen(f
,-1,-1,1);
290 /* set page size, this is also the desired default buffer size */
294 if((_Sfpage
= (size_t)getpagesize()) <= 0)
301 if(okmmap
&& size
&& (f
->mode
&SF_READ
) && f
->extent
>= 0 )
302 { /* see if we can try memory mapping */
304 for(disc
= f
->disc
; disc
; disc
= disc
->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
;
320 /* get buffer space */
322 if(size
== (size_t)SF_UNBOUND
)
323 { /* define a default size suitable for block transfer */
324 if(init
&& osize
> 0)
326 else if(f
== sfstderr
&& (f
->mode
&SF_WRITE
))
328 else if(f
->flags
&SF_STRING
)
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
)
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
;
345 sf_malloc
= (oflags
&SF_MALLOC
);
348 { /* do allocation */
349 while(!buf
&& size
> 0)
350 { if((buf
= (Void_t
*)malloc(size
)) )
355 sf_malloc
= SF_MALLOC
;
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
;
365 /* set up new buffer */
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;
375 /* read+string stream should have all data available */
376 if((f
->mode
&SF_READ
) && !sf_malloc
)
377 f
->endb
= f
->data
+size
;
380 f
->flags
= (f
->flags
& ~SF_MALLOC
)|sf_malloc
;
382 if(obuf
&& obuf
!= f
->data
&& osize
> 0 && (oflags
&SF_MALLOC
))
383 { free((Void_t
*)obuf
);
388 _Sfi
= f
->val
= obuf
? osize
: 0;
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.
395 if(blksz
<= 0 || (blksz
& (blksz
-1)) != 0 )
397 while(blksz
> f
->size
/2)
403 SFMTXRETURN(f
, (Void_t
*)obuf
);