unroff/src/prim.c

385 lines
9.7 KiB
C
Raw Normal View History

2023-02-13 08:45:50 -05:00
/* $Revision: 1.19 $
*/
/* The implementation of those Scheme primitives that do not deal with
* events, tables, streams, expressions, substitutions, and file
* insertions.
*/
#include "unroff.h"
static Object error_port;
static Object p_error_port(void) {
return error_port;
}
static Object p_read_line_expand(void) {
Buffer *ip, *op;
Object ret;
ip = buffer_new(0);
op = buffer_new(0);
if (safe_readline(ip) && ip->size == 0) {
ret = Eof;
} else {
(void)parse_expand(ip, op);
ret = Make_String(op->data, op->size);
}
buffer_delete(ip);
buffer_delete(op);
return ret;
}
static Object p_read_line(void) {
Buffer *ip;
Object ret;
ip = buffer_new(0);
if (safe_readline(ip) && ip->size == 0) {
ret = Eof;
} else
ret = Make_String(ip->data, ip->size);
buffer_delete(ip);
return ret;
}
static Object primitive_parse(int ac, Object *av, int what) {
Buffer *ip, *op;
Object ret;
ip = buffer_new(0);
op = buffer_new(0);
while (ac-- > 0) {
Object x = *av++;
switch (TYPE(x)) {
case T_Character:
buffer_putc(ip, CHAR(x));
break;
case T_Symbol:
x = SYMBOL(x)->name; /* fall through */
case T_String:
buffer_puts(ip, STRING(x)->data, STRING(x)->size);
break;
default:
Primitive_Error("cannot coerce argument to string");
}
}
switch (what) {
case 'c': parse_escape(ip, op, 1, 1); break;
case 'p': parse_escape(ip, op, 1, 0); break;
case 't': parse_escape(ip, op, 0, 0); break;
case 'l': parse_line(ip, op); break;
case 'e': parse_expand(ip, op); break;
}
ret = what == 'l' ? Void : Make_String(op->data, op->size);
buffer_delete(ip);
buffer_delete(op);
return ret;
}
static Object p_parse(int ac, Object *av) {
return primitive_parse(ac, av, 'p');
}
static Object p_translate(int ac, Object *av) {
return primitive_parse(ac, av, 't');
}
static Object p_parse_line(int ac, Object *av) {
return primitive_parse(ac, av, 'l');
}
static Object p_parse_copy_mode(int ac, Object *av) {
return primitive_parse(ac, av, 'c');
}
static Object p_parse_expand(int ac, Object *av) {
return primitive_parse(ac, av, 'e');
}
static Object concat(int ac, Object *av, int spread) {
Buffer *op;
Object ret;
op = buffer_new(0);
while (ac-- > 0) {
Object x = *av++;
switch (TYPE(x)) {
case T_Character:
buffer_putc(op, CHAR(x));
break;
case T_Symbol:
x = SYMBOL(x)->name; /* fall through */
case T_String:
buffer_puts(op, STRING(x)->data, STRING(x)->size);
break;
default:
Primitive_Error("cannot coerce argument to string");
}
if (spread && ac > 0)
buffer_putc(op, ' ')
}
ret = Make_String(op->data, op->size);
buffer_delete(op);
return ret;
}
static Object p_concat(int ac, Object *av) {
return concat(ac, av, 0);
}
static Object p_spread(int ac, Object *av) {
return concat(ac, av, 1);
}
static Object p_emit(int ac, Object *av) {
while (ac-- > 0) {
Object x = *av++;
switch (TYPE(x)) {
case T_Character:
safe_write_char(CHAR(x));
break;
case T_Symbol:
x = SYMBOL(x)->name; /* fall through */
case T_String:
safe_write(STRING(x)->data, STRING(x)->size);
break;
default:
Primitive_Error("cannot coerce argument to string");
}
}
return Void;
}
static Object p_shell_command(Object cmd) {
return Make_Integer(system(Get_Strsym(cmd)));
}
static Object p_remove_file(Object fn) {
char *s = Get_Strsym(fn);
if (remove(s)) warn("cannot remove file `%s'", s);
return Void;
}
static Object p_parse_pair(Object x) {
char *p, *ep, *s1, *s2, delim;
Object str, ret;
GC_Node3;
str = ret = False;
GC_Link3(x, str, ret);
Check_Type(x, T_String);
p = STRING(x)->data;
ep = p + STRING(x)->size;
if (p <= ep-3) {
delim = *p++;
for (s1 = p; p < ep && *p != delim; p++)
;
if (p < ep) {
for (s2 = ++p; p < ep && *p != delim; p++)
;
if (p == ep-1) {
str = Make_String(s1, s2-s1-1);
ret = Cons(str, Null);
str = Make_String(s2, p-s2);
Cdr(ret) = str;
}
}
}
GC_Unlink;
return ret;
}
static Object p_parse_triple(Object x) {
char *p, *ep, *s1, *s2, *s3, delim;
Object str, ret;
GC_Node3;
str = ret = False;
GC_Link3(x, str, ret);
Check_Type(x, T_String);
p = STRING(x)->data;
ep = p + STRING(x)->size;
if (p <= ep-4) {
delim = *p++;
for (s1 = p; p < ep && *p != delim; p++)
;
if (p < ep) {
for (s2 = ++p; p < ep && *p != delim; p++)
;
if (p < ep) {
for (s3 = ++p; p < ep && *p != delim; p++)
;
if (p == ep-1) {
str = Make_String(s3, p-s3);
ret = Cons(Null, str);
str = Make_String(s2, s3-s2-1);
Car(ret) = str;
ret = Cons(Null, ret);
str = Make_String(s1, s2-s1-1);
Car(ret) = str;
}
}
}
}
GC_Unlink;
return ret;
}
static Object p_skip_group(void) {
Buffer *ip;
int level = 0;
char *p, *ep;
ip = buffer_new(0);
do {
if (safe_readline(ip) && ip->size == 0) {
warn("end-of-scream while skipping requests");
break;
}
2023-02-15 07:37:40 -05:00
for (p = ip->data, ep = p + ip->size; p < ep-2; p++) {
if (*p == escape) {
2023-02-13 08:45:50 -05:00
if (*++p == '{') level++;
else if (*p == '}') level--;
2023-02-15 07:37:40 -05:00
}
}
2023-02-13 08:45:50 -05:00
buffer_clear(ip);
} while (level > 0);
buffer_delete(ip);
return Void;
}
static Object p_set_escape(Object c) {
Check_Type(c, T_Character);
escape = CHAR(c);
return Void;
}
static Object p_troff_compatible(void) {
extern int compatible;
return compatible ? True : False;
}
static Object p_string_prune_left(Object str, Object pref, Object fail) {
int l1, l2;
Check_Type(str, T_String);
Check_Type(pref, T_String);
l1 = STRING(str)->size, l2 = STRING(pref)->size;
if (l2 <= l1 && memcmp(STRING(str)->data, STRING(pref)->data, l2) == 0)
return Make_String(STRING(str)->data+l2, l1-l2);
return fail;
}
static Object p_string_prune_right(Object str, Object suff, Object fail) {
int l1, l2, l;
Check_Type(str, T_String);
Check_Type(suff, T_String);
l1 = STRING(str)->size, l2 = STRING(suff)->size, l = l1-l2;
if (l >= 0 && memcmp(STRING(str)->data+l, STRING(suff)->data, l2) == 0)
return Make_String(STRING(str)->data, l);
return fail;
}
static Object p_string_compose(Object old, Object new) {
Buffer *bp;
struct S_String *s, *t;
int i;
Object ret;
bp = buffer_new(0);
Check_Type(old, T_String);
Check_Type(new, T_String);
s = STRING(old), t = STRING(new);
if (t->size > 0) {
switch (t->data[0]) {
case '+':
buffer_puts(bp, s->data, s->size);
buffer_puts(bp, t->data+1, t->size-1);
break;
case '-':
for (i = 0; i < s->size; i++)
if (!memchr(t->data, s->data[i], t->size))
buffer_putc(bp, s->data[i]);
break;
default:
buffer_puts(bp, t->data, t->size);
}
}
ret = Make_String(bp->data, bp->size);
buffer_delete(bp);
return ret;
}
static Object p_repeat_string(Object num, Object str) {
Buffer *bp;
Object ret;
int n;
Check_Type(str, T_String);
bp = buffer_new(0);
for (n = Get_Integer(num); n > 0; n--)
buffer_puts(bp, STRING(str)->data, STRING(str)->size);
ret = Make_String(bp->data, bp->size);
buffer_delete(bp);
return ret;
}
static Object p_filter_eqn_line(Object str) {
char *p, *q, *ep;
Check_Type(str, T_String);
p = STRING(str)->data, ep = p + STRING(str)->size;
for ( ; p < ep && isspace(UCHAR(*p)); p++)
;
if (p == ep)
return False;
for (q = p; p < ep && !isspace(UCHAR(*p)); p++)
;
if (p == ep)
return True;
if (p-q == 5 && strncmp(q, "delim", 5) == 0) {
p++;
if (ep-p == 3 && strncmp(p, "off", 3) == 0)
eqn_delim1 = 0;
else if (ep-p >= 2)
eqn_delim1 = *p, eqn_delim2 = p[1];
return False;
}
return p-q == 6 && strncmp(q, "define", 6) == 0 ? False : True;
}
void init_prim(void) {
error_port = Make_Port (0, stderr, Make_String ("stderr", 6));
if (setvbuf(stderr, 0, _IOLBF, BUFSIZ) != 0)
fatal_error("cannot set stderr line buffered");
Global_GC_Link(error_port);
Define_Primitive(p_error_port, "error-port", 0, 0, EVAL);
Define_Primitive(p_read_line, "read-line", 0, 0, EVAL);
Define_Primitive(p_read_line_expand, "read-line-expand", 0, 0, EVAL);
Define_Primitive(p_parse, "parse", 0, MANY, VARARGS);
Define_Primitive(p_parse_copy_mode, "parse-copy-mode", 0, MANY, VARARGS);
Define_Primitive(p_parse_line, "parse-line", 0, MANY, VARARGS);
Define_Primitive(p_parse_expand, "parse-expand", 0, MANY, VARARGS);
Define_Primitive(p_translate, "translate", 0, MANY, VARARGS);
Define_Primitive(p_concat, "concat", 0, MANY, VARARGS);
Define_Primitive(p_spread, "spread", 0, MANY, VARARGS);
Define_Primitive(p_emit, "emit", 0, MANY, VARARGS);
Define_Primitive(p_substitute, "substitute", 1, MANY, VARARGS);
Define_Primitive(p_shell_command, "shell-command", 1, 1, EVAL);
Define_Primitive(p_remove_file, "remove-file", 1, 1, EVAL);
Define_Primitive(p_parse_pair, "parse-pair", 1, 1, EVAL);
Define_Primitive(p_parse_triple, "parse-triple", 1, 1, EVAL);
Define_Primitive(p_skip_group, "skip-group", 0, 0, EVAL);
Define_Primitive(p_set_escape, "set-escape!", 1, 1, EVAL);
Define_Primitive(p_troff_compatible, "troff-compatible?", 0, 0, EVAL);
Define_Primitive(p_string_prune_left, "string-prune-left", 3, 3, EVAL);
Define_Primitive(p_string_prune_right,"string-prune-right", 3, 3, EVAL);
Define_Primitive(p_string_compose, "string-compose", 2, 2, EVAL);
Define_Primitive(p_repeat_string, "repeat-string", 2, 2, EVAL);
Define_Primitive(p_filter_eqn_line, "filter-eqn-line", 1, 1, EVAL);
}