summaryrefslogtreecommitdiff
path: root/functions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'functions.cpp')
-rw-r--r--functions.cpp106
1 files changed, 106 insertions, 0 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");