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