A simple launcher

As a workaround for buffering issue of TurtleEdit, I wrote a simple launcher to cheat your code into belief that it is running in a terminal.

Usage

Download the C code below, then compile it in Mac or Linux (unfortunately, there is no Windows version) as

cc -o run run.c

Copy or move the executable file (run) into your programming folder.

Next, select Settings in Run menu of TurtleEdit, and modify "command for execution" as

./run ./a.out

in case of C. For Ruby, for example, setting is something like

./run ruby %f

Once this is done, you need not modify codes seen in textbooks when you use TurtleEdit.

Code

download run.c

/* 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 ;
}