起動用プログラム
TurtleEdit内でプログラムを実行すると,出力がバッファーされてしまうため,コンソールで動かす場合と挙動が異なってしまいます。 そこで,プログラムの標準入出力を疑似端末につなぎ替えて,コンソール上で動いているように錯覚させるためのコードを書いてみました。
使い方
下に掲載されているCのコードをファイルに保存し,MacやLinux上でコンパイルします(Windowsでは動きません)。ファイル名を run.c として
cc -o run run.c
を実行すると,runという実行ファイルが出来ます。この run を,プログラミング練習用のフォルダに コピー(移動)しておきます。
./run
のところは,runの保存先の絶対パスを書いておいたほうが良いかもしれません。
例えば、ホームディレクトリの下の bin/run
にrunコマンドを置いた場合は、
%h/bin/run
のように書くことができます。
次に,TurtleEditの「実行」メニューから「設定」を開いて,「実行コマンド」の欄を
./run ./a.out
と書き換えます(C言語等の場合)。他の言語,例えばRubyの場合は,
./run ruby %f
等と書き換えます。
これで,インタラクティブな処理であっても,教科書などに載っているコードがそのまま走るはずです。
コード
/* a simple program launcher for TurtleEdit */ /* Yoshinori Hayakawa, Tohoku University */ /* 07-MAY-2014 */ /* most of this code is based on the exmaples in */ /* http://rachid.koucha.free.fr/tech_corner/pty_pdip.html */ /* */ #define _XOPEN_SOURCE #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/select.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <termios.h> #include <sys/types.h> #include <sys/wait.h> #define BUFFLEN 1024 char **cmdargv = NULL ; char readbuf[BUFFLEN] ; int terminating ; void sigchld_handler(int); int main(int argc, char *argv[]) { int i,master,slave ; pid_t pid ; if (argc<=1) return 0 ; else { cmdargv = (char **) malloc(sizeof(char *)*argc) ; for (i=1 ; i<argc ; i++) { cmdargv[i-1] = argv[i] ; } cmdargv[argc-1]='\0' ; } master = open("/dev/ptmx", O_RDWR|O_NOCTTY); grantpt(master); unlockpt(master); slave = open(ptsname(master), O_RDWR); terminating = 0 ; if (pid=fork()) { /* parent */ fd_set fd_input ; int rc,k ; signal(SIGCHLD, sigchld_handler); close(slave) ; while (1) { FD_ZERO(&fd_input); FD_SET(0, &fd_input); FD_SET(master, &fd_input); rc = select(master + 1, &fd_input, NULL, NULL, NULL); switch(rc) { case -1 : exit(0); default : if (FD_ISSET(0, &fd_input)) { /* check stdin */ rc = read(0, readbuf, sizeof(readbuf)); if (rc > 0) { write(master, readbuf, rc); } else { if (rc < 0) { fprintf(stderr, "Error on read standard input\n"); exit(1); } } } if (FD_ISSET(master, &fd_input)) { /* check PTY */ rc = read(master, readbuf, sizeof(readbuf)); if (rc > 0) { write(1, readbuf, rc); } if (terminating) exit(0) ; } } } } else { /* child process */ struct termios term_setting ; close(master) ; dup2(slave,0) ; dup2(slave,1) ; dup2(slave,2) ; /* disable echo */ tcgetattr (0, &term_setting) ; term_setting.c_lflag &= ~ECHO; term_setting.c_cc[VEOF] = 0x04 ; // CTRL-D term_setting.c_cc[VERASE] = 0x08 ; // BACKSPACE term_setting.c_lflag |= ICANON ; tcsetattr (0, TCSAFLUSH, &term_setting) ; setsid() ; ioctl(0, TIOCSCTTY, 1); if (execvp(argv[1],cmdargv)==-1) { fprintf(stderr,"cannot execute %s\n",argv[1]) ; } _exit(0) ; } return 0 ; } void sigchld_handler(int x) { terminating = 1 ; }