[project @ 2000-04-14 16:19:43 by rrt]
[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.8 2000/04/14 16:19:43 rrt 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
42     /* First off, flush old buffer.. */
43     if ( (fo->flags & FILEOBJ_WRITE) ) {
44        rc = flushBuffer(ptr);
45     }
46     if (rc<0) return rc;
47
48     /* Let go of old buffer, and reset buffer pointers. */
49     if ( fo->buf != NULL ) {
50        free(fo->buf);
51        fo->bufWPtr = 0;
52        fo->bufRPtr = 0;
53        fo->bufSize = 0;
54        fo->buf     = NULL;
55     }
56
57 #ifndef mingw32_TARGET_OS
58     while ((flags = fcntl(fo->fd, F_GETFL)) < 0) {
59         if (errno != EINTR) {
60             cvtErrno();
61             stdErrno();
62             return -1;
63         }
64     }
65     flags &= O_ACCMODE;
66     input = flags == O_RDONLY || flags == O_RDWR;
67
68     isaterm = input && isatty(fo->fd);
69 #endif
70
71     switch (size) {
72     case SB_NB:
73         fo->flags &= ~FILEOBJ_LB & ~FILEOBJ_BB;
74
75 #ifndef mingw32_TARGET_OS
76         if (isaterm) {
77             /* Switch over to canonical mode. */
78             if (tcgetattr(fo->fd, &tio) < 0) {
79                 cvtErrno();
80                 stdErrno();
81                 return -1;
82             }
83             tio.c_lflag &=  ~ICANON;
84             tio.c_cc[VMIN] = 1;
85             tio.c_cc[VTIME] = 0;
86             if (tcsetattr(fo->fd, TCSANOW, &tio) < 0) {
87                 cvtErrno();
88                 stdErrno();
89                 return -1;
90             }
91         }
92 #endif
93         return 0;
94     case SB_LB:
95         fo->flags &= ~FILEOBJ_BB;
96         fo->flags |= FILEOBJ_LB;
97         size = BUFSIZ;
98         break;
99     case SB_BB:
100
101 #ifdef HAVE_ST_BLKSIZE
102         while (fstat(fo->fd, &sb) < 0) {
103            /* not very likely.. */
104            if ( errno != EINTR ) {
105               cvtErrno();
106               stdErrno();
107               return -1;
108            }
109         }
110         size = sb.st_blksize;
111 #else
112         size = BUFSIZ;
113 #endif
114         fo->flags &= ~FILEOBJ_LB;
115         fo->flags |= FILEOBJ_BB;
116         /* fall through */
117     default:
118         break;
119     }
120   
121     if ( size > 0) {
122        fo->buf = malloc(size*sizeof(char));
123        if (fo->buf == NULL) {
124            return -1;
125        }  
126     }
127     fo->bufSize = size;
128 #ifndef mingw32_TARGET_OS
129     if (isaterm) {
130
131         /*
132          * Try to switch back to cooked mode.
133          */
134
135         if (tcgetattr(fo->fd, &tio) < 0) {
136             cvtErrno();
137             stdErrno();
138             return -1;
139         }
140         tio.c_lflag |= ICANON;
141         if (tcsetattr(fo->fd, TCSANOW, &tio) < 0) {
142             cvtErrno();
143             stdErrno();
144             return -1;
145         }
146     }
147 #endif
148     return 0;
149 }
150
151 StgInt const_BUFSIZ() { return BUFSIZ; }
152