/* * Copyright © 2016 Keith Packard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "ao_scheme.h" static void string_mark(void *addr) { (void) addr; } static int string_size(void *addr) { struct ao_scheme_string *string = addr; if (!addr) return 0; return strlen(string->val) + 2; } static void string_move(void *addr) { (void) addr; } const struct ao_scheme_type ao_scheme_string_type = { .mark = string_mark, .size = string_size, .move = string_move, .name = "string", }; static struct ao_scheme_string * ao_scheme_string_alloc(int len) { struct ao_scheme_string *s; if (len < 0) return NULL; s = ao_scheme_alloc(len + 2); if (!s) return NULL; s->type = AO_SCHEME_STRING; s->val[len] = '\0'; return s; } struct ao_scheme_string * ao_scheme_string_new(char *a) { struct ao_scheme_string *r; r = ao_scheme_string_alloc(strlen(a)); if (!r) return NULL; strcpy(r->val, a); return r; } struct ao_scheme_string * ao_scheme_atom_to_string(struct ao_scheme_atom *a) { int alen = strlen(a->name); struct ao_scheme_string *r; ao_scheme_atom_stash(a); r = ao_scheme_string_alloc(alen); a = ao_scheme_atom_fetch(); if (!r) return NULL; strcpy(r->val, a->name); return r; } struct ao_scheme_string * ao_scheme_string_cat(struct ao_scheme_string *a, struct ao_scheme_string *b) { int alen = strlen(a->val); int blen = strlen(b->val); struct ao_scheme_string *r; ao_scheme_string_stash(a); ao_scheme_string_stash(b); r = ao_scheme_string_alloc(alen + blen); b = ao_scheme_string_fetch(); a = ao_scheme_string_fetch(); if (!r) return NULL; strcpy(r->val, a->val); strcpy(r->val+alen, b->val); return r; } static ao_poly ao_scheme_string_pack(struct ao_scheme_cons *cons) { struct ao_scheme_string *string; char *s; int len; len = ao_scheme_cons_length(cons); ao_scheme_cons_stash(cons); string = ao_scheme_string_alloc(len); cons = ao_scheme_cons_fetch(); if (!string) return AO_SCHEME_NIL; s = string->val; while (cons) { ao_poly car = cons->car; int32_t c; if (!ao_scheme_is_integer(car) || (c = ao_scheme_poly_integer(car)) == 0) return ao_scheme_error(AO_SCHEME_INVALID, "%v: Invalid %v", _ao_scheme_atom_list2d3estring, car); *s++ = c; cons = ao_scheme_cons_cdr(cons); } return ao_scheme_string_poly(string); } static ao_poly ao_scheme_string_unpack(struct ao_scheme_string *a) { ao_poly cons = AO_SCHEME_NIL; int i; for (i = strlen(a->val); --i >= 0;) { ao_scheme_string_stash(a); cons = ao_scheme_cons(ao_scheme_int_poly(a->val[i]), cons); a = ao_scheme_string_fetch(); if (!cons) break; } return cons; } void ao_scheme_string_write(FILE *out, ao_poly p, bool write) { struct ao_scheme_string *s = ao_scheme_poly_string(p); char *sval = s->val; char c; if (write) { putc('"', out); while ((c = *sval++)) { switch (c) { case '\a': fputs("\\a", out); break; case '\b': fputs("\\b", out); break; case '\t': fputs("\\t", out); break; case '\n': fputs("\\n", out); break; case '\r': fputs("\\r", out); break; case '\f': fputs("\\f", out); break; case '\v': fputs("\\v", out); break; case '\"': fputs("\\\"", out); break; case '\\': fputs("\\\\", out); break; default: if ((uint8_t) c < ' ') fprintf(out, "\\%03o", (uint8_t) c); else putc(c, out); break; } } putc('"', out); } else { while ((c = *sval++)) putc(c, out); } } ao_poly ao_scheme_do_stringp(struct ao_scheme_cons *cons) { return ao_scheme_do_typep(_ao_scheme_atom_string3f, AO_SCHEME_STRING, cons); } ao_poly ao_scheme_do_list_to_string(struct ao_scheme_cons *cons) { struct ao_scheme_cons *list; if (!ao_scheme_parse_args(_ao_scheme_atom_list2d3estring, cons, AO_SCHEME_CONS, &list, AO_SCHEME_ARG_END)) return AO_SCHEME_NIL; return ao_scheme_string_pack(list); } ao_poly ao_scheme_do_string_to_list(struct ao_scheme_cons *cons) { struct ao_scheme_string *string; if (!ao_scheme_parse_args(_ao_scheme_atom_string2d3elist, cons, AO_SCHEME_STRING, &string, AO_SCHEME_ARG_END)) return AO_SCHEME_NIL; return ao_scheme_string_unpack(string); } static char * ao_scheme_string_ref(struct ao_scheme_string *string, int32_t r) { char *s = string->val; while (*s && r) { ++s; --r; } return s; } ao_poly ao_scheme_do_string_ref(struct ao_scheme_cons *cons) { struct ao_scheme_string *string; int32_t ref; char *s; if (!ao_scheme_parse_args(_ao_scheme_atom_string2dref, cons, AO_SCHEME_STRING, &string, AO_SCHEME_INT, &ref, AO_SCHEME_ARG_END)) return AO_SCHEME_NIL; s = ao_scheme_string_ref(string, ref); if (!*s) return ao_scheme_error(AO_SCHEME_INVALID, "%v: string %v ref %v invalid", _ao_scheme_atom_string2dref, cons->car, ao_scheme_arg(cons, 1)); return ao_scheme_integer_poly(*s); } ao_poly ao_scheme_do_string_length(struct ao_scheme_cons *cons) { struct ao_scheme_string *string; if (!ao_scheme_parse_args(_ao_scheme_atom_string2dlength, cons, AO_SCHEME_STRING, &string, AO_SCHEME_ARG_END)) return AO_SCHEME_NIL; return ao_scheme_integer_poly(strlen(string->val)); } ao_poly ao_scheme_do_string_set(struct ao_scheme_cons *cons) { struct ao_scheme_string *string; int32_t ref; int32_t val; char *s; if (!ao_scheme_parse_args(_ao_scheme_atom_string2dset21, cons, AO_SCHEME_STRING, &string, AO_SCHEME_INT, &ref, AO_SCHEME_INT, &val, AO_SCHEME_ARG_END)) return AO_SCHEME_NIL; if (!val) goto fail; s = ao_scheme_string_ref(string, ref); if (!*s) goto fail; *s = val; return ao_scheme_integer_poly(val); fail: return ao_scheme_error(AO_SCHEME_INVALID, "%v: %v[%v] = %v invalid", _ao_scheme_atom_string2dset21, ao_scheme_arg(cons, 0), ao_scheme_arg(cons, 1), ao_scheme_arg(cons, 2)); } ao_poly ao_scheme_do_make_string(struct ao_scheme_cons *cons) { int32_t len; int32_t fill; struct ao_scheme_string *string; if (!ao_scheme_parse_args(_ao_scheme_atom_make2dstring, cons, AO_SCHEME_INT, &len, AO_SCHEME_INT|AO_SCHEME_ARG_OPTIONAL, ao_scheme_int_poly(' '), &fill, AO_SCHEME_ARG_END)) return AO_SCHEME_NIL; if (!fill) return ao_scheme_error(AO_SCHEME_INVALID, "%v: fill 0 invalid", _ao_scheme_atom_make2dstring); string = ao_scheme_string_alloc(len); if (!string) return AO_SCHEME_NIL; memset(string->val, fill, len); return ao_scheme_string_poly(string); } ao_poly ao_scheme_do_symbol_to_string(struct ao_scheme_cons *cons) { struct ao_scheme_atom *atom; if (!ao_scheme_parse_args(_ao_scheme_atom_symbol2d3estring, cons, AO_SCHEME_ATOM, &atom, AO_SCHEME_ARG_END)) return AO_SCHEME_NIL; return ao_scheme_string_poly(ao_scheme_atom_to_string(atom)); } ao_poly ao_scheme_do_string_to_symbol(struct ao_scheme_cons *cons) { struct ao_scheme_string *string; if (!ao_scheme_parse_args(_ao_scheme_atom_string2d3esymbol, cons, AO_SCHEME_STRING, &string, AO_SCHEME_ARG_END)) return AO_SCHEME_NIL; return ao_scheme_atom_poly(ao_scheme_string_to_atom(string)); }