summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README25
-rw-r--r--im.h93
-rw-r--r--imtable.h9
-rw-r--r--ptyim.c147
4 files changed, 274 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..d5eb34e
--- /dev/null
+++ b/README
@@ -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
diff --git a/im.h b/im.h
new file mode 100644
index 0000000..4980938
--- /dev/null
+++ b/im.h
@@ -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"},
+};
diff --git a/ptyim.c b/ptyim.c
new file mode 100644
index 0000000..047bb25
--- /dev/null
+++ b/ptyim.c
@@ -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;
+}