summaryrefslogtreecommitdiff
path: root/ghc/lib/cbits/setBuffering.lc
blob: ffccf70ca0df76a103988cea06a8dded75da6771 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
%
% (c) The GRASP/AQUA Project, Glasgow University, 1994
%
\subsection[setBuffering.lc]{hSetBuffering Runtime Support}

\begin{code}

#include "rtsdefs.h"
#include "stgio.h"

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#define SB_NB (0)
#define SB_LB (-1)
#define SB_BB (-2)

StgInt
setBuffering(fp, size)
StgAddr fp;
StgInt size;
{
    int flags;
    int input;
    struct termios tio;

    while ((flags = fcntl(fileno((FILE *) fp), F_GETFL)) < 0) {
	if (errno != EINTR) {
	    cvtErrno();
	    stdErrno();
	    return -1;
	}
    }
    flags &= O_ACCMODE;
    input = flags == O_RDONLY || flags == O_RDWR;

    switch (size) {
    case SB_NB:
	if (setvbuf((FILE *) fp, NULL, _IONBF, 0L) != 0) {
	    cvtErrno();
	    stdErrno();
	    return -1;
	}
	if (input && isatty(fileno((FILE *) fp))) {

	    /*
	     * Try to switch to CBREAK mode, or whatever they call it these days.
	     */

	    if (tcgetattr(fileno((FILE *) fp), &tio) < 0) {
		cvtErrno();
		stdErrno();
		return -1;
	    }
	    tio.c_lflag &= ~ICANON;
	    tio.c_cc[VMIN] = 1;
	    tio.c_cc[VTIME] = 0;
	    if (tcsetattr(fileno((FILE *) fp), TCSANOW, &tio) < 0) {
		cvtErrno();
		stdErrno();
		return -1;
	    }
	}
	return 0;
	break;
    case SB_LB:
	if (setvbuf((FILE *) fp, NULL, _IOLBF, BUFSIZ) != 0) {
	    cvtErrno();
	    stdErrno();
	    return -1;
	}
	break;
    case SB_BB:

	/*
	 * We should actually peek at the buffer size in the stat struct, if there
	 * is one.  Something to occupy us later, when we're bored.
	 */
	size = BUFSIZ;
	/* fall through */
    default:
	if (setvbuf((FILE *) fp, NULL, _IOFBF, size) != 0) {
	    cvtErrno();
	    stdErrno();
	    return -1;
	}
	break;
    }
    if (input && isatty(fileno((FILE *) fp))) {

	/*
	 * Try to switch back to cooked mode.
	 */

	if (tcgetattr(fileno((FILE *) fp), &tio) < 0) {
	    cvtErrno();
	    stdErrno();
	    return -1;
	}
	tio.c_lflag |= ICANON;
	if (tcsetattr(fileno((FILE *) fp), TCSANOW, &tio) < 0) {
	    cvtErrno();
	    stdErrno();
	    return -1;
	}
    }
    return 0;
}

\end{code}