root/lang/objective-cplusplus/i3/trunk/src/os-windows/fakecygpty.c @ 35133

Revision 35133, 5.0 kB (checked in by saturday06, 4 years ago)

fakecygpty

Line 
1/*
2 * Fake cygwin pty   --  fakecygpty --
3 *
4 *        Copyright (C) 2005 Kyotaro Horiguchi <horiguti@meaodwy.org>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either versions 2, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with fiber, see the file COPYING.  If not, write to the Free
19 * Software Foundation Inc., 59 Temple Place - Suite 330, Boston,
20 * MA 02111-1307, USA.
21 */
22
23/*
24 * HISTORY
25 * -------
26 *
27 *    09 Jun, 2005 : Version 1.0.0 - first release.
28 *    15 Jun, 2005 : Version 1.0.1 - bug fix and change coding style.
29 */
30
31/*
32 * COMPILATION
33 * -------
34 * gcc -o fakecygpty.exe fakecygpty.c
35 *
36 */
37
38#if defined(__INTERIX) && !defined(_ALL_SOURCE)
39#define _ALL_SOURCE
40#endif
41
42#include <errno.h>
43#include <fcntl.h>
44#include <signal.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <sys/time.h>
49#include <sys/wait.h>
50#include <termios.h>
51#include <unistd.h>
52
53#define BUFSIZE          1024   /* size of communication buffer */
54
55/* global variables */
56int child_pid;          /* pid of child proces  */
57int masterfd;           /* fd of pty served to child process */
58
59/* Create pty and fork/exec target process */
60/* This function sets child_pid and masterfd */
61void exec_target(char* argv[]) {
62    int fd;
63    int pid;
64
65    masterfd = open ("/dev/ptmx", O_RDWR);
66    if (masterfd < 0) {
67        perror("Cannot open pseudo tty");
68        exit (1);
69    }
70
71    pid = fork ();
72    if (pid < 0) {
73        perror ("Failed to fork");
74        return;
75    }
76
77    if (pid == 0) {
78        int slave;
79
80        setsid();
81
82        slave = open (ptsname (masterfd), O_RDWR);
83        if (slave < 0) {
84            perror ("Failed to open slave fd");
85            exit (1);
86        }
87
88        for (fd = 0 ; fd < 3 ; fd++) {
89            if (slave != fd) {
90                if (dup2 (slave, fd) < 0) {
91                    perror ("Failed to dup2");
92                    exit (1);
93                }
94            }
95            fcntl (fd, F_SETFD, 0);
96        }
97
98        if (slave > 2) {
99            close (slave);
100        }
101
102        execvp (argv[0], argv);
103
104        fprintf (stderr, "Failed to execute \"%s\".", argv[0]);
105        perror ("execvp");
106        exit (1);
107    }
108
109    child_pid = pid;
110
111    return;
112}
113
114struct termios oldtm;
115
116void setup_tty_attributes (void) {
117    struct termios tm;
118
119    if (tcgetattr (masterfd, &tm) == 0) {
120        /* Inhibit echo when executed under emacs/windows environment */
121        if (! isatty (0)) {
122            tm.c_iflag |= IGNCR;
123            tm.c_lflag &= ~ECHO;
124        }
125        tcsetattr (masterfd, TCSANOW, &tm);
126    }
127
128    if (tcgetattr (0, &oldtm) == 0) {
129        tm = oldtm;
130        tm.c_iflag &= ~(ICRNL | IXON | IXOFF);
131        tm.c_iflag |= IGNBRK;
132        tm.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE);
133        tcsetattr (0, TCSANOW, &tm);
134    }
135}
136
137void restore_tty_attributes (void) {
138    tcsetattr (0, TCSANOW, &oldtm);
139}
140
141#ifdef __CYGWIN__
142/* Signal handler for convert SIGINT into ^C on pty */
143/* This seems not able to be done within cygwin POSIX framework */
144#include <windows.h>
145BOOL WINAPI ctrl_handler(DWORD e) {
146    switch (e) {
147    case CTRL_C_EVENT:
148        write (masterfd, "\003", 1);
149        return TRUE;
150
151    case CTRL_CLOSE_EVENT:
152        kill (child_pid, SIGKILL);
153        return FALSE;
154    }
155    return FALSE;
156}
157#endif
158
159int main (int argc, char* argv[]) {
160    fd_set sel, sel0;
161    int status;
162
163    if (argc < 2) {
164        fprintf (stderr, "Unable to get argv[1].\n");
165        exit (1);
166    }
167
168#ifdef __CYGWIN__
169    /* SIGINT and SIGBREAK are indistinctive under cygwin environment. */
170    /* Using Win32API to handle SIGINT.                              */
171    SetConsoleCtrlHandler (ctrl_handler, TRUE);
172#endif
173
174    exec_target (argv + 1);
175
176    setup_tty_attributes ();
177
178    FD_ZERO (&sel0);
179    FD_SET (masterfd, &sel0);
180    FD_SET (0, &sel0);
181
182    /* communication loop */
183    while (1) {
184        char buf[BUFSIZE];
185        int ret;
186
187        sel = sel0;
188        if (select (FD_SETSIZE, &sel, NULL, NULL, NULL) <= 0) {
189            break;
190        }
191
192        if (FD_ISSET (masterfd, &sel)) {
193            ret = read (masterfd, buf, BUFSIZE);
194            if (ret > 0) {
195                write (1, buf, ret);
196            } else {
197                break;
198            }
199        } else if (FD_ISSET (0, &sel)) {
200            ret = read (0, buf, BUFSIZE);
201            if (ret > 0) {
202                write (masterfd, buf, ret);
203            } else {
204                FD_CLR (0, &sel0);
205                close (masterfd);
206            }
207        }
208    }
209
210    restore_tty_attributes ();
211
212    kill (child_pid, SIGKILL);
213    waitpid (child_pid, &status, 0);
214    return status;
215}
216
Note: See TracBrowser for help on using the browser.