2bb240bec186a5acaf3e95c19ddf230542367b86
[ghc-hetmet.git] / ghc / lib / std / cbits / setBuffering.c
1 /* 
2  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
3  *
4  * $Id: setBuffering.c,v 1.9 2001/01/16 14:06:14 simonmar Exp $
5  *
6  * hSetBuffering Runtime Support
7  */
8
9 #include "Rts.h"
10 #include "stgio.h"
11
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15
16 #ifdef HAVE_SYS_STAT_H
17 #include <sys/stat.h>
18 #endif
19
20 #ifdef HAVE_TERMIOS_H
21 #include <termios.h>
22 #endif
23
24 #ifdef HAVE_FCNTL_H
25 #include <fcntl.h>
26 #endif
27
28 #define SB_NB (0)
29 #define SB_LB (-1)
30 #define SB_BB (-2)
31
32 StgInt
33 setBuffering(StgForeignPtr ptr, StgInt size)
34 {
35     IOFileObject* fo = (IOFileObject*)ptr;
36     int flags, rc=0;
37     int input, isaterm;
38     struct termios tio;
39     struct stat sb;
40
41     /* First off, flush old buffer.. */
42     if ( (fo->flags & FILEOBJ_WRITE) ) {
43        rc = flushBuffer(ptr);
44     }
45     if (rc<0) return rc;
46
47     /* Let go of old buffer, and reset buffer pointers. */
48     if ( fo->buf != NULL ) {
49        free(fo->buf);
50        fo->bufWPtr = 0;
51        fo->bufRPtr = 0;
52        fo->bufSize = 0;
53        fo->buf     = NULL;
54     }
55
56 #ifndef mingw32_TARGET_OS
57     while ((flags = fcntl(fo->fd, F_GETFL)) < 0) {
58         if (errno != EINTR) {
59             cvtErrno();
60             stdErrno();
61             return -1;
62         }
63     }
64     flags &= O_ACCMODE;
65     input = flags == O_RDONLY || flags == O_RDWR;
66
67     isaterm = input && isatty(fo->fd);
68 #endif
69
70     switch (size) {
71     case SB_NB:
72         fo->flags &= ~FILEOBJ_LB & ~FILEOBJ_BB;
73
74 #ifndef mingw32_TARGET_OS
75         if (isaterm) {
76             /* Switch over to canonical mode. */
77             if (tcgetattr(fo->fd, &tio) < 0) {
78                 cvtErrno();
79                 stdErrno();
80                 return -1;
81             }
82             tio.c_lflag &=  ~ICANON;
83             tio.c_cc[VMIN] = 1;
84             tio.c_cc[VTIME] = 0;
85             if (tcSetAttr(fo->fd, TCSANOW, &tio) < 0) {
86                 cvtErrno();
87                 stdErrno();
88                 return -1;
89             }
90         }
91 #endif
92         return 0;
93     case SB_LB:
94         fo->flags &= ~FILEOBJ_BB;
95         fo->flags |= FILEOBJ_LB;
96         size = BUFSIZ;
97         break;
98     case SB_BB:
99
100 #ifdef HAVE_ST_BLKSIZE
101         while (fstat(fo->fd, &sb) < 0) {
102            /* not very likely.. */
103            if ( errno != EINTR ) {
104               cvtErrno();
105               stdErrno();
106               return -1;
107            }
108         }
109         size = sb.st_blksize;
110 #else
111         size = BUFSIZ;
112 #endif
113         fo->flags &= ~FILEOBJ_LB;
114         fo->flags |= FILEOBJ_BB;
115         /* fall through */
116     default:
117         break;
118     }
119   
120     if ( size > 0) {
121        fo->buf = malloc(size*sizeof(char));
122        if (fo->buf == NULL) {
123            return -1;
124        }  
125     }
126     fo->bufSize = size;
127 #ifndef mingw32_TARGET_OS
128     if (isaterm) {
129
130         /*
131          * Try to switch back to cooked mode.
132          */
133
134         if (tcgetattr(fo->fd, &tio) < 0) {
135             cvtErrno();
136             stdErrno();
137             return -1;
138         }
139         tio.c_lflag |= ICANON;
140         if (tcSetAttr(fo->fd, TCSANOW, &tio) < 0) {
141             cvtErrno();
142             stdErrno();
143             return -1;
144         }
145     }
146 #endif
147     return 0;
148 }
149
150 StgInt const_BUFSIZ() { return BUFSIZ; }
151