/* Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. All rights reserved. Copyright (C) 2007-2010, Gabriel Dos Reis. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of The Numerical ALgorithms Group Ltd. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* #define debug 1 */ #include #include "openaxiom-c-macros.h" #include #include #include #include #include "edible.h" #define HFT 0 #define SUN 1 #define DEC 2 #define control_to_alpha(x) (x + ('A' - 0x01)) #define alpha_to_control(x) (x - ('A' - 0x01)) int termId; QueStruct *ring = NULL; QueStruct *current = NULL; int ring_size = 0; int MAXRING = 64; int prev_check = 10; int curr_pntr; int num_pntr; int num_proc; int had_tab; int had_tab_last; extern char buff[1024]; /* Buffers for collecting input and */ extern int buff_flag[1024]; /* flags for whether buff chars are printing or non-printing */ int buff_pntr; /* present length of buff */ #include "edin.h" #include "prt.h" #include "wct.h" #include "cursor.h" #include "fnct_key.h" void init_reader(void) { char *termVal; buff[50] = '\0'; /** initialize some stuff ***/ init_flag(buff_flag, MAXLINE); buff_pntr = curr_pntr = 0; had_tab = 0; had_tab_last = 0; termVal = (char *) getenv("TERM"); if (!strcmp("sun", termVal)) termId = SUN; else if (!strcmp("xterm", termVal) || !strncmp("vt", termVal, 2)) termId = DEC; else if (!strcmp("hft", termVal) || !strncmp("aixterm", termVal, 7)) termId = HFT; } void do_reading(void) { int ttt_read; int done_completely; done_completely = 0; num_proc = 0; while (num_proc < num_read) { if(in_buff[num_proc]== _ERASE) { back_over_current_char(); num_proc++; } else { switch (in_buff[num_proc]) { /* lets start checking for different types of chars */ case _EOLN: case _CR: /* If I have read a complete line, so send it to the child */ send_line_to_child(); if (!PTY) myputchar('\n'); break; /* * Use 0x7f as delete */ case _DEL: /* Had a delete key */ delete_current_char(); break; case _CNTRL_W: move_back_word(); num_proc++; break; case _TAB: had_tab = 1; /* command completion stuff */ num_proc++; if (had_tab_last) rescan_wct(); else find_wct(); break; case _BELL: insert_buff_nonprinting(1); putchar(_BELL); fflush(stdout); break; case _ESC: /* * get 2 characters more */ while (!(num_read - num_proc > 2)) { ttt_read = read(0, in_buff + num_read, 2 - (num_read - num_proc) + 1); if (ttt_read > 0) num_read = num_read + ttt_read; } if (in_buff[num_proc + 1] == _LBRACK) { /* ESC [ */ switch (in_buff[num_proc + 2]) { /* look for arrows */ case _A: /* up arrow */ /* * The first thing I plan to do is get rid of the present * input ** */ prev_buff(); curr_pntr = buff_pntr; num_proc = num_proc + 3; break; case _B: /* down arrow */ next_buff(); curr_pntr = buff_pntr; num_proc = num_proc + 3; break; case _C: /* right arrow */ move_ahead(); num_proc = num_proc + 3; break; case _D: /* left arrow */ move_back(); num_proc = num_proc + 3; break; /* * Use ^[[P as delete */ case _P: /*** Had a delete key ****/ delete_current_char(); break; case _H: case 0: move_home(); num_proc += 3; break; case _M: case _Z: insert_buff_nonprinting(3); done_completely = 1; num_proc += 3; break; case _x: num_proc = num_read; break; case _1: case _2: case _0: /* * I have had a possible function key hit, look for the * ones I want. check for ESC ] x ~ */ while (!(num_read - num_proc > 3)) { ttt_read = read(0, in_buff + num_read, 3 - (num_read - num_proc) + 1); if (ttt_read > 0) num_read = num_read + ttt_read; } if (in_buff[num_proc + 3] == _twiddle) { /* * treat ESC ] x ~ */ switch (in_buff[num_proc + 2]) { case _2: flip(INS_MODE); if (INS_MODE) Cursor_shape(5); else Cursor_shape(2); reprint(curr_pntr); num_proc += 4; break; default: insert_buff_nonprinting(1); break; } break; } /* check for ESC ] x y ~ */ while (!(num_read - num_proc > 4)) { ttt_read = read(0, in_buff + num_read, 4 - (num_read - num_proc) + 1); if (ttt_read > 0) num_read = num_read + ttt_read; } if (in_buff[num_proc + 4] == _twiddle) { /* * treat ESC ] x y ~ */ insert_buff_nonprinting(1); break; } /* check for ESC ] x y z [q|z] */ while (!(num_read - num_proc > 5)) { ttt_read = read(0, in_buff + num_read, 5 - (num_read - num_proc) + 1); if (ttt_read > 0) num_read = num_read + ttt_read; } if (insert_toggle(&in_buff[num_proc + 3])) { flip(INS_MODE); if (INS_MODE) Cursor_shape(5); else Cursor_shape(2); reprint(curr_pntr); num_proc = num_proc + 6; break; } else if (cntrl_end(&in_buff[num_proc + 3])) { num_proc = num_proc + 6; delete_to_end_of_line(); break; } else if (back_word(&in_buff[num_proc + 3])) { move_back_word(); num_proc += 6; break; } else if (fore_word(&in_buff[num_proc + 3])) { move_fore_word(); num_proc += 6; break; } else if (end_key(&in_buff[num_proc + 3])) { move_end(); num_proc += 6; break; } switch (in_buff[num_proc + 5]) { case _q: /* * IBM function keys */ { char num[3]; int key; num[0] = in_buff[num_proc + 3]; num[1] = in_buff[num_proc + 4]; num[2] = '\0'; key = atoi(num); if (key > 0 && key < 13) { if (function_key[key].str != NULL) { handle_function_key(key, contNum); done_completely = 1; } else { insert_buff_nonprinting(6); done_completely = 1; } } else { insert_buff_nonprinting(6); done_completely = 1; } break; } case _z: /* * Sun function keys */ { char num[3]; int key; num[0] = in_buff[num_proc + 3]; num[1] = in_buff[num_proc + 4]; num[2] = '\0'; key = atoi(num) - 23; if (key > 0 && key < 13) { if (function_key[key].str != NULL) { handle_function_key(key, contNum); done_completely = 1; } else { insert_buff_nonprinting(6); done_completely = 1; } } else if (atoi(num) == 14) { move_home(); num_proc += 6; done_completely = 1; } else if (atoi(num) == 20) { move_end(); num_proc += 6; done_completely = 1; } else if (atoi(num) == 47) { flip(INS_MODE); if (INS_MODE) Cursor_shape(5); else Cursor_shape(2); reprint(curr_pntr); num_proc = num_proc + 6; done_completely = 1; } else { insert_buff_nonprinting(6); done_completely = 1; } break; } default: insert_buff_nonprinting(1); break; } default: if (!done_completely) insert_buff_nonprinting(1); break; } } /* if */ else { /* ESC w/o [ */ insert_buff_nonprinting(1); } break; case _BKSPC: back_over_current_char(); num_proc++; break; default: if (in_buff[num_proc] == _KILL) { delete_line(); num_proc++; } else { if ((in_buff[num_proc] == _INTR) || (in_buff[num_proc] == _QUIT)) { write(contNum, &in_buff[num_proc], num_read - num_proc); if (!PTY) write(contNum, "\n", 1); num_proc++; } else { if (in_buff[num_proc] == _EOF) { insert_buff_nonprinting(1); if (!PTY) write(contNum, "\n", 1); /*comment out this bit if (!buff_pntr) { write(contNum, &in_buff[num_proc], 1); if (!PTY) write(contNum, "\n", 1); } else { write(contNum, buff, buff_pntr); } */ num_proc++; } else { if (in_buff[num_proc] == _EOL) { send_line_to_child(); if (!PTY) write(contNum, "\n", 1); } else { if (in_buff[num_proc] == _ERASE) { back_over_current_char(); num_proc++; } else { if (control_char(in_buff[num_proc])) insert_buff_nonprinting(1); else insert_buff_printing(1); } } } } } /* close the default case */ break; } /* switch */ } /*else*/ if (had_tab) { had_tab_last = 1; had_tab = 0; } else had_tab_last = 0; } /* while */ } void send_line_to_child(void) { static char converted_buffer[MAXLINE]; int converted_num; /* Takes care of sending a line to the child, and resetting the buffer for new input */ back_it_up(curr_pntr); /* start by putting the line into the command line ring ***/ if (buff_pntr) insert_queue(); /* finish the line and send it to the child **/ buff[buff_pntr] = in_buff[num_proc]; buff_flag[buff_pntr++] = 1; buff[buff_pntr] = '\0'; buff_flag[buff_pntr] = -1; /* * Instead of actually writing the Line, I have to substitute in the * actual characters recieved */ converted_num = convert_buffer(converted_buffer, buff, buff_flag, buff_pntr); write(contNum, converted_buffer, converted_num); /** reinitialize the buffer ***/ init_flag(buff_flag, buff_pntr); init_buff(buff, buff_pntr); /** reinitialize my buffer pointers **/ buff_pntr = curr_pntr = 0; /** reset the ring pointer **/ current = NULL; num_proc++; return; } int convert_buffer(char *target, char *source,int * source_flag, int num) { int i, j; /* * Until I get something wierd, just keep copying */ for (i = 0, j = 0; i < num; i++, j++) { switch (source[i]) { case _CARROT: if (source_flag[i] == 1) { target[j] = source[i]; } else { if (source[i + 1] == _LBRACK) { target[j] = _ESC; i++; } else if (source[i + 1] >= 'A' && source[i + 1] <= 'Z') { target[j] = alpha_to_control(source[i + 1]); i++; } } break; case '?': default: target[j] = source[i]; } } return j; } void insert_buff_printing(int amount) { int count; /* This procedure takes the character at in_buff[num_proc] and adds it to the buffer. It first checks to see if we should be inserting or overwriting, and then does the appropriate thing */ if ((buff_pntr + amount) > 1023) { putchar(_BELL); fflush(stdout); num_proc += amount; } else { if (INS_MODE) { forwardcopy(&buff[curr_pntr + amount], &buff[curr_pntr], buff_pntr - curr_pntr); forwardflag_cpy(&buff_flag[curr_pntr + amount], &buff_flag[curr_pntr], buff_pntr - curr_pntr); for (count = 0; count < amount; count++) { buff[curr_pntr + count] = in_buff[num_proc + count]; buff_flag[curr_pntr + count] = 1; } ins_print(curr_pntr, amount); buff_pntr = buff_pntr + amount; } else { for (count = 0; count < amount; count++) { if (buff_flag[curr_pntr + count] == 2) { myputchar(buff[curr_pntr + count]); curr_pntr += count + 1; delete_current_char(); /** fix num_proc affected by delete **/ num_proc -= 3; curr_pntr -= count + 1; myputchar(_BKSPC); } buff[curr_pntr + count] = in_buff[num_proc + count]; buff_flag[curr_pntr + count] = 1; } myputchar(in_buff[num_proc]); if (curr_pntr == buff_pntr) buff_pntr++; } num_proc = num_proc + amount; curr_pntr = curr_pntr + amount; fflush(stdout); } return; } void insert_buff_nonprinting(int amount) { int count; /* This procedure takes the character at in_buff[num_proc] and adds it to the buffer. It first checks to see if we should be inserting or overwriting, and then does the appropriate thing */ /* it takes care of the special case, when I have an esc character */ if ((buff_pntr + amount) > 1023) { myputchar(_BELL); fflush(stdout); num_proc += amount; } else { if (INS_MODE) { forwardcopy(&buff[curr_pntr + amount + 1], &buff[curr_pntr], buff_pntr - curr_pntr); forwardflag_cpy(&buff_flag[curr_pntr + amount + 1], &buff_flag[curr_pntr], buff_pntr - curr_pntr); /** now insert the special character **/ switch (in_buff[num_proc]) { case _ESC: /** in this case I insert a '^[' into the string ***/ buff[curr_pntr] = _CARROT; buff_flag[curr_pntr] = 2; buff[curr_pntr + 1] = _LBRACK; buff_flag[curr_pntr + 1] = 0; break; default: if (control_char(in_buff[num_proc])) { buff[curr_pntr] = _CARROT; buff_flag[curr_pntr] = 2; buff[curr_pntr + 1] = control_to_alpha(in_buff[num_proc]); buff_flag[curr_pntr + 1] = 0; } else { /** What do I have ? **/ buff[curr_pntr] = '?'; buff_flag[curr_pntr] = 2; buff[curr_pntr + 1] = in_buff[num_proc]; buff_flag[curr_pntr] = 0; break; } } /** Now add the normal characters **/ for (count = 1; count < amount; count++) { buff[curr_pntr + count + 1] = in_buff[num_proc + count]; buff_flag[curr_pntr + count + 1] = 1; } ins_print(curr_pntr, amount + 1); buff_pntr = buff_pntr + amount + 1; } else { /** I am in the overstrike mode **/ switch (in_buff[num_proc]) { case _ESC: /** in this case I insert a '^[' into the string ***/ buff[curr_pntr] = _CARROT; buff_flag[curr_pntr] = 2; buff[curr_pntr + 1] = _LBRACK; buff_flag[curr_pntr + 1] = 0; break; default: if (control_char(in_buff[num_proc])) { buff[curr_pntr] = _CARROT; buff_flag[curr_pntr] = 2; buff[curr_pntr + 1] = control_to_alpha(in_buff[num_proc]); buff_flag[curr_pntr + 1] = 0; } else { /** What do I have ? **/ buff[curr_pntr] = '?'; buff_flag[curr_pntr] = 2; buff[curr_pntr + 1] = in_buff[num_proc]; buff_flag[curr_pntr] = 0; break; } } for (count = 1; count < amount; count++) { if (buff_flag[curr_pntr + count] == 2) { curr_pntr += count + 1; delete_current_char(); /** fix num. processed form delete **/ num_proc -= 3; curr_pntr -= count + 1; } buff[curr_pntr + count + 1] = in_buff[num_proc + count]; buff_flag[curr_pntr + count + 1] = 1; } /** now print the characters I have put in **/ printbuff(curr_pntr, amount + 1); } num_proc = num_proc + amount; curr_pntr = curr_pntr + amount + 1; if (curr_pntr > buff_pntr) buff_pntr = curr_pntr; } return; } void prev_buff(void) { /* * If the current command ring is NULL, then I should NOT clear the * current line. Thus my business is already done */ if (ring == NULL) return; clear_buff(); init_buff(buff, buff_pntr); init_flag(buff_flag, buff_pntr); if (current == NULL) { if (ring == NULL) return; current = ring; } else current = current->prev; strcpy(buff, current->buff); flagcpy(buff_flag, current->flags); /* first back up and blank the line */ fflush(stdout); printbuff(0, strlen(buff)); curr_pntr = buff_pntr = strlen(buff); fflush(stdout); return ; } void next_buff(void) { /* * If the current command ring is NULL, then I should NOT clear the * current line. Thus my business is already done */ if (ring == NULL) return; clear_buff(); init_buff(buff, buff_pntr); init_flag(buff_flag, buff_pntr); if (current == NULL) { if (ring == NULL) return; current = ring->next; } else current = current->next; strcpy(buff, current->buff); flagcpy(buff_flag, current->flags); /* first back up and blank the line **/ fflush(stdout); printbuff(0, strlen(buff)); curr_pntr = buff_pntr = strlen(buff); fflush(stdout); return ; } void forwardcopy(char *buff1,char * buff2,int num) { int count; for (count = num; count >= 0; count--) buff1[count] = buff2[count]; } void forwardflag_cpy(int *buff1,int * buff2,int num) { int count; for (count = num; count >= 0; count--) buff1[count] = buff2[count]; } void strnmov(char *dest, const char *src, size_t n) { while (n-- && (*dest++ = *src++)); } void strmov(char *dest, const char *src) { while ((*dest++ = *src++)); } void flagcpy(int *s,int *t) { while (*t >= 0) *s++ = *t++; *s = *t; } void flagncpy(int *s,int *t,int n) { while (n-- > 0) *s++ = *t++; } void insert_queue(void) { QueStruct *trace; QueStruct *new_q; int c; if (!ECHOIT) return; if (ring != NULL && !strcmp(buff, ring->buff)) return; for (c = 0, trace = ring; trace != NULL && c < (prev_check - 1); c++, trace = trace->prev) { if (!strcmp(buff, trace->buff)) { /* * throw this puppy at the end of the ring */ trace->next->prev = trace->prev; trace->prev->next = trace->next; trace->prev = ring; trace->next = ring->next; ring->next = trace; trace->next->prev = trace; ring = trace; return; } } /* * simply places the buff command into the front of the queue */ if (ring_size < MAXRING) { new_q = (QueStruct *) malloc(sizeof(struct que_struct)); if (new_q == NULL) { fprintf(stderr, "Malloc Error: Ran out of memory\n"); exit(-1); } if (ring_size == 0) { ring = new_q; ring->prev = ring->next = new_q; } else { new_q->next = ring->next; new_q->prev = ring; ring->next = new_q; new_q->next->prev = new_q; ring = new_q; } ring_size++; } else ring = ring->next; init_flag(ring->flags, MAXLINE); init_buff(ring->buff, MAXLINE); strcpy(ring->buff, buff); flagncpy(ring->flags, buff_flag, buff_pntr); (ring->buff)[buff_pntr] = '\0'; (ring->flags)[buff_pntr] = -1; } void init_flag(int *flags, int num) { int i; for (i = 0; i < num; i++) flags[i] = -1; } void init_buff(char *flags, int num) { int i; for (i = 0; i < num; i++) flags[i] = '\0'; } void send_function_to_child(void) { /* Takes care of sending a line to the child, and resetting the buffer for new input */ back_it_up(curr_pntr); /** start by putting the line into the command line ring ***/ if (buff_pntr) insert_queue(); /** finish the line and send it to the child **/ buff[buff_pntr] = _EOLN; buff_flag[buff_pntr++] = 1; buff[buff_pntr] = '\0'; buff_flag[buff_pntr] = 0; write(contNum, buff, buff_pntr); /** reinitialize the buffer ***/ init_flag(buff_flag, buff_pntr); init_buff(buff, buff_pntr); /** reinitialize my buffer pointers **/ buff_pntr = curr_pntr = 0; /** reset the ring pointer **/ current = NULL; num_proc++; return; } void send_buff_to_child(int chann) { if (buff_pntr > 0) write(chann, buff, buff_pntr); num_proc += 6; /** reinitialize the buffer ***/ init_flag(buff_flag, buff_pntr); init_buff(buff, buff_pntr); /** reinitialize my buffer pointers **/ buff_pntr = curr_pntr = 0; /** reset the ring pointer **/ current = NULL; return; }