stk/Src/sport.c

207 lines
5.7 KiB
C

/*
* s p o r t . c -- String ports management
*
* Copyright © 1993-1996 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
*
*
* Permission to use, copy, and/or distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that both the above copyright notice and this permission notice appear in
* all copies and derived works. Fees for distribution or use of this
* software or derived works may only be charged with express written
* permission of the copyright holder.
* This software is provided ``as is'' without express or implied warranty.
*
* This software is a derivative work of other copyrighted softwares; the
* copyright notices of these softwares are placed in the file COPYRIGHTS
*
*
* Author: Erick Gallesio [eg@unice.fr]
* Creation date: 17-Feb-1993 12:27
* Last file update: 13-Jun-1996 18:24
*
*
* This is achieved in a (surely very) dependant way. A string port is implemented
* via a pseudo FILE descriptor malloc'd when open-input-string is called. This
* descriptor is released when free-string-port is called.
*/
#include "stk.h"
#include "sport.h"
SCM STk_internal_open_input_string(char *str)
{
struct str_iob *p;
SCM z;
p = (struct str_iob *) must_malloc(sizeof (struct str_iob));
p->signature = SPORT_SIGNATURE;
p->flag = READING;
p->cnt = p->bufsiz = strlen(str);
p->base = p->ptr = must_malloc(p->cnt + 1);
strcpy(p->base, str);
/* Sport_descr is a short version of a port_descr */
NEWCELL(z, tc_isport);
z->storage_as.port.p = (struct port_descr *)
must_malloc(sizeof(struct sport_descr));
PORT_FILE(z) = (FILE *) p;
PORT_FLAGS(z) = 0;
return z;
}
void STk_free_string_port(SCM port)
{
struct str_iob * p;
p = (struct str_iob *) PORT_FILE(port);
free(p->base);
free(p);
free(port->storage_as.port.p);
}
SCM STk_internal_read_from_string(SCM port, int *eof, int case_significant)
{
jmp_buf jb, *prev_jb = Top_jmp_buf;
long prev_context = Error_context;
SCM result;
int k;
/* save normal error jmpbuf so that read error don't lead to toplevel */
/* If in a "catch", keep the ERR_IGNORED bit set */
if ((k = setjmp(jb)) == 0) {
Top_jmp_buf = &jb;
Error_context = (Error_context & ERR_IGNORED) | ERR_READ_FROM_STRING;
result = STk_readf(PORT_FILE(port), case_significant);
*eof = Eof(PORT_FILE(port));
}
Top_jmp_buf = prev_jb;;
Error_context = prev_context;
if (k == 0) return result;
/* if we are here, an error has occured during the string reading
* Two cases:
* - we are in a catch. Do a longjump to the catch to signal it a fail
* - otherwise error has already signaled, just return EVAL_ERROR
*/
if (Error_context & ERR_IGNORED) longjmp(*Top_jmp_buf, k);
return EVAL_ERROR;
}
PRIMITIVE STk_open_input_string(SCM s)
{
if (NSTRINGP(s)) Err("open-input-string: not a string", s);
return STk_internal_open_input_string(CHARS(s));
}
PRIMITIVE STk_open_output_string()
{
struct str_iob *p;
SCM z;
p = (struct str_iob *) must_malloc(sizeof (struct str_iob));
p->signature = SPORT_SIGNATURE;
p->flag = WRITING;
p->cnt = 0;
p->bufsiz = START_ALLOC;
p->base = p->ptr = (char *) must_malloc(START_ALLOC);
NEWCELL(z, tc_osport);
z->storage_as.port.p = (struct port_descr *)
must_malloc(sizeof(struct sport_descr));
PORT_FILE(z) = (FILE *) p;
PORT_FLAGS(z) = 0;
return z;
}
PRIMITIVE STk_get_output_string(SCM port)
{
if (NOSPORTP(port)) Err("get-output-string: Bad string-port", port);
if (PORT_FLAGS(port) & PORT_CLOSED)
Err("get-output-string: string port is closed", port);
return STk_makestrg(((struct str_iob *)PORT_FILE(port))->cnt,
((struct str_iob *)PORT_FILE(port))->base);
}
PRIMITIVE STk_input_string_portp(SCM port)
{
return (ISPORTP(port)) ? Truth: Ntruth;
}
PRIMITIVE STk_output_string_portp(SCM port)
{
return (OSPORTP(port)) ? Truth: Ntruth;
}
PRIMITIVE STk_with_input_from_string(SCM string, SCM thunk)
{
jmp_buf env, *prev_env = Top_jmp_buf;
SCM result, prev_iport = STk_curr_iport;
int prev_context = Error_context;
int k;
if (NSTRINGP(string)) Err("with-input-from-string: bad string", string);
if (!STk_is_thunk(thunk)) Err("with-input-from-string: bad thunk", thunk);
if ((k = setjmp(env)) == 0) {
Top_jmp_buf = &env;
STk_curr_iport = STk_internal_open_input_string(CHARS(string));
result = Apply(thunk, NIL);
}
/* restore normal error jmpbuf and current input port*/
STk_curr_iport = prev_iport;
Top_jmp_buf = prev_env;
Error_context = prev_context;
if (k) /*propagate error */ longjmp(*Top_jmp_buf, k);
return result;
}
PRIMITIVE STk_with_output_to_string(SCM thunk)
{
jmp_buf env, *prev_env = Top_jmp_buf;
SCM result, prev_oport = STk_curr_oport;
int prev_context = Error_context;
int k;
if (!STk_is_thunk(thunk)) Err("with-output-to-string: bad thunk", thunk);
if ((k = setjmp(env)) == 0) {
Top_jmp_buf = &env;
STk_curr_oport = STk_open_output_string();
Apply(thunk, NIL);
result = STk_get_output_string(STk_curr_oport);
}
/* restore normal error jmpbuf and current input port*/
STk_curr_oport = prev_oport;
Top_jmp_buf = prev_env;
Error_context = prev_context;
if (k) /*propagate error */ longjmp(*Top_jmp_buf, k);
return result;
}
PRIMITIVE STk_read_from_string(SCM str)
{
SCM result, port;
int eof; /* not used here */
if (NSTRINGP(str)) Err("read-from-string: Bad string", str);
/* Create a string port to read in the expression */
port = STk_internal_open_input_string(CHARS(str));
result = STk_internal_read_from_string(port, &eof, FALSE);
return result == EVAL_ERROR? UNDEFINED: result;
}