source: libcaca/trunk/test/term.c @ 1427

Last change on this file since 1427 was 1427, checked in by Sam Hocevar, 16 years ago
  • Added a test app that swallows two console applications. Switch with C-a.
  • Property svn:keywords set to Id
File size: 5.2 KB
Line 
1/*
2 *  term          swallow a terminal-based application
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: term.c 1427 2006-11-21 07:09:35Z sam $
7 *
8 *  This program is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14#include "config.h"
15#include "common.h"
16
17#if !defined __KERNEL__
18#   include <stdio.h>
19#   include <string.h>
20#   include <stdlib.h>
21#   include <unistd.h>
22#   include <fcntl.h>
23#   if defined HAVE_PTY_H
24#       include <pty.h>  /* for openpty and forkpty */
25#   endif
26#endif
27
28#include "cucul.h"
29#include "caca.h"
30
31static int run_in_pty(char *cmd);
32
33int main(int argc, char **argv)
34{
35    static cucul_canvas_t *cv, *app[2];
36    static caca_display_t *dp;
37    unsigned char *buf[2];
38    long int total[2];
39    int ptyfd[2], pty = 0;
40    int w, h, eof = 0;
41
42    if(argc < 3)
43    {
44        fprintf(stderr, "usage: %s <cmd1> <cmd2>\n", argv[0]);
45        fprintf(stderr, "eg. \"%s bash bash\"\n", argv[0]);
46        return 1;
47    }
48
49    cv = cucul_create_canvas(80 + 7, 24 + 7);
50    dp = caca_create_display(cv);
51    if(!dp)
52        return 1;
53
54//    w = cucul_get_canvas_width(cv) - 7;
55//    h = cucul_get_canvas_height(cv) - 7;
56    w = 80; h = 24;
57
58    if(w < 0 || h < 0)
59        return 1;
60
61    app[0] = cucul_create_canvas(w, h);
62    app[1] = cucul_create_canvas(w, h);
63
64    cucul_set_color_ansi(cv, CUCUL_LIGHTRED, CUCUL_BLACK);
65    cucul_draw_thin_box(cv, pty * 5, pty * 5,
66                        80 + pty * 5 + 1, 24 + pty * 5 + 1);
67
68    caca_refresh_display(dp);
69
70    buf[0] = buf[1] = NULL;
71    total[0] = total[1] = 0;
72
73    ptyfd[0] = run_in_pty(argv[1]);
74    ptyfd[1] = run_in_pty(argv[2]);
75
76    if(ptyfd[0] < 0 || ptyfd[1] < 0)
77        return -1;
78
79    fcntl(ptyfd[0], F_SETFL, O_NDELAY);
80    fcntl(ptyfd[1], F_SETFL, O_NDELAY);
81
82    for(;;)
83    {
84        struct timeval tv;
85        fd_set fdset;
86        caca_event_t ev;
87        int i, ret, refresh = 0;
88
89        ret = caca_get_event(dp, CACA_EVENT_ANY, &ev, 0);
90        if(ret && ev.type & CACA_EVENT_KEY_PRESS)
91        {
92            switch(ev.data.key.ch)
93            {
94            case CACA_KEY_CTRL_A:
95                cucul_draw_box(cv, pty * 5, pty * 5,
96                               80 + pty * 5 + 1, 24 + pty * 5 + 1, ' ');
97                pty = 1 - pty;
98                refresh = 1;
99                break;
100            case CACA_KEY_UP:
101                write(ptyfd[pty], "\x1b[A", 3); break;
102            case CACA_KEY_DOWN:
103                write(ptyfd[pty], "\x1b[B", 3); break;
104            case CACA_KEY_RIGHT:
105                write(ptyfd[pty], "\x1b[C", 3); break;
106            case CACA_KEY_LEFT:
107                write(ptyfd[pty], "\x1b[D", 3); break;
108            default:
109                write(ptyfd[pty], &ev.data.key.ch, 1); break;
110            }
111        }
112
113        /* Read data, if any */
114        FD_ZERO(&fdset);
115        FD_SET(ptyfd[0], &fdset);
116        FD_SET(ptyfd[1], &fdset);
117        tv.tv_sec = 0;
118        tv.tv_usec = 50000;
119        ret = select(ptyfd[0] + ptyfd[1] + 1, &fdset, NULL, NULL, &tv);
120
121        if(ret < 0)
122        {
123            if(!total[0] && !total[1])
124                break;
125        }
126        else if(ret) for(i = 0; i < 2; i++)
127        {
128            if(FD_ISSET(ptyfd[i], &fdset))
129            {
130                ssize_t n;
131
132                buf[i] = realloc(buf[i], total[i] + 4096);
133                n = read(ptyfd[i], buf[i] + total[i], 4096);
134
135                if(n > 0)
136                    total[i] += n;
137                else if(n == 0 || errno != EWOULDBLOCK)
138                    eof = 1;
139            }
140        }
141
142        for(i = 0; i < 2; i++) if(total[i])
143        {
144            unsigned long int bytes;
145
146            bytes = cucul_import_memory(app[i], buf[i], total[i], "utf8");
147
148            if(bytes > 0)
149            {
150                total[i] -= bytes;
151                memmove(buf[i], buf[i] + bytes, total[i]);
152                refresh = 1;
153            }
154        }
155
156        if(refresh)
157        {
158            cucul_blit(cv, 5 * !pty + 1, 5 * !pty + 1, app[!pty], NULL);
159            cucul_blit(cv, 5 * pty + 1, 5 * pty + 1, app[pty], NULL);
160            cucul_draw_thin_box(cv, pty * 5, pty * 5,
161                                80 + pty * 5 + 1, 24 + pty * 5 + 1);
162            caca_refresh_display(dp);
163        }
164
165        if(eof && !total[0] && !total[1])
166            break;
167    }
168
169    caca_get_event(dp, CACA_EVENT_KEY_PRESS, NULL, -1);
170
171    /* Clean up */
172    caca_free_display(dp);
173    cucul_free_canvas(cv);
174    cucul_free_canvas(app[0]);
175    cucul_free_canvas(app[1]);
176
177    return 0;
178}
179
180static int run_in_pty(char *cmd)
181{
182#if defined HAVE_PTY_H
183    char **argv;
184    int fd;
185    pid_t pid;
186
187    pid = forkpty(&fd, NULL, NULL, NULL);
188    if(pid < 0)
189    {
190        fprintf(stderr, "forkpty() error\n");
191        return -1;
192    }
193    else if(pid == 0)
194    {
195        putenv("CACA_DRIVER=slang");
196        argv = malloc(2 * sizeof(char *));
197        argv[0] = cmd;
198        argv[1] = NULL;
199        execvp(cmd, argv);
200        fprintf(stderr, "execvp() error\n");
201        return -1;
202    }
203
204    return fd;
205#else
206    fprintf(stderr, "forkpty() not available\n");
207    return -1;
208#endif
209}
210
Note: See TracBrowser for help on using the repository browser.