picrin/src/port.c

589 lines
14 KiB
C
Raw Normal View History

2014-01-17 06:58:31 -05:00
/**
* See Copyright Notice in picrin.h
*/
2013-10-10 04:48:01 -04:00
#include <stdlib.h>
2014-01-16 04:39:38 -05:00
#include <string.h>
#include <limits.h>
2013-10-10 04:48:01 -04:00
#include "picrin.h"
2013-10-15 00:21:40 -04:00
#include "picrin/proc.h"
2013-10-17 09:42:47 -04:00
#include "picrin/port.h"
#include "picrin/string.h"
#include "picrin/blob.h"
2013-10-10 04:48:01 -04:00
2014-01-12 10:49:25 -05:00
pic_value
pic_eof_object()
{
pic_value v;
pic_init_value(v, PIC_VTYPE_EOF);
return v;
}
2014-01-12 10:51:19 -05:00
struct pic_port *
pic_stdin(pic_state *pic)
{
struct pic_proc *proc;
proc = pic_proc_ptr(pic_ref(pic, "current-input-port"));
return pic_port_ptr(pic_apply(pic, proc, pic_nil_value()));
}
2014-01-12 11:47:46 -05:00
struct pic_port *
pic_stdout(pic_state *pic)
{
struct pic_proc *proc;
proc = pic_proc_ptr(pic_ref(pic, "current-output-port"));
return pic_port_ptr(pic_apply(pic, proc, pic_nil_value()));
}
2014-01-12 09:57:50 -05:00
static pic_value
2014-02-25 07:07:32 -05:00
port_new_stdport(pic_state *pic, xFILE *file, short dir)
2014-01-12 09:57:50 -05:00
{
struct pic_port *port;
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port), PIC_TT_PORT);
2014-02-01 21:23:23 -05:00
port->file = file;
port->flags = dir | PIC_PORT_TEXT;
2014-01-12 09:57:50 -05:00
port->status = PIC_PORT_OPEN;
return pic_obj_value(port);
}
struct pic_port *
pic_open_output_string(pic_state *pic)
{
struct pic_port *port;
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
port->file = xmopen();
port->flags = PIC_PORT_OUT | PIC_PORT_TEXT;
port->status = PIC_PORT_OPEN;
return port;
}
struct pic_string *
pic_get_output_string(pic_state *pic, struct pic_port *port)
{
long endpos;
char *buf;
/* get endpos */
xfflush(port->file);
endpos = xftell(port->file);
xrewind(port->file);
/* copy to buf */
buf = (char *)pic_alloc(pic, endpos);
xfread(buf, 1, endpos, port->file);
return pic_str_new(pic, buf, endpos);
}
void
pic_close_port(pic_state *pic, struct pic_port *port)
{
if (xfclose(port->file) == EOF) {
pic_error(pic, "close-port: failure");
}
port->status = PIC_PORT_CLOSE;
}
2013-10-24 09:56:04 -04:00
static pic_value
pic_port_input_port_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_IN) != 0) {
return pic_true_value();
}
else {
return pic_false_value();
}
}
static pic_value
pic_port_output_port_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_OUT) != 0) {
return pic_true_value();
}
else {
return pic_false_value();
}
}
static pic_value
pic_port_textual_port_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_TEXT) != 0) {
return pic_true_value();
}
else {
return pic_false_value();
}
}
static pic_value
pic_port_binary_port_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
if (pic_port_p(v) && (pic_port_ptr(v)->flags & PIC_PORT_BINARY) != 0) {
return pic_true_value();
}
else {
return pic_false_value();
}
}
static pic_value
pic_port_port_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_bool_value(pic_port_p(v));
}
static pic_value
pic_port_input_port_open_p(pic_state *pic)
{
pic_value v;
struct pic_port *port;
pic_get_args(pic, "o", &v);
if (! pic_port_p(v))
return pic_false_value();
port = pic_port_ptr(v);
if ((port->flags & PIC_PORT_IN) == 0)
return pic_false_value();
return pic_bool_value(port->status == PIC_PORT_OPEN);
}
static pic_value
pic_port_output_port_open_p(pic_state *pic)
{
pic_value v;
struct pic_port *port;
pic_get_args(pic, "o", &v);
if (! pic_port_p(v))
return pic_false_value();
port = pic_port_ptr(v);
if ((port->flags & PIC_PORT_OUT) == 0)
return pic_false_value();
return pic_bool_value(port->status == PIC_PORT_OPEN);
}
2013-10-22 03:02:20 -04:00
static pic_value
pic_port_eof_object_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
if (pic_vtype(v) == PIC_VTYPE_EOF) {
2013-10-22 03:02:20 -04:00
return pic_true_value();
}
else {
return pic_false_value();
}
}
static pic_value
pic_port_eof_object(pic_state *pic)
{
pic_get_args(pic, "");
2014-01-12 10:49:25 -05:00
return pic_eof_object();
2013-10-22 03:02:20 -04:00
}
2014-01-12 02:15:04 -05:00
static pic_value
2013-12-03 11:16:13 -05:00
pic_port_close_port(pic_state *pic)
{
struct pic_port *port;
pic_get_args(pic, "p", &port);
2013-12-03 11:16:13 -05:00
pic_close_port(pic, port);
2013-12-03 11:16:13 -05:00
2014-01-08 01:22:23 -05:00
return pic_none_value();
2013-12-03 11:16:13 -05:00
}
#define assert_port_profile(port, flgs, stat, caller) do { \
if ((port->flags & (flgs)) != (flgs)) { \
switch (flgs) { \
2014-01-12 12:06:09 -05:00
case PIC_PORT_IN: \
pic_error(pic, caller ": expected output port"); \
case PIC_PORT_OUT: \
pic_error(pic, caller ": expected input port"); \
case PIC_PORT_IN | PIC_PORT_TEXT: \
pic_error(pic, caller ": expected input/textual port"); \
case PIC_PORT_IN | PIC_PORT_BINARY: \
pic_error(pic, caller ": expected input/binary port"); \
case PIC_PORT_OUT | PIC_PORT_TEXT: \
pic_error(pic, caller ": expected output/textual port"); \
case PIC_PORT_OUT | PIC_PORT_BINARY: \
pic_error(pic, caller ": expected output/binary port"); \
} \
} \
if (port->status != stat) { \
switch (stat) { \
case PIC_PORT_OPEN: \
pic_error(pic, caller ": expected open port"); \
case PIC_PORT_CLOSE: \
pic_error(pic, caller ": expected close port"); \
} \
} \
2014-01-12 11:34:26 -05:00
} while (0)
static pic_value
pic_port_open_input_string(pic_state *pic)
{
struct pic_port *port;
char *str;
pic_get_args(pic, "z", &str);
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
port->file = xmopen();
port->flags = PIC_PORT_IN | PIC_PORT_TEXT;
port->status = PIC_PORT_OPEN;
xfputs(str, port->file);
xfflush(port->file);
xrewind(port->file);
return pic_obj_value(port);
}
static pic_value
pic_port_open_output_string(pic_state *pic)
{
struct pic_port *port;
pic_get_args(pic, "");
port = pic_open_output_string(pic);
return pic_obj_value(port);
}
static pic_value
pic_port_get_output_string(pic_state *pic)
{
struct pic_port *port = pic_stdout(pic);;
pic_get_args(pic, "|p", &port);
2014-02-09 00:29:51 -05:00
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_TEXT, PIC_PORT_OPEN, "get-output-string");
return pic_obj_value(pic_get_output_string(pic, port));
}
2014-02-08 12:41:52 -05:00
static pic_value
pic_port_open_input_blob(pic_state *pic)
{
struct pic_port *port;
struct pic_blob *blob;
pic_get_args(pic, "b", &blob);
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
port->file = xmopen();
port->flags = PIC_PORT_IN | PIC_PORT_BINARY;
port->status = PIC_PORT_OPEN;
xfwrite(blob->data, 1, blob->len, port->file);
return pic_obj_value(port);
}
2014-02-09 00:29:28 -05:00
static pic_value
pic_port_open_output_bytevector(pic_state *pic)
{
struct pic_port *port;
pic_get_args(pic, "");
port = (struct pic_port *)pic_obj_alloc(pic, sizeof(struct pic_port *), PIC_TT_PORT);
port->file = xmopen();
port->flags = PIC_PORT_OUT | PIC_PORT_BINARY;
port->status = PIC_PORT_OPEN;
return pic_obj_value(port);
}
static pic_value
pic_port_get_output_bytevector(pic_state *pic)
{
struct pic_port *port = pic_stdout(pic);;
long endpos;
char *buf;
pic_get_args(pic, "|p", &port);
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "get-output-bytevector");
/* get endpos */
xfflush(port->file);
endpos = xftell(port->file);
xrewind(port->file);
/* copy to buf */
buf = (char *)pic_alloc(pic, endpos);
xfread(buf, 1, endpos, port->file);
return pic_obj_value(pic_blob_new(pic, buf, endpos));
}
2014-01-12 10:51:30 -05:00
static pic_value
pic_port_read_char(pic_state *pic)
{
char c;
struct pic_port *port = pic_stdin(pic);
pic_get_args(pic, "|p", &port);
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "read-char");
2014-01-12 11:34:26 -05:00
2014-02-01 08:16:09 -05:00
if ((c = xfgetc(port->file)) == EOF) {
2014-01-12 11:34:26 -05:00
return pic_eof_object();
2014-01-12 10:51:30 -05:00
}
2014-01-12 11:34:26 -05:00
else {
return pic_char_value(c);
2014-01-12 10:51:30 -05:00
}
2014-01-12 11:34:26 -05:00
}
static pic_value
pic_port_peek_char(pic_state *pic)
{
char c;
struct pic_port *port = pic_stdin(pic);
pic_get_args(pic, "|p", &port);
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "peek-char");
2014-01-12 10:51:30 -05:00
2014-02-01 08:16:09 -05:00
if ((c = xfgetc(port->file)) == EOF) {
2014-01-12 10:51:30 -05:00
return pic_eof_object();
}
else {
2014-02-01 08:16:09 -05:00
xungetc(c, port->file);
2014-01-12 10:51:30 -05:00
return pic_char_value(c);
}
}
2014-02-18 04:56:14 -05:00
static pic_value
pic_port_read_line(pic_state *pic)
{
char c;
struct pic_port *port = pic_stdin(pic), *buf;
struct pic_string *str;
pic_get_args(pic, "|p", &port);
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "read-line");
buf = pic_open_output_string(pic);
while ((c = xfgetc(port->file)) != EOF && c != '\n') {
xfputc(c, buf->file);
}
str = pic_get_output_string(pic, buf);
if (pic_strlen(str) == 0 && c == EOF) {
2014-02-18 04:56:14 -05:00
return pic_eof_object();
}
else {
return pic_obj_value(str);
}
}
2014-02-18 05:20:29 -05:00
static pic_value
pic_port_char_ready_p(pic_state *pic)
{
struct pic_port *port = pic_stdin(pic);
assert_port_profile(port, PIC_PORT_IN | PIC_PORT_TEXT, PIC_PORT_OPEN, "char-ready?");
pic_get_args(pic, "|p", &port);
return pic_true_value(); /* FIXME: always returns #t */
}
2014-01-12 11:47:46 -05:00
static pic_value
pic_port_newline(pic_state *pic)
{
struct pic_port *port = pic_stdout(pic);
pic_get_args(pic, "|p", &port);
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_TEXT, PIC_PORT_OPEN, "newline");
2014-02-01 08:16:09 -05:00
xfputs("\n", port->file);
2014-01-12 11:47:46 -05:00
return pic_none_value();
}
2014-01-12 12:06:09 -05:00
static pic_value
pic_port_write_char(pic_state *pic)
{
char c;
struct pic_port *port = pic_stdout(pic);
pic_get_args(pic, "c|p", &c, &port);
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_TEXT, PIC_PORT_OPEN, "write-char");
2014-02-01 08:16:09 -05:00
xfputc(c, port->file);
2014-01-12 12:06:09 -05:00
return pic_none_value();
}
static pic_value
pic_port_write_string(pic_state *pic)
{
char *str;
struct pic_port *port;
int start, end, n, i;
n = pic_get_args(pic, "z|pii", &str, &port, &start, &end);
switch (n) {
case 1:
port = pic_stdout(pic);
case 2:
start = 0;
case 3:
end = INT_MAX;
}
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_TEXT, PIC_PORT_OPEN, "write-string");
for (i = start; i < end && str[i] != '\0'; ++i) {
xfputc(str[i], port->file);
}
return pic_none_value();
}
static pic_value
pic_port_write_byte(pic_state *pic)
{
int i;
struct pic_port *port = pic_stdout(pic);
pic_get_args(pic, "i|p", &i, &port);
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "write-u8");
xfputc(i, port->file);
return pic_none_value();
}
static pic_value
pic_port_write_blob(pic_state *pic)
{
struct pic_blob *blob;
struct pic_port *port;
int start, end, n, i;
n = pic_get_args(pic, "b|pii", &blob, &port, &start, &end);
switch (n) {
case 1:
port = pic_stdout(pic);
case 2:
start = 0;
case 3:
end = blob->len;
}
assert_port_profile(port, PIC_PORT_OUT | PIC_PORT_BINARY, PIC_PORT_OPEN, "write-bytevector");
for (i = start; i < end; ++i) {
xfputc(blob->data[i], port->file);
}
return pic_none_value();
}
2014-01-12 12:06:09 -05:00
static pic_value
pic_port_flush(pic_state *pic)
{
struct pic_port *port = pic_stdout(pic);
pic_get_args(pic, "|p", &port);
assert_port_profile(port, PIC_PORT_OUT, PIC_PORT_OPEN, "flush-output-port");
2014-02-01 08:16:09 -05:00
xfflush(port->file);
2014-01-12 12:06:09 -05:00
return pic_none_value();
}
2013-10-15 08:14:33 -04:00
void
pic_init_port(pic_state *pic)
{
2014-02-01 21:23:23 -05:00
pic_defvar(pic, "current-input-port", port_new_stdport(pic, xstdin, PIC_PORT_IN));
pic_defvar(pic, "current-output-port", port_new_stdport(pic, xstdout, PIC_PORT_OUT));
pic_defvar(pic, "current-error-port", port_new_stdport(pic, xstderr, PIC_PORT_OUT));
2014-01-12 09:57:50 -05:00
2013-10-24 09:56:04 -04:00
pic_defun(pic, "input-port?", pic_port_input_port_p);
pic_defun(pic, "output-port?", pic_port_output_port_p);
pic_defun(pic, "textual-port?", pic_port_textual_port_p);
pic_defun(pic, "binary-port?", pic_port_binary_port_p);
pic_defun(pic, "port?", pic_port_port_p);
pic_defun(pic, "input-port-open?", pic_port_input_port_open_p);
pic_defun(pic, "output-port-open?", pic_port_output_port_open_p);
2013-12-03 11:16:13 -05:00
pic_defun(pic, "close-port", pic_port_close_port);
pic_defun(pic, "close-input-port", pic_port_close_port);
pic_defun(pic, "close-output-port", pic_port_close_port);
2014-01-12 10:51:30 -05:00
2014-02-08 09:23:53 -05:00
/* string I/O */
pic_defun(pic, "open-input-string", pic_port_open_input_string);
pic_defun(pic, "open-output-string", pic_port_open_output_string);
pic_defun(pic, "get-output-string", pic_port_get_output_string);
2014-02-08 12:41:52 -05:00
pic_defun(pic, "open-input-bytevector", pic_port_open_input_blob);
2014-02-09 00:29:28 -05:00
pic_defun(pic, "open-output-bytevector", pic_port_open_output_bytevector);
pic_defun(pic, "get-output-bytevector", pic_port_get_output_bytevector);
2014-02-08 09:23:53 -05:00
2014-01-12 10:51:30 -05:00
/* input */
pic_defun(pic, "read-char", pic_port_read_char);
2014-01-12 11:34:26 -05:00
pic_defun(pic, "peek-char", pic_port_peek_char);
2014-02-18 04:56:14 -05:00
pic_defun(pic, "read-line", pic_port_read_line);
2014-02-17 14:40:19 -05:00
pic_defun(pic, "eof-object?", pic_port_eof_object_p);
pic_defun(pic, "eof-object", pic_port_eof_object);
2014-02-18 05:20:29 -05:00
pic_defun(pic, "char-ready?", pic_port_char_ready_p);
2014-02-17 14:40:19 -05:00
/* pic_defun(pic, "read-string", pic_port_read_string); */
/* pic_defun(pic, "read-u8", pic_port_read_byte); */
/* pic_defun(pic, "peek-u8", pic_port_peek_byte); */
/* pic_defun(pic, "u8-ready?", pic_port_byte_ready_p); */
/* pic_defun(pic, "read-bytevector", pic_port_read_blob); */
/* pic_defun(pic, "peek-bytevector!", pic_port_read_blob_ip); */
/* output */
pic_defun(pic, "newline", pic_port_newline);
2014-01-12 12:06:09 -05:00
pic_defun(pic, "write-char", pic_port_write_char);
pic_defun(pic, "write-string", pic_port_write_string);
pic_defun(pic, "write-u8", pic_port_write_byte);
pic_defun(pic, "write-bytevector", pic_port_write_blob);
2014-01-12 12:06:09 -05:00
pic_defun(pic, "flush-output-port", pic_port_flush);
2013-10-15 08:14:33 -04:00
}