511 lines
10 KiB
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
|