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