diff --git a/Makefile b/Makefile index fd841f7..462a9eb 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,11 @@ +ifndef CC +CC = gcc +endif + BASE_CFLAGS = --std=c99 -Wall -Wextra -Ofast -lm -lreadline -funsigned-char ifndef OS -C = gcc CFLAGS = $(BASE_CFLAGS) -ldl ifeq ($(shell uname -s), Darwin) ifeq ($(shell [ -d ~/.brew/opt/readline/include ] && echo true), true) @@ -27,18 +30,18 @@ else ifeq ($(shell uname -o), Android) CFLAGS += -s else -CFLAGS += -s -no-pie +CFLAGS += -g -no-pie endif endif CBITS = $(shell getconf LONG_BIT) BUILD_TO = clibasic -BUILD32 = $(C) clibasic.c -m32 $(CFLAGS) -DB32 -o $(BUILD_TO) && chmod +x $(BUILD_TO) +BUILD32 = $(CC) clibasic.c -m32 $(CFLAGS) -DB32 -o $(BUILD_TO) && chmod +x $(BUILD_TO) ifeq (,$(CBITS)) BUILD__ = $(BUILD32) else -BUILD__ = $(C) clibasic.c $(CFLAGS) -DB$(CBITS) -o $(BUILD_TO) && chmod +x $(BUILD_TO) +BUILD__ = $(CC) clibasic.c $(CFLAGS) -DB$(CBITS) -o $(BUILD_TO) && chmod +x $(BUILD_TO) endif MAN_PATH = docs/clibasic.man @@ -103,7 +106,7 @@ cross: ifeq ($(MAKECMDGOALS), cross) @$(MAKE) cross all else - @$(eval C = x86_64-w64-mingw32-gcc) + @$(eval CC = x86_64-w64-mingw32-gcc) @$(eval C32 = i686-w64-mingw32-gcc) @$(eval CFLAGS = $(BASE_CFLAGS) -s -Ilib) @$(eval BUILD_TO = clibasic.exe) @@ -113,7 +116,7 @@ else ifeq (,$(CBITS)) @$(eval BUILD__ = $(BUILD32)) else - @$(eval BUILD__ = cp -f lib/win64/*.dll . && $(C) clibasic.c $(CFLAGS) -Llib/win64 -DB$(CBITS) -o $(BUILD_TO) && chmod -x $(BUILD_TO)) + @$(eval BUILD__ = cp -f lib/win64/*.dll . && $(CC) clibasic.c $(CFLAGS) -Llib/win64 -DB$(CBITS) -o $(BUILD_TO) && chmod -x $(BUILD_TO)) endif @$(eval RUN = wineconsole .\\$(BUILD_TO)) @$(eval CLEAN = rm -f clibasic.exe *.dll) @@ -126,19 +129,17 @@ vt: ifeq (,$(CBITS)) @$(eval BUILD__ = $(BUILD32)) else - @$(eval BUILD__ = cp -f lib/win64/*.dll . && $(C) clibasic.c $(CFLAGS) -Llib/win64 -DB$(CBITS) -o $(BUILD_TO) && chmod -x $(BUILD_TO)) + @$(eval BUILD__ = cp -f lib/win64/*.dll . && $(CC) clibasic.c $(CFLAGS) -Llib/win64 -DB$(CBITS) -o $(BUILD_TO) && chmod -x $(BUILD_TO)) endif @true else -C = gcc - -CFLAGS = $(BASE_CFLAGS) -Ilib -s -D_CRT_NONSTDC_NO_WARNINGS +CFLAGS = $(BASE_CFLAGS) -lpthread -Ilib -s -D_CRT_NONSTDC_NO_WARNINGS BUILD_TO = clibasic.exe -BUILD64 = xcopy lib\win64\*.dll . /Y && $(C) clibasic.c -m64 $(CFLAGS) -Llib\win64 -DB64 -o $(BUILD_TO) -BUILD32 = xcopy lib\win32\*.dll . /Y && $(C) clibasic.c -m32 $(CFLAGS) -Llib\win32 -DB32 -o $(BUILD_TO) +BUILD64 = xcopy lib\win64\*.dll . /Y && $(CC) clibasic.c -m64 $(CFLAGS) -Llib\win64 -DB64 -o $(BUILD_TO) +BUILD32 = xcopy lib\win32\*.dll . /Y && $(CC) clibasic.c -m32 $(CFLAGS) -Llib\win32 -DB32 -o $(BUILD_TO) INSTALL_TO = C:\windows\system32 INSTALL = xcopy *.dll $(INSTALL_TO) /Y && xcopy $(BUILD_TO) $(INSTALL_TO) /Y diff --git a/README.md b/README.md index 1d3464a..8d33848 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,10 @@ To run, use `make run` or `./clibasic`.
To build then run, use `make` (same as `make all`).
To build CLIBASIC with support for VT escape codes, add `vt` before the rest of the rules.
+--- +### Demo
+[![asciicast](https://asciinema.org/a/447773.png)](https://asciinema.org/a/447773) + --- ### Notes
- On Arch Linux, you can install CLIBASIC by installing either the [`clibasic`](https://aur.archlinux.org/packages/clibasic/) or [`clibasic-bin`](https://aur.archlinux.org/packages/clibasic-bin/) AUR package. @@ -87,4 +91,3 @@ To build CLIBASIC with support for VT escape codes, add `vt` before the rest of - CLIBASIC will look for `~/.clibasicrc`, `~/autorun.bas`, then `~/.autorun.bas` in this order in the user's home directory and run the first file found. - The development scripts are `build.sh` which is for testing if CLIBASIC compiles correctly for Linux and Windows, `package.sh` which creates the zip files for making a CLIBASIC release, `commit.sh` which automates the build and push process, and `release-text.sh` which generates the text for making a CLIBASIC release. - Include the `clibasic.h` file when making a clibasic extension. - diff --git a/clibasic.c b/clibasic.c index 7784d1b..982a217 100644 --- a/clibasic.c +++ b/clibasic.c @@ -39,6 +39,8 @@ /* Fix implicit declaration issues */ #define _POSIX_C_SOURCE 999999L #define _XOPEN_SOURCE 999999L +#define _DEFAULT_SOURCE +#define _GNU_SOURCE /* Check if the buffer size is usable */ #if (CB_BUF_SIZE < 0) @@ -94,14 +96,16 @@ // OS-specific includes and definitions #ifndef _WIN32 + #include #include - #include #include - #include + #include + #include #else #include #include #include + #include #endif #ifdef __APPLE__ @@ -118,7 +122,7 @@ // Base defines -char VER[] = "0.28.1.4"; +char VER[] = "1.0"; #if defined(__linux__) char OSVER[] = "Linux"; @@ -154,6 +158,9 @@ char VER[] = "0.28.1.4"; #include "clibasic.h" +char* defaultstr = ""; +char* defaultnum = "0"; + int progindex = -1; char** progbuf = NULL; char** progfn = NULL; @@ -177,11 +184,6 @@ char gpbuf[CB_BUF_SIZE]; char* cmd = NULL; int cmdl = 0; -//char** tmpargs = NULL; -char** arg = NULL; -uint8_t* argt = NULL; -int32_t* argl = NULL; -int argct = -1; int cmdpos = 0; @@ -191,7 +193,7 @@ bool lockpl = false; typedef struct { uint8_t type; uint8_t block; -} cb_brkinfo; +} __attribute__((aligned(sizeof(void*)))) cb_brkinfo; cb_brkinfo brkinfo; cb_brkinfo* oldbrkinfo = NULL; @@ -200,7 +202,7 @@ typedef struct { int pl; int32_t cp; cb_brkinfo brkinfo; -} cb_jump; +} __attribute__((aligned(sizeof(void*)))) cb_jump; cb_jump dlstack[CB_PROG_LOGIC_MAX]; bool dldcmd[CB_PROG_LOGIC_MAX]; @@ -228,7 +230,7 @@ typedef struct { int fnsp; int itsp; cb_brkinfo brkinfo; -} cb_gosub; +} __attribute__((aligned(sizeof(void*)))) cb_gosub; cb_gosub gsstack[CB_PROG_LOGIC_MAX]; int gsstackp = -1; @@ -246,12 +248,14 @@ int cury = 0; int concp = 0; int32_t cp = 0; -bool cmdint = false; -bool inprompt = false; +sig_atomic_t cmdint = false; +sig_atomic_t inprompt = false; +bool dprompt = false; bool runfile = false; bool runc = false; bool autorun = false; +bool* autorunstack = NULL; bool redirection = false; bool checknl = false; @@ -265,10 +269,16 @@ bool sh_restoreAttrib = true; cb_txt txtattrib; +#ifdef _WIN32 +static __volatile__ bool textlock = false; +#else bool textlock = false; +#endif bool sneaktextlock = false; +bool hidecursor = false; bool keep = false; +bool keepall = false; char* homepath = NULL; char* cwd = NULL; @@ -291,16 +301,18 @@ bool changedtitlecmd = false; int retval = 0; +bool hideerror = false; + typedef struct { + bool inuse; int pl; int32_t cp; - bool used; char* name; int dlsp; int fnsp; int itsp; cb_brkinfo brkinfo; -} cb_goto; +} __attribute__((aligned(sizeof(void*)))) cb_goto; cb_goto* gotodata = NULL; cb_goto** proggotodata = NULL; @@ -312,14 +324,23 @@ int filemaxct = 0; int fileerror = 0; typedef struct { + bool inuse; char* name; char* data; -} cb_sub; + uint8_t type; +} __attribute__((aligned(sizeof(void*)))) cb_sub; + +typedef struct { + bool insub; + uint8_t type; +} __attribute__((aligned(sizeof(void*)))) cb_subinfo; cb_sub* subdata = NULL; int submaxct = 0; -bool addsub = false; -int subindex = -1; +int addsub = -1; +cb_subinfo subinfo; +cb_subinfo* oldsubinfo = NULL; +char* funcret = NULL; char* rl_tmpptr = NULL; @@ -334,7 +355,7 @@ typedef struct { void (*clearGlobals)(void); void (*promptReady)(void); bool (*deinit)(void); -} cb_ext; +} __attribute__((aligned(sizeof(void*)))) cb_ext; int extmaxct = 0; cb_ext* extdata = NULL; @@ -344,9 +365,9 @@ struct termios term, restore; struct termios kbhterm, kbhterm2; struct termios initterm; -void txtqunlock() {if (textlock || sneaktextlock) {tcsetattr(0, TCSANOW, &restore); textlock = false;}} +static inline void txtqunlock() {if (textlock || sneaktextlock) {tcsetattr(0, TCSANOW, &restore); textlock = false;}} -int kbhit() { +static inline int kbhit() { int inchar; ioctl(0, FIONREAD, &inchar); return inchar; @@ -416,7 +437,7 @@ static inline void clearGlobals() { memset(&gsstack[i], 0, sizeof(cb_jump)); } for (int i = 0; i < gotomaxct; ++i) { - if (gotodata[i].used) nfree(gotodata[i].name); + if (gotodata[i].inuse) nfree(gotodata[i].name); } nfree(gotodata); gotomaxct = 0; @@ -425,6 +446,8 @@ static inline void clearGlobals() { extdata[i].clearGlobals(); } } + subinfo.insub = false; + subinfo.type = false; } static inline void promptReady() { @@ -552,7 +575,7 @@ static inline void getCurPos(); static inline char* gethome(); static inline void initBaseMem(); static inline void freeBaseMem(); -static inline void printError(int); +static inline void printError(int, char*, char*); static inline void seterrstr(char*); void unloadAllProg(); static inline char* basefilename(char*); @@ -566,26 +589,12 @@ bool unloadExt(int); void cleanExit() { txtqunlock(); - int ret; - if (inprompt) { - int i = kbhit(); - if (i) {ret = read(0, &gpbuf, i);} - getCurPos(); - unloadAllProg(); - cmdint = true; - putchar('\n'); - history_set_pos(history_length); - rl_on_new_line(); - rl_replace_line("", 0); - rl_pending_input = false; - rl_redisplay(); - return; - } setsig(SIGINT, forceExit); setsig(SIGTERM, forceExit); fflush(stdout); unloadAllProg(); closeFile(-1); + int ret; ret = chdir(gethome()); (void)ret; if (autohist && !runfile) { @@ -599,11 +608,27 @@ void cleanExit() { #if defined(CHANGE_TITLE) && !defined(_WIN_NO_VT) if (esc && changedtitle) fputs("\e[23;0t", stdout); #endif - #ifndef _WIN_NO_VT - if (esc && !keep) fputs("\e[0m", stdout); - #else - if (!keep) SetConsoleTextAttribute(hConsole, ocAttrib); - #endif + if (!keep) { + #ifndef _WIN_NO_VT + if (esc) fputs("\e[0m", stdout); + #else + SetConsoleTextAttribute(hConsole, ocAttrib); + #endif + } + if (!keepall && hidecursor) { + #ifndef _WIN_NO_VT + if (esc) { + fputs("\e[?25h", stdout); + fflush(stdout); + } + #else + CONSOLE_CURSOR_INFO curinfo; + GetConsoleCursorInfo(hConsole, &curinfo); + curinfo.bVisible = true; + SetConsoleCursorInfo(hConsole, &curinfo); + #endif + hidecursor = false; + } #ifndef _WIN32 int i = kbhit(); while (i > 0) {getchar(); i--;} @@ -624,22 +649,31 @@ void cleanExit() { nfree(vardata[i].name); } } + for (int i = 0; i < submaxct; ++i) { + if (subdata[i].inuse) { + nfree(subdata[i].data); + nfree(subdata[i].name); + } + } for (int i = 0; i < gotomaxct; ++i) { - if (gotodata[i].used) { + if (gotodata[i].inuse) { nfree(gotodata[i].name); } } - for (int i = 0; i < argct; ++i) { - nfree(arg[i]); + for (int i = 1; i < progargc; ++i) { + nfree(progargs[i]); } + free(progargs); + for (int i = 1; i < newprogargc; ++i) { + nfree(newprogargs[i]); + } + free(newprogargs); nfree(startcmd); nfree(rl_tmpptr); nfree(cmd); - nfree(arg); - nfree(argt); - nfree(argl); nfree(errstr); nfree(vardata); + nfree(subdata); if (progindex > -1) { nfree(progbuf[0]); nfree(progfn[0]); @@ -659,17 +693,32 @@ void cleanExit() { clearGlobals(); unloadExt(-1); #ifndef _WIN32 - tcsetattr(0, TCSANOW, &initterm); + if (!keepall) tcsetattr(0, TCSANOW, &initterm); #endif exit(err); } void cmdIntHndl() { - if (cmdint) setsig(SIGINT, cleanExit); + if (inprompt) { + int i = kbhit(); + int ret; + if (i) {ret = read(0, &gpbuf, i);} + (void)ret; + getCurPos(); + unloadAllProg(); + putchar('\n'); + history_set_pos(history_length); + rl_on_new_line(); + rl_replace_line("", 0); + rl_pending_input = false; + rl_redisplay(); + return; + } + if (cmdint) {setsig(SIGINT, cleanExit);} cmdint = true; } -void runcmd(); +int runcmd(); #ifdef BUILT_IN_STRING_FUNCS #define copyStr(b, a) strcpy(a, b) #define copyStrApnd(b, a) strcat(a, b) @@ -677,9 +726,9 @@ void runcmd(); static inline void copyStr(char*, char*); static inline void copyStrApnd(char*, char*); #endif -static inline void copyStrApndNoEsc(char*, char*); static inline void copyStrTo(char*, int32_t, char*); static inline void copyStrSnip(char*, int32_t, int32_t, char*); +static inline char* copyStrApndO(char* str1, char* str2); uint8_t getVal(char*, char*); static inline void resetTimer(); bool loadProg(char*); @@ -687,6 +736,7 @@ void unloadProg(); static inline void updateTxtAttrib(); static inline int isFile(); static inline uint64_t usTime(); +static inline void cb_wait(uint64_t); static inline char* gethome() { if (!homepath) { @@ -738,6 +788,78 @@ static inline void ttycheck() { if (!isatty(STDOUT_FILENO)) {fputs("CLIBASIC does not support STDOUT redirection.\n", stderr); exit(1);} } +#ifdef _WIN32 +pthread_t uctHandle; +pthread_mutex_t uctMutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutexattr_t uctMutexA; +bool uctStatus[2]; +bool uctReady = false; +void* ucThread(void* data) { + bool* status = data; + while (1) { + pthread_mutex_lock(&uctMutex); + status[1] = true; + status[0] = false; + pthread_mutex_unlock(&uctMutex); + bool l1 = true; + while (l1) { + updatechars(); + pthread_mutex_lock(&uctMutex); + if (status[0]) l1 = false; + pthread_mutex_unlock(&uctMutex); + //if (l1) cb_wait(5000); + } + pthread_mutex_lock(&uctMutex); + status[1] = false; + status[0] = false; + pthread_mutex_unlock(&uctMutex); + bool l2 = true; + while (l2) { + //cb_wait(500); + pthread_mutex_lock(&uctMutex); + if (status[0]) l2 = false; + pthread_mutex_unlock(&uctMutex); + } + } +} +void uctStart() { + if (!uctReady) return; + pthread_mutex_lock(&uctMutex); + if (uctStatus[1]) return; + uctStatus[0] = true; + pthread_mutex_unlock(&uctMutex); + bool l = true; + while (l) { + pthread_mutex_lock(&uctMutex); + if (uctStatus[1]) l = false; + pthread_mutex_unlock(&uctMutex); + //if (l) cb_wait(50); + } +} +void uctStop() { + if (!uctReady) return; + pthread_mutex_lock(&uctMutex); + if (!uctStatus[1]) return; + uctStatus[0] = true; + pthread_mutex_unlock(&uctMutex); + bool l = true; + while (l) { + pthread_mutex_lock(&uctMutex); + if (!uctStatus[1]) l = false; + pthread_mutex_unlock(&uctMutex); + //if (l) cb_wait(50); + } +} +void uctInit() { + pthread_mutex_init(&uctMutex, NULL); + pthread_mutex_init(&uctMutex, &uctMutexA); + pthread_mutex_lock(&uctMutex); + pthread_mutex_unlock(&uctMutex); + pthread_create(&uctHandle, NULL, ucThread, &uctStatus); + uctReady = true; +} +#endif + static inline void readyTerm() { ttycheck(); #ifndef _WIN32 @@ -751,6 +873,7 @@ static inline void readyTerm() { #ifndef _WIN_NO_VT enablevt(); #endif + uctInit(); #endif if (!gethome()) { #ifndef _WIN32 @@ -773,6 +896,8 @@ static inline void readyTerm() { nfree(tmpcwd); (void)ret; } + #ifdef _WIN32 + #endif } uint8_t roptptr = 1; @@ -781,6 +906,9 @@ char roptstr[16] = "-"; #define RARG() {fprintf(stderr, "Short option '%c' requires argument(s) and must be last.\n", argv[i][shortopti]);} #define IACT() {fputs("Incorrect number of arguments passed.\n", stderr);} #define IOCT() {fputs("Incorrect number of options passed.\n", stderr);} +#define OHBP() {fprintf(stderr, "Option '%c' has already been passed.\n", argv[i][shortopti]);} + +char elfsnip[6]; int main(int argc, char** argv) { bool pexit = false; @@ -804,14 +932,12 @@ int main(int argc, char** argv) { fputs("No long option following dash.\n", stderr); exit(1); } else if (!strcmp(argv[i], "--version")) { if (argc > 2) {IOCT(); exit(1);} - printf("Command Line Interface BASIC version %s (%s %s-bit) using ", VER, OSVER, BVER); + printf("Command Line Interface BASIC version %s (%s %s-bit)", VER, OSVER, BVER); #ifdef _WIN32 - fputs("Windows API calls", stdout); + fputs(" using Windows API calls", stdout); #ifndef _WIN_NO_VT fputs(" and VT escape codes", stdout); #endif - #else - fputs("VT escape codes", stdout); #endif putchar('\n'); puts("Copyright (C) 2021 PQCraft"); @@ -819,13 +945,14 @@ int main(int argc, char** argv) { pexit = true; } else if (!strcmp(argv[i], "--help")) { if (argc > 2) {IOCT(); exit(1);} - printf("Usage: %s [[-x] FILE [ARG]...]\n", argv[0]); + printf("Usage: %s [OPTIONS]... [[-x] FILE [ARG]...]\n", argv[0]); puts("Options:"); puts(" --help Displays the usage and option information."); puts(" --version Displays the version and license information."); puts(" -x, --exec FILE [ARG]... Runs FILE and passes ARGs to FILE."); puts(" -c, --command COMMAND Runs COMMAND as if in shell mode."); - puts(" -k, --keep Stops CLIBASIC from resetting text attributes when exiting."); + puts(" -k, --keep Stops the text attributes from being reset."); + puts(" -K, --keep-all Stops the text attributes and terminal state from being reset."); puts(" -s, --skip Skips searching for autorun programs."); puts(" -i, --info Displays an info string when starting in shell mode."); puts(" -r, --redirection Allows for redirection (this may cause issues)."); @@ -836,60 +963,64 @@ int main(int argc, char** argv) { } else if (!strcmp(argv[i], "--exec") || (shortopt && argv[i][shortopti] == 'x')) { if (shortopt && argv[i][shortopti + 1]) {RARG(); exit(1);} if (runc) {fputs("Cannot run command and file.\n", stderr); exit(1);} - if (runfile) {unloadProg(); IOCT(); exit(1);} - ++i; - if (!argv[i]) {fputs("No filename provided.\n", stderr); exit(1);} + if (runfile) {unloadProg(); OHBP(); exit(1);} + if (!argv[++i]) {IACT(); exit(1);} argslater = true; - if (!loadProg(argv[i])) {printError(cerr); exit(1);} + if (!loadProg(argv[i])) {printError(cerr, NULL, NULL); exit(1);} inProg = true; runfile = true; progargs = (char**)malloc((argc - i) * sizeof(char*)); for (progargc = 1; progargc < argc - i; ++progargc) { - progargs[progargc] = malloc(strlen(argv[i + progargc]) + 1); - copyStr(argv[i + progargc], progargs[progargc]); + progargs[progargc] = strdup(argv[i + progargc]); } i = argc; } else if (!strcmp(argv[i], "--keep") || (shortopt && argv[i][shortopti] == 'k')) { - if (keep) {IOCT(); exit(1);} + if (keep) {OHBP(); exit(1);} keep = true; roptstr[roptptr++] = 'k'; if (shortopt) goto chkshortopt; + } else if (!strcmp(argv[i], "--keep-all") || (shortopt && argv[i][shortopti] == 'K')) { + if (keepall) {OHBP(); exit(1);} + keep = true; + keepall = true; + roptstr[roptptr++] = 'K'; + if (shortopt) goto chkshortopt; } else if (!strcmp(argv[i], "--skip") || (shortopt && argv[i][shortopti] == 's')) { - if (skip) {IOCT(); exit(1);} + if (skip) {OHBP(); exit(1);} skip = true; roptstr[roptptr++] = 's'; if (shortopt) goto chkshortopt; } else if (!strcmp(argv[i], "--info") || (shortopt && argv[i][shortopti] == 'i')) { - if (info) {IOCT(); exit(1);} + if (info) {OHBP(); exit(1);} info = true; roptstr[roptptr++] = 'i'; if (shortopt) goto chkshortopt; } else if (!strcmp(argv[i], "--redirection") || (shortopt && argv[i][shortopti] == 'r')) { - if (redirection) {IOCT(); exit(1);} + if (redirection) {OHBP(); exit(1);} redirection = true; roptstr[roptptr++] = 'r'; if (shortopt) goto chkshortopt; } else if (!strcmp(argv[i], "--newline") || (shortopt && argv[i][shortopti] == 'n')) { - if (checknl) {IOCT(); exit(1);} + if (checknl) {OHBP(); exit(1);} checknl = true; roptstr[roptptr++] = 'n'; if (shortopt) goto chkshortopt; } else if (!strcmp(argv[i], "--no-escapes") || (shortopt && argv[i][shortopti] == 'e')) { - if (!esc) {IOCT(); exit(1);} + if (!esc) {OHBP(); exit(1);} esc = false; roptstr[roptptr++] = 'e'; if (shortopt) goto chkshortopt; } else if (!strcmp(argv[i], "--no-curpos") || (shortopt && argv[i][shortopti] == 'p')) { - if (!cpos) {IOCT(); exit(1);} + if (!cpos) {OHBP(); exit(1);} cpos = false; roptstr[roptptr++] = 'p'; if (shortopt) goto chkshortopt; } else if (!strcmp(argv[i], "--command") || (shortopt && argv[i][shortopti] == 'c')) { if (shortopt && argv[i][shortopti + 1]) {RARG(); exit(1);} if (runfile) {fputs("Cannot run file and command.\n", stderr); exit(1);} - if (runc) {IOCT(); exit(1);} + if (runc) {OHBP(); exit(1);} i++; - if (!argv[i]) {fputs( "No command provided.\n", stderr); exit(1);} + if (!argv[i]) {IACT(); exit(1);} runc = true; runfile = true; copyStr(argv[i], conbuf); @@ -902,16 +1033,15 @@ int main(int argc, char** argv) { } } else { if (runc) {fputs("Cannot run command and file.\n", stderr); exit(1);} - if (runfile) {unloadProg(); IOCT(); exit(1);} - if (!argv[i]) {fputs("No filename provided.\n", stderr); exit(1);} + if (runfile) {unloadProg(); OHBP(); exit(1);} + if (!argv[i]) {IACT(); exit(1);} argslater = true; - if (!loadProg(argv[i])) {printError(cerr); exit(1);} + if (!loadProg(argv[i])) {printError(cerr, NULL, NULL); exit(1);} inProg = true; runfile = true; progargs = (char**)malloc((argc - i) * sizeof(char*)); for (progargc = 1; progargc < argc - i; ++progargc) { - progargs[progargc] = malloc(strlen(argv[i + progargc]) + 1); - copyStr(argv[i + progargc], progargs[progargc]); + progargs[progargc] = strdup(argv[i + progargc]); } i = argc; } @@ -1023,10 +1153,8 @@ int main(int argc, char** argv) { #endif #endif } - cmd = NULL; - argt = NULL; - arg = NULL; - srand(usTime()); + cmd = (char*)malloc(CB_BUF_SIZE); + srand(usTime() + clock()); if (!runfile && gethome()) { char* tmpcwd = getcwd(NULL, 0); int ret = chdir(homepath); @@ -1053,6 +1181,7 @@ int main(int argc, char** argv) { cp = 0; if (chkinProg) {inProg = true; chkinProg = false;} if (!inProg && !runc) { + cmdint = false; if (runfile) cleanExit(); clearGlobals(); promptReady(); @@ -1075,19 +1204,22 @@ int main(int argc, char** argv) { if (curx > 1) putchar('\n'); #endif updateTxtAttrib(); - inprompt = true; #ifdef _WIN32 setsig(SIGINT, rl_sigh); #endif conbuf[0] = 0; - #ifndef _WIN32 - setsig(SIGINT, cleanExit); - #endif txtqunlock(); + #ifdef _WIN32 + uctStop(); + #endif + inprompt = true; tmpstr = readline(pstr); + inprompt = false; + #ifdef _WIN32 + uctStart(); + #endif updateTxtAttrib(); concp = 0; - inprompt = false; if (!tmpstr) {err = 0; cleanExit();} int32_t tmpptr; if (tmpstr[0] == 0) {nfree(tmpstr); goto brkproccmd;} @@ -1109,7 +1241,6 @@ int main(int argc, char** argv) { if (strcmp(tmpstr, cmpstr)) {add_history(tmpstr); copyStr(tmpstr, cmpstr);} copyStr(tmpstr, conbuf); nfree(tmpstr); - cmdint = false; } if (runc) runc = false; cmdl = 0; @@ -1131,12 +1262,11 @@ int main(int argc, char** argv) { } if (lockpl) lockpl = false; while (progbuf[progindex][cp - cmdl] == ' ' && cmdl > 0) {cmdl--;} - cmd = (char*)realloc(cmd, cmdl + 1); cmdpos = cp - cmdl; copyStrSnip(progbuf[progindex], cp - cmdl, cp, cmd); cmdl = 0; - runcmd(); - if (cmdint) {inProg = false; unloadAllProg(); cmdint = false; goto brkproccmd;} + if (cmdint) {inProg = false; unloadAllProg(); txtqunlock(); goto brkproccmd;} + if (runcmd(cmd)) {cp = -1; concp = -1; chkinProg = inProg = false;} if (cp == -1) {inProg = false; unloadAllProg(); goto brkproccmd;} if (cp > -1 && progbuf[progindex][cp] == 0) { unloadProg(); @@ -1158,12 +1288,11 @@ int main(int argc, char** argv) { if (conbuf[concp] == '"') {inStr = !inStr; cmdl++;} else if ((conbuf[concp] == ':' && !inStr) || conbuf[concp] == 0) { while (conbuf[concp - cmdl] == ' ' && cmdl > 0) {cmdl--;} - cmd = (char*)realloc(cmd, cmdl + 1); cmdpos = concp - cmdl; copyStrSnip(conbuf, concp - cmdl, concp, cmd); cmdl = 0; - runcmd(); - if (cmdint) {txtqunlock(); cmdint = false; goto brkproccmd;} + if (cmdint) {runc = false; unloadAllProg(); txtqunlock(); goto brkproccmd;} + if (runcmd(cmd)) {cp = -1; concp = -1; chkinProg = inProg = false;} if (concp == -1) goto brkproccmd; if (concp > -1 && conbuf[concp] == 0) { goto brkproccmd; @@ -1175,9 +1304,6 @@ int main(int argc, char** argv) { } } brkproccmd:; - #ifndef _WIN32 - setsig(SIGINT, cleanExit); - #endif txtqunlock(); } txtqunlock(); @@ -1206,9 +1332,7 @@ static inline void cb_wait(uint64_t d) { nanosleep(&dts, NULL); #else uint64_t t = d + usTime(); - while (t > usTime() && !cmdint) { - if (!(usTime() % 5000))updatechars(); - } + while (t > usTime() && !cmdint) {} #endif } @@ -1295,15 +1419,17 @@ void unloadProg() { progfn = (char**)realloc(progfn, progindex * sizeof(char*)); progbuf = (char**)realloc(progbuf, progindex * sizeof(char*)); for (int i = 0; i < gotomaxct; ++i) { - if (gotodata[i].used) nfree(gotodata[i].name); + if (gotodata[i].inuse) nfree(gotodata[i].name); } nfree(gotodata); gotodata = proggotodata[progindex]; gotomaxct = proggotomaxct[progindex]; + if (!subinfo.insub && autorun) autorun = false; cp = progcp[progindex]; cmdl = progcmdl[progindex]; progLine = proglinebuf[progindex]; brkinfo = oldbrkinfo[progindex]; + subinfo = oldsubinfo[progindex]; dlstackp = mindlstackp[progindex]; itstackp = minitstackp[progindex]; fnstackp = minfnstackp[progindex]; @@ -1314,44 +1440,21 @@ void unloadProg() { minitstackp = (int*)realloc(minitstackp, progindex * sizeof(int)); minfnstackp = (int*)realloc(minfnstackp, progindex * sizeof(int)); oldbrkinfo = (cb_brkinfo*)realloc(oldbrkinfo, progindex * sizeof(cb_brkinfo)); + oldsubinfo = (cb_subinfo*)realloc(oldsubinfo, progindex * sizeof(cb_subinfo)); proggotodata = (cb_goto**)realloc(proggotodata, progindex * sizeof(cb_goto*)); proggotomaxct = (int*)realloc(proggotomaxct, progindex * sizeof(int)); progindex--; if (progindex < 0) inProg = false; - if (autorun) autorun = false; } void unloadAllProg() { for (int i = 0; i <= progindex; ++i) { unloadProg(); } + inProg = false; } -bool loadProg(char* filename) { - #if defined(_WIN32) && !defined(_WIN_NO_VT) - enablevt(); - #endif - retval = 0; - seterrstr(filename); - cerr = 27; - FILE* prog = fopen(filename, "r"); - if (!prog) { - if (errno == ENOENT) cerr = 15; - return false; - } - if (!isFile(filename)) { - fclose(prog); - cerr = 18; - return false; - } - ++progindex; - fseek(prog, 0, SEEK_END); - progfn = (char**)realloc(progfn, (progindex + 1) * sizeof(char*)); - #ifdef _WIN32 - progfn[progindex] = _fullpath(NULL, filename, CB_BUF_SIZE); - #else - progfn[progindex] = realpath(filename, NULL); - #endif +void prepProgData() { ++progindex; progbuf = (char**)realloc(progbuf, progindex * sizeof(char*)); progcp = (int32_t*)realloc(progcp, progindex * sizeof(int32_t)); @@ -1360,6 +1463,7 @@ bool loadProg(char* filename) { mindlstackp = (int*)realloc(mindlstackp, progindex * sizeof(int)); minitstackp = (int*)realloc(minitstackp, progindex * sizeof(int)); oldbrkinfo = (cb_brkinfo*)realloc(oldbrkinfo, progindex * sizeof(cb_brkinfo)); + oldsubinfo = (cb_subinfo*)realloc(oldsubinfo, progindex * sizeof(cb_subinfo)); minfnstackp = (int*)realloc(minfnstackp, progindex * sizeof(int)); proggotodata = (cb_goto**)realloc(proggotodata, progindex * sizeof(cb_goto*)); proggotomaxct = (int*)realloc(proggotomaxct, progindex * sizeof(int)); @@ -1372,6 +1476,7 @@ bool loadProg(char* filename) { mindlstackp[progindex] = dlstackp; minitstackp[progindex] = itstackp; oldbrkinfo[progindex] = brkinfo; + oldsubinfo[progindex] = subinfo; minfnstackp[progindex] = fnstackp; proggotodata[progindex] = gotodata; proggotomaxct[progindex] = gotomaxct; @@ -1383,6 +1488,68 @@ bool loadProg(char* filename) { cmdl = 0; progLine = 1; memset(&brkinfo, 0, sizeof(brkinfo)); + memset(&subinfo, 0, sizeof(subinfo)); +} + +bool loadSub(char* name, bool func, uint8_t* type) { + upCase(name); + seterrstr(name); + int s = -1; + for (int i = 0; i < submaxct; ++i) { + if (subdata[i].inuse && !strcmp(subdata[i].name, name)) {s = i; break;} + } + if (s == -1) {cerr = 37; return false;} + uint8_t ntype = 0; + if (func) { + if (!subdata[s].type) {cerr = 2; return false;} + ntype = subdata[s].type; + } else { + if (subdata[s].type) {cerr = 2; return false;} + } + ++progindex; + prepProgData(); + if (func) *type = ntype; + progfn = (char**)realloc(progfn, (progindex + 1) * sizeof(char*)); + progfn[progindex] = strdup(name); + progbuf[progindex] = strdup(subdata[s].data); + if (argslater) { + argslater = false; + } else { + progargc = newprogargc; + newprogargc = 0; + progargs = newprogargs; + newprogargs = NULL; + } + return true; +} + +bool loadProg(char* filename) { + #if defined(_WIN32) && !defined(_WIN_NO_VT) + enablevt(); + #endif + retval = 0; + seterrstr(filename); + cerr = 27; + FILE* prog = fopen(filename, "r"); + if (!prog) { + if (errno == ENOENT) cerr = 15; + return false; + } + if (!isFile(filename)) { + fclose(prog); + cerr = 18; + return false; + } + cerr = 0; + ++progindex; + fseek(prog, 0, SEEK_END); + progfn = (char**)realloc(progfn, (progindex + 1) * sizeof(char*)); + #ifdef _WIN32 + progfn[progindex] = _fullpath(NULL, filename, CB_BUF_SIZE); + #else + progfn[progindex] = realpath(filename, NULL); + #endif + prepProgData(); if (argslater) { argslater = false; } else { @@ -1413,9 +1580,9 @@ bool loadProg(char* filename) { return true; } -static inline double randNum(double num1, double num2) { - double range = num2 - num1; - double div = RAND_MAX / range; +static inline long double randNum(long double num1, long double num2) { + long double range = num2 - num1; + long double div = RAND_MAX / range; return num1 + (rand() / div); } @@ -1535,20 +1702,23 @@ static inline void copyStrApnd(char* str1, char* str2) { } #endif -static inline void copyStrApndQ(char* str1, char* str2) { +#ifdef _WIN32 +static inline void copyStrWinApnd(char* str1, char* str2) { + bool spc = (*str2); while (*str2) {++str2;} + if (spc) *str2++ = ' '; *str2++ = '"'; - for (; *str1; ++str1, ++str2) {*str2 = *str1;} + for (; *str1; ++str1, ++str2) {if (*str1 == '\\' || *str1 == '"') {*str2++ = '\\';} *str2 = *str1;} *str2++ = '"'; *str2 = 0; } -static inline void copyStrApndNoEsc(char* str1, char* str2) { +#endif + +static inline char* copyStrApndO(char* str1, char* str2) { while (*str2) {++str2;} - for (; *str1; ++str1, ++str2) { - if ((*str2 = *str1) == '\\') {*str2 = '\\';} - if (*str1 == '\'') {*str2 = '\\'; *++str2 = '\'';} - } + for (; *str1; ++str1, ++str2) {*str2 = *str1;} *str2 = 0; + return str2; } static inline void copyStrSnip(char* str1, int32_t i, int32_t j, char* str2) { @@ -1594,6 +1764,67 @@ static inline void seterrstr(char* newstr) { copyStr(newstr, errstr); } +#ifndef _WIN32 +typedef pid_t cb_exec_async_t; +#else +typedef HANDLE cb_exec_async_t; +char* cb_exec_async_buf = NULL; +#endif + +static inline cb_exec_async_t cb_exec_async(char** args) { + #ifndef _WIN32 + static bool exec_failed = false; + exec_failed = false; + pid_t pid = vfork(); + if (pid == 0) { + execvp(args[0], args); + exec_failed = true; + exit(127); + } else if (pid > 0) { + if (!exec_failed) return pid; + } + return 0; + #else + if (!cb_exec_async_buf) cb_exec_async_buf = malloc(CB_BUF_SIZE); + *cb_exec_async_buf = 0; + for (; *args; ++args) { + copyStrWinApnd(*args, cb_exec_async_buf); + } + STARTUPINFO si; + PROCESS_INFORMATION pi; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + memset(&pi, 0, sizeof(pi)); + if (!CreateProcess(NULL, cb_exec_async_buf, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) return NULL; + else return pi.hProcess; + #endif +} + +static inline int16_t cb_exec(char** args) { + #ifndef _WIN32 + pid_t pid = 0; + if ((pid = cb_exec_async(args))) { + int ecode = 0; + while (wait(&ecode) != pid) {} + return WEXITSTATUS(ecode); + } + return -1; + #else + HANDLE pid = NULL; + uctStop(); + if ((pid = cb_exec_async(args))) { + WaitForSingleObject(pid, INFINITE); + DWORD tmpret; + int ret = GetExitCodeProcess(pid, (LPDWORD)&tmpret); + (void)ret; + uctStart(); + return tmpret & 0xFF; + } + uctStart(); + return -1; + #endif +} + static inline void updateTxtAttrib() { #ifndef _WIN_NO_VT if (!esc) return; @@ -1621,19 +1852,10 @@ static inline void updateTxtAttrib() { #else uint8_t tmpfgc, tmpbgc; if (txtattrib.truecolor) { - uint8_t a; - tmpfgc = (((txtattrib.truefgc >> 23) & 1) << 2) | (((txtattrib.truefgc >> 15) & 1) << 1) | ((txtattrib.truefgc >> 7) & 1); - tmpfgc |= ((((txtattrib.truefgc >> 22) & 1) & ((txtattrib.truefgc >> 21) & 1)) << 2)\ - | ((((txtattrib.truefgc >> 14) & 1) & ((txtattrib.truefgc >> 13) & 1)) << 1)\ - | (((txtattrib.truefgc >> 6) & 1) & ((txtattrib.truefgc >> 5) & 1)); - a = ((((txtattrib.truefgc >> 16) & 0xFF) + ((txtattrib.truefgc >> 8) & 0xFF) + (txtattrib.truefgc & 0xFF)) / 3); - tmpfgc |= (8 * (a > 84)); - tmpbgc = (((txtattrib.truebgc >> 23) & 1) << 2) | (((txtattrib.truebgc >> 15) & 1) << 1) | ((txtattrib.truebgc >> 7) & 1); - tmpbgc |= ((((txtattrib.truebgc >> 22) & 1) & ((txtattrib.truebgc >> 21) & 1)) << 2)\ - | ((((txtattrib.truebgc >> 14) & 1) & ((txtattrib.truebgc >> 13) & 1)) << 1)\ - | (((txtattrib.truebgc >> 6) & 1) & ((txtattrib.truebgc >> 5) & 1)); - a = ((((txtattrib.truebgc >> 16) & 0xFF) + ((txtattrib.truebgc >> 8) & 0xFF) + (txtattrib.truebgc & 0xFF)) / 3); - tmpbgc |= (8 * (a > 84)); + tmpfgc = ((((txtattrib.truefgc >> 16) & 0xFF) > 85) << 2 | (((txtattrib.truefgc >> 8) & 0xFF) > 85) << 1 | ((txtattrib.truefgc & 0xFF) > 85))\ + | (((txtattrib.truefgc >> 16) & 0xFF) > 170 || ((txtattrib.truefgc >> 8) & 0xFF) > 170 || (txtattrib.truefgc & 0xFF) > 170) << 3; + tmpbgc = ((((txtattrib.truebgc >> 16) & 0xFF) > 85) << 2 | (((txtattrib.truebgc >> 8) & 0xFF) > 85) << 1 | ((txtattrib.truebgc & 0xFF) > 85))\ + | (((txtattrib.truebgc >> 16) & 0xFF) > 170 || ((txtattrib.truebgc >> 8) & 0xFF) > 170 || (txtattrib.truebgc & 0xFF) > 170) << 3; } else { uint8_t b1 = 0, b2 = 0; b1 = txtattrib.fgc & 1; b2 = (txtattrib.fgc >> 2) & 1; tmpfgc = (b1 ^ b2); @@ -1641,9 +1863,11 @@ static inline void updateTxtAttrib() { b1 = txtattrib.bgc & 1; b2 = (txtattrib.bgc >> 2) & 1; tmpbgc = (b1 ^ b2); tmpbgc = (tmpbgc) | (tmpbgc << 2); tmpbgc = txtattrib.bgc ^ tmpbgc; } - if (txtattrib.dim) {tmpfgc %= 8; tmpbgc %= 8;} + if (!txtattrib.truecolor && txtattrib.dim) {tmpfgc %= 8; tmpbgc %= 8;} if (txtattrib.reverse) swap(tmpfgc, tmpbgc); - SetConsoleTextAttribute(hConsole, (tmpfgc % 16) + ((tmpbgc % 16) << 4)); + if (!txtattrib.fgce) tmpfgc = (ocAttrib & 0b11110000); + if (!txtattrib.bgce) tmpbgc = (ocAttrib & 0b00001111) >> 4; + SetConsoleTextAttribute(hConsole, (tmpfgc % 16) | ((tmpbgc % 16) << 4)); #endif fflush(stdout); } @@ -1809,7 +2033,7 @@ uint8_t getFunc(char* inbuf, char* outbuf) { outbuf[0] = '0' + ret; outbuf[1] = 0; goto fexit; - } else if (!strcmp(farg[0], "EXECA") || !strcmp(farg[0], "EXECA$")) { + } else if (!strcmp(farg[0], "EXECA") || !strcmp(farg[0], "EXECA$") || !strcmp(farg[0], "CALLFUNC")) { skipfargsolve = true; } } @@ -2013,8 +2237,7 @@ bool setVar(char* vn, char* val, uint8_t t, int32_t s) { if (s == -1) s = 0; vardata[v].data = (char**)malloc((s + 1) * sizeof(char*)); for (int32_t i = 0; i <= s; ++i) { - vardata[v].data[i] = (char*)malloc(strlen(val) + 1); - copyStr(val, vardata[v].data[i]); + vardata[v].data[i] = strdup(val); } } else { if (s != -1) {cerr = 25; return false;} @@ -2066,7 +2289,7 @@ bool delVar(char* vn) { } nfree(vardata[v].data); if (v == varmaxct - 1) { - while (!vardata[v].inuse && v >= 0) {varmaxct--; v--;} + while (v >= 0 && !vardata[v].inuse) {varmaxct--; v--;} vardata = (cb_var*)realloc(vardata, varmaxct * sizeof(cb_var)); } } @@ -2135,327 +2358,195 @@ bool closeFile(int num) { return true; } -static inline bool gvchkchar(char* tmp, int32_t i) { - if (isSpChar(tmp[i + 1])) { - if (tmp[i + 1] == '-') { - if (isSpChar(tmp[i + 2])) { - cerr = 1; return false; - } - } else { - cerr = 1; return false; - } - } else { - if (i > 0 && isSpChar(tmp[i - 1])) { - cerr = 1; return false; - } - } - return true; -} - uint16_t getValIndex = 0; -char* getVal_tmp[4] = {NULL, NULL, NULL, NULL}; +char* getVal_tmp[4] = {NULL, NULL}; + +typedef struct { + char act; + bool neg; + char* data; + long double ndata; +} __attribute__((aligned(sizeof(void*)))) cb_gvtoken; + +cb_gvtoken token[256]; uint8_t getVal(char* inbuf, char* outbuf) { if (inbuf[0] == 0) {return 255;} - char* tmp[4]; + //printf("getVal[%d]: in: {%s}\n", getValIndex, inbuf); uint64_t starttime = usTime(); + char* tmp[2]; if (getValIndex) { tmp[0] = malloc(CB_BUF_SIZE); tmp[1] = malloc(CB_BUF_SIZE); - tmp[2] = malloc(CB_BUF_SIZE); - tmp[3] = malloc(CB_BUF_SIZE); } else { tmp[0] = getVal_tmp[0]; tmp[1] = getVal_tmp[1]; - tmp[2] = getVal_tmp[2]; - tmp[3] = getVal_tmp[3]; } getValIndex++; - int32_t ip = 0, jp = 0; - uint8_t t = 0; - uint8_t dt = 0; - bool inStr = false; - register double num1 = 0; - register double num2 = 0; - register double num3 = 0; - int numAct; - bool* seenStr = NULL; - if ((isSpChar(inbuf[0]) && inbuf[0] != '-') || isSpChar(inbuf[strlen(inbuf) - 1])) {cerr = 1; dt = 0; goto gvreturn;} + char* ip = NULL, * jp = NULL; int pct = 0, bct = 0; - tmp[0][0] = 0; tmp[1][0] = 0; tmp[2][0] = 0; tmp[3][0] = 0; + uint8_t t = 0, dt = 0; + bool* seenStr = NULL; + bool inStr = false; seenStr = malloc(sizeof(bool)); seenStr[0] = false; - for (register int32_t i = 0; inbuf[i]; ++i) { - switch (inbuf[i]) { - default:; - if (inStr) break; - if (inbuf[i] == ',' || isSpChar(inbuf[i])) seenStr[pct] = false; - break; - case '&':; - if (!inStr && pct > 0) seenStr[pct] = false; - break; - case '|':; - if (!inStr && pct > 0) seenStr[pct] = false; - break; - case '"':; - inStr = !inStr; - if (inStr && seenStr[pct]) { - dt = 0; - cerr = 1; - goto gvreturn; - } - seenStr[pct] = true; - break; - case '(':; - if (inStr) break; - if (pct == 0) {ip = i;} - pct++; - seenStr = (bool*)realloc(seenStr, (pct + 1) * sizeof(bool)); - seenStr[pct] = false; - break; - case ')':; - if (inStr) break; - pct--; - if (pct == 0 && (ip == 0 || isSpChar(inbuf[ip - 1]))) { - int32_t tmplen[2]; - tmplen[0] = strlen(inbuf); - jp = i; - copyStrSnip(inbuf, ip + 1, jp, tmp[0]); - t = getVal(tmp[0], tmp[0]); - if (t == 0) {dt = 0; goto gvreturn;} - if (dt == 0) dt = t; - if (t == 255) {t = 1; dt = 1;} - if (t != dt) {cerr = 2; dt = 0; goto gvreturn;} - copyStrFrom(inbuf, jp + 1, tmp[1]); - inbuf[ip] = 0; - if (t == 1) copyStrApndQ(tmp[0], inbuf); - else copyStrApnd(tmp[0], inbuf); - copyStrApnd(tmp[1], inbuf); - tmp[0][0] = 0; tmp[1][0] = 0; tmp[2][0] = 0; tmp[3][0] = 0; - tmplen[1] = strlen(inbuf); - i -= tmplen[0] - tmplen[1]; + cb_gvtoken* token = NULL; + tmp[0][0] = '+'; tmp[0][1] = 0; tmp[1][0] = 0; + int tokens = 0; + bool mtoken = false; + if (isSpChar(*inbuf) && *inbuf != '-') {cerr = 1; dt = 0; goto gvreturn;} + char* t1, * t2; + uint8_t sawSpChar = 0; + //printf("getVal[%d]: block 0: time: [%ld]\n", getValIndex - 1, usTime() - starttime); starttime = usTime(); + for (t1 = inbuf, t2 = tmp[0]; *t1; ++t1) { + if (!pct && !bct && !inStr) { + if (isSpChar(*t2)) { + if (*t2 == '-' && sawSpChar) { + if (sawSpChar > 1) {dt = 0; cerr = 1; goto gvreturn;} + } else if (isSpChar(*t2) && sawSpChar) { + dt = 0; cerr = 1; goto gvreturn; + } else { + ++tokens; } - break; - case '[':; - if (inStr) break; - bct++; - break; - case ']':; - if (inStr) break; - bct--; - break; + ++sawSpChar; + } else { + sawSpChar = 0; + } + } + *(++t2) = *t1; + switch (*t1) { + default:; if (inStr) break; if (*t1 == ',' || isSpChar(*t1)) seenStr[pct] = false; break; + case '&':; if (!inStr && pct > 0) seenStr[pct] = false; break; + case '|':; if (!inStr && pct > 0) seenStr[pct] = false; break; + case '"':; if (pct || bct) break; inStr = !inStr; if (inStr && seenStr[pct]) {dt = 0; cerr = 1; goto gvreturn;} seenStr[pct] = true; break; + case '(':; if (inStr) break; ++pct; seenStr = (bool*)realloc(seenStr, (pct + 1) * sizeof(bool)); seenStr[pct] = false; break; + case ')':; if (inStr) break; --pct; break; + case '[':; if (inStr) break; ++bct; break; + case ']':; if (inStr) break; --bct; break; } } - if (pct || bct) {cerr = 1; dt = 0; goto gvreturn;} - ip = 0; jp = 0; - tmp[0][0] = 0; tmp[1][0] = 0; tmp[2][0] = 0; tmp[3][0] = 0; - while (1) { - pct = 0; - bct = 0; - while (inbuf[jp]) { - if (inbuf[jp] == '"') inStr = !inStr; - if (!inStr) { - switch (inbuf[jp]) { - case '(': pct++; break; - case ')': pct--; break; - case '[': bct++; break; - case ']': bct--; break; - default:; - if ((inbuf[jp] != '-' || jp > 0) && isSpChar(inbuf[jp]) && !pct && !bct) goto gvwhileexit1; - break; - } - } - jp++; - } - gvwhileexit1:; - if (inStr) {dt = 0; cerr = 1; goto gvreturn;} - copyStrSnip(inbuf, ip, jp, tmp[0]); - t = getType(tmp[0]); - if (t == 1) getStr(tmp[0], tmp[0]); - if (t == 255) { - t = getVar(tmp[0], tmp[0]); - if (t == 0) {dt = 0; dt = 0; goto gvreturn;} - if (t == 1) { - tmp[3][0] = 0; - copyStrApndQ(tmp[0], tmp[3]); - swap(tmp[0], tmp[3]); - } + if (pct || bct || inStr) {cerr = 1; dt = 0; goto gvreturn;} + if (isSpChar(*t2)) {cerr = 1; dt = 0; goto gvreturn;} + *++t2 = 0; + //printf("getVal[%d]: block 1: time: [%ld]\n", getValIndex - 1, usTime() - starttime); starttime = usTime(); + //printf("tokens: [%d]\n", tokens); + token = malloc(tokens * sizeof(cb_gvtoken)); + mtoken = true; + for (int i = 0; i < tokens; ++i) { + memset(&token[i], 0, sizeof(cb_gvtoken)); + } + int curtkn = 0; + for (t1 = tmp[0]; *t1; ++t1) { + switch (*t1) { + case '"':; if (pct || bct) break; inStr = !inStr; break; + case '(':; if (inStr) break; ++pct; break; + case ')':; if (inStr) break; --pct; break; + case '[':; if (inStr) break; ++bct; break; + case ']':; if (inStr) break; --bct; break; } - if (t && dt == 0) {dt = t;} else - if ((t && t != dt)) {cerr = 2; dt = 0; goto gvreturn;} else - if (t == 0) {cerr = 1; dt = 0; goto gvreturn;} - if ((dt == 1 && inbuf[jp] != '+') && inbuf[jp]) {cerr = 1; dt = 0; goto gvreturn;} - if (t == 1) {copyStrSnip(tmp[0], 1, strlen(tmp[0]) - 1, tmp[2]); copyStrApnd(tmp[2], tmp[1]);} else - if (t == 2) { - if (inbuf[jp - 1]) copyStrFrom(inbuf, jp, tmp[1]); - else tmp[1][0] = 0; - copyStrApnd(tmp[1], tmp[0]); - register int32_t p1, p2, p3; - bool inStr = false; - pct = 0; - bct = 0; - while (1) { - numAct = 0; - p1 = 0, p2 = 0, p3 = 0; - for (register int32_t i = 0; tmp[0][i]; ++i) { - switch (tmp[0][i]) { - case '"': if (!pct && !bct) inStr = !inStr; break; - case '(': pct++; break; - case ')': pct--; break; - case '[': bct++; break; - case ']': bct--; break; - case '^':; - if (!inStr && !pct && !bct) { - if (!gvchkchar(tmp[0], i)) {dt = 0; goto gvreturn;} - p2 = i; numAct = 4; - if (p2) goto foundact; - } - break; - } - } - for (register int32_t i = 0; tmp[0][i]; ++i) { - switch (tmp[0][i]) { - case '"': if (!pct && !bct) inStr = !inStr; break; - case '(': pct++; break; - case ')': pct--; break; - case '[': bct++; break; - case ']': bct--; break; - case '*':; - if (!inStr && !pct && !bct) { - if (!gvchkchar(tmp[0], i)) {dt = 0; goto gvreturn;} - p2 = i; numAct = 2; - if (p2) goto foundact; - } - break; - case '/':; - if (!inStr && !pct && !bct) { - if (!gvchkchar(tmp[0], i)) {dt = 0; goto gvreturn;} - p2 = i; numAct = 3; - if (p2) goto foundact; - } - break; - } - } - for (register int32_t i = 0; tmp[0][i]; ++i) { - switch (tmp[0][i]) { - case '"': if (!pct && !bct) inStr = !inStr; break; - case '(': pct++; break; - case ')': pct--; break; - case '[': bct++; break; - case ']': bct--; break; - case '+':; - if (!inStr && !pct && !bct) { - if (!gvchkchar(tmp[0], i)) {dt = 0; goto gvreturn;} - p2 = i; numAct = 0; - if (p2) goto foundact; - } - break; - case '-':; - if (!inStr && !pct && !bct) { - if (!gvchkchar(tmp[0], i)) {dt = 0; goto gvreturn;} - p2 = i; numAct = 1; - if (p2) goto foundact; - } - break; - } + if (!pct && !bct && !inStr) { + if (isSpChar(*t1)) { + if (!(*t1 == '-' && sawSpChar)) { + ip = t1; } - foundact:; - inStr = false; - pct = 0; - bct = 0; - if (p2 == 0) { - if (p3 == 0) { - t = getType(tmp[0]); - if (t == 0) {cerr = 1; dt = 0; goto gvreturn;} else - if (t == 255) { - t = getVar(tmp[0], tmp[0]); - if (t == 0) {dt = 0; goto gvreturn;} - if (t == 255) {t = 2; tmp[0][0] = '0'; tmp[0][1] = 0;} - if (t != 2) {cerr = 2; dt = 0; goto gvreturn;} - } - } - swap(tmp[0], tmp[1]); - goto gvfexit; - } - tmp[1][0] = 0; tmp[2][0] = 0; tmp[3][0] = 0; - for (register int32_t i = p2 - 1; i > 0; --i) { - if (!pct && !bct && tmp[0][i] == '"') inStr = !inStr; - if (!inStr) { - switch (tmp[0][i]) { - case '(': pct++; break; - case ')': pct--; break; - case '[': bct++; break; - case ']': bct--; break; - default:; - if (isSpChar(tmp[0][i]) && !inStr && !pct && !bct) {p1 = i; goto gvforexit1;} - break; - } + ++sawSpChar; + } else { + sawSpChar = 0; + if (isSpChar(*(t1 + 1)) || (!*(t1 + 1))) { + jp = t1 + 1; + token[curtkn].act = *(ip++); + if (token[curtkn].act == '+' && *ip == '-') {++ip; token[curtkn].act = '-';} + bool q = true; + if (*ip == '(') { + copyStrTo(ip + 1, jp - ip - 2, tmp[1]); + t = getVal(tmp[1], tmp[1]); + if (!t) {dt = 0; goto gvreturn;} + if (t == 255) {dt = 0; cerr = 1; goto gvreturn;} + if (!dt) dt = t; + else if (t != dt) {dt = 0; cerr = 2; goto gvreturn;} + q = false; + } else { + copyStrTo(ip, jp - ip, tmp[1]); + t = getType(tmp[1]); + if (!t) {dt = 0; cerr = 1; goto gvreturn;} + if (t == 255) {t = getVar(tmp[1], tmp[1]); q = false;} + if (!t) {dt = 0; goto gvreturn;} + if (!dt) dt = t; + else if (t != dt) {dt = 0; cerr = 2; goto gvreturn;} } - } - gvforexit1:; - for (register int32_t i = p2 + 1; true; ++i) { - if (!pct && !bct && tmp[0][i] == '"') inStr = !inStr; - if (!inStr) { - switch (tmp[0][i]) { - case '(': pct++; break; - case ')': pct--; break; - case '[': bct++; break; - case ']': bct--; break; - case 0: p3 = i; goto gvforexit2; - default:; - if (isSpChar(tmp[0][i]) && i != p2 + 1 && !pct && !bct) {p3 = i; goto gvforexit2;} - break; + if (t == 1) { + if (token[curtkn].act != '+') {dt = 0; cerr = 1; goto gvreturn;} + int32_t tmplen = strlen(tmp[1]) - q; + token[curtkn].data = malloc(tmplen + 1); + copyStrSnip(tmp[1], q, tmplen, token[curtkn].data); + if (q) getStr(token[curtkn].data, token[curtkn].data); + } else { + token[curtkn].ndata = strtold(tmp[1], NULL); + if (q && (token[curtkn].act == '*' || token[curtkn].act == '/') && token[curtkn].ndata < 0) { + token[curtkn].neg = true; + token[curtkn].ndata = -token[curtkn].ndata; } } + //printf("added token: {%c} {%c}: {%s}/[%Lf]\n", token[curtkn].act, token[curtkn].neg, token[curtkn].data, token[curtkn].ndata); + ++curtkn; + jp = ip; } - gvforexit2:; - if (p1 != 0 && isSpChar(tmp[0][p1])) p1++; - copyStrSnip(tmp[0], p1, p2, tmp[2]); - t = getType(tmp[2]); - if (t == 0) {cerr = 1; dt = 0; goto gvreturn;} else - if (t == 255) {t = getVar(tmp[2], tmp[2]); if (t == 0) {dt = 0; goto gvreturn;} if (t != 2) {cerr = 2; dt = 0; goto gvreturn;}} - copyStrSnip(tmp[0], p2 + 1, p3, tmp[3]); - t = getType(tmp[3]); - if (t == 0) {cerr = 1; dt = 0; goto gvreturn;} else - if (t == 255) {t = getVar(tmp[3], tmp[3]); if (t == 0) {dt = 0; goto gvreturn;} if (t != 2) {cerr = 2; dt = 0; goto gvreturn;}} - if (!strcmp(tmp[2], ".")) {cerr = 1; dt = 0; goto gvreturn;} - num1 = atof(tmp[2]); - if (!strcmp(tmp[2], ".")) {cerr = 1; dt = 0; goto gvreturn;} - num2 = atof(tmp[3]); - switch (numAct) { - case 0: num3 = num1 + num2; break; - case 1: num3 = num1 - num2; break; - case 2: num3 = num1 * num2; break; - case 3: if (num2 == 0) {cerr = 5; dt = 0; goto gvreturn;} num3 = num1 / num2; break; - case 4:; - if (num1 == 0) {if (num2 == 0) {cerr = 5; dt = 0; goto gvreturn;} num3 = 0; break;} - if (num2 == 0) {num3 = 1; break;} - num3 = pow(num1, num2); - break; - } - sprintf(tmp[1], "%lf", num3); - int32_t i = 0, j = strlen(tmp[1]) - 1; - bool dp = false; - while (tmp[1][i]) {if (tmp[1][i++] == '.') {dp = true; tmp[1][i + 6] = 0; break;}} - if (dp) {while (tmp[1][j] == '0') {--j;} if (tmp[1][j] == '.') {--j;}} - i = (tmp[1][0] == '-'); dp = (bool)i; - while (tmp[1][i] == '0') {++i;} - if (!tmp[1][i] || tmp[1][i] == '.') {--i;} - if (dp) tmp[1][--i] = '-'; - copyStrSnip(tmp[1], i, j + 1, tmp[2]); - copyStrFrom(tmp[0], p3, tmp[3]); - if (p1) copyStrTo(tmp[0], p1, tmp[1]); - else {tmp[1][0] = 0;} - copyStrApnd(tmp[2], tmp[1]); - copyStrApnd(tmp[3], tmp[1]); - swap(tmp[1], tmp[0]); } } - if (inbuf[jp] == 0) {break;} - jp++; - ip = jp; } - gvfexit:; + //printf("getVal[%d] to solve: [%d]:{%s}\n", getValIndex, tokens, tmp[0]); + //printf("getVal[%d]: block 2: time: [%ld]\n", getValIndex - 1, usTime() - starttime); starttime = usTime(); if (dt == 2) { + if (tokens == 1) goto skipt; + for (int i = 1; i < tokens; ++i) { + if (token[i].act == '^') { + if (token[i - 1].ndata == 0) {if (token[i].ndata == 0) {cerr = 5; dt = 0; goto gvreturn;} token[i - 1].ndata = 0; continue;} + if (token[i].ndata == 0) {token[i - 1].ndata = 1; continue;} + token[i - 1].ndata = pow(token[i - 1].ndata, token[i].ndata); + if (token[i - 1].neg) {token[i - 1].ndata = -token[i - 1].ndata;} + token[i - 1].neg = false; + token[i].act = 0; + } + } + for (int i = 1; i < tokens; ++i) { + if (token[i].act == '*') { + int j; + for (j = i - 1; j >= 0 && token[j].act == 0; --j) {} + if (token[i].neg) {token[i].ndata = -token[i].ndata;} + if (token[j].neg) {token[j].ndata = -token[j].ndata;} + token[j].ndata = token[j].ndata * token[i].ndata; + token[j].neg = false; + token[i].act = 0; + } + if (token[i].act == '/') { + int j; + for (j = i - 1; j >= 0 && token[j].act == 0; --j) {} + if (token[i].neg) {token[i].ndata = -token[i].ndata;} + if (token[j].neg) {token[j].ndata = -token[j].ndata;} + if (token[i].ndata == 0) {cerr = 5; dt = 0; goto gvreturn;} + token[j].ndata = token[j].ndata / token[i].ndata; + token[j].neg = false; + token[i].act = 0; + } + } + for (int i = 1; i < tokens; ++i) { + if (token[i].act == '+') { + int j; + for (j = i - 1; j >= 0 && token[j].act == 0; --j) {} + if (token[j].act == '-') {token[j].ndata = -token[j].ndata; token[j].act = '+';} + token[j].ndata = token[j].ndata + token[i].ndata; + token[i].act = 0; + } + if (token[i].act == '-') { + int j; + for (j = i - 1; j >= 0 && token[j].act == 0; --j) {} + if (token[j].act == '-') {token[j].ndata = -token[j].ndata; token[j].act = '+';} + token[j].ndata = token[j].ndata - token[i].ndata; + token[i].act = 0; + } + } + skipt:; + //printf("last token: {%c}:[%Lf]\n", token[0].act, token[0].ndata); + sprintf(tmp[1], "%Lf", (token[0].act == '-') ? -token[0].ndata : token[0].ndata); if (!strcmp(tmp[1], ".")) {cerr = 1; dt = 0; goto gvreturn;} int32_t i = 0, j = strlen(tmp[1]) - 1; bool dp = false; @@ -2469,17 +2560,31 @@ uint8_t getVal(char* inbuf, char* outbuf) { copyStrSnip(tmp[1], i, j + 1, outbuf); if (outbuf[0] == '-' && outbuf[1] == '0' && outbuf[2] == 0) {outbuf[0] = '0'; outbuf[1] = 0;} } else { - copyStr(tmp[1], outbuf); + outbuf[0] = 0; + char* oOutbuf = outbuf; + for (int i = 0; i < tokens; ++i) { + //printf("appending: [%d]:{%s}\n", i, token[i].data); + oOutbuf = copyStrApndO(token[i].data, oOutbuf); + } + //printf("outbuf: {%s}\n", outbuf); } + //printf("getVal[%d]: block 3: time: [%ld]\n", getValIndex - 1, usTime() - starttime); starttime = usTime(); if (outbuf[0] == 0 && dt != 1) {outbuf[0] = '0'; outbuf[1] = 0; dt = 2;} gvreturn:; getValIndex--; nfree(seenStr); - if (getValIndex) {nfree(tmp[0]); nfree(tmp[1]); nfree(tmp[2]); nfree(tmp[3]);} + if (mtoken) { + for (int i = 0; i < tokens; ++i) { + nfree(token[i].data); + } + nfree(token); + } + if (getValIndex) {nfree(tmp[0]); nfree(tmp[1]);} + //printf("getVal[%d]: out: [%d]:{%s}, time: [%lu]\n", getValIndex, dt, outbuf, usTime() - starttime); return dt; } -static inline bool solvearg(int i) { +static inline bool solvearg(char** arg, uint8_t* argt, int32_t* argl, int i) { if (i == 0) { argt[0] = 0; argl[0] = strlen(arg[0]); @@ -2587,60 +2692,6 @@ static inline int getArgO(int num, char* inbuf, char* outbuf, int32_t i) { char tmpbuf[2][CB_BUF_SIZE]; -static inline void mkargs() { - int32_t j = 0; - while (cmd[j] == ' ') {++j;} - int32_t h = j; - bool sccmd = false; - if (cmd[j] == '$' || cmd[j] == '@' || cmd[j] == '%') { - int32_t tmpj = j + 1; - while (cmd[tmpj] == ' ') {++tmpj;} - if (cmd[tmpj] != '=') sccmd = true; - } - if (!sccmd) { - while (cmd[h] != ' ' && cmd[h] != '=' && cmd[h]) {++h;} - } - copyStrFrom(cmd, (cmd[h]) ? h + 1 : h, tmpbuf[0]); - if (!sccmd) { - int32_t tmph = h; - while (cmd[tmph] == ' ' && cmd[tmph]) {++tmph;} - if (cmd[tmph] == '=') { - strcpy(tmpbuf[1], "SET "); - cmd[tmph] = ','; - copyStrApnd(cmd, tmpbuf[1]); - cmd = (char*)realloc(cmd, strlen(tmpbuf[1]) + 1); - copyStr(tmpbuf[1], cmd); - copyStr(tmpbuf[1], tmpbuf[0]); - tmpbuf[1][0] = 0; - h = 3; - j = 0; - } - } - for (int i = 0; i <= argct; ++i) { - nfree(arg[i]); - } - argct = getArgCt(tmpbuf[0]); - arg = (char**)realloc(arg, (argct + 1) * sizeof(char*)); - argt = (uint8_t*)realloc(argt, (argct + 1) * sizeof(uint8_t)); - argl = (int32_t*)realloc(argl, (argct + 1) * sizeof(int32_t)); - int32_t gptr = 0; - copyStrSnip(cmd, j, ((sccmd) ? h + 1 : h), tmpbuf[0]); - argl[0] = strlen(tmpbuf[0]); - arg[0] = malloc(argl[0] + 1); - copyStr(tmpbuf[0], arg[0]); - copyStrFrom(cmd, (h >= argl[0]) ? argl[0] : h + 1, tmpbuf[0]); - for (int i = 1; i <= argct; ++i) { - int32_t ngptr = getArgO(i - 1, tmpbuf[0], tmpbuf[1], gptr); - if (ngptr == -1) return; - argl[i] = ngptr - gptr; - gptr = ngptr; - arg[i] = malloc(argl[i] + 1); - copyStr(tmpbuf[1], arg[i]); - arg[i][argl[i]] = 0; - } - if (argct == 1 && arg[1][0] == 0) {argct = 0;} -} - char* lttmp_tmp[3]; int logictestexpr_index = 0; @@ -2748,44 +2799,44 @@ static inline uint8_t logictestexpr(char* inbuf) { goto ltreturn; } else if (!strcmp(lttmp[1], ">")) { if (t1 == 1) {cerr = 2; goto ltreturn;} - double num1, num2; - sscanf(lttmp[0], "%lf", &num1); - sscanf(lttmp[2], "%lf", &num2); + long double num1, num2; + sscanf(lttmp[0], "%Lf", &num1); + sscanf(lttmp[2], "%Lf", &num2); ret = num1 > num2; goto ltreturn; } else if (!strcmp(lttmp[1], "<")) { if (t1 == 1) {cerr = 2; goto ltreturn;} - double num1, num2; - sscanf(lttmp[0], "%lf", &num1); - sscanf(lttmp[2], "%lf", &num2); + long double num1, num2; + sscanf(lttmp[0], "%Lf", &num1); + sscanf(lttmp[2], "%Lf", &num2); ret = num1 < num2; goto ltreturn; } else if (!strcmp(lttmp[1], ">=")) { if (t1 == 1) {cerr = 2; goto ltreturn;} - double num1, num2; - sscanf(lttmp[0], "%lf", &num1); - sscanf(lttmp[2], "%lf", &num2); + long double num1, num2; + sscanf(lttmp[0], "%Lf", &num1); + sscanf(lttmp[2], "%Lf", &num2); ret = num1 >= num2; goto ltreturn; } else if (!strcmp(lttmp[1], "<=")) { if (t1 == 1) {cerr = 2; goto ltreturn;} - double num1, num2; - sscanf(lttmp[0], "%lf", &num1); - sscanf(lttmp[2], "%lf", &num2); + long double num1, num2; + sscanf(lttmp[0], "%Lf", &num1); + sscanf(lttmp[2], "%Lf", &num2); ret = num1 <= num2; goto ltreturn; } else if (!strcmp(lttmp[1], "=>")) { if (t1 == 1) {cerr = 2; goto ltreturn;} - double num1, num2; - sscanf(lttmp[0], "%lf", &num1); - sscanf(lttmp[2], "%lf", &num2); + long double num1, num2; + sscanf(lttmp[0], "%Lf", &num1); + sscanf(lttmp[2], "%Lf", &num2); ret = num1 >= num2; goto ltreturn; } else if (!strcmp(lttmp[1], "=<")) { if (t1 == 1) {cerr = 2; goto ltreturn;} - double num1, num2; - sscanf(lttmp[0], "%lf", &num1); - sscanf(lttmp[2], "%lf", &num2); + long double num1, num2; + sscanf(lttmp[0], "%Lf", &num1); + sscanf(lttmp[2], "%Lf", &num2); ret = num1 <= num2; goto ltreturn; } @@ -2858,7 +2909,7 @@ uint8_t logictest(char* inbuf) { char ltmp[2][CB_BUF_SIZE]; -bool runlogic() { +bool runlogic(char* cmd) { ltmp[0][0] = 0; ltmp[1][0] = 0; int32_t i = 0; while (cmd[i] == ' ') {++i;} @@ -2871,7 +2922,7 @@ bool runlogic() { if (isLineNumber(ltmp[0])) { int tmp = -1; for (int j = 0; j < gotomaxct; ++j) { - if (!gotodata[j].used) {tmp = j; break;} + if (!gotodata[j].inuse) {tmp = j; break;} else if (!strcmp(gotodata[j].name, ltmp[0])) { if (gotodata[j].cp == cmdpos) {goto skiplbl;} cerr = 28; return true; @@ -2882,11 +2933,10 @@ bool runlogic() { ++gotomaxct; gotodata = realloc(gotodata, gotomaxct * sizeof(cb_goto)); } - gotodata[tmp].name = malloc(strlen(ltmp[0]) + 1); - copyStr(ltmp[0], gotodata[tmp].name); + gotodata[tmp].name = strdup(ltmp[0]); gotodata[tmp].cp = cmdpos; gotodata[tmp].pl = progLine; - gotodata[tmp].used = true; + gotodata[tmp].inuse = true; gotodata[tmp].dlsp = dlstackp; gotodata[tmp].fnsp = fnstackp; gotodata[tmp].itsp = itstackp; @@ -2902,6 +2952,7 @@ bool runlogic() { j -= i; i = 0; } + if (addsub > -1) return false; cerr = 0; chkCmdPtr = ltmp[0]; #include "logic.c" @@ -2911,8 +2962,6 @@ bool runlogic() { static inline void initBaseMem() { getVal_tmp[0] = malloc(CB_BUF_SIZE); getVal_tmp[1] = malloc(CB_BUF_SIZE); - getVal_tmp[2] = malloc(CB_BUF_SIZE); - getVal_tmp[3] = malloc(CB_BUF_SIZE); getFunc_gftmp[0] = malloc(CB_BUF_SIZE); getFunc_gftmp[1] = malloc(CB_BUF_SIZE); bfnbuf = malloc(CB_BUF_SIZE); @@ -2926,8 +2975,6 @@ static inline void initBaseMem() { static inline void freeBaseMem() { nfree(getVal_tmp[0]); nfree(getVal_tmp[1]); - nfree(getVal_tmp[2]); - nfree(getVal_tmp[3]); nfree(getFunc_gftmp[0]); nfree(getFunc_gftmp[1]); nfree(bfnbuf); @@ -2938,11 +2985,10 @@ static inline void freeBaseMem() { nfree(getVarBuf); } -static inline void printError(int error) { +static inline void printError(int error, char* arg0, char* cmd) { getCurPos(); if (curx != 1) putchar('\n'); - if (inProg) {printf("Error %d on line %d of '%s':\n%s\n", error, progLine, basefilename(progfnstr), cmd);} - else {printf("Error %d: ", error);} + printf("Error %d: ", error); switch (error) { default:; fputs("Unknown", stdout); @@ -3058,6 +3104,21 @@ static inline void printError(int error) { case 36:; printf("Extension already loaded: '%s'", errstr); break; + case 37:; + printf("Cannot find subfunction: '%s'", errstr); + break; + case 38:; + printf("Invalid subfunction name: '%s'", errstr); + break; + case 39:; + printf("Subfunction already exists: '%s'", errstr); + break; + case 40:; + fputs("Subfunctions cannot be nested", stdout); + break; + case 41:; + fputs("ENDSUB with no SUB", stdout); + break; case 125:; printf("Function only valid in program: '%s'", errstr); break; @@ -3068,16 +3129,140 @@ static inline void printError(int error) { printf("Not a function: '%s'", errstr); break; case 253:; - printf("Command only valid in program: '%s'", arg[0]); + printf("Command only valid in program: '%s'", arg0); break; case 254:; - printf("Command not valid in program: '%s'", arg[0]); + printf("Command not valid in program: '%s'", arg0); break; case 255:; - printf("Not a command: '%s'", arg[0]); + printf("Not a command: '%s'", arg0); break; } putchar('\n'); + if (inProg) {printf("On line %d of '%s':\n%s\n", progLine, basefilename(progfnstr), cmd);} +} + +int runcmd(char* cmd) { + if (cmd[0] == 0 || cmdint) return 0; + cerr = 0; + char** arg = NULL; + uint8_t* argt = NULL; + int32_t* argl = NULL; + int argct = 0; + bool lgc = runlogic(cmd); + if (lgc) goto cmderr; + if (cmd[0] == 0) return 0; + int32_t tmpi = 0; + while (cmd[tmpi] && cmd[tmpi] != ' ') {tmpi++;} + if (!cmd[tmpi]) tmpi = -1; + if (tmpi > -1) cmd[tmpi] = 0; + if (addsub > -1) { + if (tmpi > -1) cmd[tmpi] = 0; + if (!strcmp(cmd, "ENDSUB")) { + if (tmpi > -1) { + if (getArgCt(cmd + tmpi + 1)) { + subdata[addsub].inuse = false; + free(subdata[addsub].name); + free(subdata[addsub].data); + subdata[addsub].type = 0; + if (addsub == submaxct - 1) { + while (addsub >= 0 && !subdata[addsub].inuse) {submaxct--; addsub--;} + subdata = (cb_sub*)realloc(subdata, submaxct * sizeof(cb_sub)); + } + addsub = -1; + cerr = 3; + goto cmderr; + } + } + subdata[addsub].data = realloc(subdata[addsub].data, strlen(subdata[addsub].data) + 1); + addsub = -1; + } + if (tmpi > -1) cmd[tmpi] = ' '; + if (addsub < 0) return 0; + copyStrApnd(cmd, subdata[addsub].data); + strApndChar(subdata[addsub].data, '\n'); + return 0; + } + chkCmdPtr = cmd; + if (!chkCmd(2, "LABEL", "LBL") && cmd[0] != '@') { + if (tmpi > -1) cmd[tmpi] = ' '; + if (dlstackp > ((progindex > -1) ? mindlstackp[progindex] : -1)) {if (dldcmd[dlstackp]) return 0;} + if (itstackp > ((progindex > -1) ? minitstackp[progindex] : -1)) {if (itdcmd[itstackp]) return 0;} + if (fnstackp > ((progindex > -1) ? minfnstackp[progindex] : -1)) {if (fndcmd[fnstackp]) return 0;} + } + if (tmpi > -1) cmd[tmpi] = ' '; + int32_t j = 0; + while (cmd[j] == ' ') {++j;} + int32_t h = j; + bool sccmd = false; + if (cmd[j] == '$' || cmd[j] == '@' || cmd[j] == '%' || cmd[j] == '>') { + int32_t tmpj = j + 1; + while (cmd[tmpj] == ' ') {++tmpj;} + if (cmd[tmpj] != '=') sccmd = true; + } + if (!sccmd) { + while (cmd[h] != ' ' && cmd[h] != '=' && cmd[h]) {++h;} + } + copyStrFrom(cmd, (cmd[h]) ? h + 1 : h, tmpbuf[0]); + if (!sccmd) { + int32_t tmph = h; + while (cmd[tmph] == ' ' && cmd[tmph]) {++tmph;} + if (cmd[tmph] == '=') { + strcpy(tmpbuf[1], "SET "); + cmd[tmph] = ','; + copyStrApnd(cmd, tmpbuf[1]); + copyStr(tmpbuf[1], cmd); + copyStr(tmpbuf[1], tmpbuf[0]); + tmpbuf[1][0] = 0; + h = 3; + j = 0; + } + } + argct = getArgCt(tmpbuf[0]); + arg = (char**)malloc((argct + 1) * sizeof(char*)); + argt = (uint8_t*)malloc((argct + 1) * sizeof(uint8_t)); + argl = (int32_t*)malloc((argct + 1) * sizeof(int32_t)); + int32_t gptr = 0; + copyStrSnip(cmd, j, ((sccmd) ? h + 1 : h), tmpbuf[0]); + argl[0] = strlen(tmpbuf[0]); + arg[0] = malloc(argl[0] + 1); + copyStr(tmpbuf[0], arg[0]); + copyStrFrom(cmd, (h >= argl[0]) ? argl[0] : h + 1, tmpbuf[0]); + for (int i = 1; i <= argct; ++i) { + int32_t ngptr = getArgO(i - 1, tmpbuf[0], tmpbuf[1], gptr); + if (ngptr == -1) goto cmderr; + argl[i] = ngptr - gptr; + gptr = ngptr; + arg[i] = malloc(argl[i] + 1); + copyStr(tmpbuf[1], arg[i]); + arg[i][argl[i]] = 0; + } + if (argct == 1 && arg[1][0] == 0) {argct = 0;} + if (cerr) goto cmderr; + solvearg(arg, argt, argl, 0); + cerr = 255; + chkCmdPtr = arg[0]; + #include "commands.c" + cmderr:; + if (!hideerror) { + if (cerr) { + err = 0; + if (runc || runfile) err = 1; + printError(cerr, (arg) ? arg[0] : defaultstr, cmd); + return cerr; + } + } else { + hideerror = false; + } + noerr:; + if (lgc) return cerr; + for (int i = 0; i <= argct; ++i) { + nfree(arg[i]); + } + nfree(arg); + nfree(argt); + nfree(argl); + return cerr; } int loadExt(char* path) { @@ -3093,8 +3278,7 @@ int loadExt(char* path) { if (!oextname | !cbext_init) {cerr = 34; goto loadfail;} if (!oextname[0]) {cerr = 34; goto loadfail;} int e = -1; - char* extname = (char*)malloc(strlen(oextname) + 1); - copyStr(oextname, extname); + char* extname = strdup(oextname); upCase(extname); for (register int i = 0; i < extmaxct; ++i) { if (extdata[i].inuse && !strcmp(extname, extdata[i].name)) { @@ -3115,6 +3299,10 @@ int loadExt(char* path) { &txtattrib, &curx, &cury, startcmd, roptstr, + &progLine, &lockpl, &didloop, + &inProg, &chkinProg, + &cmdl, &cp, &concp, + cb_exec, getCurPos, gethome, seterrstr, @@ -3131,7 +3319,8 @@ int loadExt(char* path) { getVal, solvearg, logictest, - printError + printError, + runcmd }; if (!cbext_init(extargs)) {cerr = 35; goto loadfail;} if (e == -1) { @@ -3180,46 +3369,3 @@ bool unloadExt(int e) { } return true; } - -void runcmd() { - if (cmd[0] == 0) return; - cerr = 0; - bool lgc = runlogic(); - if (lgc) goto cmderr; - if (cmd[0] == 0) return; - int32_t tmpi = 0; - while (cmd[tmpi] && cmd[tmpi] != ' ') {tmpi++;} - if (!cmd[tmpi]) tmpi = -1; - if (tmpi > -1) cmd[tmpi] = 0; - chkCmdPtr = cmd; - if (!chkCmd(2, "LABEL", "LBL") && cmd[0] != '@') { - if (tmpi > -1) cmd[tmpi] = ' '; - if (dlstackp > ((progindex > -1) ? mindlstackp[progindex] : -1)) {if (dldcmd[dlstackp]) return;} - if (itstackp > ((progindex > -1) ? minitstackp[progindex] : -1)) {if (itdcmd[itstackp]) return;} - if (fnstackp > ((progindex > -1) ? minfnstackp[progindex] : -1)) {if (fndcmd[fnstackp]) return;} - } - if (tmpi > -1) cmd[tmpi] = ' '; - mkargs(); - if (cerr) goto cmderr; - solvearg(0); - cerr = 255; - chkCmdPtr = arg[0]; - #include "commands.c" - cmderr:; - if (cerr) { - err = 0; - if (runc || runfile) err = 1; - printError(cerr); - cp = -1; - concp = -1; - chkinProg = inProg = false; - } - noerr:; - if (lgc) return; - for (int i = 0; i <= argct; ++i) { - nfree(arg[i]); - } - argct = 0; - return; -} - diff --git a/clibasic.h b/clibasic.h index d96f224..c8846f0 100644 --- a/clibasic.h +++ b/clibasic.h @@ -66,17 +66,17 @@ typedef struct { uint8_t type; // type of the variable, 1 = string, 2 = number int32_t size; // max index of variable, -1 = normal variable, >= 0 = array, to get the size of the array, add 1 char** data; // array of strings containing the value(s) -} cb_var; +} __attribute__((aligned(sizeof(void*)))) cb_var; typedef struct { FILE* fptr; // pointer to FILE* struct to read from and write to the file int32_t size; // file size at open -} cb_file; +} __attribute__((aligned(sizeof(void*)))) cb_file; typedef struct { int cerr; // error to return int ftype; // type of the function, 1 = string, 2 = number -} cb_funcret; +} __attribute__((aligned(sizeof(void*)))) cb_funcret; typedef struct { bool bold; // bold text attribute @@ -98,54 +98,64 @@ typedef struct { uint8_t bgc; // 8-bit/standard bgc text attribute uint32_t truefgc; // 24-bit/truecolor fgc text attribute uint32_t truebgc; // 24-bit/truecolor bgc text attribute -} cb_txt; +} __attribute__((aligned(sizeof(void*)))) cb_txt; typedef struct { - char* VER; // CLIBASIC version - char* BVER; // bits ("64"/"32"/"?") - char* OSVER; // OS name ("Linux", "Windows", ...) - int* cerr; // pointer to the variable storing the error number - int* retval; // pointer to the variable read by the CLIBASIC function _RET() - int* fileerror; // pointer to the variable read by the CLIBASIC function _FILEERROR() - int* varmaxct; // pointer to the amount of variable spots allocated - cb_var* vardata; // pointer to the variable spots - int* filemaxct; // pointer to the amount of file spots allocated - cb_file* filedata; // pointer to the file spots - char** chkCmdPtr; // pointer to a pointer of the char array to be compared by chkCmd() - cb_txt* txtattrib; // pointer to the struct that stores text attributes - int* curx; // pointer to the text cursor x position - int* cury; // pointer to the text cursor y position - char* startcmd; // full path to the executable that was used to start CLIBASIC - char* roptstr; // option string to pass when starting a new CLIBASIC executable - void (*getCurPos)(void); // update the text cursor position - char* (*gethome)(void); // get the user's home directory - void (*seterrstr)(char*); // set the error string some errors require - char* (*basefilename)(char*); // gets the file name off of a file path - char* (*pathfilename)(char*); // gets the path name off of a file path - int (*openFile)(char*, char*); // opens a file in a new file spot and returns the position - bool (*closeFile)(int); // closes a file spot or all if supplied with -1 and returns true if successful, false otherwise - bool (*cbrm)(char*); // removes a file or directory and returns true if successful, false otherwise - uint64_t (*usTime)(void); // returns the time in nanoseconds - uint64_t (*timer)(void); // returns the timer ticks in nanoseconds - void (*resetTimer)(void); // resets the timer - void (*cb_wait)(uint64_t); // waits for a certain amount of nanoseconds - void (*updateTxtAttrib)(void); // reads the text attribute struct and applies the changes - double (*randNum)(double, double); // returns a random double from within a range - bool (*chkCmd)(int, ...); // compares chkCmdPtr to strings supplied after the string count and returns true if a match is found, false otherwise - bool (*isSpChar)(char); // checks if a char is a special character ('+', '-', '*', '\', & '^') - bool (*isExSpChar)(char); // checks if a char is a special character but with more chars ('=', '>', '<', & ',') - bool (*isValidVarChar)(char); // checks if a char is valid in a variable name - bool (*isValidHexChar)(char); // checks if a char is valid in a hexadecimal number (0-F) - int (*getArgCt)(char*); // returns the argument count of raw input - int (*getArg)(int, char*, char*); // writes the argument number in argument 1 of raw input from argument 2 into argument 3 and returns the length - int (*getArgO)(int, char*, char*, int32_t); // writes the argument number in argument 1 of raw input from argument 2 into argument 3 and returns the end, pass this to argument 4 on next call - void (*getStr)(char*, char*); // returns a string after evaluating any backslash escape codes - uint8_t (*getType)(char*); // gets the type of raw input ("\"test\"" returns 1 (string), "0" returns 2 (number), and "TEST" returns 255 (variable)) - uint8_t (*getVar)(char*, char*); // puts the value of the variable specified by argument 1 in argument 2 and returns the type (1 = string, 2 = number) - bool (*setVar)(char*, char*, uint8_t, int32_t); // sets the variable specified by argument 1 to the value specified by argument 2 and sets the type to argument 3 and size to argument 4 - bool (*delVar)(char*); // deletes a variable - uint8_t (*getVal)(char*, char*); // solves raw input in argument 1, writes the value into argument 2, and returns the type (1 = string, 2 = number, 255 = blank) or 0 on failure - bool (*solvearg)(int); // solves an argument for commands as some commands may want to read from raw input - uint8_t (*logictest)(char*); // takes raw input, tests it, and returns -1 on failure, 0 if false, and 1 if true - void (*printError)(int); // prints a built-in error string -} cb_extargs; + char* VER; // CLIBASIC version + char* BVER; // bits ("64"/"32"/"?") + char* OSVER; // OS name ("Linux", "Windows", ...) + int* cerr; // pointer to the variable storing the error number + int* retval; // pointer to the variable read by the CLIBASIC function _RET() + int* fileerror; // pointer to the variable read by the CLIBASIC function _FILEERROR() + int* varmaxct; // pointer to the amount of variable spots allocated + cb_var* vardata; // pointer to the variable spots + int* filemaxct; // pointer to the amount of file spots allocated + cb_file* filedata; // pointer to the file spots + char** chkCmdPtr; // pointer to a pointer of the char array to be compared by chkCmd() + cb_txt* txtattrib; // pointer to the struct that stores text attributes + int* curx; // pointer to the text cursor x position + int* cury; // pointer to the text cursor y position + char* startcmd; // full path to the executable that was used to start CLIBASIC + char* roptstr; // option string to pass when starting a new CLIBASIC executable + int* progLine; // pointer to the current line in the program + bool* lockpl; // pointer to a flag to temporarily stop the program line from being incremented + bool* didloop; // pointer to a flag indicating that you did some magic with the program position counter + bool* inProg; // pointer to a flag indicating if a program is being interpreted + bool* chkinProg; // pointer to a flag indicating if you loaded a program + int32_t* cmdl; // pointer length of the length of the command string + int32_t* cp; // pointer length of the program data position + int32_t* concp; // pointer length of the console program data position + int16_t (*cb_exec)(char**); // pointer to a function which will start another process using a NULL-terminated string (char*) array + void (*getCurPos)(void); // update the text cursor position + char* (*gethome)(void); // get the user's home directory + void (*seterrstr)(char*); // set the error string some errors require + char* (*basefilename)(char*); // gets the file name off of a file path + char* (*pathfilename)(char*); // gets the path name off of a file path + int (*openFile)(char*, char*); // opens a file in a new file spot and returns the position + bool (*closeFile)(int); // closes a file spot or all if supplied with -1 and returns true if successful, false otherwise + bool (*cbrm)(char*); // removes a file or directory and returns true if successful, false otherwise + uint64_t (*usTime)(void); // returns the time in nanoseconds + uint64_t (*timer)(void); // returns the timer ticks in nanoseconds + void (*resetTimer)(void); // resets the timer + void (*cb_wait)(uint64_t); // waits for a certain amount of nanoseconds + void (*updateTxtAttrib)(void); // reads the text attribute struct and applies the changes + long double (*randNum)(long double, long double); // returns a random double from within a range + bool (*chkCmd)(int, ...); // compares chkCmdPtr to strings supplied after the string count and returns true if a match is found, false otherwise + bool (*isSpChar)(char); // checks if a char is a special character ('+', '-', '*', '\', & '^') + bool (*isExSpChar)(char); // checks if a char is a special character but with more chars ('=', '>', '<', & ',') + bool (*isValidVarChar)(char); // checks if a char is valid in a variable name + bool (*isValidHexChar)(char); // checks if a char is valid in a hexadecimal number (0-F) + int (*getArgCt)(char*); // returns the argument count of raw input + int (*getArg)(int, char*, char*); // writes the argument number in argument 1 of raw input from argument 2 into argument 3 and returns the length + int (*getArgO)(int, char*, char*, int32_t); // writes the argument number in argument 1 of raw input from argument 2 into argument 3 and returns the end, pass this to argument 4 on next call + void (*getStr)(char*, char*); // returns a string after evaluating any backslash escape codes + uint8_t (*getType)(char*); // gets the type of raw input ("\"test\"" returns 1 (string), "0" returns 2 (number), and "TEST" returns 255 (variable)) + uint8_t (*getVar)(char*, char*); // puts the value of the variable specified by argument 1 in argument 2 and returns the type (1 = string, 2 = number) + bool (*setVar)(char*, char*, uint8_t, int32_t); // sets the variable specified by argument 1 to the value specified by argument 2 and sets the type to argument 3 and size to argument 4 + bool (*delVar)(char*); // deletes a variable + uint8_t (*getVal)(char*, char*); // solves raw input in argument 1, writes the value into argument 2, and returns the type (1 = string, 2 = number, 255 = blank) or 0 on failure + bool (*solvearg)(char**, uint8_t*, int32_t*, int); // solves an argument for commands as some commands may want to read from raw input + uint8_t (*logictest)(char*); // takes raw input, tests it, and returns -1 on failure, 0 if false, and 1 if true + void (*printError)(int, char*, char*); // prints a built-in error string + int (*runcmd)(char*); // parses and runs a single command and returns an error (0 for none) +} __attribute__((aligned(sizeof(void*)))) cb_extargs; diff --git a/commands.c b/commands.c index 366446c..dfeb4be 100644 --- a/commands.c +++ b/commands.c @@ -13,35 +13,43 @@ if (chkCmdPtr[0] == '_') goto _cmd; if (chkCmd(2, "EXIT", "QUIT")) { if (argct > 1) {cerr = 3; goto cmderr;} cerr = 0; - err = 0; - if (argct == 1) { - if (!solvearg(1)) goto cmderr; - err = atoi(arg[1]); - if (runfile) { - retval = err; + if (subinfo.insub && subinfo.type > 0) { + if (argct == 1) { + if (!solvearg(arg, argt, argl, 1)) goto cmderr; + if (argt[1] != subinfo.type) {cerr = 2; goto cmderr;} + funcret = strdup(arg[1]); } } else { err = 0; + if (argct) { + if (!solvearg(arg, argt, argl, 1)) goto cmderr; + err = atoi(arg[1]); + if (runfile) { + retval = err; + } + } else { + err = 0; + } + if (inProg) { + if (progindex > 0) unloadProg(); + else cmdint = true; + retval = err; + } else { + cleanExit(); + } } - if (inProg) { - if (progindex > 0) unloadProg(); - else cmdint = true; - retval = err; - } else { - cleanExit(); - } - goto cmderr; + goto noerr; } -if (chkCmd(1, "PUT")) { +if (chkCmd(2, "PUT", ">")) { cerr = 0; - for (int i = 1; i <= argct; i++) {if (!solvearg(i)) {goto cmderr;} fputs(arg[i], stdout);} + for (int i = 1; i <= argct; i++) {if (!solvearg(arg, argt, argl, i)) {goto cmderr;} fputs(arg[i], stdout);} fflush(stdout); goto noerr; } if (chkCmd(2, "SET", "LET")) { if (argct != 2) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (!arg[1][0] || !argt[2]) {cerr = 1; goto cmderr;} if (!setVar(arg[1], arg[2], argt[2], -1)) goto cmderr; goto noerr; @@ -49,8 +57,8 @@ if (chkCmd(2, "SET", "LET")) { if (chkCmd(1, "DIM")) { if (argct < 2 || argct > 3) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(2)) goto cmderr; - if (argct == 3 && !solvearg(3)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; + if (argct == 3 && !solvearg(arg, argt, argl, 3)) goto cmderr; if (argt[2] != 2) {cerr = 2; goto cmderr;} int32_t asize = atoi(arg[2]); if (asize < 0) {cerr = 16; goto cmderr;} @@ -60,7 +68,7 @@ if (chkCmd(1, "DIM")) { val = arg[3]; type = argt[3]; } else { - val = ((arg[1][argl[1] - 1] == '$') ? "" : "0"); + val = (arg[1][argl[1] - 1] == '$') ? defaultstr : defaultnum; type = 2 - (arg[1][argl[1] - 1] == '$'); } if (!setVar(arg[1], val, type, asize)) goto cmderr; @@ -69,7 +77,7 @@ if (chkCmd(1, "DIM")) { if (chkCmd(1, "REDIM")) { if (argct < 2) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (argt[2] != 2) {cerr = 2; goto cmderr;} int v = -1; for (register int i = 0; i < varmaxct; ++i) { @@ -167,7 +175,7 @@ if (chkCmd(3, "@", "LABEL", "LBL")) { upCase(arg[1]); int i = -1; for (int j = 0; j < gotomaxct; ++j) { - if (!gotodata[j].used) {i = j; break;} + if (!gotodata[j].inuse) {i = j; break;} else if (!strcmp(gotodata[j].name, arg[1])) { if (gotodata[j].cp == cmdpos) {goto noerr;} cerr = 28; goto cmderr; @@ -178,17 +186,13 @@ if (chkCmd(3, "@", "LABEL", "LBL")) { ++gotomaxct; gotodata = realloc(gotodata, gotomaxct * sizeof(cb_goto)); } - gotodata[i].name = malloc(strlen(arg[1]) + 1); - copyStr(arg[1], gotodata[i].name); + gotodata[i].name = strdup(arg[1]); gotodata[i].cp = cmdpos; gotodata[i].pl = progLine; - gotodata[i].used = true; + gotodata[i].inuse = true; gotodata[i].dlsp = dlstackp; gotodata[i].fnsp = fnstackp; gotodata[i].itsp = itstackp; - #ifdef _WIN32 - updatechars(); - #endif goto noerr; } if (chkCmd(3, "%", "GOTO", "GO")) { @@ -197,7 +201,7 @@ if (chkCmd(3, "%", "GOTO", "GO")) { upCase(arg[1]); int i = -1; for (int j = 0; j < gotomaxct; ++j) { - if (gotodata[j].used) { + if (gotodata[j].inuse) { if (!strcmp(gotodata[j].name, arg[1])) {i = j;} } } @@ -212,9 +216,9 @@ if (chkCmd(3, "%", "GOTO", "GO")) { dlstackp = gotodata[i].dlsp; fnstackp = gotodata[i].fnsp; itstackp = gotodata[i].itsp; - gotodata[i].used = false; + gotodata[i].inuse = false; bool r = false; - while (gotomaxct > 0 && !gotodata[gotomaxct - 1].used) {--gotomaxct; r = true;} + while (gotomaxct > 0 && !gotodata[gotomaxct - 1].inuse) {--gotomaxct; r = true;} if (r) gotodata = realloc(gotodata, gotomaxct * sizeof(cb_goto)); didloop = true; lockpl = true; @@ -227,7 +231,7 @@ if (chkCmd(1, "GOSUB")) { upCase(arg[1]); int i = -1; for (int j = 0; j < gotomaxct; ++j) { - if (gotodata[j].used) { + if (gotodata[j].inuse) { if (!strcmp(gotodata[j].name, arg[1])) {i = j;} } } @@ -246,9 +250,9 @@ if (chkCmd(1, "GOSUB")) { concp = gotodata[i].cp; } progLine = gotodata[i].pl; - gotodata[i].used = false; + gotodata[i].inuse = false; bool r = false; - while (gotomaxct > 0 && !gotodata[gotomaxct - 1].used) {--gotomaxct; r = true;} + while (gotomaxct > 0 && !gotodata[gotomaxct - 1].inuse) {--gotomaxct; r = true;} if (r) gotodata = realloc(gotodata, gotomaxct * sizeof(cb_goto)); didloop = true; lockpl = true; @@ -273,6 +277,39 @@ if (chkCmd(1, "RETURN")) { lockpl = true; goto noerr; } +if (chkCmd(2, "DELLABEL", "DELLBL")) { + if (argct < 1) {cerr = 3; goto cmderr;} + cerr = 0; + for (int i = 1; i <= argct; ++i) { + upCase(arg[i]); + int s = -1; + for (int j = 0; j < gotomaxct; ++j) { + if (gotodata[j].inuse && !strcmp(gotodata[j].name, arg[i])) { + s = j; + } + } + if (s != -1) { + gotodata[s].inuse = false; + free(gotodata[s].name); + if (s == submaxct - 1) { + while (s >= 0 && !gotodata[s].inuse) {gotodata--; s--;} + gotodata = (cb_goto*)realloc(gotodata, gotomaxct * sizeof(cb_goto)); + } + } + } + goto noerr; +} +if (chkCmd(2, "DEFRAGLBLS", "DEFRAGLABELS")) { + cerr = 0; + if (argct > 0) {cerr = 3; goto cmderr;} + int so = 0; + for (register int i = 0; i < submaxct;) { + if (!gotodata[i].inuse) {++so; --gotomaxct;} + else {++i;} + if (so) {gotodata[i] = gotodata[i + so];} + } + goto noerr; +} if (chkCmd(2, "CONTINUE", "BREAK")) { if (argct) {cerr = 3; goto cmderr;} cerr = 0; @@ -287,10 +324,110 @@ if (chkCmd(2, "CONTINUE", "BREAK")) { brkinfo.type = 1 + !strcmp(arg[0], "BREAK"); goto noerr; } +if (chkCmd(3, "SUB", "FUNC", "FUNC$")) { + if (subinfo.insub) {cerr = 40; goto cmderr;} + if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; + upCase(arg[1]); + int i = -1; + for (int j = 0; j < submaxct; ++j) { + if (!subdata[j].inuse) {i = j; break;} + else if (!strcmp(subdata[j].name, arg[1])) { + seterrstr(arg[1]); cerr = 39; goto cmderr; + } + } + if (i == -1) { + i = submaxct; + ++submaxct; + subdata = realloc(subdata, submaxct * sizeof(cb_sub)); + } + subdata[i].inuse = true; + subdata[i].name = strdup(arg[1]); + subdata[i].data = malloc(CB_BUF_SIZE); + subdata[i].data[0] = 0; + subdata[i].type = (arg[0][0] == 'S') ? 0 : (arg[0][argl[0] - 1] == '$') ? 1 : 2; + addsub = i; + goto noerr; +} +if (chkCmd(1, "ENDSUB")) { + if (argct) {cerr = 3; goto cmderr;} + cerr = 41; + goto cmderr; +} +if (chkCmd(1, "CALLSUB")) { + if (argct < 1) {cerr = 3; goto cmderr;} + cerr = 0; + newprogargc = argct; + newprogargs = (char**)malloc((argct + 1) * sizeof(char*)); + for (int i = 1; i < newprogargc; ++i) { + newprogargs[i] = NULL; + } + for (int i = 2; i <= argct; ++i) { + if (!solvearg(arg, argt, argl, i)) { + for (int j = i - 1; j > 0; --j) { + free(newprogargs[j]); + } + free(newprogargs); + goto cmderr; + } + newprogargs[i - 1] = strdup(arg[i]); + } + if (!loadSub(arg[1], false, NULL)) goto callsub_err; + goto callsub_noerr; + callsub_err:; + for (int i = 1; i < newprogargc; ++i) { + nfree(newprogargs[i]); + } + nfree(newprogargs); + newprogargc = 0; + goto cmderr; + callsub_noerr:; + subinfo.insub = true; + subinfo.type = 0; + chkinProg = true; + cp = 0; + didloop = true; + goto noerr; +} +if (chkCmd(1, "DELSUB")) { + if (argct < 1) {cerr = 3; goto cmderr;} + cerr = 0; + for (int i = 1; i <= argct; ++i) { + upCase(arg[i]); + int s = -1; + for (int j = 0; j < submaxct; ++j) { + if (subdata[j].inuse && !strcmp(subdata[j].name, arg[i])) { + s = j; + } + } + if (s != -1) { + subdata[s].inuse = false; + free(subdata[s].name); + free(subdata[s].data); + subdata[s].type = 0; + if (s == submaxct - 1) { + while (s >= 0 && !subdata[s].inuse) {submaxct--; s--;} + subdata = (cb_sub*)realloc(subdata, submaxct * sizeof(cb_sub)); + } + } + } + goto noerr; +} +if (chkCmd(1, "DEFRAGSUBS")) { + cerr = 0; + if (argct > 0) {cerr = 3; goto cmderr;} + int so = 0; + for (register int i = 0; i < submaxct;) { + if (!subdata[i].inuse) {++so; --submaxct;} + else {++i;} + if (so) {subdata[i] = subdata[i + so];} + } + goto noerr; +} if (chkCmd(1, "COLOR")) { if (argct > 2 || argct < 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; int32_t tmp = 0; if (argt[1] == 0) {} else if (argt[1] != 2) {cerr = 2; goto cmderr;} @@ -313,7 +450,7 @@ if (chkCmd(1, "COLOR")) { #endif } if (argct > 1) { - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (argt[2] == 0) {} else if (argt[2] != 2) {cerr = 2; goto cmderr;} else { @@ -342,7 +479,10 @@ if (chkCmd(1, "LOCATE")) { if (argct > 2 || argct < 1) {cerr = 3; goto cmderr;} cerr = 0; int tmp = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; + #ifdef _WIN_NO_VT + getCurPos(); + #endif if (argt[1] == 0) {} else if (argt[1] != 2) {cerr = 2; goto cmderr;} else { @@ -357,7 +497,7 @@ if (chkCmd(1, "LOCATE")) { } } if (argct > 1) { - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (argt[1] == 0 && argt[2] == 0) {cerr = 3; goto cmderr;} else if (argt[2] == 0) {} else if (argt[2] != 2) {cerr = 2; goto cmderr;} @@ -388,8 +528,8 @@ if (chkCmd(1, "RLOCATE")) { if (argct > 2 || argct < 1) {cerr = 3; goto cmderr;} cerr = 0; int tmp = 0; - if (!solvearg(1)) goto cmderr; - #ifndef _WIN_NO_VT + if (!solvearg(arg, argt, argl, 1)) goto cmderr; + #ifdef _WIN_NO_VT getCurPos(); #endif if (argt[1] == 0) {} @@ -413,7 +553,7 @@ if (chkCmd(1, "RLOCATE")) { } } if (argct > 1) { - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (argt[1] == 0 && argt[2] == 0) {cerr = 3; goto cmderr;} else if (argt[2] == 0) {} else if (argt[2] != 2) {cerr = 2; goto cmderr;} @@ -444,36 +584,83 @@ if (chkCmd(1, "RLOCATE")) { goto noerr; } if (chkCmd(1, "CLS")) { - if (argct > 1) {cerr = 3; goto cmderr;} + if (argct > 2) {cerr = 3; goto cmderr;} cerr = 0; uint8_t tbgc = txtattrib.bgc; - #ifndef _WIN_NO_VT - uint32_t ttbgc = txtattrib.truebgc; - #endif + int32_t ttbgc = txtattrib.truebgc; + int line = 0; if (argct) { - if (!solvearg(1)) goto cmderr; - if (argt[1] != 2) {cerr = 2; goto cmderr;} - #ifndef _WIN_NO_VT - if (txtattrib.truecolor) { - ttbgc = (uint32_t)atoi(arg[1]); - } else { - tbgc = (uint8_t)atoi(arg[1]); + if (!solvearg(arg, argt, argl, 1)) goto cmderr; + if (argct == 2) { + if (!solvearg(arg, argt, argl, 2)) goto cmderr; + if (argt[2]) { + if (argt[2] != 2) {cerr = 2; goto cmderr;} + line = atoi(arg[2]); + if (line < 1) {cerr = 16; goto cmderr;} + } else { + #ifdef _WIN_NO_VT + getCurPos(); + line = cury; + #else + line = -1; + #endif + } + } + if (argt[1]) { + if (argt[1] != 2) {cerr = 2; goto cmderr;} + if (txtattrib.truecolor) { + ttbgc = atoi(arg[1]); + if (ttbgc < 0 || ttbgc > 0xFFFFFF) {cerr = 16; goto cmderr;} + } else { + tbgc = atoi(arg[1]); + if (ttbgc < 0 || ttbgc > 255) {cerr = 16; goto cmderr;} + } } - #else - tbgc = (uint8_t)atoi(arg[1]); - #endif } #ifndef _WIN_NO_VT - if (esc && argct) { - if (txtattrib.truecolor) printf("\e[48;2;%u;%u;%um", (uint8_t)(ttbgc >> 16), (uint8_t)(ttbgc >> 8), (uint8_t)ttbgc); - else printf("\e[48;5;%um", tbgc); + if (esc) { + if (argct && argt[1]) { + if (txtattrib.truecolor) printf("\e[48;2;%u;%u;%um", (uint8_t)(ttbgc >> 16), (uint8_t)(ttbgc >> 8), (uint8_t)ttbgc); + else printf("\e[48;5;%um", tbgc); + } + if (line > 0) { + printf("\e[s\e[%d;0H\e[2K\e[u", line); + } else { + if (line == -1) fputs("\e[2K", stdout); + else fputs("\e[H\e[2J\e[3J", stdout); + } + updateTxtAttrib(); + fflush(stdout); } - if (esc) fputs("\e[H\e[2J\e[3J", stdout); - updateTxtAttrib(); - fflush(stdout); #else - SetConsoleTextAttribute(hConsole, (txtattrib.fgc % 16) + (tbgc % 16) * 16); - system("cls"); + if (argct && argt[1]) { + if (txtattrib.truecolor) { + tbgc = ((((ttbgc >> 16) & 0xFF) > 85) << 2 | (((ttbgc >> 8) & 0xFF) > 85) << 1 | ((ttbgc & 0xFF) > 85))\ + | (((ttbgc >> 16) & 0xFF) > 170 || ((ttbgc >> 8) & 0xFF) > 170 || (ttbgc & 0xFF) > 170) << 3; + } else { + uint8_t b1 = 0, b2 = 0; + uint8_t tmpbgc = tbgc; + b1 = tbgc & 1; b2 = (tbgc >> 2) & 1; tmpbgc = (b1 ^ b2); + tmpbgc = (tmpbgc) | (tmpbgc << 2); tmpbgc = tbgc ^ tmpbgc; + tbgc = tmpbgc; + } + SetConsoleTextAttribute(hConsole, (txtattrib.fgc % 16) + (tbgc % 16) * 16); + } + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD count; + GetConsoleScreenBufferInfo(hConsole, &csbi); + DWORD cellCount; + bool l = false; + if (line > 0) { + cellCount = csbi.dwSize.X; + --line; + l = true; + } else { + cellCount = csbi.dwSize.X * csbi.dwSize.Y; + } + FillConsoleOutputCharacter(hConsole, (TCHAR)' ', cellCount, (COORD){0, line}, &count); + FillConsoleOutputAttribute(hConsole, csbi.wAttributes, cellCount, (COORD){0, line}, &count); + if (!l) SetConsoleCursorPosition(hConsole, (COORD){0, line}); updateTxtAttrib(); #endif goto noerr; @@ -481,7 +668,7 @@ if (chkCmd(1, "CLS")) { if (chkCmd(1, "WAITUS")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} if (arg[1][0] == '-') {cerr = 16; goto cmderr;} uint64_t d; @@ -492,22 +679,22 @@ if (chkCmd(1, "WAITUS")) { if (chkCmd(1, "WAITMS")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} if (arg[1][0] == '-') {cerr = 16; goto cmderr;} - double d; - sscanf(arg[1], "%lf", &d); + long double d; + sscanf(arg[1], "%Lf", &d); cb_wait(d * 1000); goto noerr; } if (chkCmd(1, "WAIT")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} if (arg[1][0] == '-') {cerr = 16; goto cmderr;} - double d; - sscanf(arg[1], "%lf", &d); + long double d; + sscanf(arg[1], "%Lf", &d); cb_wait(d * 1000000); goto noerr; } @@ -520,10 +707,10 @@ if (chkCmd(1, "RESETTIMER")) { if (chkCmd(2, "SRAND", "SRND")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} - double rs; - sscanf(arg[1], "%lf", &rs); + long double rs; + sscanf(arg[1], "%Lf", &rs); srand(rs); goto noerr; } @@ -533,7 +720,7 @@ if (chkCmd(2, "CALL", "CALLA")) { bool execa = false; char** tmparg = NULL; int tmpargct = 0; - if (!strcmp(arg[0], "CALLA")) { + if (arg[0][4] == 'A') { if (argct != 1) {cerr = 3; goto cmderr;} execa = true; int v = -1; @@ -547,14 +734,14 @@ if (chkCmd(2, "CALL", "CALLA")) { arg = vardata[v].data - 1; argct = vardata[v].size + 1; } else { - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} } newprogargc = argct; newprogargs = (char**)malloc((argct + 1) * sizeof(char*)); for (int i = 2; i <= argct; ++i) { if (!execa) { - if (!solvearg(i)) { + if (!solvearg(arg, argt, argl, i)) { for (int j = i - 1; j > 0; --j) { free(newprogargs[j]); } @@ -565,8 +752,6 @@ if (chkCmd(2, "CALL", "CALLA")) { newprogargs[i - 1] = malloc(argl[i] + 1); copyStr(arg[i], newprogargs[i - 1]); } - inprompt = !runfile; - setsig(SIGINT, cleanExit); if (!loadProg(arg[1])) goto cmderr; chkinProg = true; cp = 0; @@ -583,7 +768,7 @@ if (chkCmd(2, "RUN", "RUNA")) { bool execa = false; char** tmparg = NULL; int tmpargct = 0; - if (!strcmp(arg[0], "RUNA")) { + if (arg[0][3] == 'A') { if (argct != 1) {cerr = 3; goto cmderr;} execa = true; int v = -1; @@ -597,10 +782,9 @@ if (chkCmd(2, "RUN", "RUNA")) { arg = vardata[v].data - 1; argct = vardata[v].size + 1; } else { - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} } - #ifndef _WIN32 char** runargs = (char**)malloc((argct + 3) * sizeof(char*)); runargs[0] = startcmd; runargs[1] = roptstr; @@ -608,42 +792,13 @@ if (chkCmd(2, "RUN", "RUNA")) { argct += 2; int argno = 3; for (; argno < argct; argno++) { - if (!execa) if (!solvearg(argno - 1)) {free(runargs); goto cmderr;} + if (!execa) if (!solvearg(arg, argt, argl, argno - 1)) {free(runargs); goto cmderr;} runargs[argno] = arg[argno - 1]; } - argct -= 2; runargs[argno] = NULL; - pid_t pid = fork(); - if (pid < 0) cerr = -1; - else if (pid == 0) { - execvp(startcmd, runargs); - exit(0); - } - else if (pid > 0) { - while (wait(&retval) != pid) {} - retval = WEXITSTATUS(retval); - } + argct -= 2; + retval = cb_exec(runargs); free(runargs); - #else - char* tmpcmd = malloc(CB_BUF_SIZE); - tmpcmd[0] = 0; - bool nq; - if ((nq = winArgNeedsQuotes(startcmd))) copyStrApnd(" \"", tmpcmd); - copyStrApnd(startcmd, tmpcmd); - if (nq) strApndChar(tmpcmd, '"'); - copyStrApnd(" -x", tmpcmd); - for (int argno = 1; argno <= argct; ++argno) { - if (!execa) if (argno > 1) if (!solvearg(argno)) {free(tmpcmd); goto cmderr;} - strApndChar(tmpcmd, ' '); - bool nq = winArgNeedsQuotes(arg[argno]); - if (nq) strApndChar(tmpcmd, '"'); - copyStrApnd(arg[argno], tmpcmd); - if (nq) strApndChar(tmpcmd, '"'); - } - int ret = system(tmpcmd); - (void)ret; - free(tmpcmd); - #endif if (execa) { argct = tmpargct; arg = tmparg; @@ -654,7 +809,7 @@ if (chkCmd(2, "RUN", "RUNA")) { if (chkCmd(2, "$", "SH")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} #ifndef _WIN_NO_VT if (esc && sh_clearAttrib) fputs("\e[0m", stdout); @@ -685,7 +840,7 @@ if (chkCmd(2, "EXEC", "EXECA")) { bool execa = false; char** tmparg = NULL; int tmpargct = 0; - if (!strcmp(arg[0], "EXECA")) { + if (arg[0][4] == 'A') { if (argct != 1) {cerr = 3; goto cmderr;} execa = true; int v = -1; @@ -699,7 +854,7 @@ if (chkCmd(2, "EXEC", "EXECA")) { arg = vardata[v].data - 1; argct = vardata[v].size + 1; } else { - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} } #ifndef _WIN_NO_VT @@ -708,12 +863,11 @@ if (chkCmd(2, "EXEC", "EXECA")) { if (sh_clearAttrib) SetConsoleTextAttribute(hConsole, ocAttrib); #endif fflush(stdout); - #ifndef _WIN32 char** runargs = (char**)malloc((argct + 1) * sizeof(char*)); runargs[0] = arg[1]; int argno = 1; for (; argno < argct; ++argno) { - if (!execa) if (!solvearg(argno + 1)) {free(runargs); goto cmderr;} + if (!execa) if (!solvearg(arg, argt, argl, argno + 1)) {free(runargs); goto cmderr;} runargs[argno] = arg[argno + 1]; } runargs[argno] = NULL; @@ -725,53 +879,13 @@ if (chkCmd(2, "EXEC", "EXECA")) { dup2(fd, 1); dup2(fd, 2); } - pid_t pid = fork(); - if (pid < 0) cerr = -1; - if (pid == 0) { - execvp(runargs[0], runargs); - exit(127); - } - else if (pid > 0) { - while (wait(&retval) != pid) {} - retval = ((retval >> 8) & 0xFF); - } - else if (sh_silent) { + retval = cb_exec(runargs); + if (sh_silent) { dup2(stdout_dup, 1); dup2(stderr_dup, 2); } getCurPos(); free(runargs); - #else - char* tmpcmd = malloc(CB_BUF_SIZE); - tmpcmd[0] = 0; - bool winecho = false; - for (int argno = 1; argno <= argct; ++argno) { - if (!execa) if (argno > 1) if (!solvearg(argno)) {free(tmpcmd); goto cmderr;}; - strApndChar(tmpcmd, ' '); - bool nq = winArgNeedsQuotes(arg[argno]); - if (argno == 1) { - upCase(arg[argno]); - winecho = !strcmp(arg[argno], "ECHO"); - } - if (nq && !winecho) copyStrApnd(" \"", tmpcmd); - copyStrApnd(arg[argno], tmpcmd); - if (nq && !winecho) strApndChar(tmpcmd, '"'); - } - int stdout_dup = 0, stderr_dup = 0; - if (sh_silent) { - stdout_dup = dup(1); - stderr_dup = dup(2); - int fd = open("NUL", _O_WRONLY | _O_CREAT); - dup2(fd, 1); - dup2(fd, 2); - } - retval = WEXITSTATUS(system(tmpcmd)); - if (sh_silent) { - dup2(stdout_dup, 1); - dup2(stderr_dup, 2); - } - free(tmpcmd); - #endif if (execa) { argct = tmpargct; arg = tmparg; @@ -783,21 +897,21 @@ if (chkCmd(2, "EXEC", "EXECA")) { if (chkCmd(1, "BELL")) { cerr = 0; int ct = 1; - double d = 750; + long double d = 750; if (argct > 2) {cerr = 3; goto cmderr;} if (argct >= 1) { - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] == 0) {cerr = 3; goto cmderr;} if (argt[1] != 2) {cerr = 2; goto cmderr;} ct = atoi(arg[1]); if (ct < 1) {cerr = 16; goto cmderr;} } if (argct == 2) { - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (argt[2] == 0) {cerr = 3; goto cmderr;} if (argt[2] != 2) {cerr = 2; goto cmderr;} if (arg[2][0] == '-') {cerr = 16; goto cmderr;} - sscanf(arg[2], "%lf", &d); + sscanf(arg[2], "%Lf", &d); } putchar('\a'); fflush(stdout); @@ -814,7 +928,7 @@ if (chkCmd(1, "FILES")) { if (argct > 1) {cerr = 3; goto cmderr;} char* olddn = NULL; if (argct) { - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} int tmpret = isFile(arg[1]); if (tmpret) { @@ -873,7 +987,7 @@ if (chkCmd(1, "EXTENSIONS")) { if (chkCmd(2, "CHDIR", "CD")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} if (chdir(arg[1])) { seterrstr(arg[1]); @@ -886,7 +1000,7 @@ if (chkCmd(1, "FCLOSE")) { cerr = 0; fileerror = 0; if (argct != 1) {cerr = 3; goto cmderr;} - if (!solvearg(1)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 1)) {goto cmderr;} if (argt[1] != 2) {cerr = 3; goto cmderr;} if (!closeFile(atoi(arg[1]))) {cerr = 16; goto cmderr;} goto noerr; @@ -895,8 +1009,8 @@ if (chkCmd(1, "FWRITE")) { cerr = 0; fileerror = 0; if (argct != 2) {cerr = 3; goto cmderr;} - if (!solvearg(1)) {goto cmderr;} - if (!solvearg(2)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 1)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 2)) {goto cmderr;} if (argt[1] != 2 || argt[2] != 1) {cerr = 2; goto cmderr;} int fnum = atoi(arg[1]); if (fnum < 0 || fnum >= filemaxct) { @@ -913,8 +1027,8 @@ if (chkCmd(1, "FSEEK")) { cerr = 0; fileerror = 0; if (argct != 2) {cerr = 3; goto cmderr;} - if (!solvearg(1)) {goto cmderr;} - if (!solvearg(2)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 1)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 2)) {goto cmderr;} if (argt[1] != 2 || argt[2] != 2) {cerr = 2; goto cmderr;} int fnum = atoi(arg[1]); if (fnum < 0 || fnum >= filemaxct) { @@ -936,7 +1050,7 @@ if (chkCmd(1, "FLUSH")) { cerr = 0; fileerror = 0; if (argct != 1) {cerr = 3; goto cmderr;} - if (!solvearg(1)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 1)) {goto cmderr;} if (argt[1] != 2) {cerr = 2; goto cmderr;} int fnum = atoi(arg[1]); if (fnum < 0 || fnum >= filemaxct) { @@ -952,7 +1066,7 @@ if (chkCmd(2, "MD", "MKDIR")) { cerr = 0; fileerror = 0; if (argct != 1) {cerr = 3; goto cmderr;} - if (!solvearg(1)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 1)) {goto cmderr;} if (argt[1] != 1) {cerr = 2; goto cmderr;} errno = 0; #ifndef _WIN32 @@ -967,7 +1081,7 @@ if (chkCmd(2, "RM", "REMOVE")) { cerr = 0; fileerror = 0; if (argct != 1) {cerr = 3; goto cmderr;} - if (!solvearg(1)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 1)) {goto cmderr;} if (argt[1] != 1) {cerr = 2; goto cmderr;} cbrm(arg[1]); goto noerr; @@ -976,8 +1090,8 @@ if (chkCmd(4, "MV", "MOVE", "REN", "RENAME")) { cerr = 0; fileerror = 0; if (argct != 2) {cerr = 3; goto cmderr;} - if (!solvearg(1)) {goto cmderr;} - if (!solvearg(2)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 1)) {goto cmderr;} + if (!solvearg(arg, argt, argl, 2)) {goto cmderr;} if (argt[1] != 1 || argt[2] != 1) {cerr = 2; goto cmderr;} errno = 0; rename(arg[1], arg[2]); @@ -988,7 +1102,7 @@ if (chkCmd(1, "LOADEXT")) { if (argct < 1) {cerr = 3; goto cmderr;} cerr = 0; for (int i = 1; i <= argct; i++) { - if (!solvearg(i) || argt[i] != 1) {cerr = 2; goto cmderr;} + if (!solvearg(arg, argt, argl, i) || argt[i] != 1) {cerr = 2; goto cmderr;} if (loadExt(arg[i]) < 0) {goto cmderr;} } goto noerr; @@ -996,7 +1110,7 @@ if (chkCmd(1, "LOADEXT")) { if (chkCmd(1, "UNLOADEXT")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] == 1) { upCase(arg[1]); for (register int i = 0; i < extmaxct; ++i) { @@ -1038,7 +1152,7 @@ if (chkCmd(1, "_RESETTITLE")) { if (chkCmd(1, "_TITLE")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} #ifndef _WIN_NO_VT if (esc) { @@ -1058,8 +1172,8 @@ if (chkCmd(1, "_TITLE")) { if (chkCmd(1, "_SETENV")) { if (argct != 2) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (argt[1] != 1 || argt[2] != 1) {cerr = 2; goto cmderr;} #ifndef _WIN32 setenv(arg[1], arg[2], 1); @@ -1071,7 +1185,7 @@ if (chkCmd(1, "_SETENV")) { if (chkCmd(1, "_UNSETENV")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} #ifndef _WIN32 unsetenv(arg[1]); @@ -1085,7 +1199,7 @@ if (chkCmd(1, "_PROMPT")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; copyStr(arg[1], prompt); - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} goto noerr; } @@ -1093,7 +1207,7 @@ if (chkCmd(1, "_PROMPTTAB")) { if (inProg && !autorun) {cerr = 254; goto cmderr;} if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} tab_width = atoi(arg[1]); goto noerr; @@ -1110,7 +1224,7 @@ if (chkCmd(1, "_SAVECMDHIST")) { if (argct > 1) {cerr = 3; goto cmderr;} cerr = 0; if (argct) { - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} write_history(arg[1]); } else { @@ -1131,7 +1245,7 @@ if (chkCmd(1, "_LOADCMDHIST")) { cerr = 0; clear_history(); if (argct) { - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} read_history(arg[1]); } else { @@ -1147,7 +1261,7 @@ if (chkCmd(1, "_LIMITCMDHIST")) { if (inProg && !autorun) {cerr = 254; goto cmderr;} if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} int32_t l = atoi(arg[1]); if (l < -1) { @@ -1159,6 +1273,40 @@ if (chkCmd(1, "_LIMITCMDHIST")) { } goto noerr; } +if (chkCmd(1, "_HIDECUR")) { + if (argct) {cerr = 3; goto cmderr;} + cerr = 0; + hidecursor = true; + #ifndef _WIN_NO_VT + if (esc) { + fputs("\e[?25l", stdout); + fflush(stdout); + } + #else + CONSOLE_CURSOR_INFO curinfo; + GetConsoleCursorInfo(hConsole, &curinfo); + curinfo.bVisible = false; + SetConsoleCursorInfo(hConsole, &curinfo); + #endif + goto noerr; +} +if (chkCmd(1, "_SHOWCUR")) { + if (argct) {cerr = 3; goto cmderr;} + cerr = 0; + #ifndef _WIN_NO_VT + if (esc) { + fputs("\e[?25h", stdout); + fflush(stdout); + } + #else + CONSOLE_CURSOR_INFO curinfo; + GetConsoleCursorInfo(hConsole, &curinfo); + curinfo.bVisible = true; + SetConsoleCursorInfo(hConsole, &curinfo); + #endif + hidecursor = false; + goto noerr; +} if (chkCmd(1, "_TXTLOCK")) { if (argct) {cerr = 3; goto cmderr;} cerr = 0; @@ -1185,7 +1333,7 @@ if (chkCmd(1, "_TXTUNLOCK")) { if (chkCmd(1, "_TXTATTRIB")) { if (argct < 1 || argct > 2) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] == 0) {cerr = 3; goto cmderr;} int attrib = 0; if (argt[1] == 1) { @@ -1197,7 +1345,7 @@ if (chkCmd(1, "_TXTATTRIB")) { if (!strcmp(arg[1], "BOLD")) attrib = 1; else if (!strcmp(arg[1], "ITALIC")) attrib = 2; else if (!strcmp(arg[1], "UNDERLINE")) attrib = 3; else - if (!strcmp(arg[1], "DBL_UNDERLINE") || !strcmp(arg[1], "DOUBLE_UNDERLINE")) attrib = 4; else + if (!strcmp(arg[1], "DBL_UNDERLINE") || !strcmp(arg[1], "long double_UNDERLINE")) attrib = 4; else if (!strcmp(arg[1], "SQG_UNDERLINE") || !strcmp(arg[1], "SQUIGGLY_UNDERLINE")) attrib = 5; else if (!strcmp(arg[1], "STRIKETHROUGH")) attrib = 6; else if (!strcmp(arg[1], "OVERLINE")) attrib = 7; else @@ -1212,7 +1360,7 @@ if (chkCmd(1, "_TXTATTRIB")) { {cerr = 16; goto cmderr;} } else { attrib = atoi(arg[1]); - if (attrib < 0 || attrib > 12) {cerr = 16; goto cmderr;} + if (attrib < 0 || attrib > 15) {cerr = 16; goto cmderr;} } int val = 0; if (attrib == 0) { @@ -1224,7 +1372,7 @@ if (chkCmd(1, "_TXTATTRIB")) { if (attrib == 12) {cerr = 16; goto cmderr;} val = 1; } else { - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (attrib == 12) { if (argt[2] != 2) {cerr = 2; goto cmderr;} val = atoi(arg[2]); @@ -1265,7 +1413,7 @@ if (chkCmd(1, "_TXTATTRIB")) { if (chkCmd(1, "_SHATTRIB")) { if (argct < 1 || argct > 2) {cerr = 3; goto cmderr;} cerr = 0; - if (!solvearg(1)) goto cmderr; + if (!solvearg(arg, argt, argl, 1)) goto cmderr; if (argt[1] == 0) {cerr = 3; goto cmderr;} int attrib = 0; if (argt[1] == 1) { @@ -1293,7 +1441,7 @@ if (chkCmd(1, "_SHATTRIB")) { if (attrib == 12) {cerr = 16; goto cmderr;} val = 1; } else { - if (!solvearg(2)) goto cmderr; + if (!solvearg(arg, argt, argl, 2)) goto cmderr; if (argt[2] == 0) {cerr = 3; goto cmderr;} if (argt[2] == 1) { upCase(arg[2]); diff --git a/docs b/docs index 79193cd..3de3233 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 79193cd786491c2c4ce600839daf68de30c51833 +Subproject commit 3de3233daf721f602f549d39236c35b8ca16890a diff --git a/examples b/examples index 94695d1..7cce387 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 94695d1a6d1ed9a36453e366bafd1f79e3ce6fe2 +Subproject commit 7cce387cf803896f99b3d918cfd404ef04774c80 diff --git a/functions.c b/functions.c index 5767ba9..efd94b6 100644 --- a/functions.c +++ b/functions.c @@ -59,20 +59,20 @@ if (chkCmd(1, "CHRAT$")) { if (chkCmd(2, "RND", "RAND")) { cerr = 0; ftype = 2; - double min = 0; - double max; + long double min = 0; + long double max; if (fargct == 1) { if (fargt[1] != 2) {cerr = 2; goto fexit;} - sscanf(farg[1], "%lf", &max); + sscanf(farg[1], "%Lf", &max); } else if (fargct == 2) { if (fargt[1] + fargt[2] != 4) {cerr = 2; goto fexit;} - sscanf(farg[1], "%lf", &min); - sscanf(farg[2], "%lf", &max); + sscanf(farg[1], "%Lf", &min); + sscanf(farg[2], "%Lf", &max); } else { cerr = 3; goto fexit; } - sprintf(outbuf, "%lf", randNum(min, max)); + sprintf(outbuf, "%Lf", randNum(min, max)); goto fexit; } if (chkCmd(1, "TIMERUS")) { @@ -149,12 +149,12 @@ if (chkCmd(2, "EXEC", "EXECA")) { bool execa = false; char** tmpfarg = NULL; int tmpfargct = 0; - if (!strcmp(farg[0], "EXECA")) { + if (farg[0][4] == 'A') { if (fargct != 1) {cerr = 3; goto fexit;} execa = true; int v = -1; for (register int i = 0; i < varmaxct; ++i) { - if (vardata[i].inuse && !strcmp(arg[1], vardata[i].name)) {v = i; break;} + if (vardata[i].inuse && !strcmp(farg[1], vardata[i].name)) {v = i; break;} } if (v == -1 || vardata[v].size == -1) {cerr = 23; seterrstr(farg[1]); goto fexit;} if (vardata[v].type != 1) {cerr = 2; goto fexit;} @@ -170,7 +170,6 @@ if (chkCmd(2, "EXEC", "EXECA")) { #else if (sh_clearAttrib) SetConsoleTextAttribute(hConsole, ocAttrib); #endif - #ifndef _WIN32 char** runargs = (char**)malloc((fargct + 1) * sizeof(char*)); runargs[0] = farg[1]; int argno = 1; @@ -178,7 +177,6 @@ if (chkCmd(2, "EXEC", "EXECA")) { runargs[argno] = farg[argno + 1]; } runargs[argno] = NULL; - int status; int stdout_dup = 0, stderr_dup = 0, fd = 0; if (sh_silent) { stdout_dup = dup(1); @@ -187,51 +185,13 @@ if (chkCmd(2, "EXEC", "EXECA")) { dup2(fd, 1); dup2(fd, 2); } - pid_t pid = fork(); - if (pid < 0) cerr = -1; - if (pid == 0) { - execvp(runargs[0], runargs); - exit(127); - } - else if (pid > 0) { - while (wait(&status) != pid) {} - sprintf(outbuf, "%d", (retval = WEXITSTATUS(status))); - } - else if (sh_silent) { + sprintf(outbuf, "%d", (retval = cb_exec(runargs))); + if (sh_silent) { dup2(stdout_dup, 1); dup2(stderr_dup, 2); close(fd); } free(runargs); - #else - char* tmpcmd = malloc(CB_BUF_SIZE); - tmpcmd[0] = 0; - bool winecho = false; - for (int argno = 1; argno <= fargct; argno++) { - bool nq = winArgNeedsQuotes(farg[argno]); - if (argno == 1) { - upCase(farg[argno]); - winecho = !strcmp(farg[argno], "ECHO"); - } - if (nq && !winecho) copyStrApnd(" \"", tmpcmd); - copyStrApnd(farg[argno], tmpcmd); - if (nq && !winecho) strApndChar(tmpcmd, '"'); - } - int stdout_dup = 0, stderr_dup = 0; - if (sh_silent) { - stdout_dup = dup(1); - stderr_dup = dup(2); - int fd = open("NUL", _O_WRONLY); - dup2(fd, 1); - dup2(fd, 2); - } - retval = WEXITSTATUS(system(tmpcmd)); - if (sh_silent) { - dup2(stdout_dup, 1); - dup2(stderr_dup, 2); - } - free(tmpcmd); - #endif if (execa) { fargct = tmpfargct; farg = tmpfarg; @@ -265,7 +225,7 @@ if (chkCmd(2, "EXEC$", "EXECA$")) { bool execa = false; char** tmpfarg = NULL; int tmpfargct = 0; - if (!strcmp(farg[0], "EXECA$")) { + if (farg[0][4] == 'A') { if (fargct != 1) {cerr = 3; goto fexit;} execa = true; int v = -1; @@ -281,7 +241,6 @@ if (chkCmd(2, "EXEC$", "EXECA$")) { } else { if (fargt[1] != 1) {cerr = 2; goto fexit;} } - #ifndef _WIN32 char** runargs = (char**)malloc((fargct + 1) * sizeof(char*)); runargs[0] = farg[1]; int argno = 1; @@ -290,60 +249,96 @@ if (chkCmd(2, "EXEC$", "EXECA$")) { } runargs[argno] = NULL; int stdout_dup = 0, stderr_dup = 0, fd[2]; - if (pipe(fd) == -1) {cerr = -1; goto fexit;} + #ifndef _WIN32 + pipe2(fd, O_NONBLOCK); + #else + _pipe(fd, CB_BUF_SIZE, _O_BINARY); + #endif stdout_dup = dup(1); stderr_dup = dup(2); dup2(fd[1], 1); dup2(fd[1], 2); - pid_t pid = fork(); - if (pid < 0) cerr = -1; - else if (pid == 0) { - execvp(runargs[0], runargs); - putchar(0); - exit(127); - } - else if (pid > 0) { - while (wait(&retval) != pid) {} - retval = WEXITSTATUS(retval); - outbuf[read(fd[0], outbuf, CB_BUF_SIZE - 1)] = 0; + retval = cb_exec(runargs); + *outbuf = 0; + if (retval >= 0) { + #ifndef _WIN32 + int inchar = 0; + ioctl(fd[0], FIONREAD, &inchar); + #else + DWORD inchar = 0; + PeekNamedPipe((HANDLE)_get_osfhandle(fd[0]), NULL, 0, NULL, &inchar, NULL); + #endif + if (inchar) outbuf[read(fd[0], outbuf, CB_BUF_SIZE - 1)] = 0; } dup2(stdout_dup, 1); dup2(stderr_dup, 2); close(fd[0]); close(fd[1]); free(runargs); - #else - char* tmpcmd = malloc(CB_BUF_SIZE); - tmpcmd[0] = 0; - bool winecho = false; - for (int argno = 1; argno <= fargct; argno++) { - bool nq = winArgNeedsQuotes(farg[argno]); - if (argno == 1) { - upCase(farg[argno]); - winecho = !strcmp(farg[argno], "ECHO"); - } - if (nq && !winecho) copyStrApnd(" \"", tmpcmd); - copyStrApnd(farg[argno], tmpcmd); - if (nq && !winecho) strApndChar(tmpcmd, '"'); - } - int duperr; - duperr = dup(2); - close(2); - outbuf[0] = 0; - FILE* p = popen(tmpcmd, "r"); - if (p) { - outbuf[fread(outbuf, 1, CB_BUF_SIZE, p)] = 0; - retval = WEXITSTATUS(pclose(p)); - } - dup2(duperr, 2); - close(duperr); - free(tmpcmd); - #endif if (execa) { fargct = tmpfargct; farg = tmpfarg; } - //printf("farg[1]: {%s}\n", farg[1]); + goto fexit; +} +if (chkCmd(1, "CALLFUNC")) { + if (fargct < 1) {cerr = 3; goto fexit;} + cerr = 0; + ftype = 1; + newprogargc = fargct; + newprogargs = (char**)malloc((fargct + 1) * sizeof(char*)); + for (int i = 1; i < newprogargc; ++i) { + newprogargs[i] = NULL; + } + for (int i = 2; i <= fargct; ++i) { + newprogargs[i - 1] = malloc(CB_BUF_SIZE); + if (!getVal(farg[i], newprogargs[i - 1])) { + for (int j = i - 1; j > 0; --j) { + free(newprogargs[j]); + } + free(newprogargs); + goto fexit; + } + newprogargs[i - 1] = realloc(newprogargs[i - 1], strlen(newprogargs[i - 1]) + 1); + } + + if (!loadSub(farg[1], true, &subinfo.type)) goto callfunc_err; + subinfo.insub = true; + ftype = subinfo.type; + bool oip = inProg; + inProg = true; + int ptr1 = 0, ptr2 = 0; + char* buf = (char*)malloc(CB_BUF_SIZE); + while (1) { + while (progbuf[progindex][ptr2] && progbuf[progindex][ptr2] != '\n') {++ptr2;} + copyStrSnip(progbuf[progindex], ptr1, ptr2, buf); + if ((cerr = runcmd(buf))) {hideerror = true; break;} + if (!progbuf[progindex][ptr2]) break; + if (!didloop) ++progLine; + else didloop = false; + ++ptr2; + ptr1 = ptr2; + } + free(buf); + inProg = oip; + unloadProg(); + goto callfunc_noerr; + callfunc_err:; + for (int i = 1; i < newprogargc; ++i) { + nfree(newprogargs[i]); + } + nfree(newprogargs); + newprogargc = 0; + goto fexit; + callfunc_noerr:; + if (!cerr) { + if (funcret) { + copyStr(funcret, outbuf); + nfree(funcret); + } else { + copyStr((ftype == 1) ? defaultstr : defaultnum, outbuf); + } + } goto fexit; } if (chkCmd(1, "CINT")) { @@ -351,7 +346,7 @@ if (chkCmd(1, "CINT")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - sprintf(outbuf, "%d", (int)round(atof(farg[1]))); + sprintf(outbuf, "%d", (int)round(strtold(farg[1], NULL))); goto fexit; } if (chkCmd(1, "INT")) { @@ -359,8 +354,8 @@ if (chkCmd(1, "INT")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); sprintf(outbuf, "%d", (int)dbl); int32_t i; for (i = 0; outbuf[i] != '.' && outbuf[i]; i++) {} @@ -373,12 +368,7 @@ if (chkCmd(1, "VAL")) { if (fargct < 1 || fargct > 2) {cerr = 3; goto fexit;} if (fargt[1] != 1) {cerr = 2; goto fexit;} if (fargct == 2 && fargt[2] != 2) {cerr = 2; goto fexit;} - double dbl; - if (fargct == 1) { - sscanf(farg[1], "%lf", &dbl); - sprintf(outbuf, "%lf", dbl); - goto fexit; - } + long double dbl; int act = 0; uint64_t num; char* tmpstr = NULL; @@ -388,6 +378,7 @@ if (chkCmd(1, "VAL")) { switch (act) { case 0:; tmplen = strlen(farg[1]); + if (!tmplen) {copyStr(defaultstr, outbuf); break;} for (int32_t i = 0; farg[1][i] == '0' && i < tmplen; i++) { tmppos++; } @@ -398,9 +389,9 @@ if (chkCmd(1, "VAL")) { outbuf[1] = 0; break; } - sscanf(tmpstr, "%lf", &dbl); + sscanf(tmpstr, "%Lf", &dbl); free(tmpstr); - sprintf(outbuf, "%lf", dbl); + sprintf(outbuf, "%Lf", dbl); break; case 1:; sscanf(farg[1], "%llx", (long long unsigned int*)&num); @@ -438,10 +429,10 @@ if (chkCmd(1, "MOD")) { ftype = 2; if (fargct != 2) {cerr = 3; goto fexit;} if (fargt[1] != 2 || fargt[2] != 2) {cerr = 2; goto fexit;} - double dbl1, dbl2; - sscanf(farg[1], "%lf", &dbl1); - sscanf(farg[2], "%lf", &dbl2); - sprintf(outbuf, "%lf", fmod(dbl1, dbl2)); + long double dbl1, dbl2; + sscanf(farg[1], "%Lf", &dbl1); + sscanf(farg[2], "%Lf", &dbl2); + sprintf(outbuf, "%Lf", fmodl(dbl1, dbl2)); goto fexit; } if (chkCmd(1, "PI")) { @@ -456,7 +447,7 @@ if (chkCmd(1, "ABS")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - sprintf(outbuf, "%lf", fabs(atof(farg[1]))); + sprintf(outbuf, "%Lf", fabsl(strtold(farg[1], NULL))); goto fexit; } if (chkCmd(1, "SIN")) { @@ -464,9 +455,9 @@ if (chkCmd(1, "SIN")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); - sprintf(outbuf, "%lf", sin(dbl)); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); + sprintf(outbuf, "%Lf", sinl(dbl)); goto fexit; } if (chkCmd(1, "COS")) { @@ -474,9 +465,9 @@ if (chkCmd(1, "COS")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); - sprintf(outbuf, "%lf", cos(dbl)); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); + sprintf(outbuf, "%Lf", cosl(dbl)); goto fexit; } if (chkCmd(1, "TAN")) { @@ -484,9 +475,11 @@ if (chkCmd(1, "TAN")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); - sprintf(outbuf, "%lf", tan(dbl)); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); + dbl = tanl(dbl); + if (!isfinite(dbl)) {cerr = 5; goto fexit;} + sprintf(outbuf, "%Lf", dbl); goto fexit; } if (chkCmd(1, "SINH")) { @@ -494,11 +487,11 @@ if (chkCmd(1, "SINH")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); - dbl = sinh(dbl); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); + dbl = sinhl(dbl); if (!isfinite(dbl)) {cerr = 5; goto fexit;} - sprintf(outbuf, "%lf", dbl); + sprintf(outbuf, "%Lf", dbl); goto fexit; } if (chkCmd(1, "COSH")) { @@ -506,11 +499,11 @@ if (chkCmd(1, "COSH")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); - dbl = cosh(dbl); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); + dbl = coshl(dbl); if (!isfinite(dbl)) {cerr = 5; goto fexit;} - sprintf(outbuf, "%lf", dbl); + sprintf(outbuf, "%Lf", dbl); goto fexit; } if (chkCmd(1, "TANH")) { @@ -518,9 +511,11 @@ if (chkCmd(1, "TANH")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); - sprintf(outbuf, "%lf", tanh(dbl)); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); + dbl = tanhl(dbl); + if (!isfinite(dbl)) {cerr = 5; goto fexit;} + sprintf(outbuf, "%Lf", dbl); goto fexit; } if (chkCmd(1, "LOG")) { @@ -528,11 +523,11 @@ if (chkCmd(1, "LOG")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); dbl = log(dbl); if (!isfinite(dbl)) {cerr = 5; goto fexit;} - sprintf(outbuf, "%lf", dbl); + sprintf(outbuf, "%Lf", dbl); goto fexit; } if (chkCmd(1, "LOG10")) { @@ -540,11 +535,11 @@ if (chkCmd(1, "LOG10")) { ftype = 2; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); dbl = log10(dbl); if (!isfinite(dbl)) {cerr = 5; goto fexit;} - sprintf(outbuf, "%lf", dbl); + sprintf(outbuf, "%Lf", dbl); goto fexit; } if (chkCmd(1, "SHIFT")) { @@ -612,11 +607,11 @@ if (chkCmd(1, "EXP")) { cerr = 0; ftype = 2; if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); dbl = exp(dbl); if (!isfinite(dbl)) {cerr = 5; goto fexit;} - sprintf(outbuf, "%lf", dbl); + sprintf(outbuf, "%Lf", dbl); goto fexit; } if (chkCmd(1, "INKEY$")) { @@ -638,9 +633,10 @@ if (chkCmd(1, "INKEY$")) { } outbuf[obp] = 0; #else - updatechars(); + uctStop(); copyStr(kbinbuf, outbuf); kbinbuf[0] = 0; + uctStart(); #endif goto fexit; } @@ -727,9 +723,9 @@ if (chkCmd(1, "HEX$")) { ftype = 1; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); - sprintf(outbuf, "%llx", (long long unsigned int)dbl); + uint64_t num; + sscanf(farg[1], "%llu", (long long unsigned int *)&num); + sprintf(outbuf, "%llx", (long long unsigned int)num); upCase(outbuf); goto fexit; } @@ -738,8 +734,8 @@ if (chkCmd(1, "OCT$")) { ftype = 1; if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 2) {cerr = 2; goto fexit;} - double dbl; - sscanf(farg[1], "%lf", &dbl); + long double dbl; + sscanf(farg[1], "%Lf", &dbl); sprintf(outbuf, "%llo", (long long unsigned int)dbl); upCase(outbuf); goto fexit; @@ -763,27 +759,27 @@ if (chkCmd(1, "RGB")) { if (chkCmd(1, "LIMIT")) { cerr = 0; ftype = 2; - double num = 0; + long double num = 0; if (fargct < 2 || fargct > 3) {cerr = 3; goto fexit;} if (fargt[1] != 2 || fargt[2] != 2) {cerr = 2; goto fexit;} if (fargct == 3 && fargt[3] == 1) {cerr = 2; goto fexit;} - num = atof(farg[1]); + num = strtold(farg[1], NULL); if (fargct == 2) { - double max = atof(farg[2]); + long double max = strtold(farg[2], NULL); if (num > max) {num = max;} } else if (fargct == 3 && fargt[3] == 0) { - double min = atof(farg[2]); + long double min = strtold(farg[2], NULL); if (num < min) {num = min;} } else if (fargct == 3) { - double min = atof(farg[2]); - double max = atof(farg[3]); + long double min = strtold(farg[2], NULL); + long double max = strtold(farg[3], NULL); if (num > max) {num = max;} else if (num < min) {num = min;} } else { cerr = 3; goto fexit; } - sprintf(outbuf, "%lf", num); + sprintf(outbuf, "%Lf", num); goto fexit; } if (chkCmd(1, "PAD$")) { @@ -887,27 +883,24 @@ if (chkCmd(1, "INPUT$")) { cerr = 0; ftype = 1; if (fargct > 1) {cerr = 3; goto fexit;} - if (fargct == 1 && fargt[1] != 1) {cerr = 2; goto fexit;} - if (fargct != 1) { - farg[1] = malloc(4); - strcpy(farg[1], "?: "); - } + if (fargct && fargt[1] != 1) {cerr = 2; goto fexit;} + copyStr((fargct) ? farg[1] : "?: ", gpbuf); char* tmp = NULL; - #ifndef _WIN32 + #ifdef _WIN32 + uctStop(); + #else getCurPos(); - curx--; - farg[1] = realloc(farg[1], strlen(farg[1]) + curx); - int32_t ptr = strlen(farg[1]); - while (curx) {farg[1][ptr] = 22; ptr++; curx--;} - farg[1][ptr] = 0; - #endif - #ifndef _WIN32 + char* tfarg = gpbuf + strlen(gpbuf); + while (--curx) {*tfarg++ = 22;} + *tfarg = 0; __typeof__(rl_getc_function) old_rl_getc_function = rl_getc_function; rl_getc_function = getc; #endif - tmp = readline(farg[1]); + tmp = readline(gpbuf); #ifndef _WIN32 rl_getc_function = old_rl_getc_function; + #else + uctStart(); #endif if (tmp != NULL) { copyStr(tmp, outbuf); @@ -1510,6 +1503,60 @@ if (chkCmd(1, "_TXTLOCK")) { sprintf(outbuf, "%d", (int)textlock); goto fexit; } +if (chkCmd(1, "_TXTATTRIB")) { + if (fargct != 1) {cerr = 3; goto fexit;} + cerr = 0; + ftype = 2; + if (fargt[1] == 0) {cerr = 3; goto fexit;} + int attrib = 0; + if (fargt[1] == 1) { + for (int32_t i = 0; farg[1][i]; i++) { + if (farg[1][i] >= 'a' && farg[1][i] <= 'z') farg[1][i] -= 32; + if (farg[1][i] == ' ') farg[1][i] = '_'; + } + if (!strcmp(farg[1], "RESET")) attrib = 0; else + if (!strcmp(farg[1], "BOLD")) attrib = 1; else + if (!strcmp(farg[1], "ITALIC")) attrib = 2; else + if (!strcmp(farg[1], "UNDERLINE")) attrib = 3; else + if (!strcmp(farg[1], "DBL_UNDERLINE") || !strcmp(farg[1], "long double_UNDERLINE")) attrib = 4; else + if (!strcmp(farg[1], "SQG_UNDERLINE") || !strcmp(farg[1], "SQUIGGLY_UNDERLINE")) attrib = 5; else + if (!strcmp(farg[1], "STRIKETHROUGH")) attrib = 6; else + if (!strcmp(farg[1], "OVERLINE")) attrib = 7; else + if (!strcmp(farg[1], "DIM")) attrib = 8; else + if (!strcmp(farg[1], "BLINK")) attrib = 9; else + if (!strcmp(farg[1], "HIDDEN")) attrib = 10; else + if (!strcmp(farg[1], "REVERSE")) attrib = 11; else + if (!strcmp(farg[1], "UNDERLINE_COLOR")) attrib = 12; else + if (!strcmp(farg[1], "FGC")) attrib = 13; else + if (!strcmp(farg[1], "BGC")) attrib = 14; else + if (!strcmp(farg[1], "TRUECOLOR") || !strcmp(farg[1], "TRUE_COLOR") || !strcmp(farg[1], "24BITCOLOR") || !strcmp(farg[1], "24BIT_COLOR")) attrib = 15; else + {cerr = 16; goto fexit;} + } else { + attrib = atoi(farg[1]); + if (attrib < 0 || attrib > 15) {cerr = 16; goto fexit;} + } + int val = 0; + switch (attrib) { + case 0: val = 0; break; + case 1: val = txtattrib.bold; break; + case 2: val = txtattrib.italic; break; + case 3: val = txtattrib.underln; break; + case 4: val = txtattrib.underlndbl; break; + case 5: val = txtattrib.underlnsqg; break; + case 6: val = txtattrib.strike; break; + case 7: val = txtattrib.overln; break; + case 8: val = txtattrib.dim; break; + case 9: val = txtattrib.blink; break; + case 10: val = txtattrib.hidden; break; + case 11: val = txtattrib.reverse; break; + case 12: val = txtattrib.underlncolor; break; + case 13: val = txtattrib.fgce; break; + case 14: val = txtattrib.bgce; break; + case 15: val = txtattrib.truecolor; break; + } + sprintf(outbuf, "%d", (int)val); + goto fexit; +} if (chkCmd(1, "_VER$")) { cerr = 0; ftype = 1; diff --git a/logic.c b/logic.c index d6cd1ea..f880c3d 100644 --- a/logic.c +++ b/logic.c @@ -107,9 +107,6 @@ if (chkCmd(1, "DO")) { dlstack[dlstackp].pl = progLine; dlstack[dlstackp].brkinfo = brkinfo; brkinfo.block = 1; - #ifdef _WIN32 - updatechars(); - #endif return true; } if (chkCmd(2, "WHILE", "DOWHILE")) { @@ -133,9 +130,6 @@ if (chkCmd(2, "WHILE", "DOWHILE")) { dlstack[dlstackp].cp = cmdpos; dlstack[dlstackp].brkinfo = brkinfo; brkinfo.block = 1; - #ifdef _WIN32 - updatechars(); - #endif } dldcmd[dlstackp] = !testval; return true; @@ -329,9 +323,6 @@ if (chkCmd(1, "FOR")) { fnstack[fnstackp].cp = cmdpos; fnstack[fnstackp].pl = progLine; brkinfo.block = 2; - #ifdef _WIN32 - updatechars(); - #endif return true; } if (chkCmd(1, "NEXT")) {