1 /*
2  * Copyright (c) 1990, 2007 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * and/or other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 /* No user fns here.  Pesch 15apr92. */
18 
19 #define _DEFAULT_SOURCE
20 #include <_ansi.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <sys/unistd.h>
26 #include "local.h"
27 
28 #define _DEFAULT_ASPRINTF_BUFSIZE 64
29 
30 /*
31  * Allocate a file buffer, or switch to unbuffered I/O.
32  * Per the ANSI C standard, ALL tty devices default to line buffered.
33  *
34  * As a side effect, we set __SOPT or __SNPT (en/dis-able fseek
35  * optimization) right after the _fstat() that finds the buffer size.
36  */
37 
38 void
_smakebuf(register FILE * fp)39 _smakebuf (
40        register FILE *fp)
41 {
42   register void *p;
43   int flags;
44   size_t size;
45   int couldbetty;
46 
47   if (fp->_flags & __SNBF)
48     {
49       fp->_bf._base = fp->_p = fp->_nbuf;
50       fp->_bf._size = 1;
51       return;
52     }
53   flags = _swhatbuf ( fp, &size, &couldbetty);
54   if ((p = malloc (size)) == NULL)
55     {
56       if (!(fp->_flags & __SSTR))
57 	{
58 	  fp->_flags = (fp->_flags & ~__SLBF) | __SNBF;
59 	  fp->_bf._base = fp->_p = fp->_nbuf;
60 	  fp->_bf._size = 1;
61 	}
62     }
63   else
64     {
65       fp->_flags |= __SMBF;
66       fp->_bf._base = fp->_p = (unsigned char *) p;
67       fp->_bf._size = size;
68       if (couldbetty && isatty (fp->_file))
69 	fp->_flags = (fp->_flags & ~__SNBF) | __SLBF;
70       fp->_flags |= flags;
71     }
72 }
73 
74 /*
75  * Internal routine to determine `proper' buffering for a file.
76  */
77 int
_swhatbuf(FILE * fp,size_t * bufsize,int * couldbetty)78 _swhatbuf (
79 	FILE *fp,
80 	size_t *bufsize,
81 	int *couldbetty)
82 {
83 #ifdef _FSEEK_OPTIMIZATION
84   const int snpt = __SNPT;
85 #else
86   const int snpt = 0;
87 #endif
88 
89 #ifdef __USE_INTERNAL_STAT64
90   struct stat64 st;
91 
92   if (fp->_file < 0 || fstat64 (fp->_file, &st) < 0)
93 #else
94   struct stat st;
95 
96   if (fp->_file < 0 || fstat (fp->_file, &st) < 0)
97 #endif
98     {
99       *couldbetty = 0;
100       /* Check if we are be called by asprintf family for initial buffer.  */
101       if (fp->_flags & __SMBF)
102         *bufsize = _DEFAULT_ASPRINTF_BUFSIZE;
103       else
104         *bufsize = BUFSIZ;
105       return (0);
106     }
107 
108   /* could be a tty iff it is a character device */
109   *couldbetty = S_ISCHR(st.st_mode);
110 #ifdef HAVE_BLKSIZE
111   if (st.st_blksize > 0)
112     {
113       /*
114        * Optimise fseek() only if it is a regular file.  (The test for
115        * __sseek is mainly paranoia.)  It is safe to set _blksize
116        * unconditionally; it will only be used if __SOPT is also set.
117        */
118       *bufsize = st.st_blksize;
119       fp->_blksize = st.st_blksize;
120       return ((st.st_mode & S_IFMT) == S_IFREG ?  __SOPT : snpt);
121     }
122 #endif
123   *bufsize = BUFSIZ;
124   return (snpt);
125 }
126