#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#include <locale.h>
#include "open-axiom.h"
#include "sockio.h"
#include "edible.h"
#include "com.h"
#include "bsdsignal.h"
#include "openpty.h"
#include "prt.h"
#include "edin.h"
#include "wct.h"
#include "fnct_key.h"
#include "cfuns.h"
using namespace OpenAxiom;
#ifdef AXIOM_UNLIKELY
#define log 1
#define logterm 1
#define siglog 1
#endif
#define Cursor_shape(x)
static void check_flip(void);
static void catch_signals(void);
static void init_parent(void);
static void set_function_chars(void);
#ifdef siglog
int sigfile;
char sigbuff[256];
#endif
struct termios childbuf;
struct termios oldbuf;
struct termios rawbuf;
struct termios canonbuf;
unsigned char _INTR, _QUIT, _ERASE, _KILL, _EOF, _EOL, _RES1, _RES2;
int ppid;
int child_pid;
short INS_MODE ;
short ECHOIT = 1;
short PTY;
int MODE;
char in_buff[1024];
char buff[MAXLINE];
int buff_flag[MAXLINE];
char serverPath[20];
int contNum, serverNum;
int num_read;
#ifdef log
int logfd;
char logpath[30];
#endif
int
main(int argc, char *argv[])
{
using namespace OpenAxiom;
fd_set rfds;
int code;
char out_buff[MAXLINE];
int out_flag[MAXLINE] ;
char *program;
char **pargs = 0;
int not_command = 1;
oa_setenv("LC_ALL", "C");
setlocale(LC_ALL, "");
if (ptyopen(&contNum, &serverNum, serverPath) == -1) {
perror("ptyopen failed");
exit(-1);
}
catch_signals();
while(*++argv && not_command) {
if(!strcmp(*argv, "-f"))
load_wct_file(*++argv);
else if(!strcmp(*argv, "-e")) {
not_command = 0;
pargs = ++argv;
}
else {
fprintf(stderr, "usage: clef [-f fname] -e command\n");
exit(-1);
}
}
skim_wct();
#ifdef log
sprintf(logpath, "/tmp/cleflog%d", oa_getpid());
logfd = open(logpath, O_CREAT | O_RDWR, 0666);
#endif
if(tcgetattr(0,&childbuf) == -1) {
perror("clef trying to get the initial terminal settings");
exit(-1);
}
child_pid = fork();
switch(child_pid) {
case -1 :
perror("clef can't create a new process");
exit(-1);
case 0:
setsid();
serverNum = open(serverPath,O_RDWR);
if (serverNum == -1) perror("open serverPath failed");
if (dup2(serverNum, 0) == -1) perror("dup2 0 failed");
if (dup2(serverNum, 1) == -1) perror("dup2 1 failed");
if (dup2(serverNum, 2) == -1) perror("dup2 2 failed");
if( (dup2(serverNum, 0) == -1) ||
(dup2(serverNum, 1) == -1) ||
(dup2(serverNum, 2) == -1) ) {
perror("clef trying to dup2");
exit(-1);
}
close(serverNum);
close(contNum);
if(tcsetattr(0, TCSAFLUSH, &childbuf) == -1) {
perror("clef child trying to set child's terminal");
exit(-1);
}
if(pargs){
execvp( pargs[0], pargs);
perror("clef trying to execvp its argument");
fprintf(stderr, "Process --> %s\n", pargs[0]);
}
else{
program = oa_getenv("SHELL");
if (!program)
program = strdup("/bin/sh");
else
program = strdup (program);
execlp( program,program, (char *) NULL);
perror("clef trying to execlp the default child");
fprintf(stderr, "Process --> %s\n", program);
}
exit(-1);
break;
}
close(serverNum);
ppid = getppid();
init_flag(out_flag, MAXLINE);
define_function_keys();
init_reader();
PTY = 1;
init_parent();
while(1) {
FD_ZERO(&rfds);
FD_SET(contNum,&rfds);
FD_SET(0,&rfds);
set_function_chars();
#ifdef log
{
char modepath[30];
sprintf(modepath, "\nMODE = %d\n", MODE);
write(logfd, modepath, strlen(modepath));
}
#endif
#ifdef logterm
{
struct termio ptermio;
char pbuff[1024];
tcgetattr(contNum, &ptermio);
sprintf(pbuff, "child's settings: Lflag = %d, Oflag = %d, Iflag = %d\n",
ptermio.c_lflag, ptermio.c_oflag, ptermio.c_iflag);
write(logfd, pbuff, strlen(pbuff));
}
#endif
code = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
for(; code < 0 ;) {
if(errno == EINTR) {
code = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
}
else {
perror("clef select failure");
exit(-1);
}
}
if( FD_ISSET(contNum,&rfds)) {
if( (num_read = read(contNum, out_buff, MAXLINE)) == -1) {
num_read = 0;
}
#ifdef log
write(logfd, "OUT<<<<<", strlen("OUT<<<<<"));
write(logfd, out_buff, num_read);
#endif
if(num_read > 0) {
if(MODE!= CLEFRAW) {
back_up(buff_pntr);
write(1,out_buff, num_read);
print_whole_buff();
}
else write(1,out_buff, num_read);
}
}
else {
if(FD_ISSET(0,&rfds)) {
num_read = read(0, in_buff, MAXLINE);
#ifdef log
write(logfd, "IN<<<<<", strlen("IN<<<<<"));
write(logfd, in_buff, num_read);
#endif
if(MODE == CLEFRAW )
write(contNum, in_buff, num_read);
else
do_reading();
}
}
}
}
static void
init_parent(void)
{
if(tcgetattr(0, &oldbuf) == -1) {
perror("clef trying to get terminal initial settings");
exit(-1);
}
if ((tcgetattr(0, &canonbuf) == -1) ||
(tcgetattr(0, &rawbuf) == -1) ) {
perror("clef trying to get terminal settings");
exit(-1);
}
canonbuf.c_lflag &= ~(ICANON | ECHO | ISIG);
canonbuf.c_lflag |= ISIG;
canonbuf.c_cc[VMIN] = 1;
canonbuf.c_cc[VTIME] = 1;
rawbuf.c_oflag = rawbuf.c_iflag = rawbuf.c_lflag = 0;
rawbuf.c_cc[VMIN] = 1;
rawbuf.c_cc[VTIME] = 1;
if(tcsetattr(0, TCSAFLUSH, &canonbuf) == -1) {
perror("clef setting parent terminal to canonical processing");
exit(0);
}
MODE = CLEFCANONICAL;
INS_MODE = 1;
Cursor_shape(2);
}
static void
hangup_handler(int sig)
{
#ifdef siglog
sigfile = open(sigbuff, O_RDWR | O_APPEND);
write(sigfile, "Hangup Handler\n", strlen("Hangup Handler\n"));
close(sigfile);
#endif
if(kill(child_pid, 0)) kill(child_pid, SIGTERM);
if(kill(ppid, 0) >= 0) {
if(tcsetattr(0, TCSAFLUSH, &oldbuf) == -1) {
perror("clef restoring terminal in hangup handler");
}
printf("\n");
}
unlink(editorfilename);
exit(-1);
}
static void
terminate_handler(int sig)
{
#ifdef siglog
sigfile = open(sigbuff, O_RDWR | O_APPEND);
write(sigfile, "Terminate Handler\n", strlen("Terminate Handler\n") + 1);
close(sigfile);
openaxiom_sleep(1);
#endif
kill(child_pid, SIGTERM);
if(tcsetattr(0, TCSAFLUSH, &oldbuf) == -1) {
perror("clef restoring terminal in terminate handler");
}
printf("\n");
Cursor_shape(2);
fprintf(stderr, "\n");
unlink(editorfilename);
exit(0);
}
static void
interrupt_handler(int sig)
{
#ifdef siglog
sigfile = open(sigbuff, O_RDWR | O_APPEND);
write(sigfile, "Interrupt Handler\n", strlen("Interrupt Handler\n") + 1);
close(sigfile);
openaxiom_sleep(1);
#endif
kill(child_pid, SIGINT);
}
static void
child_handler(int sig)
{
#ifdef siglog
sigfile = open(sigbuff, O_RDWR | O_APPEND );
write(sigfile, "Child Handler\n", strlen("Child Handler\n") + 1);
close(sigfile);
#endif
Cursor_shape(2);
close(contNum);
if(kill(ppid, 0) >= 0) {
if(tcsetattr(0, TCSAFLUSH, &oldbuf) == -1) {
perror("clef restoring terminal in child handler");
}
printf("\n");
}
unlink(editorfilename);
exit(0);
}
static void
alarm_handler(int sig)
{
int newppid = getppid();
#ifdef siglog
sigfile = open(sigbuff, O_RDWR | O_APPEND);
write(sigfile, "Alarm Handler\n", strlen("Alarm Handler\n")+ 1 );
close(sigfile);
#endif
if(ppid == newppid) {
alarm(60);
return;
}
else {
if(tcsetattr(0, TCSAFLUSH, &oldbuf) == -1) {
perror("clef restoring terminal in alarm handler");
}
Cursor_shape(2);
fprintf(stderr, "\n");
unlink(editorfilename);
exit(0);
}
}
static void
catch_signals(void)
{
#ifdef siglog
sprintf(sigbuff, "/tmp/csig%d", oa_getpid());
sigfile = open(sigbuff, O_RDWR | O_TRUNC | O_CREAT);
write(sigfile, "Started \n", strlen("Started \n"));
close(sigfile);
#endif
bsdSignal(SIGHUP, hangup_handler,RestartSystemCalls);
bsdSignal(SIGCHLD,child_handler,RestartSystemCalls);
bsdSignal(SIGTERM, terminate_handler,RestartSystemCalls);
bsdSignal(SIGINT, interrupt_handler,RestartSystemCalls);
bsdSignal(SIGALRM, alarm_handler,RestartSystemCalls);
alarm(60);
}
#define etc_whitespace(c) ((c == ' ' || c == '\t')?(1):(0))
static void
set_function_chars(void)
{
_INTR = childbuf.c_cc[VINTR];
_QUIT = childbuf.c_cc[VQUIT];
_ERASE = childbuf.c_cc[VERASE];
_KILL = childbuf.c_cc[VKILL];
_EOF = childbuf.c_cc[VEOF];
_EOL = childbuf.c_cc[VEOL];
return;
}