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 <stdio.h>
21 #include <stdlib.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <sys/unistd.h>
25 #include "local.h"
26 
27 #define _DEFAULT_ASPRINTF_BUFSIZE 64
28 
29 /*
30  * Allocate a file buffer, or switch to unbuffered I/O.
31  * Per the ANSI C standard, ALL tty devices default to line buffered.
32  *
33  * As a side effect, we set __SOPT or __SNPT (en/dis-able fseek
34  * optimization) right after the _fstat() that finds the buffer size.
35  */
36 
37 void
_smakebuf(register FILE * fp)38 _smakebuf (
39        register FILE *fp)
40 {
41   register void *p;
42   int flags;
43   size_t size;
44   int couldbetty;
45 
46   if (fp->_flags & __SNBF)
47     {
48       fp->_bf._base = fp->_p = fp->_nbuf;
49       fp->_bf._size = 1;
50       return;
51     }
52   flags = _swhatbuf ( fp, &size, &couldbetty);
53   if ((p = malloc (size)) == NULL)
54     {
55       if (!(fp->_flags & __SSTR))
56 	{
57 	  fp->_flags = (fp->_flags & ~__SLBF) | __SNBF;
58 	  fp->_bf._base = fp->_p = fp->_nbuf;
59 	  fp->_bf._size = 1;
60 	}
61     }
62   else
63     {
64       fp->_flags |= __SMBF;
65       fp->_bf._base = fp->_p = (unsigned char *) p;
66       fp->_bf._size = size;
67       if (couldbetty && isatty (fp->_file))
68 	fp->_flags = (fp->_flags & ~__SNBF) | __SLBF;
69       fp->_flags |= flags;
70     }
71 }
72 
73 /*
74  * Internal routine to determine `proper' buffering for a file.
75  */
76 int
_swhatbuf(FILE * fp,size_t * bufsize,int * couldbetty)77 _swhatbuf (
78 	FILE *fp,
79 	size_t *bufsize,
80 	int *couldbetty)
81 {
82 #ifdef _FSEEK_OPTIMIZATION
83   const int snpt = __SNPT;
84 #else
85   const int snpt = 0;
86 #endif
87 
88 #ifdef __USE_INTERNAL_STAT64
89   struct stat64 st;
90 
91   if (fp->_file < 0 || fstat64 (fp->_file, &st) < 0)
92 #else
93   struct stat st;
94 
95   if (fp->_file < 0 || fstat (fp->_file, &st) < 0)
96 #endif
97     {
98       *couldbetty = 0;
99       /* Check if we are be called by asprintf family for initial buffer.  */
100       if (fp->_flags & __SMBF)
101         *bufsize = _DEFAULT_ASPRINTF_BUFSIZE;
102       else
103         *bufsize = BUFSIZ;
104       return (0);
105     }
106 
107   /* could be a tty iff it is a character device */
108   *couldbetty = S_ISCHR(st.st_mode);
109 #ifdef HAVE_BLKSIZE
110   if (st.st_blksize > 0)
111     {
112       /*
113        * Optimise fseek() only if it is a regular file.  (The test for
114        * __sseek is mainly paranoia.)  It is safe to set _blksize
115        * unconditionally; it will only be used if __SOPT is also set.
116        */
117       *bufsize = st.st_blksize;
118       fp->_blksize = st.st_blksize;
119       return ((st.st_mode & S_IFMT) == S_IFREG ?  __SOPT : snpt);
120     }
121 #endif
122   *bufsize = BUFSIZ;
123   return (snpt);
124 }
125