|
20.3 Interpreting Commands from a File
For all practical purposes, any interpreter is pretty useless if it only
works interactively. I have added a `source' built-in command to
`sic_builtin.c' which takes lines of input from a file and
evaluates them using `sic_repl.c' in much the same way as lines
typed at the prompt are evaluated otherwise. Here is the built-in handler:
|
/* List of built in functions. */
#define builtin_functions \
BUILTIN(exit, 0, 1) \
BUILTIN(load, 1, 1) \
BUILTIN(source, 1, -1) \
BUILTIN(unload, 1, -1)
BUILTIN_DECLARATION (source)
{
int status = SIC_OKAY;
int i;
for (i = 1; status == SIC_OKAY && argv[i]; ++i)
status = source (sic, argv[i]);
return status;
}
|
And the source function from `sic_repl.c':
|
int
source (Sic *sic, const char *path)
{
FILE *stream;
int result = SIC_OKAY;
int save_interactive = is_interactive;
SIC_ASSERT (sic && path);
is_interactive = 0;
if ((stream = fopen (path, "rt")) == NULL)
{
sic_result_clear (sic);
sic_result_append (sic, "cannot source \"", path, "\": ",
strerror (errno), NULL);
result = SIC_ERROR;
}
else
result = evalstream (sic, stream);
is_interactive = save_interactive;
return result;
}
|
The reason for separating the source function in this way, is
that it makes it easy for the startup sequence in main to
evaluate a startup file. In traditional Unix fashion, the startup file
is named `.sicrc', and is evaluated if it is present in the user's
home directory:
|
static int
evalsicrc (Sic *sic)
{
int result = SIC_OKAY;
char *home = getenv ("HOME");
char *sicrcpath, *separator = "";
int len;
if (!home)
home = "";
len = strlen (home);
if (len && home[len -1] != '/')
separator = "/";
len += strlen (separator) + strlen (SICRCFILE) + 1;
sicrcpath = XMALLOC (char, len);
sprintf (sicrcpath, "%s%s%s", home, separator, SICRCFILE);
if (access (sicrcpath, R_OK) == 0)
result = source (sic, sicrcpath);
return result;
}
|
|