[project @ 1998-11-26 09:17:22 by sof]
[ghc-hetmet.git] / ghc / lib / std / cbits / setBuffering.lc
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1994
3 %
4 \subsection[setBuffering.lc]{hSetBuffering Runtime Support}
5
6 \begin{code}
7
8 #include "rtsdefs.h"
9 #include "stgio.h"
10
11 #ifdef HAVE_SYS_TYPES_H
12 #include <sys/types.h>
13 #endif
14
15 #ifdef HAVE_SYS_STAT_H
16 #include <sys/stat.h>
17 #endif
18
19 #ifdef HAVE_TERMIOS_H
20 #include <termios.h>
21 #endif
22
23 #ifdef HAVE_FCNTL_H
24 #include <fcntl.h>
25 #endif
26
27 #define SB_NB (0)
28 #define SB_LB (-1)
29 #define SB_BB (-2)
30
31 StgInt
32 setBuffering(ptr, size)
33 StgForeignObj ptr;
34 StgInt size;
35 {
36     IOFileObject* fo = (IOFileObject*)ptr;
37     int flags, rc=0;
38     int input, isaterm;
39     struct termios tio;
40     struct stat sb;
41    
42
43     /* First off, flush old buffer.. */
44     if ( (fo->flags & FILEOBJ_FLUSH) ) {
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     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
70     switch (size) {
71     case SB_NB:
72         fo->flags &= ~FILEOBJ_LB & ~FILEOBJ_BB;
73
74         if (isaterm) {
75             /* Switch over to canonical mode. */
76             if (tcgetattr(fo->fd, &tio) < 0) {
77                 cvtErrno();
78                 stdErrno();
79                 return -1;
80             }
81             tio.c_lflag &=  ~ICANON;
82             tio.c_cc[VMIN] = 1;
83             tio.c_cc[VTIME] = 0;
84             if (tcsetattr(fo->fd, TCSANOW, &tio) < 0) {
85                 cvtErrno();
86                 stdErrno();
87                 return -1;
88             }
89         }
90         return 0;
91     case SB_LB:
92         fo->flags &= ~FILEOBJ_BB;
93         fo->flags |= FILEOBJ_LB;
94         size = BUFSIZ;
95         break;
96     case SB_BB:
97
98 #if HAVE_ST_BLKSIZE
99         while (fstat(fo->fd, &sb) < 0) {
100            /* not very likely.. */
101            if ( errno != EINTR ) {
102               cvtErrno();
103               stdErrno();
104               return -1;
105            }
106         }
107         size = sb.st_blksize;
108 #else
109         size = BUFSIZ;
110 #endif
111         fo->flags &= ~FILEOBJ_LB;
112         fo->flags |= FILEOBJ_BB;
113         /* fall through */
114     default:
115         break;
116     }
117   
118     if ( size > 0) {
119        fo->buf = malloc(size*sizeof(char));
120        if (fo->buf == NULL) {
121            return -1;
122        }
123        fo->bufSize = size;
124     }
125     if (isaterm) {
126
127         /*
128          * Try to switch back to cooked mode.
129          */
130
131         if (tcgetattr(fo->fd, &tio) < 0) {
132             cvtErrno();
133             stdErrno();
134             return -1;
135         }
136         tio.c_lflag |= ICANON;
137         if (tcsetattr(fo->fd, TCSANOW, &tio) < 0) {
138             cvtErrno();
139             stdErrno();
140             return -1;
141         }
142     }
143     return 0;
144 }
145
146 \end{code}