1255 lines
19 KiB
C++
1255 lines
19 KiB
C++
/*
|
|
* 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 <stdio.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include HEADER_FD
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#if defined HAVE_SYS_SOCKET_H
|
|
# include <sys/socket.h>
|
|
# include <netinet/in.h>
|
|
# include <arpa/inet.h>
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
|
|
// 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; i<l; i++)
|
|
put(line[i]);
|
|
put('\n');
|
|
hist->enter(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; i<l; i++)
|
|
put(line[i]);
|
|
}
|
|
cooking= 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
cl_f::cooked(void)
|
|
{
|
|
line[cursor= 0]= 0;
|
|
esc_buffer[0]= 0;
|
|
last_ln= 0;
|
|
if (tty)
|
|
{
|
|
cooking= 1;
|
|
}
|
|
else if (type == F_SOCKET)
|
|
{
|
|
cooking= 1;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cl_f::echo(class cl_f *out)
|
|
{
|
|
if (echo_to)
|
|
{
|
|
echo_to->echo_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 */
|