/*
* Euler - a numerical lab
*
* platform : all
*
* file : command.c -- builtin command handling
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <float.h>
#include <stdarg.h>
#include "command.h"
#include "builtin.h"
#include "express.h"
#include "input.h"
#include "meta.h"
#include "metaps.h"
#include "graphics.h"
#include "output.h"
#include "help.h"
#include "udf.h"
#include "mainloop.h"
#define EXTENSION ".e"
#define BOOKEXTENSION ".en"
int promptnotebook=1,booktype=0;
FILE *infile=0,*outfile=0;
char* path[32];
int npath=0;
static int printcomments=1;
static void load_file (void)
/***** load_file
interpret a file.
*****/
{
char filename[256];
char oldline[1024],fn[256],*oldnext;
int oldbooktype=booktype,pn;
header *hd;
FILE *oldinfile;
if (udfon)
{ output("Cannot load a file in a function!\n");
error=221; return;
}
scan_space();
if (*next=='(')
{ hd=scan_value();
if (error) return;
if (hd->type!=s_string)
{ output("String value expected!\n");
error=1; return;
}
strcpy(filename,stringof(hd));
}
else
{ scan_namemax(filename,256);
}
if (error) return;
oldinfile=infile;
pn=-1;
retry :
if (pn>=0)
{ strcpy(fn,path[pn]);
strcat(fn,PATH_DELIM_STR);
strcat(fn,filename);
}
else strcpy(fn,filename);
infile=fopen(fn,"r");
if (!infile)
{ strcat(fn,EXTENSION);
infile=fopen(fn,"r");
pn++;
if (!infile)
{ if (pn>=npath)
{ output1("Could not open %s!\n",filename);
error=53; infile=oldinfile; return;
}
else goto retry;
}
}
strcpy(oldline,input_line); oldnext=next;
*input_line=0; next=input_line;
booktype=0;
while (!error && infile && !quit) command();
booktype=oldbooktype;
if (infile) fclose(infile);
infile=oldinfile;
strcpy(input_line,oldline); next=oldnext;
}
static void load_book (void)
/***** load_book
interpret a notebook file.
*****/
{ header *hd;
char name[256];
char oldline[1024],fn[256],*oldnext;
int oldbooktype=booktype;
FILE *oldinfile;
if (udfon)
{ output("Cannot load a notebook in a function!\n");
error=221; return;
}
scan_space();
if (*next=='(')
{ hd=scan_value();
if (error) return;
if (hd->type!=s_string)
{ output("String value expected!\n");
error=1; return;
}
strcpy(name,stringof(hd));
}
else
{ scan_namemax(name,256);
}
if (error) return;
oldinfile=infile;
infile=fopen(name,"r");
if (!infile)
{ strcpy(fn,name);
strcat(fn,BOOKEXTENSION);
infile=fopen(fn,"r");
if (!infile)
{ output1("Could not open %s!\n",stringof(name));
error=53; infile=oldinfile; return;
}
}
strcpy(oldline,input_line); oldnext=next;
*input_line=0; next=input_line;
booktype=1;
while (!error && infile && !quit)
{ startglobal=startlocal; endglobal=endlocal;
command();
}
booktype=oldbooktype;
if (infile) fclose(infile);
infile=oldinfile;
strcpy(input_line,oldline); next=oldnext;
}
static void do_clg (void)
{ graphic_mode(); gclear(); gflush();
}
static void do_cls (void)
{ text_mode(); clear_screen();
}
void clear (void)
/***** clear
clears the stack and remove all variables and functions.
*****/
{ char name[32];
scan_space();
if (*next==';' || *next==',' || *next==0)
{ endlocal=startlocal;
}
else
while(1)
{ scan_name(name); if (error) return;
kill_local(name);
scan_space();
if (*next==',') { next++; continue; }
else break;
}
}
static void do_clear (void)
{ if (udfon)
{ output("Cannot clear in a function!\n");
error=120; return;
}
clear();
}
static void do_quit (void)
{ quit=1;
}
static void do_exec (void)
{ header *name;
char *s;
name=scan_value(); if (error) return;
if (name->type!=s_string)
{ output("Cannot execute a number or matrix!\n");
error=130; return;
}
s=stringof(name);
while (*s && !isspace(*s)) s++;
if (*s) *s++=0;
if (execute(stringof(name),s))
{ output("Execution failed or program returned a failure!\n");
error=131;
}
}
static void do_forget (void)
{ char name[16];
header *hd;
int r;
if (udfon)
{ output("Cannot forget functions in a function!\n");
error=720; return;
}
while (1)
{ scan_space();
scan_name(name);
r=xor(name);
hd=(header *)ramstart;
while ((char *)hd<udfend)
{ if (r==hd->xor && !strcmp(hd->name,name)) break;
hd=nextof(hd);
}
if ((char *)hd>=udfend)
{ output1("Function %s not found!\n",name);
error=160; return;
}
kill_udf(name);
scan_space();
if (*next!=',') break;
else next++;
}
}
extern int builtin_count;
extern builtintyp builtin_list[];
extern int command_count;
extern commandtyp command_list[];
static void do_list (void)
{
header *hd;
int i, c, cend, lw=linelength/16;
output(" *** Builtin functions:\n");
for (i=0; i<builtin_count; i+=lw) {
cend = i+lw;
if (cend>=builtin_count) cend=builtin_count;
for (c=i; c<cend ; c++) {
output1("%-16s",builtin_list[c].name);
if (test_key()==escape) return;
}
output("\n");
}
output("\n *** Commands:\n");
for (i=0; i<command_count; i+=lw) {
cend = i+lw;
if (cend>=command_count) cend=command_count;
for (c=i; c<cend ; c++) {
output1("%-16s",command_list[c].name);
if (test_key()==escape) return;
}
output("\n");
}
output("\n *** Your functions:\n");
hd=(header *)ramstart;i=0;
while ((char *)hd<udfend)
{ if (hd->type!=s_udf) break;
if (i>=lw) {
i=0;
output("\n");
}
output1("%-16s",hd->name);
if (test_key()==escape) return;
hd=nextof(hd);
i++;
}
output("\n");
}
static void listvar1 (char *s, header *hd)
{ output1("%-20sType: %s\n",hd->name,s);
}
static void listvar2 (char *s, header *hd)
{ output1("%-20sType: %s (%dx%d)\n",hd->name,s,dimsof(hd)->r,dimsof(hd)->c);
}
static void listvar3 (char *s, header *hd)
{ output1("%-20sType: %s (%dx%0d)",hd->name,s,
submdimsof(hd)->r,submdimsof(hd)->c);
}
static void do_listvar (void)
{ header *hd=(header *)startlocal;
while (hd<(header *)endlocal)
{ switch (hd->type)
{ case s_real : listvar1("Real",hd); break;
case s_interval : listvar1("Interval",hd); break;
case s_complex : listvar1("Complex",hd); break;
case s_string : listvar1("String",hd); break;
case s_matrix : listvar2("Real Matrix",hd); break;
case s_cmatrix : listvar2("Complex Matrix",hd); break;
case s_imatrix : listvar2("Interval Matrix",hd); break;
case s_reference : listvar1("Reference",hd); break;
case s_submatrix : listvar3("Real Submatrix",hd); break;
case s_isubmatrix : listvar3("Interval Submatrix",hd); break;
case s_csubmatrix : listvar3("Complex Submatrix",hd); break;
default: listvar1("Unknown Type",hd); break;
}
hd=nextof(hd);
if (test_key()==escape) break;
}
}
static void do_dump (void)
{ header *file;
if (outfile)
{ if (fclose(outfile))
{ output("Error while closing dumpfile.\n");
}
outfile=0;
}
scan_space();
if (*next==';' || *next==',' || *next==0)
{ if (*next) next++; return; }
file=scan_value();
if (error || file->type!=s_string)
{ output("Dump needs a filename!\n");
error=201; return;
}
outfile=fopen(stringof(file),"a");
if (!outfile)
{ output1("Could not open %s.\n",stringof(file));
}
}
static void do_dir (void)
{
header *file;
int len, npl, i, j, k, imax;
char **entries=NULL;
int n_entries=0;
scan_space();
if (*next==';' || *next==',' || *next==0)
{
file=new_string("*",5,"");
}
else file=scan_value();
if (error || file->type!=s_string)
{ output("Dir needs a string!\n");
error=201; return;
}
len = scan_dir(".",stringof(file),&entries,&n_entries);
len +=2;
npl = linelength/len;
imax = n_entries/npl;
if (n_entries % npl) imax++;
for (i=0; i<imax;i++) {
for (j=0; j<npl; j++) {
if (outputing) {
int l;
if (npl*i+j>=n_entries) break;
output1("%s", entries[npl*i+j]);
l=strlen(entries[npl*i+j]);
for (k=0;k<len-l;k++)
output(" ");
if (test_key()==escape) outputing=0;
}
free(entries[npl*i+j]);
}
output("\n");
}
free(entries);
if (!outputing) {
outputing=1;
output("\n");
}
if (*next==',' || *next==';') next++;
}
static void do_path (void)
{
header *ppath;
char s[256],*p,*q;
int i;
scan_space();
if (*next==';' || *next==',' || *next==0)
{ out :
for (i=0; i<npath; i++)
{ output1("%s;",path[i]);
}
output("\n");
return;
}
ppath=scan_value();
if (error || ppath->type!=s_string)
{ output("Path needs a string!\n");
error=201; return;
}
p=stringof(ppath);
for (i=2; i<npath; i++) free(path[i]);
npath=2;
while (*p)
{ q=s;
while (*p && *p!=';') *q++=*p++;
if (q>s && *(q-1)==PATH_DELIM_CHAR) q--;
*q=0;
if (*p==';') p++;
path[npath]=(char *)malloc(strlen(s)+1);
strcpy(path[npath],s);
npath++;
}
if (*next!=';') goto out;
}
static void do_cd (void)
{ header *hd;
char name[256];
char *s;
scan_space();
if (*next==';' || *next==',' || *next==0)
{ s=cd("");
output1("%s\n",s);
return;
}
if (*next=='(')
{ hd=scan_value();
if (error) return;
if (hd->type!=s_string)
{ output("String value expected!\n");
error=1; return;
}
strcpy(name,stringof(hd));
}
else
{ scan_namemax(name,256);
}
if (error) return;
s=cd(name);
if (*next!=';') output1("%s\n",s);
if (*next==',' || *next==';') next++;
}
static void do_meta (void)
{ header *file;
scan_space();
file=scan_value();
if (error || file->type!=s_string)
{ output("Meta needs a filename!\n");
error=201; return;
}
if (!dump_meta(stringof(file)))
{ output1("Could not open %s.\n",stringof(file));
}
}
static void do_postscript (void)
{
header *file;
scan_space();
file=scan_value();
if (error || file->type!=s_string)
{ output("postscript needs a filename!\n");
error=201; return;
}
if (!dump_postscript(stringof(file)))
output1("Could not open %s.\n",stringof(file));
}
static void do_remove (void)
{ header *hd;
char name[256];
if (*next=='(')
{ hd=scan_value();
if (error) return;
if (hd->type!=s_string)
{ output("String value expected!\n");
error=1; return;
}
strcpy(name,stringof(hd));
}
else
{ scan_namemax(name,256);
}
if (error) return;
remove(name);
}
static void do_do (void)
{ int udfold;
char name[16];
char *oldnext=next,*udflineold;
header *var;
scan_space(); scan_name(name); if (error) return;
var=searchudf(name);
if (!var || var->type!=s_udf)
{ output("Need a udf!\n"); error=220; return;
}
udflineold=udfline; udfline=next=udfof(var); udfold=udfon; udfon=1;
while (!error && udfon==1)
{ command();
if (udfon==2) break;
if (test_key()==escape)
{ output("User interrupted!\n"); error=58; break;
}
}
if (error) output1("Error in function %s\n",var->name);
if (udfon==0)
{ output1("Return missing in %s!\n",var->name); error=55; }
udfon=udfold; udfline=udflineold;
if (udfon) next=oldnext;
else { next=input_line; *next=0; }
}
static void do_mdump (void)
{ header *hd;
#ifndef SPLIT_MEM
output1("ramstart : 0\nstartlocal : %ld\n",startlocal-ramstart);
output1("endlocal : %ld\n",endlocal-ramstart);
output1("newram : %ld\n",newram-ramstart);
output1("ramend : %ld\n",ramend-ramstart);
#else
output1("ramstart : 0\nstartlocal : %ld\n",startlocal-varstart);
output1("endlocal : %ld\n",endlocal-varstart);
output1("newram : %ld\n",newram-varstart);
output1("ramend : %ld\n",ramend-varstart);
#endif
hd=(header *)ramstart;
#ifdef SPLIT_MEM
while ((char *)hd<udfend)
{
output1("%6ld : %16s, ",(char *)hd-ramstart,hd->name);
output1("size %6ld ",(long)hd->size);
output1("type %d\n",hd->type);
hd=nextof(hd);
}
hd=(header *)varstart;
#endif
while ((char *)hd<newram)
{
#ifndef SPLIT_MEM
output1("%6ld : %16s, ",(char *)hd-ramstart,hd->name);
#else
output1("%6ld : %16s, ",(char *)hd-varstart,hd->name);
#endif
output1("size %6ld ",(long)hd->size);
output1("type %d\n",hd->type);
hd=nextof(hd);
}
}
static void hex_out1 (int n)
{ if (n<10) output1("%c",n+'0');
else output1("%c",n-10+'A');
}
static void hex_out (unsigned int n)
{ hex_out1(n/16);
hex_out1(n%16);
output(" ");
}
static void string_out (unsigned char *p)
{ int i;
unsigned char a;
for (i=0; i<16; i++)
{ a=*p++;
output1("%c",(a<' ')?'_':a);
}
}
static void do_hexdump (void)
{ char name[16];
unsigned char *p,*end;
int i=0,j;
unsigned long count=0;
header *hd;
scan_space(); scan_name(name); if (error) return;
hd=searchvar(name);
if (!hd) hd=searchudf(name);
if (error || hd==0) return;
p=(unsigned char *)hd; end=p+hd->size;
output1("\n%5lx ",count);
while (p<end)
{ hex_out(*p++); i++; count++;
if (i>=16)
{ i=0; string_out(p-16);
output1("\n%5lx ",count);
if (test_key()==escape) break;
}
}
for (j=i; j<16; j++) output(" ");
string_out(p-i);
output("\n");
}
void do_help (void)
{ char name[256];
header *hd;
int count,i,defaults;
char *p,*end,*pnote;
builtintyp *b;
scan_space();
p=name;
while (*next!=0 && *next!=' ')
{ *p++=*next++;
if (p-name>254) break;
}
*p=0;
if (!*name) strcpy(name,"help");
b=find_builtin(name);
if (b)
{ if (b->nargs>=0)
{ output1(
"%s is a builtin function with %d argument(s).\n"
,name,b->nargs);
}
else
output1(
"%s is a builtin function.\n"
,name);
}
hd=searchudf(name);
if (hd && hd->type==s_udf)
{ if (b) output1("%s is also a user defined function.\n",name);
output1("function %s (",name);
end=udfof(hd);
p=helpof(hd);
memmove(&count,p,sizeof(inttyp));
p+=sizeof(inttyp);
pnote=p;
for (i=0; i<count; i++)
{ memmove(&defaults,p,sizeof(inttyp)); p+=sizeof(inttyp);
output1("%s",p);
p+=16+sizeof(inttyp);
if (defaults)
{ output("=...");
p=(char *)nextof((header *)p);
}
if (i!=count-1) output(",");
}
output(")\n");
p=pnote;
for (i=0; i<count; i++)
{ memmove(&defaults,p,sizeof(inttyp)); p+=sizeof(inttyp);
if (defaults) output1("## Default for %s :\n",p);
p+=16+sizeof(inttyp);
if (defaults)
{ give_out((header *)p);
p=(char *)nextof((header *)p);
}
}
while (*p!=1 && p<end)
{ output(p); output("\n");
p+=strlen(p); p++;
}
}
externhelp(name);
}
static void do_output (void)
/**** do_output
toggles output.
****/
{ scan_space();
if (!strncmp(next,"off",3))
{ outputing=0; next+=3;
}
else if (!strncmp(next,"on",2))
{ outputing=1; output("\n"); next+=2;
}
else outputing=!outputing;
}
static void do_prompt (void)
/**** do_prompt
toggles notebook prompt.
****/
{ scan_space();
if (!strncmp(next,"off",3))
{ promptnotebook=0; next+=3;
}
else if (!strncmp(next,"on",2))
{ promptnotebook=1; output("\n"); next+=2;
}
else promptnotebook=!promptnotebook;
}
void do_comments (void)
/**** do_comments
toggles comments
****/
{ scan_space();
if (!strncmp(next,"off",3))
{ printcomments=0; next+=3;
}
else if (!strncmp(next,"on",2))
{ printcomments=1; output("\n"); next+=2;
}
else printcomments=!printcomments;
}
static void do_comment (void)
{ FILE *fp=infile;
if (!fp || udfon)
{ output("comment illegal at this place\n");
error=1001; return;
}
while (1)
{ next_line();
if (infile!=fp)
{ output("endcomment missing!\n"); error=1002;
return;
}
if (strncmp(next,"endcomment",10)!=0)
{ if (printcomments)
{ output(input_line); output("\n");
}
}
else break;
}
next_line();
}
int command_count;
commandtyp command_list[] = {
{"quit",c_quit,do_quit},
{"hold",c_hold,ghold},
{"shg",c_shg,show_graphics},
{"load",c_load,load_file},
{"function",c_udf,get_udf},
{"return",c_return,do_return},
{"for",c_for,do_for},
{"endif",c_endif,do_endif},
{"end",c_end,do_end},
{"break",c_break,do_break},
{"loop",c_loop,do_loop},
{"else",c_else,do_else},
{"elseif",c_elseif,do_elseif},
{"if",c_if,do_if},
{"repeat",c_repeat,do_repeat},
{"clear",c_clear,do_clear},
{"clg",c_clg,do_clg},
{"cls",c_cls,do_cls},
{"exec",c_exec,do_exec},
{"forget",c_forget,do_forget},
{"global",c_global,do_global},
{"useglobal",c_global,do_useglobal},
{"list",c_global,do_list},
{"listvar",c_global,do_listvar},
{"type",c_global,do_type},
{"dump",c_global,do_dump},
{"remove",c_global,do_remove},
{"help",c_global,do_help},
{"do",c_global,do_do},
{"memorydump",c_global,do_mdump},
{"hexdump",c_global,do_hexdump},
{"output",c_global,do_output},
{"comments",c_global,do_comments},
{"meta",c_global,do_meta},
{"postscript",c_global,do_postscript},
{"comment",c_global,do_comment},
{"trace",c_global,do_trace},
{"notebook",c_global,load_book},
{"prompt",c_global,do_prompt},
{"cd",c_global,do_cd},
{"dir",c_global,do_dir},
{"path",c_global,do_path},
{0,c_none,0}
};
int command_compare (const commandtyp *p1, const commandtyp *p2)
{ return strcmp(p1->name,p2->name);
}
void sort_command (void)
{ command_count=0;
while (command_list[command_count].name) command_count++;
qsort(command_list,command_count,sizeof(commandtyp),
(int (*)(const void *, const void *))command_compare);
}
commandtyp *preview_command (unsigned long *l)
{ commandtyp h;
char name[16],*a,*n;
*l=0;
a=next; n=name;
while (*l<15 && isalpha(*a)) { *n++=*a++; *l+=1; }
*n=0; if (isalpha(*a)) return 0;
h.name=name;
return (commandtyp *)bsearch(&h,command_list,command_count,sizeof(commandtyp),
(int (*)(const void *, const void *))command_compare);
}
syntax highlighted by Code2HTML, v. 0.9.1