factor/native/fd.c

232 lines
4.1 KiB
C
Raw Normal View History

#include "factor.h"
2004-07-24 00:54:57 -04:00
void init_io(void)
{
env.user[STDIN_ENV] = port(0);
2004-08-13 01:38:15 -04:00
set_nonblocking(0);
env.user[STDOUT_ENV] = port(1);
2004-08-13 01:38:15 -04:00
set_nonblocking(1);
env.user[STDERR_ENV] = port(2);
2004-08-13 18:43:03 -04:00
/* set_nonblocking(2); */
2004-07-24 00:54:57 -04:00
}
2004-08-13 02:32:11 -04:00
/* Return true if something was read */
bool read_step(PORT* port)
{
2004-08-13 02:32:11 -04:00
FIXNUM amount = read(port->fd,
port->buffer + 1,
port->buffer->capacity * 2);
2004-08-13 01:38:15 -04:00
2004-08-13 02:32:11 -04:00
if(amount == -1)
2004-08-13 01:38:15 -04:00
{
2004-08-13 02:32:11 -04:00
if(errno != EAGAIN)
io_error(__FUNCTION__);
return false;
}
else
{
port->buf_fill = (amount < 0 ? 0 : amount);
port->buf_pos = 0;
return true;
2004-08-13 01:38:15 -04:00
}
2004-07-24 15:11:55 -04:00
}
2004-08-12 23:40:28 -04:00
READLINE_STAT read_line_step(PORT* port)
{
2004-07-24 00:54:57 -04:00
int i;
2004-08-13 02:32:11 -04:00
char ch;
2004-07-24 00:54:57 -04:00
2004-08-12 23:40:28 -04:00
SBUF* line = port->line;
2004-08-12 23:40:28 -04:00
if(port->buf_pos >= port->buf_fill)
{
2004-08-13 02:32:11 -04:00
if(!read_step(port))
return READLINE_WAIT;
2004-08-13 02:32:11 -04:00
if(port->buf_fill == 0)
2004-08-12 23:40:28 -04:00
return READLINE_EOF;
}
for(i = port->buf_pos; i < port->buf_fill; i++)
{
2004-08-12 23:40:28 -04:00
ch = bget((CELL)port->buffer + sizeof(STRING) + i);
if(ch == '\n')
{
2004-08-12 23:40:28 -04:00
port->buf_pos = i + 1;
return READLINE_EOL;
}
else
set_sbuf_nth(line,line->top,ch);
}
2004-07-24 17:37:42 -04:00
2004-08-12 23:40:28 -04:00
port->buf_pos = port->buf_fill;
2004-07-24 17:37:42 -04:00
2004-08-12 23:40:28 -04:00
/* We've reached the end of the above loop, without seeing a newline
or EOF, so read again */
return READLINE_AGAIN;
}
void primitive_read_line_fd_8(void)
{
PORT* port = untag_port(dpeek());
SBUF* line;
READLINE_STAT state;
init_buffer(port,B_READ);
if(port->line == NULL)
port->line = sbuf(LINE_SIZE);
else
port->line->top = 0;
line = port->line;
2004-08-13 02:32:11 -04:00
add_io_task(IO_TASK_READ_LINE,port,F);
2004-08-12 23:40:28 -04:00
for(;;)
{
state = read_line_step(port);
2004-08-13 02:32:11 -04:00
if(state == READLINE_WAIT)
iomux();
else if(state == READLINE_EOF && line->top == 0)
{
/* didn't read anything before EOF */
drepl(F);
break;
}
else if(state == READLINE_EOL)
2004-07-24 00:54:57 -04:00
{
2004-08-13 02:32:11 -04:00
drepl(tag_object(sbuf_to_string(line)));
break;
2004-07-24 00:54:57 -04:00
}
}
2004-08-13 02:32:11 -04:00
remove_io_task(IO_TASK_READ_LINE,port);
}
2004-08-13 02:19:22 -04:00
/* Return true if write was done */
bool write_step(PORT* port)
2004-08-11 16:56:48 -04:00
{
2004-08-12 23:40:28 -04:00
char* chars = (char*)port->buffer + sizeof(STRING);
2004-08-11 16:56:48 -04:00
2004-08-13 02:19:22 -04:00
FIXNUM amount = write(port->fd,chars + port->buf_pos,
port->buf_fill - port->buf_pos);
2004-08-13 01:38:15 -04:00
2004-08-13 02:19:22 -04:00
if(amount == -1)
2004-08-13 01:38:15 -04:00
{
2004-08-13 02:32:11 -04:00
if(errno != EAGAIN)
2004-08-13 02:19:22 -04:00
io_error(__FUNCTION__);
2004-08-13 02:32:11 -04:00
return false;
2004-08-13 01:38:15 -04:00
}
2004-08-13 02:19:22 -04:00
else
{
port->buf_pos += amount;
return true;
}
2004-08-11 16:56:48 -04:00
}
2004-08-12 23:40:28 -04:00
/* keep writing to the stream until everything is written */
void flush_buffer(PORT* port)
2004-08-11 16:56:48 -04:00
{
2004-08-13 18:43:03 -04:00
IO_TASK* task;
if(port->buf_mode != B_WRITE || port->buf_fill == 0)
2004-08-11 16:56:48 -04:00
return;
2004-08-13 18:43:03 -04:00
task = add_io_task(IO_TASK_WRITE,port,F);
2004-08-13 02:19:22 -04:00
2004-08-12 23:40:28 -04:00
for(;;)
{
if(port->buf_fill == port->buf_pos)
break;
2004-08-13 02:19:22 -04:00
if(!write_step(port))
iomux();
2004-08-12 23:40:28 -04:00
}
2004-08-13 02:19:22 -04:00
remove_io_task(IO_TASK_WRITE,port);
2004-08-12 23:40:28 -04:00
port->buf_pos = 0;
port->buf_fill = 0;
2004-08-11 16:56:48 -04:00
}
void write_fd_char_8(PORT* port, FIXNUM ch)
{
2004-08-11 16:56:48 -04:00
char c = (char)ch;
init_buffer(port,B_WRITE);
2004-08-11 16:56:48 -04:00
/* Is the buffer full? */
if(port->buf_fill == port->buffer->capacity * CHARS)
flush_buffer(port);
2004-08-11 16:56:48 -04:00
bput((CELL)port->buffer + sizeof(STRING) + port->buf_fill,c);
port->buf_fill++;
}
void write_fd_string_8(PORT* port, STRING* str)
{
char* c_str = to_c_string(str);
2004-08-11 16:56:48 -04:00
init_buffer(port,B_WRITE);
2004-08-11 16:56:48 -04:00
/* Is the string longer than the buffer? */
if(str->capacity > port->buffer->capacity * CHARS)
2004-08-11 16:56:48 -04:00
{
flush_buffer(port);
2004-08-12 23:40:28 -04:00
/* Increase the buffer to fit the string */
port->buffer = allot_string(str->capacity / CHARS + 1);
2004-08-11 16:56:48 -04:00
}
2004-08-12 23:40:28 -04:00
/* Is there enough room in the buffer? If not, flush */
if(port->buf_fill + str->capacity
> port->buffer->capacity * CHARS)
2004-08-11 16:56:48 -04:00
{
2004-08-12 23:40:28 -04:00
flush_buffer(port);
}
2004-08-11 16:56:48 -04:00
2004-08-12 23:40:28 -04:00
/* Append string to buffer */
memcpy((void*)((CELL)port->buffer + sizeof(STRING)
+ port->buf_fill),c_str,str->capacity);
2004-08-11 16:56:48 -04:00
2004-08-12 23:40:28 -04:00
port->buf_fill += str->capacity;
}
void primitive_write_fd_8(void)
{
PORT* port = untag_port(dpop());
CELL text = dpop();
CELL type = type_of(text);
switch(type)
{
case FIXNUM_TYPE:
2004-07-31 16:11:30 -04:00
case BIGNUM_TYPE:
write_fd_char_8(port,to_fixnum(text));
break;
case STRING_TYPE:
write_fd_string_8(port,untag_string(text));
break;
default:
type_error(STRING_TYPE,text);
break;
}
}
void primitive_flush_fd(void)
{
PORT* port = untag_port(dpop());
flush_buffer(port);
2004-07-24 17:37:42 -04:00
}
2004-08-11 16:56:48 -04:00
void primitive_close_fd(void)
2004-07-24 17:37:42 -04:00
{
PORT* port = untag_port(dpop());
flush_buffer(port);
close(port->fd);
}
2004-08-13 01:38:15 -04:00
void set_nonblocking(int fd)
{
if(fcntl(fd,F_SETFL,O_NONBLOCK,1) == -1)
io_error(__FUNCTION__);
}