/**
* This compiles the soul files into a non human readable format. The
* format is far more useful to the soul though :)
*/
#include "soul.h"
#include "user_parser.h"
private nosave string _current_file;
private nosave int _current_line;
private nosave int _file_len;
private nosave int _depth;
private nosave int _look_for;
private nosave mixed *_to_compile;
private nosave mixed *_arguments;
private nosave object _current_player;
void start_compile();
void parse_chunk(string chunk);
void make_into_soul_commands(mapping commands);
/* Number of lines in a chunk */
#define CHUNK_SIZE 20
#define OPEN_BRACKET 1
#define START_ARGUMENT 2
#define END_BRACKET 3
#define END_STRING 4
#define ARGUMENT_VALUE 5
#define ARGUMENT_NAME 6
#define REST_OF_ARGUMENT 7
void create() {
_to_compile = ({ });
seteuid("Root");
} /* create() */
/** @ignore yes */
int test_security(string fname) {
return 1;
} /* test_security() */
/** @ignore yes */
void notify(string mess) {
if (_current_player)
tell_object(_current_player, mess);
} /* notify() */
/**
* Compiles up the file into the useful soul format. It also tells
* the soul about it.
* <p>
* See the soul data files in /save/new_soul for details of the format
* for the soul files. The file has to come from the soul save
* directory or the call will not work.
* @param fname the name of the file to compile
*/
void compile_file(string fname) {
/*
* First, do we have read access to the file.
* and is it actually a file?
*/
if (file_size(SOUL_DIR+fname) == -1) {
tell_object(this_player(), "The file "+
SOUL_DIR+fname+" does not exist.\n");
return ;
}
if (file_size(SOUL_DIR+fname) == -2) {
tell_object(this_player(), "The file "+
SOUL_DIR+fname+" is a directory exist.\n");
return ;
}
_to_compile += ({ SOUL_DIR+fname, this_player() });
start_compile();
} /* compile_file() */
/**
* Compiles up a directory full of files.
* @see compile_file()
* @param fname the directory name to compile
*/
void compile_directory(string fname) {
string *bits, start;
int i;
if (file_size(SOUL_DIR+fname) != -2) {
tell_object(this_player(), "The file "+
fname+" is not a directory exist.\n");
return ;
}
bits = explode(fname, "/");
start = implode(bits[0..<1], "/");
if (start != "")
start += "/";
fname = SOUL_DIR+fname;
if (fname[<1] == '/')
fname += "*.s";
else
fname += "/*.s";
bits = get_dir(fname);
for (i=0;i<sizeof(bits);i++) {
bits[i] = start+bits[i];
tell_object(this_player(), "Compiling "+bits[i]+"\n");
compile_file(bits[i]);
}
} /* compile_directory() */
/** @ignore yes */
void start_compile() {
/* We are already compiling */
if (_current_file || !sizeof(_to_compile))
return ;
_current_file = _to_compile[0];
_current_player = _to_compile[1];
_to_compile = _to_compile[2..];
_current_line = 1;
_depth = 0;
_look_for = OPEN_BRACKET;
_file_len = file_length(_current_file);
_arguments = ({ 0, ([ ]) });
call_out("compile_chunk", 2);
} /* start_compile() */
/** @ignore yes */
void compile_chunk() {
string chunk;
int end;
if (_current_line+CHUNK_SIZE > _file_len)
end = _file_len+1;
else
end = _current_line+CHUNK_SIZE;
chunk = unguarded((: read_file, _current_file, _current_line,
end-_current_line :));
_current_line = end;
parse_chunk(chunk);
if (end > _file_len) {
/* finished file */
call_out("start_compile", 2);
_current_file = 0;
make_into_soul_commands(_arguments[1]);
} else {
call_out("compile_chunk", 2);
}
} /* compile_chunk() */
/** @ignore yes */
void parse_chunk(string chunk) {
/* Now. What are we looking for? */
/* Love, a nice place in the world, a happy bag full of groceries. */
string *bits, s1, s2;
int pos, chunk_size, start;
chunk_size = strlen(chunk);
pos = 0;
bits = explode(chunk, "(");
while (pos < chunk_size) {
switch (_look_for) {
case OPEN_BRACKET :
if (sscanf(chunk[pos..], "%s(%s", s1, s2)) {
chunk = s2;
chunk_size = strlen(chunk);
pos = 0;
_depth++;
_arguments += ({ 0, 0 });
_look_for = ARGUMENT_NAME;
} else {
pos = chunk_size;
}
break;
case ARGUMENT_NAME :
/* We look for the first non-space, non-tab, non-nl */
while (pos < chunk_size && (chunk[pos] == ' ' ||
chunk[pos] == '\t' || chunk[pos] == '\n'))
pos++;
if (pos == chunk_size)
break;
start = pos;
/* Ok, now we search for the next one. */
while (pos < chunk_size && chunk[pos] != ' ' &&
chunk[pos] != '\t' && chunk[pos] != '\n')
pos++;
/* Thats it. Our argument name. */
_arguments[_depth*2] = chunk[start..pos-1];
_look_for = ARGUMENT_VALUE;
break;
case ARGUMENT_VALUE :
while (pos < chunk_size && (chunk[pos] == ' ' ||
chunk[pos] == '\t' || chunk[pos] == '\n'))
pos++;
if (pos >= chunk_size)
break;
switch (chunk[pos]) {
case '(' :
_arguments[_depth*2+1] = ([ ]);
_depth++;
_arguments += ({ 0, 0 });
_look_for = ARGUMENT_NAME;
pos++;
break;
case '"' :
_arguments[_depth*2+1] = "";
_look_for = END_STRING;
pos++;
break;
default :
/* A string, at most one space seperator between them... */
start = pos;
if (sscanf(chunk[pos..], "%s)%s", s1, s2) == 2) {
_arguments[_depth*2+1] = replace(implode(explode(replace(s1,
({ "\n", " ", "\r", "" })), " ")-({ "" }), " "), ", ", ",");
pos = 0;
chunk = ")"+s2;
_look_for = END_BRACKET;
} else {
_arguments[_depth*2+1] = chunk[pos..];
_look_for = REST_OF_ARGUMENT;
pos = 0;
chunk = "";
}
chunk_size = strlen(chunk);
break;
}
break;
case REST_OF_ARGUMENT :
if (sscanf(chunk[pos..], "%s)%s", s1, s2) == 2) {
_arguments[_depth*2+1] = replace(implode(explode(
replace(_arguments[_depth*2+1]+s1, "\n", " "),
" ") - ({ "" }),
" "), ", ", ",");
pos = 0;
chunk = ")"+s2;
_look_for = END_BRACKET;
} else {
_arguments[_depth*2+1] += chunk[pos..];
pos = 0;
chunk = "";
}
chunk_size = strlen(chunk);
break;
case END_BRACKET :
if (sscanf(chunk[pos..], "%s)%s", s1, s2)) {
switch (_depth) {
case 2 :
case 3 :
if (pointerp(_arguments[_depth*2-1][_arguments[_depth*2]]))
_arguments[_depth*2-1][_arguments[_depth*2]] += ({ _arguments[_depth*2+1] });
else
_arguments[_depth*2-1][_arguments[_depth*2]] = ({ _arguments[_depth*2+1] });
break;
case 1 :
case 4 :
case 5 :
case 6 :
case 7 :
_arguments[_depth*2-1][_arguments[_depth*2]] = _arguments[_depth*2+1];
break;
}
chunk = s2;
chunk_size = strlen(s2);
_depth--;
pos = 0;
_arguments = _arguments[0.._depth*2+1];
if (_depth)
_look_for = START_ARGUMENT;
else
_look_for = OPEN_BRACKET;
}
break;
case START_ARGUMENT :
while (pos < chunk_size && (chunk[pos] == ' '
|| chunk[pos] == '\t' || chunk[pos] == '\n'))
pos++;
if (pos >= chunk_size)
break;
switch (chunk[pos]) {
case ')' :
_look_for = END_BRACKET;
break;
case '(' :
_look_for = OPEN_BRACKET;
break;
default :
if (!sscanf(chunk[pos..], "%s\n%s", s1, s2))
s1 = chunk;
printf("Syntax error in file %s, near %s\n", _current_file, s1);
_look_for = END_BRACKET;
break;
}
break;
case END_STRING :
if (sscanf(chunk[pos..], "%s\"%s", s1, s2)) {
if (strlen(s1) > 0 && s1[strlen(s1)-1] == '\\') {
_arguments[_depth*2+1] += replace(s1[0..strlen(s1)-2], "\n", "")+"\"";
chunk = s2;
pos = 0;
chunk_size = strlen(s2);
} else {
_arguments[_depth*2+1] += replace(s1, "\n", "");
_look_for = END_BRACKET;
chunk = s2;
pos = 0;
chunk_size = strlen(s2);
}
} else {
_arguments[_depth*2+1] += replace(chunk, "\n", "");
pos = chunk_size;
}
break;
default :
notify("Horrible error "+_look_for+"\n");
pos = chunk_size;
break;
}
}
} /* parse_chunk() */
/** @ignore yes */
int check_sort(string pat1, string pat2) {
int lvl1, lvl2;
lvl1 = ((mixed *)PATTERN_OB->compile_pattern(pat1))[0];
lvl2 = ((mixed *)PATTERN_OB->compile_pattern(pat2))[0];
return lvl2-lvl1;
} /* check_sort() */
/** @ignore yes */
string *sort_patterns(string *inp) {
if (!pointerp(inp)) {
printf("%O\n", inp);
return ({ });
}
return sort_array(inp, "check_sort", this_object());
/*
string *ret;
int *lvl, i, j, level;
lvl = allocate(sizeof(inp));
ret = ({ });
for (i=0;i<sizeof(inp);i++) {
level = ((mixed *)PATTERN_OB->compile_pattern(inp[i]))[0];
for (j=0;j<sizeof(ret);j++)
if (lvl[j] < level) {
if (j) {
ret = ret[0..j-1]+({ inp[i] })+ret[j..];
lvl = lvl[0..j-1]+({ level })+lvl[j..];
} else {
ret = ({ inp[i] })+ret[j..];
lvl = ({ level })+lvl[j..];
}
break;
}
if (j == sizeof(ret)) {
ret += ({ inp[i] });
lvl += ({ level });
}
}
return ret;
*/
} /* sort_patterns() */
/** @ignore yes */
void make_into_soul_commands(mapping comms) {
string *fluff;
int i, failed, j;
mapping ret, tmp;
fluff = keys(comms);
ret = ([ ]);
for (i=0;i<sizeof(fluff);i++) {
/* No arguments and arguments... */
ret[fluff[i]] = ({ comms[fluff[i]]["pattern"], 0, 0 });
/* Ok, now we see if we have a single bit */
if (comms[fluff[i]]["single"]) {
/* Yes! */
if (comms[fluff[i]]["single"][0]["no-arguments"]) {
tmp = comms[fluff[i]]["single"][0]["no-arguments"][0];
if (!tmp["self"]) {
notify("The 'self' type is missing in the no-argument, single for the soul command "+fluff[i]+"\n");
failed = 1;
} else if (!tmp["rest"]) {
notify("The 'rest' type is missing in the no-argument, single for the soul command "+fluff[i]+"\n");
failed = 1;
} else {
ret[fluff[i]][SINGLE] = ({ ({ tmp["self"], tmp["rest"],
tmp["position"] }),
0 });
}
}
if (comms[fluff[i]]["single"][0]["arguments"]) {
j = sizeof(comms[fluff[i]]["single"][0]["arguments"]);
if (!ret[fluff[i]][SINGLE])
ret[fluff[i]][SINGLE] = ({ 0, allocate(j*SMALL_ARG_SIZE) });
else
ret[fluff[i]][SINGLE][ARGUMENTS] = allocate(j*SMALL_ARG_SIZE);
for (j=0;j<sizeof(comms[fluff[i]]["single"][0]["arguments"]);j++) {
tmp = comms[fluff[i]]["single"][0]["arguments"][j];
if (!mapp(tmp)) {
notify("The soul command "+fluff[i]+" is totaly stuffed.\n");
failed = 1;
} else if (!tmp["self"]) {
notify("The 'self' type is missing in the argument, single for the soul command "+fluff[i]+"\n");
failed = 1;
} else if (!tmp["rest"]) {
notify("The 'rest' type is missing in the argument, single for the soul command "+fluff[i]+"\n");
failed = 1;
} else if (!tmp["arguments"]) {
notify("The 'arguments' type is missing in the argument, single for the soul command "+fluff[i]+"\n");
failed = 1;
} else {
ret[fluff[i]][SINGLE][ARGUMENTS][j*SMALL_ARG_SIZE+SELF] = tmp["self"];
ret[fluff[i]][SINGLE][ARGUMENTS][j*SMALL_ARG_SIZE+REST] = tmp["rest"];
ret[fluff[i]][SINGLE][ARGUMENTS][j*SMALL_ARG_SIZE+ARGS] = explode(tmp["arguments"], ",");
ret[fluff[i]][SINGLE][ARGUMENTS][j*SMALL_ARG_SIZE+POSITION_SINGLE] = tmp["position"];
}
}
}
}
if (comms[fluff[i]]["targeted"]) {
/* Yes! */
if (comms[fluff[i]]["targeted"][0]["no-arguments"]) {
tmp = comms[fluff[i]]["targeted"][0]["no-arguments"][0];
if (!tmp["self"]) {
notify("The 'self' type is missing in the no-argument, target for the soul command "+fluff[i]+"\n");
failed = 1;
} else if (!tmp["rest"]) {
notify("The 'rest' type is missing in the no-argument, target for the soul command "+fluff[i]+"\n");
failed = 1;
} else {
ret[fluff[i]][TARGET] = ({ ({ tmp["self"], tmp["rest"],
tmp["target"], 0, tmp["force"], tmp["position"] }),
0 });
}
}
if (comms[fluff[i]]["targeted"][0]["arguments"]) {
j = sizeof(comms[fluff[i]]["targeted"][0]["arguments"]);
if (!ret[fluff[i]][TARGET])
ret[fluff[i]][TARGET] = ({ 0, allocate(j*ARG_SIZE) });
else
ret[fluff[i]][TARGET][ARGUMENTS] = allocate(j*ARG_SIZE);
for (j=0;j<sizeof(comms[fluff[i]]["targeted"][0]["arguments"]);j++) {
tmp = comms[fluff[i]]["targeted"][0]["arguments"][j];
if (!tmp["self"]) {
notify("The 'self' type is missing in the argument, target for the soul command "+fluff[i]+"\n");
failed = 1;
} else if (!tmp["rest"]) {
notify("The 'rest' type is missing in the argument, target for the soul command "+fluff[i]+"\n");
failed = 1;
} else if (!tmp["arguments"]) {
notify("The 'arguments' type is missing in the argument, target for the soul command "+fluff[i]+"\n");
failed = 1;
} else {
ret[fluff[i]][TARGET][ARGUMENTS][j*ARG_SIZE+SELF] = tmp["self"];
ret[fluff[i]][TARGET][ARGUMENTS][j*ARG_SIZE+REST] = tmp["rest"];
ret[fluff[i]][TARGET][ARGUMENTS][j*ARG_SIZE+TARG] = tmp["target"];
ret[fluff[i]][TARGET][ARGUMENTS][j*ARG_SIZE+ARGS] = explode(tmp["arguments"], ",");
ret[fluff[i]][TARGET][ARGUMENTS][j*ARG_SIZE+FORCE] = tmp["force"];
ret[fluff[i]][TARGET][ARGUMENTS][j*ARG_SIZE+POSITION] = tmp["position"];
}
}
}
}
}
fluff = keys(ret);
for (i=0;i<sizeof(fluff);i++) {
ret[fluff[i]][PATTERNS] = sort_patterns(ret[fluff[i]][PATTERNS]);
SOUL_OBJECT->add_soul_command(fluff[i], ret[fluff[i]]);
notify("Added soul command "+fluff[i]+".\n");
}
} /* make_into_soul_commands() */
/** @ignore yes */
void blue() {
printf("%O\n", sort_patterns(({ "[at] <indirect:object>", "<string>" })));
} /* blue() */