|
|
@@ -0,0 +1,210 @@ |
|
|
|
/* |
|
|
|
* term swallow a terminal-based application |
|
|
|
* Copyright (c) 2006 Sam Hocevar <sam@zoy.org> |
|
|
|
* All Rights Reserved |
|
|
|
* |
|
|
|
* $Id$ |
|
|
|
* |
|
|
|
* This program is free software; you can redistribute it and/or |
|
|
|
* modify it under the terms of the Do What The Fuck You Want To |
|
|
|
* Public License, Version 2, as published by Sam Hocevar. See |
|
|
|
* http://sam.zoy.org/wtfpl/COPYING for more details. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include "config.h" |
|
|
|
#include "common.h" |
|
|
|
|
|
|
|
#if !defined __KERNEL__ |
|
|
|
# include <stdio.h> |
|
|
|
# include <string.h> |
|
|
|
# include <stdlib.h> |
|
|
|
# include <unistd.h> |
|
|
|
# include <fcntl.h> |
|
|
|
# if defined HAVE_PTY_H |
|
|
|
# include <pty.h> /* for openpty and forkpty */ |
|
|
|
# endif |
|
|
|
#endif |
|
|
|
|
|
|
|
#include "cucul.h" |
|
|
|
#include "caca.h" |
|
|
|
|
|
|
|
static int run_in_pty(char *cmd); |
|
|
|
|
|
|
|
int main(int argc, char **argv) |
|
|
|
{ |
|
|
|
static cucul_canvas_t *cv, *app[2]; |
|
|
|
static caca_display_t *dp; |
|
|
|
unsigned char *buf[2]; |
|
|
|
long int total[2]; |
|
|
|
int ptyfd[2], pty = 0; |
|
|
|
int w, h, eof = 0; |
|
|
|
|
|
|
|
if(argc < 3) |
|
|
|
{ |
|
|
|
fprintf(stderr, "usage: %s <cmd1> <cmd2>\n", argv[0]); |
|
|
|
fprintf(stderr, "eg. \"%s bash bash\"\n", argv[0]); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
cv = cucul_create_canvas(80 + 7, 24 + 7); |
|
|
|
dp = caca_create_display(cv); |
|
|
|
if(!dp) |
|
|
|
return 1; |
|
|
|
|
|
|
|
// w = cucul_get_canvas_width(cv) - 7; |
|
|
|
// h = cucul_get_canvas_height(cv) - 7; |
|
|
|
w = 80; h = 24; |
|
|
|
|
|
|
|
if(w < 0 || h < 0) |
|
|
|
return 1; |
|
|
|
|
|
|
|
app[0] = cucul_create_canvas(w, h); |
|
|
|
app[1] = cucul_create_canvas(w, h); |
|
|
|
|
|
|
|
cucul_set_color_ansi(cv, CUCUL_LIGHTRED, CUCUL_BLACK); |
|
|
|
cucul_draw_thin_box(cv, pty * 5, pty * 5, |
|
|
|
80 + pty * 5 + 1, 24 + pty * 5 + 1); |
|
|
|
|
|
|
|
caca_refresh_display(dp); |
|
|
|
|
|
|
|
buf[0] = buf[1] = NULL; |
|
|
|
total[0] = total[1] = 0; |
|
|
|
|
|
|
|
ptyfd[0] = run_in_pty(argv[1]); |
|
|
|
ptyfd[1] = run_in_pty(argv[2]); |
|
|
|
|
|
|
|
if(ptyfd[0] < 0 || ptyfd[1] < 0) |
|
|
|
return -1; |
|
|
|
|
|
|
|
fcntl(ptyfd[0], F_SETFL, O_NDELAY); |
|
|
|
fcntl(ptyfd[1], F_SETFL, O_NDELAY); |
|
|
|
|
|
|
|
for(;;) |
|
|
|
{ |
|
|
|
struct timeval tv; |
|
|
|
fd_set fdset; |
|
|
|
caca_event_t ev; |
|
|
|
int i, ret, refresh = 0; |
|
|
|
|
|
|
|
ret = caca_get_event(dp, CACA_EVENT_ANY, &ev, 0); |
|
|
|
if(ret && ev.type & CACA_EVENT_KEY_PRESS) |
|
|
|
{ |
|
|
|
switch(ev.data.key.ch) |
|
|
|
{ |
|
|
|
case CACA_KEY_CTRL_A: |
|
|
|
cucul_draw_box(cv, pty * 5, pty * 5, |
|
|
|
80 + pty * 5 + 1, 24 + pty * 5 + 1, ' '); |
|
|
|
pty = 1 - pty; |
|
|
|
refresh = 1; |
|
|
|
break; |
|
|
|
case CACA_KEY_UP: |
|
|
|
write(ptyfd[pty], "\x1b[A", 3); break; |
|
|
|
case CACA_KEY_DOWN: |
|
|
|
write(ptyfd[pty], "\x1b[B", 3); break; |
|
|
|
case CACA_KEY_RIGHT: |
|
|
|
write(ptyfd[pty], "\x1b[C", 3); break; |
|
|
|
case CACA_KEY_LEFT: |
|
|
|
write(ptyfd[pty], "\x1b[D", 3); break; |
|
|
|
default: |
|
|
|
write(ptyfd[pty], &ev.data.key.ch, 1); break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Read data, if any */ |
|
|
|
FD_ZERO(&fdset); |
|
|
|
FD_SET(ptyfd[0], &fdset); |
|
|
|
FD_SET(ptyfd[1], &fdset); |
|
|
|
tv.tv_sec = 0; |
|
|
|
tv.tv_usec = 50000; |
|
|
|
ret = select(ptyfd[0] + ptyfd[1] + 1, &fdset, NULL, NULL, &tv); |
|
|
|
|
|
|
|
if(ret < 0) |
|
|
|
{ |
|
|
|
if(!total[0] && !total[1]) |
|
|
|
break; |
|
|
|
} |
|
|
|
else if(ret) for(i = 0; i < 2; i++) |
|
|
|
{ |
|
|
|
if(FD_ISSET(ptyfd[i], &fdset)) |
|
|
|
{ |
|
|
|
ssize_t n; |
|
|
|
|
|
|
|
buf[i] = realloc(buf[i], total[i] + 4096); |
|
|
|
n = read(ptyfd[i], buf[i] + total[i], 4096); |
|
|
|
|
|
|
|
if(n > 0) |
|
|
|
total[i] += n; |
|
|
|
else if(n == 0 || errno != EWOULDBLOCK) |
|
|
|
eof = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for(i = 0; i < 2; i++) if(total[i]) |
|
|
|
{ |
|
|
|
unsigned long int bytes; |
|
|
|
|
|
|
|
bytes = cucul_import_memory(app[i], buf[i], total[i], "utf8"); |
|
|
|
|
|
|
|
if(bytes > 0) |
|
|
|
{ |
|
|
|
total[i] -= bytes; |
|
|
|
memmove(buf[i], buf[i] + bytes, total[i]); |
|
|
|
refresh = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if(refresh) |
|
|
|
{ |
|
|
|
cucul_blit(cv, 5 * !pty + 1, 5 * !pty + 1, app[!pty], NULL); |
|
|
|
cucul_blit(cv, 5 * pty + 1, 5 * pty + 1, app[pty], NULL); |
|
|
|
cucul_draw_thin_box(cv, pty * 5, pty * 5, |
|
|
|
80 + pty * 5 + 1, 24 + pty * 5 + 1); |
|
|
|
caca_refresh_display(dp); |
|
|
|
} |
|
|
|
|
|
|
|
if(eof && !total[0] && !total[1]) |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
caca_get_event(dp, CACA_EVENT_KEY_PRESS, NULL, -1); |
|
|
|
|
|
|
|
/* Clean up */ |
|
|
|
caca_free_display(dp); |
|
|
|
cucul_free_canvas(cv); |
|
|
|
cucul_free_canvas(app[0]); |
|
|
|
cucul_free_canvas(app[1]); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int run_in_pty(char *cmd) |
|
|
|
{ |
|
|
|
#if defined HAVE_PTY_H |
|
|
|
char **argv; |
|
|
|
int fd; |
|
|
|
pid_t pid; |
|
|
|
|
|
|
|
pid = forkpty(&fd, NULL, NULL, NULL); |
|
|
|
if(pid < 0) |
|
|
|
{ |
|
|
|
fprintf(stderr, "forkpty() error\n"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
else if(pid == 0) |
|
|
|
{ |
|
|
|
putenv("CACA_DRIVER=slang"); |
|
|
|
argv = malloc(2 * sizeof(char *)); |
|
|
|
argv[0] = cmd; |
|
|
|
argv[1] = NULL; |
|
|
|
execvp(cmd, argv); |
|
|
|
fprintf(stderr, "execvp() error\n"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
return fd; |
|
|
|
#else |
|
|
|
fprintf(stderr, "forkpty() not available\n"); |
|
|
|
return -1; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|