/* * Simulator of microcontrollers (fio.cc) * * Copyright (C) 1997,16 Drotos Daniel, Talker Bt. * * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu * */ /* This file is part of microcontroller simulator: ucsim. UCSIM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. UCSIM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with UCSIM; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*@1@*/ #include "ddconfig.h" #include #include #include #include #include HEADER_FD #include #include #if defined HAVE_SYS_SOCKET_H # include # include # include #endif #include #include #include #include #include // These two flags aren't defined on some platforms #ifndef S_IRGRP #define S_IRGRP 0 #endif #ifndef S_IROTH #define S_IROTH 0 #endif #include "fiocl.h" // prj #include "utils.h" cl_history::cl_history(char *aname): cl_ustrings(100, 10, aname) { nr= 0; //actual_line= ""; } cl_history::cl_history(const char *aname): cl_ustrings(100, 10, aname) { nr= 0; //actual_line= ""; } cl_history::~cl_history(void) { } char * cl_history::up(chars line) { replace(line); if (nr > 0) nr--; return (char*)(Items[nr]); } char * cl_history::down(chars line) { replace(line); if (nr < count) nr++; if (nr < count) return (char*)(Items[nr]); return NULL; } char * cl_history::enter(chars line) { if (count > 1000) { free_at(0); /*if (nr > count) nr= count;*/ } if (!line.empty()) { add(strdup(line)); nr= count; } return NULL; } void cl_history::replace(chars line) { if (nr < count) { free(Items[nr]); if (line.empty()) Items[nr]= strdup(""); else Items[nr]= strdup(line); } } /****************************************************************************/ cl_f::cl_f(void) { file_id= -1; own= false; tty= false; file_name= 0; file_mode= 0; server_port= -1; echo_of= NULL; echo_to= NULL; echo_color= (char*)""; at_end= 0; last_used= first_free= 0; cooking= 0; line[0]= 0; cursor= 0; esc_buffer[0]= 0; attributes_saved= 0; hist= new cl_history("history"); proc_telnet= false; proc_escape= false; } cl_f::cl_f(chars fn, chars mode): cl_base() { file_id= -1; file_name= fn; file_mode= mode; tty= false; own= false; server_port= -1; echo_of= NULL; echo_to= NULL; echo_color= (char*)""; at_end= 0; last_used= first_free= 0; cooking= 0; line[0]= 0; cursor= 0; esc_buffer[0]= 0; attributes_saved= 0; hist= new cl_history("history"); proc_telnet= false; } cl_f::cl_f(int the_server_port) { file_id= -1; own= false; tty= false; file_name= 0; file_mode= 0; server_port= the_server_port; echo_of= NULL; echo_to= NULL; echo_color= (char*)""; at_end= 0; last_used= first_free= 0; cooking= 0; line[0]= 0; cursor= 0; esc_buffer[0]= 0; attributes_saved= 0; hist= new cl_history("history"); proc_telnet= false; } class cl_f * cl_f::copy(chars mode) { class cl_f *io= mk_io(chars(""), chars("")); io->use_opened(file_id, mode); return io; } static int open_flags(char *m) { if (strcmp(m, "r") == 0) return O_RDONLY; else if (strcmp(m, "r+") == 0) return O_RDWR | O_CREAT; else if (strcmp(m, "w") == 0) return O_WRONLY | O_TRUNC | O_CREAT; else if (strcmp(m, "w+") == 0) return O_RDWR | O_CREAT; else if (strcmp(m, "a") == 0) return O_APPEND | O_WRONLY | O_CREAT; else if (strcmp(m, "a+") == 0) return O_APPEND | O_RDWR | O_CREAT; return O_RDWR; } int cl_f::init(void) { if (server_port > 0) { file_id= mk_srv_socket(server_port); listen(file_id, 50); own= true; tty= false; changed(); } else if (!file_name.empty()) { if (file_mode.empty()) file_mode= cchars("r+"); if ((file_id= ::open(file_name, open_flags(file_mode), (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))) >= 0) { tty= isatty(file_id); own= true; save_attributes(); changed(); } else { file_id= -1; own= false; } } return file_id; } int cl_f::use_opened(int opened_file_id, char *mode) { close(); if (mode) file_mode= mode; else file_mode= cchars("r+"); own= false; if (opened_file_id >= 0) { file_id= opened_file_id; tty= isatty(file_id); changed(); } return file_id; } int cl_f::own_opened(int opened_file_id, char *mode) { use_opened(opened_file_id, mode); own= true; return file_id; } int cl_f::use_opened(FILE *f, chars mode) { close(); if (f) { file_mode= mode; if ((file_id= fileno(f)) >= 0) { tty= isatty(file_id); own= false; changed(); } else file_id= -1; } return file_id; } int cl_f::own_opened(FILE *f, chars mode) { use_opened(f, mode); own= true; return file_id; } int cl_f::open(char *fn) { close(); if (fn) file_name= fn; return init(); } int cl_f::open(char *fn, char *mode) { close(); if (mode) file_mode= mode; if (fn) file_name= fn; return init(); } void cl_f::changed(void) { } int cl_f::close(void) { int i= 0; if (file_id >= 0) ::close(file_id); file_id= -1; own= false; file_name= 0; file_mode= 0; changed(); return i; } int cl_f::stop_use(void) { //printf("cl_f stop_use fid=%d\n", file_id); file_id= -1; own= false; file_name= 0; file_mode= 0; attributes_saved= 0; changed(); return 0; } cl_f::~cl_f(void) { delete hist; } /* Buffer handling */ int cl_f::put(int c) { int n= (first_free + 1) % 1024; if (n == last_used) { printf("put: %d FULL!\n",c); return -1; } buffer[first_free]= c; first_free= n; return 0; } int cl_f::get(void) { if (last_used == first_free) { return -1; } int c= buffer[last_used] & 0xff; last_used= (last_used + 1) % 1024; return c; } int cl_f::free_place(void) { if (first_free >= last_used) return 1024 - (first_free - last_used) -1; return last_used - first_free -1; } int cl_f::finish_esc(int k) { esc_buffer[0]= 0; return k; } int cl_f::process_telnet(unsigned char ci) { int l= strlen(esc_buffer); esc_buffer[l]= ci; l++; esc_buffer[l]= 0; if ((ci == 0xff) && (l == 2)) { return finish_esc(0xff); } if (l == 3) { return finish_esc(0); } return 0; } int cl_f::process_csi(void) { int l= strlen(esc_buffer); if (l < 3) return 0; int /*f,*/ ret= 0; char c= esc_buffer[l-1]; switch (esc_buffer[2]) { case 'M': if (l == 6) { switch (esc_buffer[3]) { case ' ': ret= TU_BTN1; break; case '!': ret= TU_BTN2; break; case '"': ret= TU_BTN3; break; case '0': ret= TU_CBTN1; break; case '1': ret= TU_CBTN2; break; case '2': ret= TU_CBTN3; break; case '(': ret= TU_ABTN1; break; case ')': ret= TU_ABTN2; break; case '*': ret= TU_ABTN3; break; case '`': ret= TU_SUP; break; case 'a': ret= TU_SDOWN; break; case 'p': ret= TU_CSUP; break; case 'q': ret= TU_CSDOWN; break; } //f= ret; ret&= ~0xffff00; int x= (esc_buffer[4] - 0x20) & 0xff; int y= (esc_buffer[5] - 0x20) & 0xff; ret|= x << 16; ret|= y << 8; //fprintf(stderr, "Mouse: 0x%0x (f=%d,0x%x)\n", ret, f, f); return finish_esc(ret); } return 0; break; } // first char not recognized, check the last switch (c) { case 'A': return finish_esc(TU_UP); case 'B': return finish_esc(TU_DOWN); case 'C': return finish_esc(TU_RIGHT); case 'D': return finish_esc(TU_LEFT); case 'H': return finish_esc(TU_HOME); case 'F': return finish_esc(TU_END); case 'E': return finish_esc(0); // NumPad 5 case '~': { int n; n= strtol(&esc_buffer[2], 0, 0); switch (n) { case 1: return finish_esc(TU_HOME); case 2: return finish_esc(TU_INS); case 3: return finish_esc(TU_DEL); case 4: return finish_esc(TU_END); case 5: return finish_esc(TU_PGUP); case 6: return finish_esc(TU_PGDOWN); case 11: return finish_esc(TU_F1); case 12: return finish_esc(TU_F2); case 13: return finish_esc(TU_F3); case 14: return finish_esc(TU_F4); case 15: return finish_esc(TU_F5); case 17: return finish_esc(TU_F6); case 18: return finish_esc(TU_F7); case 19: return finish_esc(TU_F8); case 20: return finish_esc(TU_F9); case 21: return finish_esc(TU_F10); case 23: return finish_esc(TU_F11); case 24: return finish_esc(TU_F12); default: return finish_esc(c); } } } return 0; } int cl_f::process_esc(char c) { int l; //char s[100]; unsigned int ci= c&0xff, b0= esc_buffer[0]&0xff; if (b0 == '\033') { l= strlen(esc_buffer); esc_buffer[l]= c; l++; esc_buffer[l]= 0; switch (esc_buffer[1]) { case 'O': if (l < 3) return 0; switch (c) { case 'P': return finish_esc(TU_F1); case 'Q': return finish_esc(TU_F2); case 'R': return finish_esc(TU_F3); case 'S': return finish_esc(TU_F4); case 'H': return finish_esc(TU_HOME); case 'F': return finish_esc(TU_END); default: return finish_esc(c); } break; case 'N': if (l < 3) return 0; switch (c) { default: return finish_esc(c); } break; case '[': return process_csi(); break; default: return finish_esc(c); } } else if (b0 == 0xff) { return process_telnet(ci); } else // start sequence { if (ci == '\033') { esc_buffer[0]= '\033', esc_buffer[1]= 0; return 0; } if (ci == 0xff) { esc_buffer[0]= 0xff, esc_buffer[1]= 0; return 0; } } return c; } int j= 0; int cl_f::process(char c) { int i; unsigned int ci= c&0xff; if (!cooking) { if (proc_escape) { if ((ci == '\033') || (esc_buffer[0] != 0)) { i= process_esc(ci); if (i != 0) return put(i); else return 0; } } if (proc_telnet) { if ((ci == 0xff) || (esc_buffer[0] != 0)) { ci= process_telnet(ci); if (!ci) { return last_ln= 0; } } if ((ci == '\n') || (ci == '\r') || (ci == 0) || (last_ln != 0)) { if ((last_ln == 0) && (ci != 0)) { last_ln= ci; } else { if (last_ln != (int)ci) { return last_ln= 0; } if (ci == 0) { return last_ln= 0; } } } } if ((ci<31) && (ci!='\n') && (ci!='\r')) { char s[3]= "^ "; s[1]= 'A'+ci-1; echo_write_str(s); } else if (ci >= 127) { char s[100]; sprintf(s, "\\%02x", ci); echo_write_str(s); } else { echo_write(&c, 1); } last_ln= 0; return put(c); } int l= strlen(line); int k= process_esc(c); int ret= 0; if (!k) return last_ln= 0; // CURSOR MOVEMENT if (k == TU_LEFT) { if (cursor > 0) { cursor--; echo_cursor_go_left(1); } } else if (k == TU_RIGHT) { if (line[cursor] != 0) { cursor++; echo_cursor_go_right(1); } } else if ((k == TU_HOME) || (k == 'A'-'A'+1)) { if (cursor > 0) { echo_cursor_go_left(cursor); cursor= 0; } } else if ((k == TU_END) || (k == 'E'-'A'+1)) { if (line[cursor] != 0) { echo_cursor_go_right(l-cursor); cursor= l; } } // HISTORY else if (k == TU_UP) { char *s= hist->up(line); if (cursor > 0) echo_cursor_go_left(cursor); echo_cursor_save(); while (l--) echo_write_str(" "); echo_cursor_restore(); line[cursor= 0]= 0; if (s != NULL) { strcpy(line, s); echo_write_str(s); cursor= strlen(s); } } else if (k == TU_DOWN) { char *s= hist->down(line); if (cursor > 0) echo_cursor_go_left(cursor); echo_cursor_save(); while (l--) echo_write_str(" "); echo_cursor_restore(); line[cursor= 0]= 0; if (s != NULL) { strcpy(line, s); echo_write_str(s); cursor= strlen(s); } } // FINISH EDITING else if ((k == '\n') || (k == '\r') || (k == 0)) { if (last_ln && (last_ln != k)) { last_ln= 0; return 0; } last_ln= k; for (i= 0; ienter(line); //tu_cooked(); line[cursor= 0]= 0; esc_buffer[0]= 0; ret= l+1; echo_write_str("\n"); } // DELETING else if ((k == 127) || /*DEL*/ (k == 8 /*BS*/)) { if (cursor > 0) { for (i= cursor; line[i]; i++) line[i-1]= line[i]; l--; line[l]= 0; cursor--; echo_cursor_go_left(1); echo_cursor_save(); if (line[cursor]) echo_write_str(&line[cursor]); echo_write_str(" "); echo_cursor_restore(); } } else if (//(k == 127) || /*DEL*/ (k == TU_DEL)) { if (line[cursor] != 0) { for (i= cursor+1; line[i]; i++) line[i-1]= line[i]; l--; line[l]= 0; echo_cursor_save(); if (line[cursor]) echo_write_str(&line[cursor]); echo_write_str(" "); echo_cursor_restore(); } } else if (k == 'K'-'A'+1) { if (cursor > 0) echo_cursor_go_left(cursor); echo_cursor_save(); while (l--) //write(STDOUT_FILENO, " ", 1); echo_write_str(" "); echo_cursor_restore(); line[cursor= 0]= 0; } else if (k < 0) ; else if (isprint(k)) { if (l < /*tu_buf_size*/1023) { if (line[cursor] == 0) { line[cursor++]= k; line[cursor]= 0; echo_write(&c, 1); } else { int j; for (j= l; j>=cursor; j--) line[j+1]= line[j]; line[cursor++]= k; echo_cursor_save(); echo_write(&line[cursor-1], l-cursor+2); echo_cursor_restore(); echo_cursor_go_right(1); } } } return ret; } int cl_f::pick(void) { char b[100]; int fp= free_place(); if (fp < 5) return 0; int i= ::read(file_id, b, (fp>101)?99:fp-1); if (i > 0) { int j; for (j= 0; j < i; j++) { process(b[j]); } } if (i == 0) { at_end= 1; } if (i < 0) ; return i; } int cl_f::pick(char c) { int i= /*put*/process(c); return i; } int cl_f::pick(const char *s) { int i, ret= 0; if (s) for (i= 0; s[i]; i++) ret= pick(s[i]); return ret; } int cl_f::input_avail(void) { int ret= check_dev(); if (ret) return ret; return at_end; } int cl_f::read(int *buf, int max) { return read_dev(buf, max); } int cl_f::get_c(void) { int c; while (!check_dev()) ; int i= read_dev(&c, 1); if (i > 0) return c; else return i; } chars cl_f::get_s(void) { chars s= ""; char c; if (eof()) return s; c= get_c(); while ((c == '\n') || (c == '\r')) { if (eof()) return s; c= get_c(); } if (eof()) return s; s+= c; c= get_c(); while (!eof() && (c != '\n') && (c != '\r')) { s+= c; c= get_c(); } return s; } /* IO primitives */ int cl_f::read_dev(int *buf, int max) { int i= 0, c; if (max == 0) return -1; while (i < max) { c= get(); if (c == -1) { if (i>0) // got something return i; if (at_end) // no more data, and we are at the end return 0; // buffer is empty now, but no eof detected yet return -1; } buf[i]= c; i++; } if (i>0) return i; if (at_end) return 0; return -2; } int cl_f::write(char *buf, int count) { int i; if (file_id >= 0) { if (type != F_SOCKET) { return ::write(file_id, buf, count); } // on socket, assume telnet for (i= 0; i < count; i++) { int j; if ((buf[i] == '\r') || (buf[i] == '\n')) { j= ::write(file_id, "\r\n", 2); if (j != 2) ; } else { j= ::write(file_id, &buf[i], 1); if (j != 1) ; } } return i; } return -1; } int cl_f::write_str(char *s) { if (!s || !*s) return 0; return write(s, strlen(s)); } int cl_f::write_str(const char *s) { if (!s || !*s) return 0; return write((char*)s, strlen((char*)s)); } int cl_f::vprintf(const char *format, va_list ap) { char *s= vformat_string(format, ap); int i= write_str(s); free(s); return i; } int cl_f::prntf(const char *format, ...) { va_list ap; int ret= 0; va_start(ap, format); ret= vprintf(format, ap); va_end(ap); return ret; } bool cl_f::eof(void) { if (file_id < 0) return true; return at_end && (last_used == first_free); } /*void cl_f::flush(void) { }*/ /* Echoing */ void cl_f::echo_cursor_save() { if (echo_to) { echo_to->write(cchars("\033[s"), 3); //echo_to->flush(); } } void cl_f::echo_cursor_restore() { if (echo_to) { echo_to->write(cchars("\033[u"), 3); //echo_to->flush(); } } void cl_f::echo_cursor_go_left(int n) { char b[100]; if (echo_to) { snprintf(b, 99, "\033[%dD", n); echo_to->write_str(b); //echo_to->flush(); } } void cl_f::echo_cursor_go_right(int n) { char b[100]; if (echo_to) { snprintf(b, 99, "\033[%dC", n); echo_to->write_str(b); //echo_to->flush(); } } void cl_f::echo_write(char *b, int l) { if (echo_to) { if (echo_color.nempty()) echo_to->prntf("%s", (char*)echo_color); echo_to->write(b, l); //echo_to->flush(); } } void cl_f::echo_write_str(char *s) { if (echo_to) { if (echo_color.nempty()) echo_to->prntf("%s", (char*)echo_color); echo_to->write_str(s); //echo_to->flush(); } } void cl_f::echo_write_str(const char *s) { if (echo_to) { if (echo_color.nempty()) echo_to->prntf("%s", (char*)echo_color); echo_to->write_str(s); //echo_to->flush(); } } void cl_f::set_echo_color(chars col) { echo_color= col; } /* Device handling */ void cl_f::prepare_terminal() { } void cl_f::save_attributes() { } void cl_f::restore_attributes() { } int cl_f::raw(void) { if (cooking) { int l= strlen(line), i; for (i= 0; iecho_of= NULL; echo_to= NULL; } if (out != NULL) { out->echo_of= this; echo_to= out; } return 0; } void cl_f::interactive(class cl_f *echo_out) { save_attributes(); echo(echo_out); cooked(); prepare_terminal(); } void cl_f::set_telnet(bool val) { proc_telnet= val; } void cl_f::set_escape(bool val) { proc_escape= val; } chars fio_type_name(enum file_type t) { switch (t) { case F_UNKNOWN: return "unknown"; case F_FILE: return "file"; case F_CHAR: return "char"; case F_SOCKET: return "socket"; case F_LISTENER: return "listener"; case F_PIPE: return "pipe"; case F_CONSOLE: return "console"; case F_SERIAL: return "serial"; } return "undef"; } /* End of fio.cc */