factor/native/unix/write.c

147 lines
2.7 KiB
C
Raw Normal View History

2004-12-10 22:47:03 -05:00
#include "../factor.h"
2004-08-20 01:49:14 -04:00
/* Return true if write was done */
void write_step(F_PORT* port)
2004-08-20 01:49:14 -04:00
{
BYTE* chars = (BYTE*)untag_string(port->buffer) + sizeof(F_STRING);
2004-08-20 01:49:14 -04:00
F_FIXNUM amount = write(port->fd,chars + port->buf_pos,
2004-08-20 01:49:14 -04:00
port->buf_fill - port->buf_pos);
if(amount == -1)
{
if(errno != EAGAIN)
postpone_io_error(port,__FUNCTION__);
2004-08-20 01:49:14 -04:00
}
else
port->buf_pos += amount;
}
bool can_write(F_PORT* port, F_FIXNUM len)
2004-08-20 01:49:14 -04:00
{
CELL buf_capacity;
if(port->type != PORT_WRITE)
general_error(ERROR_INCOMPATIBLE_PORT,tag_object(port));
buf_capacity = untag_string(port->buffer)->capacity * CHARS;
2004-08-29 01:04:42 -04:00
/* Is the string longer than the buffer? */
if(port->buf_fill == 0 && len > buf_capacity)
2004-08-20 01:49:14 -04:00
{
2004-08-29 01:04:42 -04:00
/* Increase the buffer to fit the string */
port->buffer = tag_object(allot_string(len / CHARS + 1));
2004-08-29 01:04:42 -04:00
return true;
2004-08-20 01:49:14 -04:00
}
2004-08-29 01:04:42 -04:00
else
return (port->buf_fill + len <= buf_capacity);
2004-08-20 01:49:14 -04:00
}
void primitive_can_write(void)
{
F_PORT* port;
F_FIXNUM len;
maybe_garbage_collection();
port = untag_port(dpop());
len = to_fixnum(dpop());
2004-09-02 21:51:19 -04:00
pending_io_error(port);
2004-11-08 22:36:51 -05:00
box_boolean(can_write(port,len));
2004-08-20 01:49:14 -04:00
}
void primitive_add_write_io_task(void)
{
CELL callback, port;
maybe_garbage_collection();
callback = dpop();
port = dpop();
add_io_task(IO_TASK_WRITE,port,F,callback,
2004-08-20 01:49:14 -04:00
write_io_tasks,&write_fd_count);
}
bool perform_write_io_task(F_PORT* port)
2004-08-20 01:49:14 -04:00
{
2004-08-23 20:44:58 -04:00
if(port->buf_pos == port->buf_fill || port->io_error != F)
2004-08-20 01:49:14 -04:00
{
2004-08-23 20:44:58 -04:00
/* Nothing to write */
port->buf_pos = 0;
port->buf_fill = 0;
return true;
}
else
{
write_step(port);
return false;
2004-08-20 01:49:14 -04:00
}
}
void write_char_8(F_PORT* port, F_FIXNUM ch)
2004-08-20 01:49:14 -04:00
{
BYTE c = (BYTE)ch;
2004-08-20 01:49:14 -04:00
2004-09-02 21:51:19 -04:00
pending_io_error(port);
2004-08-20 01:49:14 -04:00
if(!can_write(port,1))
io_error(__FUNCTION__);
bput((CELL)untag_string(port->buffer) + sizeof(F_STRING) + port->buf_fill,c);
2004-08-20 01:49:14 -04:00
port->buf_fill++;
}
/* Caller must ensure buffer is of the right size. */
void write_string_raw(F_PORT* port, BYTE* str, CELL len)
{
/* Append string to buffer */
memcpy((void*)((CELL)untag_string(port->buffer) + sizeof(F_STRING)
+ port->buf_fill),str,len);
port->buf_fill += len;
}
void write_string_8(F_PORT* port, F_STRING* str)
2004-08-20 01:49:14 -04:00
{
BYTE* c_str;
2004-09-02 21:51:19 -04:00
pending_io_error(port);
2004-08-20 01:49:14 -04:00
/* Note this ensures the buffer is large enough to fit the string */
if(!can_write(port,str->capacity))
io_error(__FUNCTION__);
2004-11-13 18:07:18 -05:00
c_str = to_c_string_unchecked(str);
write_string_raw(port,c_str,str->capacity);
2004-08-20 01:49:14 -04:00
}
void primitive_write_8(void)
{
F_PORT* port;
CELL text, type;
F_STRING* str;
2004-08-20 01:49:14 -04:00
maybe_garbage_collection();
port = untag_port(dpop());
text = dpop();
type = type_of(text);
pending_io_error(port);
2004-08-20 01:49:14 -04:00
switch(type)
{
case FIXNUM_TYPE:
case BIGNUM_TYPE:
write_char_8(port,to_fixnum(text));
break;
case STRING_TYPE:
str = untag_string(text);
write_string_8(port,str);
2004-08-20 01:49:14 -04:00
break;
default:
2004-08-29 01:04:42 -04:00
type_error(TEXT_TYPE,text);
2004-08-20 01:49:14 -04:00
break;
}
}