[project @ 1998-12-02 13:17:09 by simonm]
[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.3 1998/12/02 13:27:54 simonm 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_FLUSH) ) {
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     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
71     switch (size) {
72     case SB_NB:
73         fo->flags &= ~FILEOBJ_LB & ~FILEOBJ_BB;
74
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         return 0;
92     case SB_LB:
93         fo->flags &= ~FILEOBJ_BB;
94         fo->flags |= FILEOBJ_LB;
95         size = BUFSIZ;
96         break;
97     case SB_BB:
98
99 #if HAVE_ST_BLKSIZE
100         while (fstat(fo->fd, &sb) < 0) {
101            /* not very likely.. */
102            if ( errno != EINTR ) {
103               cvtErrno();
104               stdErrno();
105               return -1;
106            }
107         }
108         size = sb.st_blksize;
109 #else
110         size = BUFSIZ;
111 #endif
112         fo->flags &= ~FILEOBJ_LB;
113         fo->flags |= FILEOBJ_BB;
114         /* fall through */
115     default:
116         break;
117     }
118   
119     if ( size > 0) {
120        fo->buf = malloc(size*sizeof(char));
121        if (fo->buf == NULL) {
122            return -1;
123        }
124        fo->bufSize = size;
125     }
126     if (isaterm) {
127
128         /*
129          * Try to switch back to cooked mode.
130          */
131
132         if (tcgetattr(fo->fd, &tio) < 0) {
133             cvtErrno();
134             stdErrno();
135             return -1;
136         }
137         tio.c_lflag |= ICANON;
138         if (tcsetattr(fo->fd, TCSANOW, &tio) < 0) {
139             cvtErrno();
140             stdErrno();
141             return -1;
142         }
143     }
144     return 0;
145 }
146
147 StgInt const_BUFSIZ() { return BUFSIZ; }
148