1 /* source: xio-stdio.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening addresses stdio type */
7 #include "xiosysincludes.h"
10 #include "xio-fdnum.h"
11 #include "xio-stdio.h"
16 static int xioopen_stdio(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*fd
, unsigned groups
, int dummy1
, int dummy2
, int dummy3
);
17 static int xioopen_stdfd(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xfd
, unsigned groups
, int fd
, int dummy2
, int dummy3
);
20 /* we specify all option groups that we can imagine for a FD, becasue the
21 changed parsing mechanism does not allow us to check the type of FD before
22 applying the options */
23 const struct addrdesc addr_stdio
= { "stdio", 3, xioopen_stdio
, GROUP_FD
|GROUP_FIFO
|GROUP_CHR
|GROUP_BLK
|GROUP_FILE
|GROUP_SOCKET
|GROUP_TERMIOS
|GROUP_SOCK_UNIX
|GROUP_SOCK_IP
|GROUP_IPAPP
, 0, 0, 0 HELP(NULL
) };
24 const struct addrdesc addr_stdin
= { "stdin", 1, xioopen_stdfd
, GROUP_FD
|GROUP_FIFO
|GROUP_CHR
|GROUP_BLK
|GROUP_FILE
|GROUP_SOCKET
|GROUP_TERMIOS
|GROUP_SOCK_UNIX
|GROUP_SOCK_IP
|GROUP_IPAPP
, 0, 0, 0 HELP(NULL
) };
25 const struct addrdesc addr_stdout
= { "stdout", 2, xioopen_stdfd
, GROUP_FD
|GROUP_FIFO
|GROUP_CHR
|GROUP_BLK
|GROUP_FILE
|GROUP_SOCKET
|GROUP_TERMIOS
|GROUP_SOCK_UNIX
|GROUP_SOCK_IP
|GROUP_IPAPP
, 1, 0, 0 HELP(NULL
) };
26 const struct addrdesc addr_stderr
= { "stderr", 2, xioopen_stdfd
, GROUP_FD
|GROUP_FIFO
|GROUP_CHR
|GROUP_BLK
|GROUP_FILE
|GROUP_SOCKET
|GROUP_TERMIOS
|GROUP_SOCK_UNIX
|GROUP_SOCK_IP
|GROUP_IPAPP
, 2, 0, 0 HELP(NULL
) };
29 /* process a bidirectional "stdio" or "-" argument with options.
30 generate a dual address. */
31 int xioopen_stdio_bi(xiofile_t
*sock
) {
33 unsigned int groups1
= addr_stdio
.groups
;
36 if (xioopen_makedual(sock
) < 0) {
40 sock
->dual
.stream
[0]->tag
= XIO_TAG_RDONLY
;
41 sock
->dual
.stream
[0]->fd
= 0 /*stdin*/;
42 sock
->dual
.stream
[1]->tag
= XIO_TAG_WRONLY
;
43 sock
->dual
.stream
[1]->fd
= 1 /*stdout*/;
44 sock
->dual
.stream
[0]->howtoend
=
45 sock
->dual
.stream
[1]->howtoend
= END_NONE
;
48 if (Isatty(sock
->dual
.stream
[0]->fd
)) {
49 if (Tcgetattr(sock
->dual
.stream
[0]->fd
,
50 &sock
->dual
.stream
[0]->savetty
)
52 Warn2("cannot query current terminal settings on fd %d: %s",
53 sock
->dual
.stream
[0]->fd
, strerror(errno
));
55 sock
->dual
.stream
[0]->ttyvalid
= true;
58 if (Isatty(sock
->dual
.stream
[1]->fd
)) {
59 if (Tcgetattr(sock
->dual
.stream
[1]->fd
,
60 &sock
->dual
.stream
[1]->savetty
)
62 Warn2("cannot query current terminal settings on fd %d: %s",
63 sock
->dual
.stream
[1]->fd
, strerror(errno
));
65 sock
->dual
.stream
[1]->ttyvalid
= true;
68 #endif /* WITH_TERMIOS */
70 /* options here are one-time and one-direction, no second use */
71 retropt_bool(sock
->stream
.opts
, OPT_IGNOREEOF
, &sock
->dual
.stream
[0]->ignoreeof
);
73 /* extract opts that should be applied only once */
74 if ((optspr
= copyopts(sock
->stream
.opts
, GROUP_PROCESS
)) == NULL
) {
77 /* here we copy opts, because most have to be applied twice! */
78 if ((sock
->dual
.stream
[1]->opts
= copyopts(sock
->stream
.opts
, GROUP_FD
|GROUP_APPL
|(groups1
&~GROUP_PROCESS
))) == NULL
) {
81 sock
->dual
.stream
[0]->opts
= sock
->stream
.opts
;
82 sock
->stream
.opts
= NULL
;
84 if (applyopts_single(sock
->dual
.stream
[0],
85 sock
->dual
.stream
[0]->opts
, PH_INIT
)
88 if (applyopts_single(sock
->dual
.stream
[1],
89 sock
->dual
.stream
[1]->opts
, PH_INIT
)
92 applyopts(-1, sock
->dual
.stream
[0]->opts
, PH_INIT
);
93 applyopts(-1, sock
->dual
.stream
[1]->opts
, PH_INIT
);
94 if ((result
= applyopts(-1, optspr
, PH_EARLY
)) < 0)
96 if ((result
= applyopts(-1, optspr
, PH_PREOPEN
)) < 0)
99 /* apply options to first FD */
101 applyopts(sock
->dual
.stream
[0]->fd
,
102 sock
->dual
.stream
[0]->opts
, PH_ALL
))
106 if ((result
= _xio_openlate(sock
->dual
.stream
[0],
107 sock
->dual
.stream
[0]->opts
)) < 0) {
111 /* ignore this opt */
112 retropt_bool(sock
->dual
.stream
[0]->opts
, OPT_COOL_WRITE
);
115 /* apply options to second FD */
116 if ((result
= applyopts(sock
->dual
.stream
[1]->fd
,
117 sock
->dual
.stream
[1]->opts
, PH_ALL
)) < 0) {
120 if ((result
= _xio_openlate(sock
->dual
.stream
[1],
121 sock
->dual
.stream
[1]->opts
)) < 0) {
126 if ((result
= _xio_openlate(sock
->dual
.stream
[1], optspr
)) < 0) {
131 Notice("reading from and writing to stdio");
136 /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw.
137 Do not set FD_CLOEXEC flag. */
138 static int xioopen_stdio(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*fd
, unsigned groups
, int dummy1
, int dummy2
, int dummy3
) {
139 int rw
= (xioflags
&XIO_ACCMODE
);
142 Error2("%s: wrong number of parameters (%d instead of 0)", argv
[0], argc
-1);
145 if (rw
== XIO_RDWR
) {
146 return xioopen_stdio_bi(fd
);
149 Notice2("using %s for %s",
150 &("stdin\0\0\0stdout"[rw
<<3]),
152 return xioopen_fd(opts
, rw
, &fd
->stream
, rw
, dummy2
, dummy3
);
155 /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw.
156 Do not set FD_CLOEXEC flag. */
157 static int xioopen_stdfd(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xfd
, unsigned groups
, int fd
, int dummy2
, int dummy3
) {
158 int rw
= (xioflags
&XIO_ACCMODE
);
161 Error2("%s: wrong number of parameters (%d instead of 0)", argv
[0], argc
-1);
163 Notice2("using %s for %s",
164 &("stdin\0\0\0stdout\0\0stderr"[fd
<<3]),
166 return xioopen_fd(opts
, rw
, &xfd
->stream
, fd
, dummy2
, dummy3
);
168 #endif /* WITH_STDIO */