This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/gnoemoe/list.c

511 lines
10 KiB
C

/* 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 <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <glib.h>
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 <MOOvalue>\n\n", argv[0]);
exit(1);
}
v = MOOVar_parse(argv[1]);
MOOVar_print(v);
exit(0);
}
#endif