diff options
-rw-r--r-- | README | 25 | ||||
-rw-r--r-- | im.h | 93 | ||||
-rw-r--r-- | imtable.h | 9 | ||||
-rw-r--r-- | ptyim.c | 147 |
4 files changed, 274 insertions, 0 deletions
@@ -0,0 +1,25 @@ +termios sets the stdin terminal to raw + +make sure to use read/write syscalls, these are non blocking, and will not mess +up the output of things. + +now all line discipline is handled by the pty + + +-------------------------------=[Controlling TTY]=------------------------------ +Forked bash process makes itself a session leader, then sets the pty as the +controlling tty + +It now acts as a bash +----------------------------------=[Resizeing]=--------------------------------- +SIGWINCH hook, very simple + +-----------------------------------=[Testing]=---------------------------------- +fg/bg ctrl-c ctrl-z all works + +cmus, bcmus, all work + +-------------------------------=[Useful Commands]=------------------------------ +ps l +tty +infocmp @@ -0,0 +1,93 @@ +#include "imtable.h" +#define IM_BUFFER_LEN 32 +char im_buffer[IM_BUFFER_LEN]; +char im_buffer_pos = 0; +//recursive search, returns -1 on failure +//searches from [start, end) +int im_search(char * input, int start, int end) { + // 0 width search + if (end <= start) { + return -1; + } + //test for middle, works even for 1 width middle=start + int middle = start + (end-start)/2; + printf("testing:%s\n",im_table[middle][0]); + int test = strncmp(im_table[middle][0], input, IM_TABLE_ENTRY_LEN); + if (test == 0) { + return middle; + } + //special case for width 1,2 region + if ((end - start) == 1) { + if (test == 0) { + return start; + } else { + return -1; + } + } + if (test == 0) { + return 0; + } else { + if (test > 0) { + return im_search(input,start,middle); + } else { + return im_search(input,middle,end); + } + } + +} +//returns output len, since we want to be able to handle null bytes as well +int update_im_state(char input, char * output) { + if ( ('a' <= input <= 'z')||('0' <= input <= '9')||(input == ' ') ) { + if (im_buffer_pos < IM_BUFFER_LEN) { + im_buffer[im_buffer_pos] = input; + im_buffer_pos++; + } else { + //passthrough + output[0] = input; + output[1] = 0; + return 1; + } + } + int im_entry = im_search(im_buffer,0, IM_TABLE_LEN); + if (im_entry != -1) { + strncpy(output, im_table[im_entry][1], IM_TABLE_ENTRY_LEN); + im_buffer[0] = 0; + im_buffer_pos = 0; + return strlen(im_table[im_entry][1]); + } + //these only do something if there's something in the buffer, otherwise + //passthrough + if (im_buffer_pos > 0) { + switch (input) { + //escape, cancels + case 0x1B: + im_buffer[0] = 0; + im_buffer_pos = 0; + return 0; + break; + //enter, enters the buffer + case 0x0A: + for (int i = 0; i <im_buffer_pos; i++) { + output[i] = im_buffer[i]; + } + output[im_buffer_pos] = 0; + int tmp = im_buffer_pos; + im_buffer_pos = 0; + return tmp; + break; + //backspace + case 0x08: + if (im_buffer_pos > 0) { + im_buffer_pos--; + im_buffer[im_buffer_pos] = 0; + } + return 0; + break; + } + } + //default behavior of passthrough + output[0] = input; + output[1] = 0; + return 1; + +} diff --git a/imtable.h b/imtable.h new file mode 100644 index 0000000..dc51809 --- /dev/null +++ b/imtable.h @@ -0,0 +1,9 @@ +#define IM_TABLE_LEN 4 +#define IM_TABLE_ENTRY_LEN 8 +//assumes this is sorted +char im_table[][3][IM_TABLE_ENTRY_LEN] = { + {"a ", "對", "100"}, + {"aa ", "對", "100"}, + {"b ", "八", "100"}, + {"ba ", "不", "100"}, +}; @@ -0,0 +1,147 @@ +//required for posix_openpt to work +#define _XOPEN_SOURCE 600 +#define _DEFAULT_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <termios.h> +//#include <asm/termbits.h> +#include <string.h> +#include <signal.h> +#include "im.h" +int running = 1; +//hook for when the pty child process dies +void childhook(int a) { + running = 0; +} +int pty_slave = -1; +//hook for SIGWINCH +void winchhook(int a) { + struct winsize sz; + ioctl(STDIN_FILENO, TIOCGWINSZ, &sz); + ioctl(pty_slave, TIOCSWINSZ, &sz); + +} +int main (int argc, char * argv[], char * envp[]) { + printf("%s: %d\n", "a", im_search("a",0,IM_TABLE_LEN)); + printf("%s: %d\n", "bb", im_search("bb",0,IM_TABLE_LEN)); + printf("%s: %d\n", "c", im_search("c",0,IM_TABLE_LEN)); + printf("%s: %d\n", "ba", im_search("ba",0,IM_TABLE_LEN)); + //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); + printf("Slave name %s\n", pty_slave_fn); + //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(); + printf("forked w/ pid %d\n", mypid); + 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(STDIN_FILENO,readbuffer,1); + } + //relays input from stdin + char input_buffer[IM_TABLE_ENTRY_LEN] = {0}; + + chars_read = read(STDIN_FILENO, readbuffer, 1); + if (chars_read > 0) { + write(pty_master,readbuffer,1); + } + } + } + close(pty_master); + tcsetattr(STDIN_FILENO,TCSANOW,&stdin_termio_bk); + //close(pty_slave); + return 0; +} |