/* gmoo - a gtk+ based graphical MOO/MUD/MUSH/... client * Copyright (C) 1999-2000 Gert Scholten * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "list.h" #include #include #include #include stream_t * stream_new(int len) { stream_t *s = g_malloc(sizeof(stream_t)); s->len = MAX(len, 1); s->pos = 0; s->buf = g_malloc(s->len + 1); s->buf[s->pos] = '\0'; return s; } void stream_append(stream_t * s, char c) { if (s->pos >= s->len - 1) { s->len *= 2; s->buf = g_realloc(s->buf, s->len + 1); } s->buf[s->pos++] = c; s->buf[s->pos] = '\0'; } void stream_append_string(stream_t * s, const char *string) { if (string) { while (*string) { stream_append(s, *string); string++; } } } void stream_append_string_quoted(stream_t * s, const char *string) { int i; stream_append(s, '\"'); for (i = 0; string[i]; i++) { if (string[i] == '\\' || string[i] == '\"') stream_append(s, '\\'); stream_append(s, string[i]); } stream_append(s, '\"'); } void stream_free(stream_t * s) { g_free(s->buf); g_free(s); } MOOVar * do_MOOVar_parse(const char **s) { MOOVar *var = NULL, *item; stream_t *stream; int i; while (isspace(**s)) (*s)++; if (**s == '{') { /* list */ (*s)++; var = MOOVar_new_list(); while (**s && **s != '}') { if ((item = do_MOOVar_parse(s))) { MOOVar_listappend(var, item); } else goto error; while (isspace(**s)) (*s)++; if (**s == ',') (*s)++; else break; } if (**s == '}') { /* things went ok */ (*s)++; return var; } else { error: MOOVar_free(var); return NULL; } } stream = stream_new(80); if (**s == '\"') { /* String */ (*s)++; i = 0; while (**s) { switch (**s) { case '\"': if (!i) { /* string officially terminated */ var = MOOVar_new_string(stream->buf); stream_free(stream); (*s)++; return var; } else { stream_append(stream, **s); break; } case '\\': if (!i) { i = 1; break; } default: stream_append(stream, **s); i = 0; } (*s)++; } stream_free(stream); return NULL; } if (**s == '#') { /* Object */ (*s)++; if (**s == '-') { stream_append(stream, **s); (*s)++; } while (isdigit(**s)) { stream_append(stream, **s); (*s)++; } if (!stream->pos || stream->buf[stream->pos - 1] == '-') { stream_free(stream); return NULL; } var = MOOVar_new_object(atoi(stream->buf)); stream_free(stream); return var; } if (((**s == 'E') || (**s == 'e')) && (*((*s) + 1) == '_')) { stream_append(stream, 'e'); stream_append(stream, '_'); (*s) += 2; while (isalpha(**s)) { stream_append(stream, **s); (*s)++; } var = MOOVar_new_error(stream->buf); stream_free(stream); return var; } if (**s == '-') { stream_append(stream, **s); (*s)++; } if (isdigit(**s) || (**s == '.') || (**s == 'e') || (**s == 'E')) { i = FALSE; while (isdigit(**s) || (**s == '.') || (**s == 'e') || (**s == 'E')) { if ((**s == '.') || (**s == 'e') || (**s == 'E')) i = TRUE; stream_append(stream, **s); (*s)++; } if (i) { var = MOOVar_new_float(stream->buf); } else { var = MOOVar_new_int(stream->buf); } stream_free(stream); return var; } stream_free(stream); return NULL; } MOOVar * MOOVar_parse(const char *s) { MOOVar *v = do_MOOVar_parse(&s); while (isspace(*s)) s++; if (*s) { MOOVar_free(v); return NULL; } return v; } MOOVar * MOOVar_new_list() { MOOVar *var = g_malloc(sizeof(MOOVar)); var->type = LIST; var->s = NULL; var->i = 0; var->d = 0.0; var->list = NULL; var->next = NULL; return var; } MOOVar * MOOVar_new_object(int obj) { MOOVar *var = g_malloc(sizeof(MOOVar)); var->type = OBJECT; var->s = NULL; var->i = obj; var->d = 0.0; var->list = NULL; var->next = NULL; return var; } MOOVar * MOOVar_new_string(const char *string) { MOOVar *var = g_malloc(sizeof(MOOVar)); var->type = STRING; var->s = g_strdup(string); var->i = strlen(string); var->d = 0.0; var->list = NULL; var->next = NULL; return var; } int parse_error(const char *e, int *i, char **s) { if (g_strcasecmp(e, "E_NONE") == 0) { *i = E_NONE; *s = g_strdup("No error"); } else if (g_strcasecmp(e, "E_TYPE") == 0) { *i = E_TYPE; *s = g_strdup("Type mismatch"); } else if (g_strcasecmp(e, "E_DIV") == 0) { *i = E_DIV; *s = g_strdup("Division by zero"); } else if (g_strcasecmp(e, "E_PERM") == 0) { *i = E_PERM; *s = g_strdup("Permission denied"); } else if (g_strcasecmp(e, "E_PROPNF") == 0) { *i = E_PROPNF; *s = g_strdup("Property not found"); } else if (g_strcasecmp(e, "E_VERBNF") == 0) { *i = E_VERBNF; *s = g_strdup("Verb not found"); } else if (g_strcasecmp(e, "E_VARNF") == 0) { *i = E_VARNF; *s = g_strdup("Variable not found"); } else if (g_strcasecmp(e, "E_INVIND") == 0) { *i = E_INVIND; *s = g_strdup("Invalid indirection"); } else if (g_strcasecmp(e, "E_RECMOVE") == 0) { *i = E_RECMOVE; *s = g_strdup("Recursive move"); } else if (g_strcasecmp(e, "E_MAXREC") == 0) { *i = E_MAXREC; *s = g_strdup("Too many verb calls"); } else if (g_strcasecmp(e, "E_RANGE") == 0) { *i = E_RANGE; *s = g_strdup("Range error"); } else if (g_strcasecmp(e, "E_ARGS") == 0) { *i = E_ARGS; *s = g_strdup("Incorrect number of arguments"); } else if (g_strcasecmp(e, "E_NACC") == 0) { *i = E_NACC; *s = g_strdup("Move refused by destination"); } else if (g_strcasecmp(e, "E_INVARG") == 0) { *i = E_INVARG; *s = g_strdup("Invalid argument"); } else if (g_strcasecmp(e, "E_QUOTA") == 0) { *i = E_QUOTA; *s = g_strdup("Resource limit exceeded"); } else if (g_strcasecmp(e, "E_FLOAT") == 0) { *i = E_FLOAT; *s = g_strdup("Floating-point arithmetic error"); } else { return FALSE; } return TRUE; } char * to_error(int e) { if (e == E_NONE) return "E_NONE"; if (e == E_TYPE) return "E_TYPE"; if (e == E_DIV) return "E_DIV"; if (e == E_PERM) return "E_PERM"; if (e == E_PROPNF) return "E_PROPNF"; if (e == E_VERBNF) return "E_VERBNF"; if (e == E_VARNF) return "E_VARNF"; if (e == E_INVIND) return "E_INVIND"; if (e == E_RECMOVE) return "E_RECMOVE"; if (e == E_MAXREC) return "E_MAXREC"; if (e == E_RANGE) return "E_RANGE"; if (e == E_NACC) return "E_NACC"; if (e == E_INVARG) return "E_INVARG"; if (e == E_QUOTA) return "E_QUOTA"; if (e == E_FLOAT) return "E_FLOAT"; return ""; } MOOVar * MOOVar_new_error(const char *try_error) { MOOVar *var = g_malloc(sizeof(MOOVar)); var->type = ERROR; var->s = NULL; var->i = 0; var->d = 0.0; var->list = NULL; var->next = NULL; if (parse_error(try_error, &(var->i), &(var->s))) { return var; } g_free(var); return NULL; } MOOVar * MOOVar_new_float(const char *d) { char *s = NULL; double f = strtod(d, &s); MOOVar *var; if (!(s && !*s)) { return NULL; } var = g_malloc(sizeof(MOOVar)); var->type = FLOAT; var->s = NULL; var->i = 0; var->d = f; var->list = NULL; var->next = NULL; return var; } MOOVar * MOOVar_new_int(const char *i) { char *s = NULL; int in = strtol(i, &s, 10); MOOVar *var; if (!(s && !*s)) return NULL; var = g_malloc(sizeof(MOOVar)); var->type = INT; var->s = NULL; var->i = in; var->d = 0.0; var->list = NULL; var->next = NULL; return var; } void MOOVar_free(MOOVar * var) { if (!var) return; g_free(var->s); MOOVar_free(var->list); MOOVar_free(var->next); g_free(var); } void MOOVar_listappend(MOOVar * var, MOOVar * item) { if (var->type == LIST) { var->i++; if (var->i > 1) { for (var = var->list; var->next; var = var->next); var->next = item; } else { var->list = item; } } } void do_MOOVar_tostr(MOOVar * v, stream_t * stream) { int i; MOOVar *v2 = NULL; char *s; if (!v) return; switch (v->type) { case LIST: stream_append(stream, '{'); for (i = 0; i < v->i; i++) { v2 = i == 0 ? v->list : v2->next; do_MOOVar_tostr(v2, stream); if (i != v->i - 1) { stream_append(stream, ','); } } stream_append(stream, '}'); return; case ERROR: stream_append_string(stream, to_error(v->i)); return; case STRING: stream_append_string_quoted(stream, v->s); return; case INT: s = g_strdup_printf("%d", v->i); break; case FLOAT: s = g_strdup_printf("%f", v->d); break; case OBJECT: s = g_strdup_printf("#%d", v->i); break; default: /* this should never happen */ return; } stream_append_string(stream, s); g_free(s); } char * MOOVar_tostr(MOOVar * v) { stream_t *stream; char *s; stream = stream_new(100); do_MOOVar_tostr(v, stream); s = stream->buf; g_free(stream); return s; } MOOVar * MOOVar_listindex(MOOVar * list, int index) { MOOVar *v; int i; if (list->type != LIST || index < 1 || index > list->i) return NULL; v = list->list; for (i = 1; i < index; i++) { v = v->next; } return v; } #ifdef STANDALONE void MOOVar_print(MOOVar * v) { char *s = MOOVar_tostr(v); if (v) printf("=> %s\n\n", s); else printf("Error in parsing !\n\n"); g_free(s); } int main(int argc, char *argv[]) { MOOVar *v; if (argc != 2) { printf("Use: %s \n\n", argv[0]); exit(1); } v = MOOVar_parse(argv[1]); MOOVar_print(v); exit(0); } #endif