summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <hallo@tomsmeding.nl>2015-12-29 13:17:37 +0100
committertomsmeding <hallo@tomsmeding.nl>2015-12-29 13:17:37 +0100
commit2a952e107509cbc743b351e32663bfc8c6df9211 (patch)
tree0f3f47899e07ad1e495ad551f9ab19b4f16e9b2e
parent92c104d8a2ba69db1f59890d2f62019186aece05 (diff)
add sys_select (WIP) and fix source from stdin
-rw-r--r--functions.cpp106
-rw-r--r--postrun.cpp30
-rw-r--r--runtime.cpp16
3 files changed, 139 insertions, 13 deletions
diff --git a/functions.cpp b/functions.cpp
index 4e67bfa..91f6ba9 100644
--- a/functions.cpp
+++ b/functions.cpp
@@ -10,6 +10,9 @@
#include <cassert>
#include <unistd.h>
#include <fcntl.h>
+#include <termios.h>
+#include <sys/time.h>
+#include <sys/select.h>
#include "runtime.h"
@@ -20,6 +23,20 @@ extern char **g_argv;
#define BUILTIN_GUARD_STACKSIZE(nm,sz) {if(S.size()<(sz))throw string("Builtin '" nm "' needs " #sz " stack item")+(sz==1?"":"s");}
+struct Fdinfo{
+ bool read,write;
+ bool open;
+
+ Fdinfo(void):read(false),write(false),open(false){}
+ Fdinfo(bool _r,bool _w,bool _o):read(_r),write(_w),open(_o){}
+};
+
+unordered_map<int,Fdinfo> fdtable={
+ {0,{true,false,false}},
+ {0,{false,true,false}},
+ {0,{false,true,false}}
+};
+
stack<unordered_map<string,pair<Stackitem,bool>>> scopestack;
//Each stack frame contains the variables local to the stack frame. The bool is
//whether it was already present in the previous frame, and the Stackitem
@@ -191,6 +208,8 @@ unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stack
Stackitem file=move(S.back()); S.pop_back();
Stackitem v=move(S.back()); S.pop_back();
if(file.type!=SIT_INT)throw string("Second argument to 'fprint' not a number");
+ if(!fdtable[file.intval].open||!fdtable[file.intval].write)
+ throw string("File not open or not writable in 'fprint'");
if(v.type==SIT_STR)write(file.intval,v.strval.data(),v.strval.size());
else {
string s=to_string(v);
@@ -201,12 +220,16 @@ unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stack
BUILTIN_GUARD_STACKSIZE("flf",1)
Stackitem file=move(S.back()); S.pop_back();
if(file.type!=SIT_INT)throw string("Argument to 'flf' not a number");
+ if(!fdtable[file.intval].open||!fdtable[file.intval].write)
+ throw string("File not open or not writable in 'flf'");
write(file.intval,"\n",1);
}},
{"fgetc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
BUILTIN_GUARD_STACKSIZE("fgetc",1)
Stackitem file=move(S.back()); S.pop_back();
if(file.type!=SIT_INT)throw string("Argument to 'fgetc' not a number");
+ if(!fdtable[file.intval].open||!fdtable[file.intval].read)
+ throw string("File not open or not readable in 'fgetc'");
char c;
int ret=read(file.intval,&c,1);
if(ret==-1)perror("read");
@@ -230,8 +253,20 @@ unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stack
if(oflag==0)oflag=O_RDONLY;
int ret=open(fname.strval.c_str(),oflag);
if(ret<0)perror("open");
+ fdtable[ret].read=(oflag&(O_RDONLY|O_RDWR))!=0;
+ fdtable[ret].write=(oflag&(O_WRONLY|O_RDWR))!=0;
+ fdtable[ret].open=true;
S.emplace_back(ret);
}},
+ {"fclose",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("fclose",1)
+ Stackitem file=move(S.back()); S.pop_back();
+ if(file.type!=SIT_INT)throw string("Argument to 'fclose' not a number");
+ if(!fdtable[file.intval].open)
+ throw string("File not open in 'fclose'");
+ fdtable.erase(file.intval);
+ if(close(file.intval))perror("close");
+ }},
{"argc",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
BUILTIN_GUARD_STACKSIZE("argc",0)
S.emplace_back(g_argc);
@@ -522,6 +557,77 @@ unordered_map<string,function<void(vector<Stackitem>&,unordered_map<string,Stack
const int rval=rand();
S.emplace_back(rval%(to.intval-from.intval)+from.intval);
}},
+ {"sys_select",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("sys_select",4);
+ const Stackitem timeoutstk=move(S.back()); S.pop_back();
+ const Stackitem erstk=move(S.back()); S.pop_back();
+ const Stackitem wrstk=move(S.back()); S.pop_back();
+ const Stackitem rdstk=move(S.back()); S.pop_back();
+ if(rdstk.type!=SIT_ARR)throw string("First argument to 'sys_select' not an array");
+ if(wrstk.type!=SIT_ARR)throw string("Second argument to 'sys_select' not an array");
+ if(erstk.type!=SIT_ARR)throw string("Third argument to 'sys_select' not an array");
+ if(timeoutstk.type!=SIT_INT)throw string("Fourth argument to 'sys_select' not a number");
+ fd_set rd,wr,er;
+ FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&er);
+ int mxf=0;
+ for(const Stackitem &si : rdstk.arrval){
+ if(!fdtable[si.intval].read)
+ throw string("File in read array to 'sys_select' not readable");
+ FD_SET(si.intval,&rd);
+ if(si.intval>mxf)mxf=si.intval;
+ }
+ for(const Stackitem &si : wrstk.arrval){
+ if(!fdtable[si.intval].write)
+ throw string("File in read array to 'sys_select' not writable");
+ FD_SET(si.intval,&wr);
+ if(si.intval>mxf)mxf=si.intval;
+ }
+ for(const Stackitem &si : erstk.arrval){
+ FD_SET(si.intval,&er);
+ if(si.intval>mxf)mxf=si.intval;
+ }
+ struct timeval *timeout,start,end;
+ if(timeoutstk.intval<0)timeout=NULL;
+ else {
+ timeout=new struct timeval;
+ timeout->tv_sec=timeoutstk.intval/1000000;
+ timeout->tv_usec=timeoutstk.intval%1000000;
+ }
+ gettimeofday(&start,NULL);
+ select(mxf+1,&rd,&wr,&er,timeout);
+ gettimeofday(&end,NULL);
+ const int timetaken=(end.tv_sec-start.tv_sec)*1000000+end.tv_usec-start.tv_usec;
+ delete timeout;
+ Stackitem rdstk2,wrstk2,erstk2;
+ rdstk2.type=SIT_ARR; wrstk2.type=SIT_ARR; erstk2.type=SIT_ARR;
+ for(const Stackitem &si : rdstk.arrval)
+ if(FD_ISSET(si.intval,&rd))rdstk2.arrval.push_back(si.intval);
+ for(const Stackitem &si : wrstk.arrval)
+ if(FD_ISSET(si.intval,&wr))wrstk2.arrval.push_back(si.intval);
+ for(const Stackitem &si : erstk.arrval)
+ if(FD_ISSET(si.intval,&er))erstk2.arrval.push_back(si.intval);
+ S.push_back(move(rdstk2));
+ S.push_back(move(wrstk2));
+ S.push_back(move(erstk2));
+ if(timeoutstk.intval<0||timetaken>=timeoutstk.intval||(rdstk2.arrval.size()==0&&wrstk2.arrval.size()==0&&erstk2.arrval.size()==0))S.emplace_back(0);
+ else S.emplace_back(timeoutstk.intval-timetaken);
+ }},
+ {"sys_rawmode",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("sys_rawmode",0);
+ struct termios old={0};
+ if(tcgetattr(0,&old)<0)perror("tcgetattr");
+ old.c_lflag&=~ICANON;
+ old.c_lflag&=~ECHO;
+ if(tcsetattr(0,TCSANOW,&old)<0)perror("tcsetattr");
+ }},
+ {"sys_unrawmode",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
+ BUILTIN_GUARD_STACKSIZE("sys_unrawmode",0);
+ struct termios old={0};
+ if(tcgetattr(0,&old)<0)perror("tcgetattr");
+ old.c_lflag|=ICANON;
+ old.c_lflag|=ECHO;
+ if(tcsetattr(0,TCSANOW,&old)<0)perror("tcsetattr");
+ }},
{"sleep",[](vector<Stackitem> &S,unordered_map<string,Stackitem> &variables){
BUILTIN_GUARD_STACKSIZE("sleep",1)
if(S.back().type!=SIT_INT)throw string("Argument to 'sleep' not a number");
diff --git a/postrun.cpp b/postrun.cpp
index 2c3c97f..c880337 100644
--- a/postrun.cpp
+++ b/postrun.cpp
@@ -11,6 +11,8 @@ using namespace std;
int g_argc;
char **g_argv;
+bool input_is_stdin=false;
+
string readfile(ifstream stream){
stream.seekg(0,ios::end);
size_t len=stream.tellg();
@@ -26,24 +28,30 @@ int main(int argc,char **argv){
cerr<<"Call this interpreter with the Postrun source file"<<endl;
return 1;
}
- g_argc=argc-2;
- g_argv=argv+2; //skip this executable and the postrun file
- ifstream srcf(argv[1]);
- if(!srcf){
- cerr<<"Could not open file '"<<argv[1]<<"'"<<endl;
- return 1;
- }
struct timeval tv;
gettimeofday(&tv,NULL);
srand(tv.tv_sec*1000000+tv.tv_usec);
- //string source=readfile(srcf);
+ g_argc=argc-2;
+ g_argv=argv+2; //skip this executable and the postrun file
+
try {
- const vector<string> tokens=tokenise(srcf);
- //for(const string &tok : tokens)cerr<<'['<<tok<<"] "; cerr<<endl;
+ ifstream srcf;
+ vector<string> tokens;
+ if(strcmp(argv[1],"-")==0){
+ tokens=tokenise(cin);
+ input_is_stdin=true;
+ } else {
+ srcf.open(argv[1]);
+ if(!srcf){
+ cerr<<"Could not open file '"<<argv[1]<<"'"<<endl;
+ return 1;
+ }
+ tokens=tokenise(srcf);
+ }
run(tokens);
- srcf.close();
+ if(srcf)srcf.close();
} catch(string e){
cerr<<"ERROR: "<<e<<endl;
return 1;
diff --git a/runtime.cpp b/runtime.cpp
index 19108cd..9fbb3c5 100644
--- a/runtime.cpp
+++ b/runtime.cpp
@@ -7,9 +7,12 @@
#include <functional>
#include <cstring>
#include <cassert>
+#include <termios.h>
#include "runtime.h"
+extern bool input_is_stdin;
+
using namespace std;
inline bool isword(char c){return isalpha(c)||c=='_'||c=='@'||c=='$';}
@@ -94,8 +97,8 @@ vector<string> tokenise(istream &stream){
while(c=='#'){
while((c=stream.get())!='\n'&&stream);
c=stream.get();
- if(!stream)break;
}
+ if(!stream)break;
if(isdigit(c)){
if(token.size()==0){
token="#";
@@ -149,7 +152,7 @@ vector<string> tokenise(istream &stream){
token+=c;
}
} else if(isspace(c));
- else throw string("Invalid character found in source: '")+c+'\'';
+ else throw string("Invalid character found in source: '")+c+"' ("+to_string((int)(unsigned char)c)+')';
}
}
if(token.size())tokens.push_back(move(token));
@@ -346,4 +349,13 @@ void run(vector<string> T){
//third pass, evaluate code
runpasseval(T,S,functions,variables,jumpmap);
+
+ if(!input_is_stdin){
+ //restore canonical mode, since the code might have changed it to raw mode
+ struct termios old={0};
+ if(tcgetattr(0,&old)<0)perror("tcgetattr");
+ old.c_lflag|=ICANON;
+ old.c_lflag|=ECHO;
+ if(tcsetattr(0,TCSANOW,&old)<0)perror("tcsetattr");
+ }
}