//required for posix_openpt to work #define _XOPEN_SOURCE 600 #define _DEFAULT_SOURCE #include #include #include #include #include #include #include //#include #include #include #include "im.h" int running = 1; //hook for when the pty child process dies void childhook(int a) { running = 0; } int pty_slave = -1; //terminal rows and cols int trows = 0; int tcols = 0; //hook for SIGWINCH void winchhook(int a) { struct winsize sz; ioctl(STDIN_FILENO, TIOCGWINSZ, &sz); trows = sz.ws_row; tcols = sz.ws_col; //trick programs into thinking the terminal is smaller than it is if (sz.ws_row >= 1) { sz.ws_row--; } ioctl(pty_slave, TIOCSWINSZ, &sz); } void disp_im() { //3 spaces for the im indicator +1 for automargin int im_col = tcols - IM_TABLE_ENTRY_LEN - 4; char pos_str[32] = ""; int l = sprintf(pos_str, "\033[%d;%df",trows, im_col); //printf("\0337"); //printf("\033[%d;%df",trows,im_col); //printf("\033[0;0f",trows,im_col); //printf("\033[7m"); //if (im_on) { // printf("漢"); //} else { // printf("英"); //} //printf("%s",im_buffer); //printf("\033[0m"); //printf("\0338"); write(STDOUT_FILENO,"\0337",2); //also writes to top left the current im buffer //write(STDOUT_FILENO,"\033[33;14f",8); //write(STDOUT_FILENO,"\033[0;4f",6); //write to the bottom left corner write(STDOUT_FILENO, pos_str,l); //invert video write(STDOUT_FILENO,"\033[7m",4); //overwrite what was there previously write(STDOUT_FILENO," ", IM_TABLE_ENTRY_LEN+4); write(STDOUT_FILENO, pos_str,l); //im mode indicator if (im_on) { write(STDOUT_FILENO,"漢:",4); } else { write(STDOUT_FILENO,"英:",4); } //actual buffer write(STDOUT_FILENO,im_buffer,im_buffer_pos); //restore cursor pos and attrbutes write(STDOUT_FILENO,"\033[0m",4); write(STDOUT_FILENO,"\0338",2); } int main (int argc, char * argv[], char * envp[]) { //creates the pty master int pty_master = posix_openpt(O_RDWR); if (pty_master < 0) { fprintf(stderr, "errno: %d, failed to create pty master", errno); return errno; } //makes it nonblocking fcntl(pty_master, F_SETFL,O_NONBLOCK); //make it raw struct termios stdin_termio; struct termios stdin_termio_bk; tcgetattr(STDIN_FILENO,&stdin_termio); tcgetattr(STDIN_FILENO,&stdin_termio_bk); cfmakeraw(&stdin_termio); tcsetattr(STDIN_FILENO,TCSANOW,&stdin_termio); //make it nonblocking fcntl(STDIN_FILENO, F_SETFL,O_NONBLOCK); if ( unlockpt(pty_master) <0) { fprintf(stderr, "errno: %d, failed to unlock pty slave", errno); return errno; } //gets slave path char * pty_slave_fn = ptsname(pty_master); //tries to open pty slave pty_slave = open(pty_slave_fn, O_RDWR); if (pty_slave < 0) { fprintf(stderr, "errno: %d, failed to open pty slave '%s'",\ errno, pty_slave_fn); return errno; } //make the pty slave the same line discipline stdin was tcsetattr(pty_slave,TCSANOW,&stdin_termio_bk); //syncs the window sizes for the first time winchhook(0); //forks for running bash pid_t mypid = fork(); if (mypid == 0) { //set self to be session leader if (setsid() <0) { fprintf(stderr, "failed to make new session\n"); } //all the stand streams freopen(pty_slave_fn, "r", stdin); freopen(pty_slave_fn, "w", stdout); freopen(pty_slave_fn, "w", stderr); //must be a session leader to set the controlling terminal if (ioctl(pty_slave, TIOCSCTTY, 0)) { fprintf(stderr, "errno: %d, failed to set controlling tty\n", errno); } /* * Opens up the Shell now */ //opens up the slave pty //needs to fork //then set its own process group //need to set the terminal //exec bash then //gets the shell to use, order is // argument 1, then $SHELL< then /bin/sh char * shellpath = "/bin/sh"; if (argc >1) { shellpath = argv[1]; } else if (getenv("SHELL") != NULL) { shellpath = getenv("SHELL"); } //gets the terminal environmental variabke, 32 should be enough char env_term[32] = "TERM="; strcat(env_term, getenv("TERM")); char env_home[32] = "HOME="; strcat(env_home, getenv("HOME")); char * shell_envs[3] = {env_term,env_home, NULL}; char * shell_args[2] = {shellpath, NULL}; //if (execve(shellpath,shell_args, shell_envs) == -1) { if (execve(shellpath,shell_args, envp) == -1) { fprintf(stderr, "errno: %d, Failed to start shell '%s'\n", errno, shellpath); return errno; } //should automatically close any file descriptors _exit(0); } else { signal(SIGCHLD, childhook); signal(SIGWINCH, winchhook); char readbuffer[1] = {0}; int chars_read = 0; //open while (running) { //just relay everything for now //read uses file descriptors and is a system call chars_read = read(pty_master,readbuffer,1); if (chars_read >0) { write(STDOUT_FILENO,readbuffer,1); } chars_read = read(STDIN_FILENO, readbuffer, 1); if (chars_read > 0) { //write(pty_master,readbuffer,1); //relays input from stdin char input_buffer[IM_TABLE_ENTRY_LEN] = {0}; int im_chars = update_im_state(readbuffer[0], input_buffer); input_buffer[im_chars] = 0; if (im_chars >0) { write(pty_master,input_buffer,im_chars); } disp_im(); } } } close(pty_master); tcsetattr(STDIN_FILENO,TCSANOW,&stdin_termio_bk); //close(pty_slave); return 0; }