From b5913ee321e50b10e827594c245a0e0688317522 Mon Sep 17 00:00:00 2001 From: PQCraft <0456523@gmail.com> Date: Fri, 3 Dec 2021 00:56:03 -0500 Subject: [PATCH] 1.0 Bugfixes Fixed a bug in CLS Added the ability to clear a single line in CLS Added subfunctions Switched from double to long double Rewrote getVal() and improved accuracy Fixed getVal() power solving bug due to rewrite Windows now uses CreateProcess() instead of system() for EXEC, EXEC(), and EXEC$() Fixed Windows _kbhit() --- Makefile | 25 +- README.md | 5 +- clibasic.c | 1318 ++++++++++++++++++++++++++++----------------------- clibasic.h | 114 +++-- commands.c | 534 +++++++++++++-------- docs | 2 +- examples | 2 +- functions.c | 375 ++++++++------- logic.c | 9 - 9 files changed, 1365 insertions(+), 1019 deletions(-) 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")) {