diff --git a/Makefile b/Makefile index 216ce69..b8192b9 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,28 @@ BASE_CFLAGS = --std=c99 -Wall -Wextra -Ofast -lm -lreadline -ifdef OS -ifeq ($(findstring :/, $(PATH)), :/) -IS_LINUX = true -else -IS_LINUX = false -endif -else -IS_LINUX = true -endif - -ifeq ($(IS_LINUX), true) +ifndef OS C = gcc CFLAGS = $(BASE_CFLAGS) ifeq ($(shell uname -s), Darwin) -CFLAGS += -I/usr/local/opt/readline/include -L/usr/local/opt/readline/lib +ifeq ($(shell [ -d ~/.brew/opt/readline/include ] && echo true), true) +CFLAGS += -I~/.brew/opt/readline/include +endif +ifeq ($(shell [ -d /opt/homebrew/opt/readline/include ] && echo true), true) +CFLAGS += -I/opt/homebrew/opt/readline/include +endif +ifeq ($(shell [ -d /usr/local/opt/readline/include ] && echo true), true) +CFLAGS += -I/usr/local/opt/readline/include +endif +ifeq ($(shell [ -d ~/.brew/opt/readline/lib ] && echo true), true) +CFLAGS += -L~/.brew/opt/readline/lib +endif +ifeq ($(shell [ -d /opt/homebrew/opt/readline/lib ] && echo true), true) +CFLAGS += -L/opt/homebrew/opt/readline/lib +endif +ifeq ($(shell [ -d /usr/local/opt/readline/lib ] && echo true), true) +CFLAGS += -L/usr/local/opt/readline/lib +endif else ifeq ($(shell uname -o), Android) CFLAGS += -s @@ -26,17 +33,33 @@ endif CBITS = $(shell getconf LONG_BIT) -BUILD_TO = "clibasic" -BUILD__ = $(C) clibasic.c $(CFLAGS) -DB$(CBITS) -o $(BUILD_TO) && chmod +x $(BUILD_TO) +BUILD_TO = clibasic BUILD32 = $(C) 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) +endif + +MAN_PATH = docs/clibasic.man + +ifeq ($(shell id -u), 0) +MAN_INSTALL_PATH = /usr/share/man/man1/clibasic.1 +INSTALL_TO = /usr/bin/clibasic +else +MAN_INSTALL_PATH = ~/.local/share/man/man1/clibasic.1 +INSTALL_TO = ~/.local/bin/clibasic +endif +INSTALL = mkdir -p $(shell dirname -- $(INSTALL_TO)) $(shell dirname -- $(MAN_INSTALL_PATH)); cp $(BUILD_TO) $(INSTALL_TO); cp $(MAN_PATH) $(MAN_INSTALL_PATH); gzip -f $(MAN_INSTALL_PATH) -INSTALL_TO = "/usr/bin/clibasic" -INSTALL = if [ "$$(id -u)" -eq 0 ]; then cp $(BUILD_TO) $(INSTALL_TO); else echo "Root privileges are needed to install."; fi +UNINSTALL = rm -f $(INSTALL_TO) $(MAN_INSTALL_PATH).gz -RUN = ./clibasic +RUN = ./$(BUILD_TO) CLEAN = rm -f clibasic +.ONESHELL: + .PHONY: all all32 build build32 update install install32 run clean cross all: clean build run @@ -54,38 +77,58 @@ update: ([[ ! "$$I" =~ ^[^Yy]$$ ]] && sh -c 'git restore . && git pull' &> /dev/null && chmod +x *.sh) || exit 0 install: - if [ ! -f $(INSTALL_TO) ]; then $(BUILD__); fi + if [ ! -f $(BUILD_TO) ]; then $(BUILD__); fi $(INSTALL) install32: - if [ ! -f $(INSTALL_TO) ]; then $(BUILD32); fi + if [ ! -f $(BUILD_TO) ]; then $(BUILD32); fi $(INSTALL) +uninstall: + $(UNINSTALL) + run: +ifeq (32,$(CBITS)) + [ ! -f "$(BUILD_TO)" ] && ($(BUILD32)) +else + [ ! -f "$(BUILD_TO)" ] && ($(BUILD__)) +endif $(RUN) clean: $(CLEAN) -.ONESHELL: - cross: ifeq ($(MAKECMDGOALS), cross) @$(MAKE) cross all else @$(eval C = x86_64-w64-mingw32-gcc) @$(eval C32 = i686-w64-mingw32-gcc) - @$(eval CFLAGS = $(BASE_CFLAGS) -Ilib) - @$(eval BUILD_TO = "clibasic.exe") - @$(eval BUILD__ = cp -f lib/win64/*.dll . && $(C) clibasic.c $(CFLAGS) -Llib/win64 -DB$(CBITS) -o $(BUILD_TO) && chmod -x ./clibasic.exe) - @$(eval BUILD32 = cp -f lib/win32/*.dll . && $(C32) clibasic.c -m32 $(CFLAGS) -Llib/win32 -DB32 -o $(BUILD_TO) && chmod -x ./clibasic.exe) - @$(eval INSTALL_TO = "$$HOME/.wine/drive_c/windows/system32") + @$(eval CFLAGS = $(BASE_CFLAGS) -s -Ilib) + @$(eval BUILD_TO = clibasic.exe) + @$(eval INSTALL_TO = "$$HOME/.wine/drive_c/windows/system32/") @$(eval INSTALL = cp $(BUILD_TO) *.dll $(INSTALL_TO)) - @$(eval RUN = wineconsole clibasic.exe) + @$(eval BUILD32 = cp -f lib/win32/*.dll . && $(C32) clibasic.c -m32 $(CFLAGS) -Llib/win32 -DB32 -o $(BUILD_TO) && chmod -x $(BUILD_TO)) +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)) +endif + @$(eval RUN = wineconsole .\\$(BUILD_TO)) @$(eval CLEAN = rm -f clibasic.exe *.dll) endif @true +vt: + @$(eval CFLAGS = $(CFLAGS) -DFORCE_VT) + @$(eval BUILD32 = cp -f lib/win32/*.dll . && $(C32) clibasic.c -m32 $(CFLAGS) -Llib/win32 -DB32 -o $(BUILD_TO) && chmod -x $(BUILD_TO)) +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)) +endif + @true + else C = gcc @@ -96,9 +139,11 @@ 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) -INSTALL_TO = "C:\\windows\\system32" +INSTALL_TO = C:\windows\system32 INSTALL = xcopy *.dll $(INSTALL_TO) /Y && xcopy $(BUILD_TO) $(INSTALL_TO) /Y +UNINSTALL = del $(INSTALL_TO)\\$(BUILD_TO) + .PHONY: all all32 build build32 update run clean all: clean build run @@ -128,5 +173,13 @@ run: clean: del /q /f $(BUILD_TO) *.dll +vt: +ifeq ($(MAKECMDGOALS), vt) + @$(MAKE) vt all +else + @$(eval CFLAGS = $(CFLAGS) -DFORCE_VT) +endif + @echo > nul + endif diff --git a/README.md b/README.md index 7aea45e..a4c24dd 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Debian (`apt`): `build-essential`, `libreadline-dev`
Arch (`pacman`): `base-devel`, `readline`
Alpine (`apk`): `build-base`, `readline-dev`
#### Windows
-NT - 10 (download): [`MinGW`](http://mingw-w64.org/doku.php/download/mingw-builds), [`Make for Windows`](http://gnuwin32.sourceforge.net/packages/make.htm)
+NT - 10 (download): [`MinGW`](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe/download), [`Make for Windows`](http://gnuwin32.sourceforge.net/packages/make.htm)
7 - 10 (`choco`): `mingw`, `make`
#### MacOS
Mojave - Big Sur (`brew`): `gcc`, `make`, `readline`
@@ -31,15 +31,36 @@ Mojave - Big Sur (`brew`): `git`
--- ### Building and Running
-#### Linux/Windows/MacOS
+#### Linux/MacOS
To build, use `make build`.
To run, use `make run` or `./clibasic`.
To build then run, use `make` (same as `make all`).
+#### Windows
+Make sure the bin of MinGW is in the %PATH%. +- Type `gcc` into CMD and if you received a "Can't recognize" message, MinGW is not in your %PATH%. +To add MinGW to the %PATH% if you used the downloaded installer: +1. Navigate to where you installed MinGW +2. Open the `mingw64` folder +3. Open the `bin` folder +4. Copy the location +5. Add the location you copied to the %PATH% environment variable + - For Windows 7 and older + 1. Open the Start Menu + 2. Right-click on Computer and click Properties + 3. Click Advanced system settings + 4. Click the Advanced tab + 5. Click Environment Variables + 6. Under System variables, find Path and click Edit + - For Windows 8 and newer + 1. Open the Start Menu + 2. Search for and run 'Edit the system environment variables' + 3. Click Environment Variables + 4. Under System variables, find Path and click Edit --- ### 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. -- If CLIBASIC is not run in a terminal on unix-like OSs it will, unless GUI_CHECK is not defined, attempt to open in XTerm and skip reading arguments. +- On unix-like OSs, if CLIBASIC is not run in a terminal it will attempt to open in XTerm unless GUI_CHECK is undefined. - Due to Windows not having proper fork() and exec\*() functions, EXEC, EXEC(), and EXEC$() are passed through system() under Windows and one issue out of the many with this is a space parsing issue where running `EXEC "test prog"` will attempt to execute `EXEC "test", "prog"` if `test prog` cannot be found in the current directory or %PATH%. - On Windows, pressing CTRL+C will not display a new prompt line due to the Windows version of readline catching and ignoring the CTRL+C. - If the file `.clibasic_history` is present in the user's home directory CLIBASIC will automatically save history there. Run `_AUTOCMDHIST`, `_SAVECMDHIST` (without any arguments), or create the file `.clibasic_history` in your home/user folder to enable this feature. Remove the file to disable this feature. diff --git a/build.sh b/build.sh index a50d35a..1b86126 100644 --- a/build.sh +++ b/build.sh @@ -1,5 +1,6 @@ -# tests if clibasic build on linux and windows successfully +# tests if clibasic builds on linux and windows successfully make build clean +make cross vt build clean make cross build clean diff --git a/clibasic.c b/clibasic.c index 83dab03..5878274 100644 --- a/clibasic.c +++ b/clibasic.c @@ -115,7 +115,7 @@ // Base defines -char VER[] = "0.21.1"; +char VER[] = "0.22"; #if defined(__linux__) char OSVER[] = "Linux"; @@ -143,13 +143,17 @@ char VER[] = "0.21.1"; char BVER[] = "?"; #endif +#if defined(FORCE_VT) && defined(_WIN_NO_VT) + #undef _WIN_NO_VT +#endif + // Global vars and functions int progindex = -1; char** progbuf = NULL; char** progfn = NULL; char* progfnstr = NULL; -int64_t* progcp = NULL; +int32_t* progcp = NULL; int* progcmdl = NULL; int* proglinebuf = NULL; @@ -204,7 +208,9 @@ bool itdcmd[CB_PROG_LOGIC_MAX]; int itstackp = -1; int* minitstackp = NULL; bool didelse = false; +bool didelseif = false; bool* olddidelse = NULL; +bool* olddidelseif = NULL; cb_jump fnstack[CB_PROG_LOGIC_MAX]; bool fndcmd[CB_PROG_LOGIC_MAX]; @@ -229,7 +235,7 @@ int curx = 0; int cury = 0; int concp = 0; -int64_t cp = 0; +int32_t cp = 0; bool cmdint = false; bool inprompt = false; @@ -276,6 +282,8 @@ char* startcmd = NULL; bool changedtitle = false; bool changedtitlecmd = false; +int retval = 0; + typedef struct { int pl; int32_t cp; @@ -291,37 +299,39 @@ cb_goto** proggotodata = NULL; int gotomaxct = 0; int* proggotomaxct = NULL; -#ifdef __unix__ +typedef struct { + FILE* fptr; + int32_t size; +} cb_file; + +cb_file* filedata = NULL; +int filemaxct = 0; +int fileerror = 0; + +#ifndef _WIN32 struct termios term, restore; +struct termios kbhterm, kbhterm2; void txtqunlock() {if (textlock || sneaktextlock) {tcsetattr(0, TCSANOW, &restore); textlock = false;}} int kbhit() { - static const int STDIN = 0; - static bool initialized = false; - if (!initialized) { - struct termios term; - tcgetattr(STDIN, &term); - term.c_lflag &= ~ICANON; - tcsetattr(STDIN, TCSANOW, &term); - setbuf(stdin, NULL); - initialized = true; - } - int bytesWaiting; - ioctl(STDIN, FIONREAD, &bytesWaiting); - return bytesWaiting; + int byteswaiting; + ioctl(0, FIONREAD, &byteswaiting); + return byteswaiting; } + +sigset_t intmask, oldmask; #endif static inline void* setsig(int sig, void* func) { - #ifdef __unix__ + #ifndef _WIN32 struct sigaction act, old; memset (&act, 0, sizeof(act)); memset (&old, 0, sizeof(old)); sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, sig); act.sa_handler = func; - act.sa_flags = SA_RESTART; + //act.sa_flags = SA_RESTART; sigaction(sig, &act, &old); return old.sa_handler; #else @@ -375,6 +385,9 @@ void txtqunlock() {} #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4 #endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(x) ((uint8_t)(x)) +#endif char kbinbuf[256]; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" @@ -415,11 +428,11 @@ uint64_t tval; void* oldsigh = NULL; -void nokill() { +static inline void nokill() { if (!oldsigh) oldsigh = setsig(SIGINT, nokill); } -void yeskill() { +static inline void yeskill() { setsig(SIGINT, oldsigh); oldsigh = NULL; } @@ -427,24 +440,24 @@ void yeskill() { void forceExit() { #ifndef _WIN32 txtqunlock(); + tcsetattr(0, TCSANOW, &kbhterm); #endif exit(0); } static inline void getCurPos(); - -char* gethome(); - -inline void initBaseMem(); -inline void freeBaseMem(); - -void printError(int); - +static inline char* gethome(); +static inline void initBaseMem(); +static inline void freeBaseMem(); +static inline void printError(int); static inline void seterrstr(char*); - void unloadAllProg(); - -char* basefilename(char*); +static inline char* basefilename(char*); +static inline char* pathfilename(char*); +int openFile(char*, char*); +bool closeFile(int); +static inline void upCase(char*); +uint8_t logictest(char*); void cleanExit() { txtqunlock(); @@ -457,11 +470,14 @@ void cleanExit() { putchar('\n'); rl_on_new_line(); rl_replace_line("", 0); - rl_redisplay(); + rl_pending_input = false; + rl_forced_update_display(); return; } setsig(SIGINT, forceExit); setsig(SIGTERM, forceExit); + fflush(stdout); + closeFile(-1); int ret = chdir(gethome()); (void)ret; if (autohist && !runfile) { @@ -478,14 +494,10 @@ void cleanExit() { #else if (!keep) SetConsoleTextAttribute(hConsole, ocAttrib); #endif - do {getCurPos();} while (!curx); - if (curx != 1) putchar('\n'); - #ifdef __unix__ + #ifndef _WIN32 int i = kbhit(); while (i > 0) {getchar(); i--;} - #endif - #ifndef _WIN_NO_VT - fputs("\e[2K", stdout); + tcsetattr(0, TCSANOW, &kbhterm); #endif freeBaseMem(); exit(err); @@ -507,18 +519,20 @@ 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*); uint8_t getVal(char*, char*); static inline void resetTimer(); bool loadProg(char*); void unloadProg(); void updateTxtAttrib(); -static inline bool isFile(); +static inline int isFile(); static inline uint64_t usTime(); -char* gethome() { +static inline char* gethome() { if (!homepath) { - #ifdef __unix__ + #ifndef _WIN32 homepath = getenv("HOME"); #else char* str1 = getenv("HOMEDRIVE"); @@ -533,7 +547,7 @@ char* gethome() { char* bfnbuf = NULL; -char* basefilename(char* fn) { +static inline char* basefilename(char* fn) { int32_t fnlen = strlen(fn); int32_t i; for (i = fnlen; i > -1; --i) { @@ -546,7 +560,7 @@ char* basefilename(char* fn) { return bfnbuf; } -char* pathfilename(char* fn) { +static inline char* pathfilename(char* fn) { int32_t fnlen = strlen(fn); int32_t i; for (i = fnlen; i > -1; --i) { @@ -555,11 +569,11 @@ char* pathfilename(char* fn) { if (fn[i] == '\\') break; #endif } - copyStrSnip(fn, 0, i + 1, bfnbuf); + copyStrTo(fn, i + 1, bfnbuf); return bfnbuf; } -void ttycheck() { +static inline void ttycheck() { if (!isatty(STDERR_FILENO)) {exit(1);} if (!isatty(STDIN_FILENO)) {fputs("CLIBASIC does not support STDIN redirection.\n", stderr); exit(1);} if (!isatty(STDOUT_FILENO)) {fputs("CLIBASIC does not support STDOUT redirection.\n", stderr); exit(1);} @@ -569,8 +583,14 @@ int main(int argc, char** argv) { #if defined(GUI_CHECK) && defined(__unix__) if (system("tty -s 1> /dev/null 2> /dev/null")) { char* command = malloc(CB_BUF_SIZE); - copyStr("xterm -T CLIBASIC -b 0 -bg black -bcn 200 -bcf 200 -e 'echo -e -n \"\x1b[\x33 q\" && ", command); - copyStrApnd(argv[0], command); + copyStr("xterm -T CLIBASIC -b 0 -bg black -bcn 200 -bcf 200 -e $'clear &&", command); + for (int i = 0; i < argc; ++i) { + copyStrApnd(" $\\'", command); + gpbuf[0] = 0; + copyStrApndNoEsc(argv[i], gpbuf); + copyStrApndNoEsc(gpbuf, command); + copyStrApnd("\\'", command); + } strApndChar(command, '\''); int ret = system(command); free(command); @@ -602,17 +622,17 @@ int main(int argc, char** argv) { pexit = true; } else if (!strcmp(argv[i], "--help")) { if (argc > 2) {fputs("Incorrect number of options passed.\n", stderr); exit(1);} - printf("Usage: %s [options] {[[{-f|--file}] FILE] [options] [--args [ARG...]] | --exec FILE [ARG...]}\n", argv[0]); + printf("Usage: %s [OPTION]...\n", argv[0]); puts("Options:"); - puts(" --help Shows this help text."); - puts(" --version Shows the version and license information."); - puts(" --args [ARG...] Passes ARGs to the program."); - puts(" {-x|--exec} FILE [ARG...] Runs and passes ARGs to FILE."); - puts(" {-f|--file} FILE Runs FILE."); - puts(" {-c|--command} COMMAND Runs COMMAND and exits."); - puts(" {-k|--keep} Stops CLIBASIC from resetting text attributes."); - puts(" {-s|--skip} Skips searching for autorun programs."); - puts(" {-i|--info} Enables the info text."); + puts(" --help Displays this help text."); + puts(" --version Displays the version and license information."); + puts(" --args [ARG]... Passes ARGs to the program."); + puts(" -x, --exec FILE [ARG]... Runs and passes ARGs to FILE, then exits."); + puts(" -f, --file FILE Runs FILE and exits."); + puts(" -c, --command COMMAND Runs COMMAND and exits."); + puts(" -k, --keep Stops CLIBASIC from resetting text attributes before exiting."); + puts(" -s, --skip Skips searching for autorun programs."); + puts(" -i, --info Displays an info string when starting in shell mode."); pexit = true; } else if (!strcmp(argv[i], "--args")) { if (runc || !runfile) {fputs("Args can only be passed when running a program.\n", stderr); exit(1);} @@ -657,6 +677,21 @@ int main(int argc, char** argv) { runc = true; runfile = true; copyStr(argv[i], conbuf); + bool inStr = false; + bool inCmd = true; + for (int32_t i = 0; conbuf[i]; ++i) { + switch (conbuf[i]) { + case 'a' ... 'z': + if (!inStr || inCmd) conbuf[i] = conbuf[i] - 32; + break; + case '"': + if (!inCmd) inStr = !inStr; + break; + case ' ': + if (!inStr && inCmd) inCmd = false; + break; + } + } } else if (shortopt && (argv[i][shortopti] == 'c' || argv[i][shortopti] == 'f' || argv[i][shortopti] == 'x')) { fprintf(stderr, "Short option '%c' requires argument and cannot be grouped.\n", argv[i][shortopti]); exit(1); } else { @@ -681,6 +716,14 @@ int main(int argc, char** argv) { } if (pexit) exit(0); ttycheck(); + #ifndef _WIN32 + tcgetattr(0, &kbhterm); + kbhterm2 = kbhterm; + kbhterm2.c_lflag &= ~ICANON; + tcsetattr(0, TCSANOW, &kbhterm2); + sigemptyset(&intmask); + sigaddset(&intmask, SIGINT); + #endif rl_readline_name = "CLIBASIC"; char* rl_tmpptr = calloc(1, 1); rl_completion_entry_function = rl_get_tab; @@ -744,7 +787,7 @@ int main(int argc, char** argv) { #endif #else uint32_t tmpsize = CB_BUF_SIZE; - if (_NSGetExecutablePath(startcmd, &size)) { + if (_NSGetExecutablePath(startcmd, &tmpsize)) { goto scargv; } char* tmpstartcmd = realpath(startcmd, NULL); @@ -779,7 +822,7 @@ int main(int argc, char** argv) { if (info) printf("Command Line Interface BASIC version %s (%s %s-bit)\n", VER, OSVER, BVER); strcpy(prompt, "\"CLIBASIC> \""); #ifdef CHANGE_TITLE - #ifdef __unix__ + #ifndef _WIN32 fputs("\e[22;0t", stdout); changedtitle = true; printf("\e]2;CLIBASIC %s (%s-bit)%c", VER, BVER, 7); @@ -799,16 +842,16 @@ int main(int argc, char** argv) { srand(usTime()); if (!runfile) { if (!gethome()) { - #ifdef __unix__ - fputs("Could not find home folder! Please set the 'HOME' environment variable.", stderr); + #ifndef _WIN32 + fputs("Could not find home folder! Please set the 'HOME' environment variable.\n", stderr); #else - fputs("Could not find home folder!", stderr); + fputs("Could not find home folder!\n", stderr); #endif } else if (!skip) { char* tmpcwd = getcwd(NULL, 0); int ret = chdir(homepath); FILE* tmpfile = fopen(HIST_FILE, "r"); - if ((autohist = (bool)tmpfile)) {fclose(tmpfile); read_history(HIST_FILE);} + if ((autohist = (tmpfile != NULL))) {fclose(tmpfile); read_history(HIST_FILE);} inProg = true; if (!loadProg("AUTORUN.BAS")) if (!loadProg("autorun.bas")) inProg = false; ret = chdir(tmpcwd); @@ -845,7 +888,7 @@ int main(int argc, char** argv) { int tmpt = getVal(prompt, pstr); if (tmpt != 1) strcpy(pstr, "CLIBASIC> "); getCurPos(); - #ifdef __unix__ + #ifndef _WIN32 curx--; int32_t ptr = strlen(pstr); while (curx > 0) {pstr[ptr] = 22; ptr++; curx--;} @@ -859,14 +902,14 @@ int main(int argc, char** argv) { setsig(SIGINT, rl_sigh); #endif conbuf[0] = 0; - #ifdef __unix__ + #ifndef _WIN32 setsig(SIGINT, cleanExit); #endif txtqunlock(); tmpstr = readline(pstr); concp = 0; inprompt = false; - if (!tmpstr) cleanExit(); + if (!tmpstr) {err = 0; cleanExit();} int32_t tmpptr; if (tmpstr[0] == 0) {free(tmpstr); goto brkproccmd;} for (tmpptr = 0; tmpstr[tmpptr] == ' '; ++tmpptr) {} @@ -888,12 +931,28 @@ int main(int argc, char** argv) { if (!tmphist || strcmp(tmpstr, tmphist->line)) add_history(tmpstr); copyStr(tmpstr, conbuf); free(tmpstr); + bool inStr = false; + bool inCmd = true; + for (int32_t i = 0; conbuf[i]; ++i) { + switch (conbuf[i]) { + case 'a' ... 'z': + if (!inStr || inCmd) conbuf[i] = conbuf[i] - 32; + break; + case '"': + if (!inCmd) inStr = !inStr; + break; + case ' ': + if (!inStr && inCmd) inCmd = false; + break; + } + } cmdint = false; } if (runc) runc = false; cmdl = 0; didloop = false; didelse = false; + didelseif = false; bool inStr = false; if (!runfile) setsig(SIGINT, cmdIntHndl); progLine = 1; @@ -929,11 +988,12 @@ int main(int argc, char** argv) { copyStrSnip(progbuf[progindex], cp - cmdl, cp, cmd); cmdl = 0; runcmd(); - if (cmdint) {inProg = false; unloadAllProg(); cmdint = false; goto brkproccmd;} - if (cp == -1) {inProg = false; unloadAllProg(); goto brkproccmd;} + if (cmdint) {err = 0; inProg = false; unloadAllProg(); cmdint = false; goto brkproccmd;} + if (cp == -1) {err = 0; inProg = false; unloadAllProg(); goto brkproccmd;} if (cp > -1 && progbuf[progindex][cp] == 0) { unloadProg(); if (progindex < 0) { + err = 0; inProg = false; goto rechk; } else { @@ -966,7 +1026,7 @@ int main(int argc, char** argv) { } } brkproccmd:; - #ifdef __unix__ + #ifndef _WIN32 setsig(SIGINT, cleanExit); #endif txtqunlock(); @@ -990,27 +1050,41 @@ static inline void resetTimer() { } static inline void cb_wait(uint64_t d) { - #ifdef __unix__ + #ifndef _WIN32 struct timespec dts; dts.tv_sec = d / 1000000; dts.tv_nsec = (d % 1000000) * 1000; nanosleep(&dts, NULL); #else uint64_t t = d + usTime(); - while (t > usTime() && !cmdint) {} + while (t > usTime() && !cmdint) { + if (!textlock) { + char kbc; + int kbh = kbhit(); + for (int i = 0; i < kbh; ++i) { + kbc = _getch(); + kbinbuf[i] = kbc; + putchar(kbc); + if (kbc == 3) { + cmdint = true; + return; + } + } + fflush(stdout); + } + } #endif } -static inline bool isFile(char* path) { +static inline int isFile(char* path) { struct stat pathstat; - stat(path, &pathstat); + if (stat(path, &pathstat)) return -1; return !(S_ISDIR(pathstat.st_mode)); } #ifndef _WIN32 - int gcpret, gcpi; -__sighandler_t gcpoldsigh; +void (*gcpoldsigh)(int); bool gcpint = false; void gcpsigh() { @@ -1022,6 +1096,7 @@ void gcpsigh() { return; } +bool gcp_sig = true; #endif static inline void getCurPos() { @@ -1030,7 +1105,8 @@ static inline void getCurPos() { #ifndef _WIN32 char buf[16]; register int i; - nokill(); + //nokill(); + if (gcp_sig) pthread_sigmask(SIG_SETMASK, &intmask, &oldmask); i = kbhit(); while (i > 0) {getchar(); i--;} if (!textlock) { @@ -1042,16 +1118,22 @@ static inline void getCurPos() { } fputs("\e[6n", stdout); fflush(stdout); - while (!(gcpi += kbhit())) {} + i = 0; + gcpi = 0; + while (!gcpi) {gcpi = kbhit();} + while (i) {gcpi += i = kbhit();} gcpret = read(1, &buf, gcpi + 1); if (!textlock) { tcsetattr(0, TCSANOW, &restore); sneaktextlock = false; } - yeskill(); - if (!gcpret) return; - if (cmdint) {cmdint = false; return;} - sscanf(buf, "\e[%d;%dR", &cury, &curx); + i = kbhit(); + while (i > 0) {getchar(); i--;} + //yeskill(); + //if (cmdint) {cmdint = false; return;} + if (gcpret != gcpi) {gcp_sig = false; getCurPos(); gcp_sig = true;} + else {sscanf(buf, "\e[%d;%dR", &cury, &curx);} + if (gcp_sig) pthread_sigmask(SIG_SETMASK, &oldmask, NULL); #else CONSOLE_SCREEN_BUFFER_INFO con; GetConsoleScreenBufferInfo(hConsole, &con); @@ -1060,7 +1142,7 @@ static inline void getCurPos() { #endif } -void unloadProg() { +void unloadProg() { if (progindex > 0) progfnstr = progfn[progindex - 1]; free(progbuf[progindex]); free(progfn[progindex]); @@ -1074,16 +1156,18 @@ void unloadProg() { cmdl = progcmdl[progindex]; progLine = proglinebuf[progindex]; didelse = olddidelse[progindex]; + didelseif = olddidelseif[progindex]; dlstackp = mindlstackp[progindex]; itstackp = minitstackp[progindex]; fnstackp = minfnstackp[progindex]; - progcp = (int64_t*)realloc(progcp, progindex * sizeof(int64_t)); + progcp = (int32_t*)realloc(progcp, progindex * sizeof(int32_t)); progcmdl = (int*)realloc(progcmdl, progindex * sizeof(int)); proglinebuf = (int*)realloc(proglinebuf, progindex * sizeof(int)); mindlstackp = (int*)realloc(mindlstackp, progindex * sizeof(int)); minitstackp = (int*)realloc(minitstackp, progindex * sizeof(int)); minfnstackp = (int*)realloc(minfnstackp, progindex * sizeof(int)); olddidelse = (bool*)realloc(olddidelse, progindex * sizeof(bool)); + olddidelseif = (bool*)realloc(olddidelseif, progindex * sizeof(bool)); proggotodata = (cb_goto**)realloc(proggotodata, progindex * sizeof(cb_goto*)); proggotomaxct = (int*)realloc(proggotomaxct, progindex * sizeof(int)); progindex--; @@ -1097,6 +1181,7 @@ void unloadAllProg() { } bool loadProg(char* filename) { + retval = 0; fputs("Loading...", stdout); fflush(stdout); seterrstr(filename); @@ -1148,12 +1233,13 @@ bool loadProg(char* filename) { progfnstr = progfn[progindex]; ++progindex; progbuf = (char**)realloc(progbuf, progindex * sizeof(char*)); - progcp = (int64_t*)realloc(progcp, progindex * sizeof(int64_t)); + progcp = (int32_t*)realloc(progcp, progindex * sizeof(int32_t)); progcmdl = (int*)realloc(progcmdl, progindex * sizeof(int)); proglinebuf = (int*)realloc(proglinebuf, progindex * sizeof(int)); mindlstackp = (int*)realloc(mindlstackp, progindex * sizeof(int)); minitstackp = (int*)realloc(minitstackp, progindex * sizeof(int)); olddidelse = (bool*)realloc(olddidelse, progindex * sizeof(bool)); + olddidelseif = (bool*)realloc(olddidelseif, progindex * sizeof(bool)); minfnstackp = (int*)realloc(minfnstackp, progindex * sizeof(int)); proggotodata = (cb_goto**)realloc(proggotodata, progindex * sizeof(cb_goto*)); proggotomaxct = (int*)realloc(proggotomaxct, progindex * sizeof(int)); @@ -1173,9 +1259,10 @@ bool loadProg(char* filename) { cmdl = 0; progLine = 1; didelse = false; + didelseif = false; getCurPos(); int tmpx = curx, tmpy = cury; - uint32_t fsize = (uint32_t)ftell(prog); + int32_t fsize = (uint32_t)ftell(prog); uint64_t time2 = usTime(); fseek(prog, 0, SEEK_SET); #ifndef _WIN_NO_VT @@ -1186,7 +1273,7 @@ bool loadProg(char* filename) { printf("(%llu bytes)...", (long long unsigned)fsize); fflush(stdout); progbuf[progindex] = (char*)malloc(fsize + 1); - int64_t j = 0; + int32_t j = 0; bool comment = false; bool inStr = false; #ifndef _WIN_NO_VT @@ -1196,13 +1283,14 @@ bool loadProg(char* filename) { #endif printf("(0/%llu bytes)...", (long long unsigned)fsize); fflush(stdout); - while (!feof(prog)) { + while (j < fsize && !feof(prog)) { int tmpc = fgetc(prog); if (tmpc == '"') inStr = !inStr; if (!inStr && (tmpc == '\'' || tmpc == '#')) comment = true; if (tmpc == '\n') comment = false; if (tmpc == '\r' || tmpc == '\t') tmpc = ' '; - if (!comment) {progbuf[progindex][j] = (char)tmpc; j++;} + if (tmpc < 0) tmpc = 0; + if (!comment) {progbuf[progindex][j] = (char)((inStr) ? tmpc : ((tmpc >= 'a' && tmpc <= 'z') ? tmpc -= 32 : tmpc)); j++;} if (usTime() - time2 >= 250000) { time2 = usTime(); #ifndef _WIN_NO_VT @@ -1234,8 +1322,7 @@ bool loadProg(char* filename) { #endif putchar('\r'); fflush(stdout); - if (j < 1) j = 1; - progbuf[progindex][j - 1] = 0; + progbuf[progindex][j] = 0; fclose(prog); return true; } @@ -1293,6 +1380,25 @@ static inline bool isSpChar(char c) { } } +static inline bool isExSpChar(char c) { + switch (c) { + case '+': + case '-': + case '*': + case '/': + case '^': + case '=': + case '<': + case '>': + case ',': + return true; + break; + default: + return false; + break; + } +} + static inline bool isValidVarChar(char c) { switch (c) { case 'A' ... 'Z': @@ -1330,48 +1436,60 @@ static inline bool isValidHexChar(char c) { #ifndef BUILT_IN_STRING_FUNCS static inline void copyStr(char* str1, char* str2) { - int32_t i; - for (i = 0; str1[i]; ++i) {str2[i] = str1[i];} - str2[i] = 0; + for (; *str1; ++str1, ++str2) {*str2 = *str1;} + *str2 = 0; } static inline void copyStrApnd(char* str1, char* str2) { - int32_t j = 0, i = 0; - for (i = strlen(str2); str1[j]; ++i) {str2[i] = str1[j]; ++j;} - str2[i] = 0; + while (*str2) {++str2;} + for (; *str1; ++str1, ++str2) {*str2 = *str1;} + *str2 = 0; } #endif +static inline void copyStrApndNoEsc(char* str1, char* str2) { + while (*str2) {++str2;} + for (; *str1; ++str1, ++str2) { + if ((*str2 = *str1) == '\\') {*str2 = '\\';} + if (*str1 == '\'') {*str2 = '\\'; *++str2 = '\'';} + } + *str2 = 0; +} + static inline void copyStrSnip(char* str1, int32_t i, int32_t j, char* str2) { - int32_t i2 = 0; - for (; i < j && str1[i]; ++i) {str2[i2] = str1[i]; ++i2;} - str2[i2] = 0; + str1 += i; + for (; i < j && *str1; ++str1, ++str2, ++i) {*str2 = *str1;} + *str2 = 0; } static inline void copyStrTo(char* str1, int32_t i, char* str2) { int32_t i2 = 0; - int32_t i3; - for (i3 = i; str1[i]; ++i) {str2[i3] = str1[i2]; ++i2; ++i3;} - str2[i3] = 0; + for (; *str1 && i2 < i; ++str1, ++str2, ++i2) {*str2 = *str1;} + *str2 = 0; +} + +static inline void copyStrFrom(char* str1, int32_t i, char* str2) { + str1 += i; + for (; *str1; ++str1, ++str2) {*str2 = *str1;} + *str2 = 0; } static inline void strApndChar(char* str, char c) { - int32_t len = 0; - while (str[len]) {len++;} - str[len] = c; - len++; - str[len] = 0; + while (*str) {++str;} + *str = c; + ++str; + *str = 0; } static inline void upCase(char* str) { - for (int32_t i = 0; str[i]; ++i) { - if (str[i] >= 'a' && str[i] <= 'z') str[i] -= 32; + for (;*str; ++str) { + if (*str >= 'a' && *str <= 'z') *str -= 32; } } static inline void lowCase(char* str) { - for (int32_t i = 0; str[i]; ++i) { - if (str[i] >= 'A' && str[i] <= 'Z') str[i] += 32; + for (;*str; ++str) { + if (*str >= 'A' && *str <= 'Z') *str += 32; } } @@ -1435,7 +1553,7 @@ void updateTxtAttrib() { char buf[CB_BUF_SIZE]; -void getStr(char* str1, char* str2) { +static inline void getStr(char* str1, char* str2) { int32_t j = 0, i; for (i = 0; str1[i]; ++i) { char c = str1[i]; @@ -1474,17 +1592,61 @@ void getStr(char* str1, char* str2) { copyStr(buf, str2); } -uint8_t getType(char* str) { - if (str[0] == '"') {if (str[strlen(str) - 1] != '"') {return 0;} return 1;} +static inline uint8_t getType(char* str) { + if (*str == '"') {if (str[strlen(str) - 1] != '"') {return 0;} return 1;} bool p = false; - for (int32_t i = 0; str[i]; ++i) { - if (str[i] == '-') {} else - if ((str[i] < '0' || str[i] > '9') && str[i] != '.') {return 255;} else - if (str[i] == '.') {if (p) {return 0;} p = true;} + for (; *str; ++str) { + if (*str == '-') {} else + if ((*str < '0' || *str > '9') && *str != '.') {return 255;} else + if (*str == '.') {if (p) {return 0;} p = true;} } return 2; } +static inline bool isLineNumber(char* str) { + if (!*str || *str == '-') return false; + while (*str) { + if (*str == '.') return false; + if (*str < '0' || *str > '9') return false; + ++str; + } + return true; +} + +int cbrmIndex = 0; + +bool cbrm(char* path) { + fileerror = 0; + if (isFile(path)) { + if (remove(path)) {fileerror = errno; return false;} + return true; + } + char* odir = (cbrmIndex) ? NULL : getcwd(NULL, 0); + ++cbrmIndex; + if (chdir(path)) {fileerror = errno; goto cbrm_fail;} + DIR* cwd = opendir("."); + struct dirent* dir; + struct stat pathstat; + while ((dir = readdir(cwd))) { + if (strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..")) { + stat(dir->d_name, &pathstat); + if (S_ISDIR(pathstat.st_mode)) {cbrm(dir->d_name);} + else {remove(dir->d_name);} + } + } + --cbrmIndex; + chdir((cbrmIndex) ? ".." : odir); + if (!cbrmIndex) free(odir); + if (rmdir(path)) {fileerror = errno; return false;} + return true; + cbrm_fail: + --cbrmIndex; + chdir((cbrmIndex) ? ".." : odir); + if (!cbrmIndex) free(odir); + if (rmdir(path)) fileerror = errno; + return false; +} + static inline int getArg(int, char*, char*); static inline int getArgCt(char*); @@ -1507,27 +1669,44 @@ uint8_t getFunc(char* inbuf, char* outbuf) { gftmp[1] = getFunc_gftmp[1]; } ++getFuncIndex; - int32_t i; - for (i = 0; inbuf[i] != '('; ++i) {if (inbuf[i] >= 'a' && inbuf[i] <= 'z') inbuf[i] = inbuf[i] - 32;} - copyStrSnip(inbuf, i + 1, strlen(inbuf) - 1, gftmp[0]); - fargct = getArgCt(gftmp[0]); - farg = malloc((fargct + 1) * sizeof(char*)); - flen = malloc((fargct + 1) * sizeof(int)); - fargt = malloc((fargct + 1) * sizeof(uint8_t)); - for (int j = 0; j <= fargct; ++j) { - if (j == 0) { - flen[0] = i; - farg[0] = (char*)malloc(flen[0] + 1); - copyStrSnip(inbuf, 0, i, farg[0]); - } else { - getArg(j - 1, gftmp[0], gftmp[1]); - fargt[j] = getVal(gftmp[1], gftmp[1]); - if (fargt[j] == 0) goto fnoerrscan; - if (fargt[j] == 255) fargt[j] = 0; - flen[j] = strlen(gftmp[1]); - farg[j] = (char*)malloc(flen[j] + 1); - copyStr(gftmp[1], farg[j]); - ftmpct++; + { + int32_t i; + for (i = 0; inbuf[i] != '('; ++i) {if (inbuf[i] >= 'a' && inbuf[i] <= 'z') inbuf[i] = inbuf[i] - 32;} + int32_t j = strlen(inbuf) - 1; + copyStrSnip(inbuf, i + 1, j, gftmp[0]); + fargct = getArgCt(gftmp[0]); + farg = malloc((fargct + 1) * sizeof(char*)); + flen = malloc((fargct + 1) * sizeof(int)); + fargt = malloc((fargct + 1) * sizeof(uint8_t)); + for (int j = 0; j <= fargct; ++j) { + farg[j] = NULL; + } + for (int j = 0; j <= fargct; ++j) { + if (j == 0) { + flen[0] = i; + farg[0] = (char*)malloc(flen[0] + 1); + copyStrTo(inbuf, i, farg[0]); + if (!strcmp(farg[0], "~") || !strcmp(farg[0], "_TEST")) { + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + cerr = 0; + if (getArg(0, gftmp[0], gftmp[1]) == -1) {outbuf[0] = 0; goto fexit;} + int ret = logictest(gftmp[1]); + if (ret == -1) {outbuf[0] = 0; goto fexit;} + outbuf[0] = '0' + ret; + outbuf[1] = 0; + goto fexit; + } + } else { + if (getArg(j - 1, gftmp[0], gftmp[1]) == -1) {outbuf[0] = 0; goto fexit;} + fargt[j] = getVal(gftmp[1], gftmp[1]); + if (fargt[j] == 0) goto fnoerrscan; + if (fargt[j] == 255) fargt[j] = 0; + flen[j] = strlen(gftmp[1]); + farg[j] = (char*)malloc(flen[j] + 1); + copyStr(gftmp[1], farg[j]); + ftmpct++; + } } } outbuf[0] = 0; @@ -1556,7 +1735,6 @@ uint8_t getVar(char* vn, char* varout) { if (vn[vnlen - 1] == ')') { return getFunc(vn, varout); } - upCase(vn); if (!vn[0] || vn[0] == '[' || vn[0] == ']') { cerr = 4; seterrstr(vn); @@ -1632,11 +1810,8 @@ uint8_t getVar(char* vn, char* varout) { return 0; } -bool delVar(char*); - bool setVar(char* vn, char* val, uint8_t t, int32_t s) { int32_t vnlen = strlen(vn); - upCase(vn); if (!vn[0] || vn[0] == '[' || vn[0] == ']') { cerr = 4; seterrstr(vn); @@ -1705,11 +1880,6 @@ bool setVar(char* vn, char* val, uint8_t t, int32_t s) { 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); - if (!vardata[v].data[i]) { - delVar(vn); - cerr = 26; - return false; - } copyStr(val, vardata[v].data[i]); } } else { @@ -1728,7 +1898,6 @@ bool setVar(char* vn, char* val, uint8_t t, int32_t s) { } bool delVar(char* vn) { - upCase(vn); if (!vn[0] || vn[0] == '[' || vn[0] == ']') { cerr = 4; seterrstr(vn); @@ -1772,6 +1941,68 @@ bool delVar(char* vn) { return true; } +int openFile(char* path, char* mode) { + fileerror = 0; + int i = 0; + int j = -1; + for (; i < filemaxct; ++i) { + if (!filedata[i].fptr) {j = i; break;} + } + if (j == -1) { + j = filemaxct; + ++filemaxct; + filedata = (cb_file*)realloc(filedata, filemaxct * sizeof(cb_file)); + } + if (!(filedata[j].fptr = fopen(path, mode))) { + fileerror = errno; + --filemaxct; + filedata = (cb_file*)realloc(filedata, filemaxct * sizeof(cb_file)); + return -1; + } + fseek(filedata[j].fptr, 0, SEEK_END); + filedata[j].size = ftell(filedata[j].fptr); + fseek(filedata[j].fptr, 0, SEEK_SET); + return j; +} + +bool closeFile(int num) { + fileerror = 0; + if (num > -1 && num < filemaxct) { + if (filedata[num].fptr) { + if (fclose(filedata[num].fptr)) { + fileerror = errno; + filedata[num].fptr = NULL; + return false; + } + filedata[num].fptr = NULL; + for (int i = filemaxct - 1; i > -1; --i) { + if (!(filedata[i].fptr)) { + --filemaxct; + } else { + break; + } + } + filedata = (cb_file*)realloc(filedata, filemaxct * sizeof(cb_file)); + } else { + return false; + } + } else { + if (num == -1) { + for (int i = 0; i < filemaxct; ++i) { + if (filedata[i].fptr) { + fclose(filedata[i].fptr); + filedata[i].fptr = NULL; + } + } + filemaxct = 0; + } else { + fileerror = EINVAL; + return false; + } + } + return true; +} + static inline bool gvchkchar(char* tmp, int32_t i) { if (isSpChar(tmp[i + 1])) { if (tmp[i + 1] == '-') { @@ -1930,7 +2161,6 @@ uint8_t getVal(char* inbuf, char* outbuf) { pct = 0; bct = 0; while (1) { - //printf("-: [%d]: [%d] [%d %d %d] {%s} {%s} {%s} {%s}\n", getValIndex, numAct, p1, p2, p3, tmp[0], tmp[1], tmp[2], tmp[3]); numAct = 0; p1 = 0, p2 = 0, p3 = 0; for (register int32_t i = 0; tmp[0][i]; ++i) { @@ -2080,7 +2310,7 @@ uint8_t getVal(char* inbuf, char* outbuf) { if (dp) tmp[1][--i] = '-'; copyStrSnip(tmp[1], i, j + 1, tmp[2]); copyStrSnip(tmp[0], p3, strlen(tmp[0]), tmp[3]); - if (p1) copyStrSnip(tmp[0], 0, p1, tmp[1]); + if (p1) copyStrTo(tmp[0], p1, tmp[1]); else {tmp[1][0] = 0;} copyStrApnd(tmp[2], tmp[1]); copyStrApnd(tmp[3], tmp[1]); @@ -2103,6 +2333,7 @@ uint8_t getVal(char* inbuf, char* outbuf) { if (!tmp[1][i] || tmp[1][i] == '.') {--i;} if (dp) tmp[1][--i] = '-'; 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); } @@ -2116,7 +2347,7 @@ uint8_t getVal(char* inbuf, char* outbuf) { char satmpbuf[CB_BUF_SIZE]; -bool solvearg(int i) { +static inline bool solvearg(int i) { if (i == 0) { argt[0] = 0; arg[0] = tmpargs[0]; @@ -2138,22 +2369,27 @@ static inline int getArgCt(char* inbuf) { int ct = 0; bool inStr = false; int pct = 0, bct = 0; - int32_t j = 0; - while (inbuf[j] == ' ') {--j;} - for (int32_t i = j; inbuf[i]; ++i) { + while (*inbuf == ' ') {++inbuf;} + for (; *inbuf; ++inbuf) { if (ct == 0) ct = 1; - if (inbuf[i] == '(' && !inStr) {pct++;} - if (inbuf[i] == ')' && !inStr) {pct--;} - if (inbuf[i] == '[' && !inStr) {bct++;} - if (inbuf[i] == ']' && !inStr) {bct--;} - if (inbuf[i] == '"') inStr = !inStr; - if (inbuf[i] == ',' && !inStr && pct == 0 && bct == 0) ct++; + if (*inbuf == '"') inStr = !inStr; + if (!inStr) { + switch (*inbuf) { + case '(': ++pct; break; + case ')': --pct; break; + case '[': ++bct; break; + case ']': --bct; break; + case ',': if (pct == 0 && bct == 0) {++ct;}; break; + } + } } return ct; } static inline int getArg(int num, char* inbuf, char* outbuf) { bool inStr = false; + bool lookingForSpChar = false; + bool sawSpChar = false; int pct = 0, bct = 0; int ct = 0; int32_t len = 0; @@ -2167,12 +2403,22 @@ static inline int getArg(int num, char* inbuf, char* outbuf) { } } if (inbuf[i] == '"') inStr = !inStr; - if (!inStr && pct == 0 && bct == 0 && inbuf[i] == ',') {++ct;} else - if (ct == num && (inStr || inbuf[i] != ' ')) {outbuf[len] = inbuf[i]; len++;} + if (!inStr && pct == 0 && bct == 0 && inbuf[i] == ',') {++ct;} + else if (ct == num) { + if (!inStr) { + if (inbuf[i] == ' ' && !sawSpChar && len > 0) {lookingForSpChar = true;} + if (isExSpChar(inbuf[i])) {lookingForSpChar = false; sawSpChar = true;} + } + if (inStr || inbuf[i] != ' ') { + if (!isExSpChar(inbuf[i])) sawSpChar = false; + if (lookingForSpChar) {outbuf[0] = 0; cerr = 1; return -1;} + outbuf[len] = inbuf[i]; + ++len; + } + } } if (pct || bct || inStr) {outbuf[0] = 0; cerr = 1; return -1;} outbuf[len] = 0; - //printf("arg outbuf: {%s}\n", outbuf); return len; } @@ -2180,12 +2426,12 @@ char tmpbuf[2][CB_BUF_SIZE]; void mkargs() { int32_t j = 0; - while (cmd[j] == ' ') {j++;} + while (cmd[j] == ' ') {++j;} int32_t h = j; - while (cmd[h] != ' ' && cmd[h] != '=' && cmd[h]) {h++;} + while (cmd[h] != ' ' && cmd[h] != '=' && cmd[h]) {++h;} copyStrSnip(cmd, h + 1, strlen(cmd), tmpbuf[0]); int32_t tmph = h; - while (cmd[tmph] == ' ' && cmd[tmph]) {tmph++;} + while (cmd[tmph] == ' ' && cmd[tmph]) {++tmph;} if (cmd[tmph] == '=') { strcpy(tmpbuf[1], "SET "); cmd[tmph] = ','; @@ -2200,16 +2446,19 @@ void mkargs() { argct = getArgCt(tmpbuf[0]); tmpargs = (char**)realloc(tmpargs, (argct + 1) * sizeof(char*)); argl = (int32_t*)realloc(argl, (argct + 1) * sizeof(int32_t)); + for (int i = 0; i <= argct; ++i) { + tmpargs[i] = NULL; + } for (int i = 0; i <= argct; ++i) { argl[i] = 0; if (i == 0) { copyStrSnip(cmd, j, h, tmpbuf[0]); - argl[i] = strlen(tmpbuf[0]); - tmpargs[i] = malloc(argl[i] + 1); - copyStr(tmpbuf[0], tmpargs[i]); + argl[0] = strlen(tmpbuf[0]); + tmpargs[0] = malloc(argl[0] + 1); + copyStr(tmpbuf[0], tmpargs[0]); copyStrSnip(cmd, h + 1, strlen(cmd), tmpbuf[0]); } else { - argl[i] = getArg(i - 1, tmpbuf[0], tmpbuf[1]); + if ((argl[i] = getArg(i - 1, tmpbuf[0], tmpbuf[1])) == -1) {cerr = 1; return;} tmpargs[i] = malloc(argl[i] + 1); copyStr(tmpbuf[1], tmpargs[i]); } @@ -2219,27 +2468,53 @@ void mkargs() { for (int i = 0; i <= argct; ++i) {tmpargs[i][argl[i]] = 0;} } -char lttmp[3][CB_BUF_SIZE]; +char* lttmp_tmp[3]; +int logictestexpr_index = 0; -uint8_t logictestexpr(char* inbuf) { +static inline uint8_t logictestexpr(char* inbuf) { int32_t tmpp = 0; uint8_t t1 = 0; uint8_t t2 = 0; int32_t p = 0; bool inStr = false; + bool lookingForSpChar = false; + bool sawSpChar = false; int pct = 0, bct = 0; + int ret = 255; + char* lttmp[3]; + if (!logictestexpr_index) { + lttmp[0] = lttmp_tmp[0]; + lttmp[1] = lttmp_tmp[1]; + lttmp[2] = lttmp_tmp[2]; + } else { + lttmp[0] = malloc(CB_BUF_SIZE); + lttmp[1] = malloc(CB_BUF_SIZE); + lttmp[2] = malloc(CB_BUF_SIZE); + } + ++logictestexpr_index; while (inbuf[p] == ' ') {++p;} if (p >= (int32_t)strlen(inbuf)) {cerr = 10; goto ltreturn;} - for (int32_t i = p; true; ++i) { - if (inbuf[i] == '(' && !inStr) {pct++;} - if (inbuf[i] == ')' && !inStr) {pct--;} - if (inbuf[i] == '[' && !inStr) {bct++;} - if (inbuf[i] == ']' && !inStr) {bct--;} + for (int32_t i = p; inbuf[i]; ++i) { + if (!inStr) { + switch (inbuf[i]) { + case '(': ++pct; break; + case ')': --pct; break; + case '[': ++bct; break; + case ']': --bct; break; + } + } if (inbuf[i] == '"') {inStr = !inStr;} if (inbuf[i] == 0) {cerr = 1; goto ltreturn;} if ((inbuf[i] == '<' || inbuf[i] == '=' || inbuf[i] == '>') && !inStr && pct == 0 && bct == 0) {p = i; break;} - if (inbuf[i] == ' ' && !inStr) {} else - {lttmp[0][tmpp] = inbuf[i]; tmpp++;} + if (!inStr && pct == 0 && bct == 0) { + if (inbuf[i] == ' ' && !sawSpChar) {lookingForSpChar = true;} + if (isExSpChar(inbuf[i])) {lookingForSpChar = false; sawSpChar = true;} + } + if (inStr || inbuf[i] != ' ') { + if (!isExSpChar(inbuf[i])) sawSpChar = false; + if (lookingForSpChar) {cerr = 1; goto ltreturn;} + lttmp[0][tmpp] = inbuf[i]; tmpp++; + } } lttmp[0][tmpp] = 0; tmpp = 0; @@ -2250,10 +2525,32 @@ uint8_t logictestexpr(char* inbuf) { } lttmp[1][tmpp] = 0; tmpp = 0; - for (int32_t i = p; true; ++i) { - if (inbuf[i] == 0) {break;} - if (inbuf[i] == ' ' && !inStr) {} else - {lttmp[2][tmpp] = inbuf[i]; tmpp++;} + inStr = false; + lookingForSpChar = false; + sawSpChar = false; + pct = 0; bct = 0; + while (inbuf[p] == ' ') {++p;} + for (int32_t i = p; inbuf[i]; ++i) { + if (!inStr) { + switch (inbuf[i]) { + case '(': ++pct; break; + case ')': --pct; break; + case '[': ++bct; break; + case ']': --bct; break; + } + } + if (inbuf[i] == '"') {inStr = !inStr;} + if (inbuf[i] == 0) {cerr = 1; goto ltreturn;} + if ((inbuf[i] == '<' || inbuf[i] == '=' || inbuf[i] == '>') && !inStr && pct == 0 && bct == 0) {p = i; break;} + if (!inStr && pct == 0 && bct == 0) { + if (inbuf[i] == ' ' && !sawSpChar) {lookingForSpChar = true;} + if (isExSpChar(inbuf[i])) {lookingForSpChar = false; sawSpChar = true;} + } + if (inStr || inbuf[i] != ' ') { + if (!isExSpChar(inbuf[i])) sawSpChar = false; + if (lookingForSpChar) {cerr = 1; goto ltreturn;} + lttmp[2][tmpp] = inbuf[i]; tmpp++; + } } lttmp[2][tmpp] = 0; t1 = getVal(lttmp[0], lttmp[0]); @@ -2262,89 +2559,116 @@ uint8_t logictestexpr(char* inbuf) { if (t2 == 0) goto ltreturn; if (t1 != t2) {cerr = 2; goto ltreturn;} if (!strcmp(lttmp[1], "=")) { - return (uint8_t)(bool)!strcmp(lttmp[0], lttmp[2]); + ret = (uint8_t)(bool)!strcmp(lttmp[0], lttmp[2]); + goto ltreturn; } else if (!strcmp(lttmp[1], "<>")) { - return (uint8_t)(bool)strcmp(lttmp[0], lttmp[2]); + ret = (uint8_t)(bool)strcmp(lttmp[0], lttmp[2]); + 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); - return num1 > 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); - return num1 < 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); - return num1 >= 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); - return num1 <= 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); - return num1 >= 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); - return num1 <= num2; + ret = num1 <= num2; + goto ltreturn; } cerr = 1; ltreturn:; - return 255; + --logictestexpr_index; + if (logictestexpr_index) { + free(lttmp[0]); + free(lttmp[1]); + free(lttmp[2]); + } + return ret; } -char ltbuf[CB_BUF_SIZE]; +char* ltbuf_tmp = NULL; +int logictest_index = 0; uint8_t logictest(char* inbuf) { bool inStr = false; int32_t i = 0, j = 0; + int pct = 0, bct = 0; uint8_t ret = 0, out = 0; uint8_t logicActOld = 0; + char* ltbuf; + if (!logictest_index) { + ltbuf = ltbuf_tmp; + } else { + ltbuf = malloc(CB_BUF_SIZE); + } + ++logictest_index; while (inbuf[i]) { uint8_t logicAct = 0; for (;inbuf[j] && !logicAct; ++j) { switch (inbuf[j]) { case '"': inStr = !inStr; break; - case '|': if (!inStr) {logicAct = 1; --j;} break; - case '&': if (!inStr) {logicAct = 2; --j;} break; + case '(': if (!inStr) ++pct; break; + case ')': if (!inStr) --pct; break; + case '[': if (!inStr) ++bct; break; + case ']': if (!inStr) --bct; break; + case '|': if (!inStr && !pct && !bct) {logicAct = 1; --j;} break; + case '&': if (!inStr && !pct && !bct) {logicAct = 2; --j;} break; } } copyStrSnip(inbuf, i, j, ltbuf); - //printf("{%s} {%s} [%d, %d] [%d, %d]\n", inbuf, ltbuf, i, j, logicAct, logicActOld); switch (logicActOld) { case 1: - //printf("OR: {%s}\n", ltbuf); - if ((ret = logictestexpr(ltbuf)) == 255) {return 255;} + if ((ret = logictestexpr(ltbuf)) == 255) {out = 255; goto ltexit;} out |= ret; break; case 2: - //printf("AND: {%s}\n", ltbuf); - if ((ret = logictestexpr(ltbuf)) == 255) {return 255;} + if ((ret = logictestexpr(ltbuf)) == 255) {out = 255; goto ltexit;} out &= ret; break; default: - //printf("NONE: {%s}\n", ltbuf); out = logictestexpr(ltbuf); break; } + if (!inbuf[j]) break; i = ++j; - if (!inbuf[i + 1]) break; + if (!inbuf[i]) {if (inbuf[j - 1] == '|' || inbuf[j - 1] == '&') {cerr = 10; out = 255;} break;} logicActOld = logicAct; } + ltexit:; + --logictest_index; + if (logictest_index) free(ltbuf); return out; } @@ -2353,21 +2677,53 @@ char ltmp[2][CB_BUF_SIZE]; bool runlogic() { ltmp[0][0] = 0; ltmp[1][0] = 0; int32_t i = 0; - while (cmd[i] == ' ') {i++;} + while (cmd[i] == ' ') {++i;} int32_t j = i; - while (cmd[j] != ' ' && cmd[j]) {j++;} + while (cmd[j] != ' ' && cmd[j]) {++j;} int32_t h = j; - while (cmd[h] == ' ') {h++;} + while (cmd[h] == ' ') {++h;} if (cmd[h] == '=') return false; copyStrSnip(cmd, i, j, ltmp[0]); - upCase(ltmp[0]); + if (isLineNumber(ltmp[0])) { + int tmp = -1; + for (int j = 0; j < gotomaxct; ++j) { + if (!gotodata[j].used) {tmp = j; break;} + else if (!strcmp(gotodata[j].name, ltmp[0])) { + if (gotodata[j].cp == cmdpos) {goto skiplbl;} + cerr = 28; return true; + } + } + if (tmp == -1) { + tmp = gotomaxct; + ++gotomaxct; + gotodata = realloc(gotodata, gotomaxct * sizeof(cb_goto)); + } + gotodata[tmp].name = malloc(strlen(ltmp[0]) + 1); + copyStr(ltmp[0], gotodata[tmp].name); + gotodata[tmp].cp = cmdpos; + gotodata[tmp].pl = progLine; + gotodata[tmp].used = true; + gotodata[tmp].dlsp = dlstackp; + gotodata[tmp].fnsp = fnstackp; + gotodata[tmp].itsp = itstackp; + skiplbl:; + while (cmd[i] != ' ' && cmd[i]) {++i;} + while (cmd[i] == ' ') {++i;} + j = i; + while (cmd[j] != ' ' && cmd[j]) {++j;} + h = j; + while (cmd[h] == ' ') {++h;} + if (cmd[h] == '=') return false; + copyStrSnip(cmd, i, j, ltmp[0]); + copyStrFrom(cmd, i, cmd); + } cerr = 0; chkCmdPtr = ltmp[0]; #include "logic.c" return false; } -void initBaseMem() { +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); @@ -2375,9 +2731,13 @@ void initBaseMem() { getFunc_gftmp[0] = malloc(CB_BUF_SIZE); getFunc_gftmp[1] = malloc(CB_BUF_SIZE); bfnbuf = malloc(CB_BUF_SIZE); + ltbuf_tmp = malloc(CB_BUF_SIZE); + lttmp_tmp[0] = malloc(CB_BUF_SIZE); + lttmp_tmp[1] = malloc(CB_BUF_SIZE); + lttmp_tmp[2] = malloc(CB_BUF_SIZE); } -void freeBaseMem() { +static inline void freeBaseMem() { nfree(getVal_tmp[0]); nfree(getVal_tmp[1]); nfree(getVal_tmp[2]); @@ -2385,9 +2745,13 @@ void freeBaseMem() { nfree(getFunc_gftmp[0]); nfree(getFunc_gftmp[1]); nfree(bfnbuf); + nfree(ltbuf_tmp); + nfree(lttmp_tmp[0]); + nfree(lttmp_tmp[1]); + nfree(lttmp_tmp[2]); } -void printError(int error) { +static inline void printError(int error) { getCurPos(); if (curx != 1) putchar('\n'); if (inProg) {printf("Error %d on line %d of '%s': '%s': ", error, progLine, basefilename(progfnstr), cmd);} @@ -2418,7 +2782,7 @@ void printError(int error) { fputs("ENDIF without IF", stdout); break; case 8: - fputs("ELSE without IF", stdout); + fputs("ELSE or ELSEIF without IF", stdout); break; case 9: fputs("NEXT without FOR", stdout); @@ -2439,7 +2803,7 @@ void printError(int error) { fputs("Reached FOR limit", stdout); break; case 15: - printf("File not found: '%s'", errstr); + printf("File or directory not found: '%s'", errstr); break; case 16: fputs("Invalid data or data range exceeded", stdout); @@ -2501,9 +2865,6 @@ void printError(int error) { case 255: printf("Not a command: '%s'", arg[0]); break; - case -1: - fputs("Internal error", stdout); - break; } putchar('\n'); } @@ -2513,20 +2874,24 @@ void runcmd() { cerr = 0; bool lgc = runlogic(); if (lgc) goto cmderr; + if (cmd[0] == 0) return; 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;} + bool madeargs = false; mkargs(); + if (cerr) goto cmderr; + madeargs = true; argt = (uint8_t*)realloc(argt, argct + 1); arg = (char**)realloc(arg, (argct + 1) * sizeof(char*)); for (int i = 1; i <= argct; ++i) {arg[i] = NULL;} solvearg(0); - upCase(arg[0]); cerr = 255; chkCmdPtr = arg[0]; #include "commands.c" cmderr:; if (cerr) { + err = 0; if (runc || runfile) err = 1; printError(cerr); cp = -1; @@ -2538,8 +2903,10 @@ void runcmd() { for (int i = 0; i <= argct; ++i) { free(tmpargs[i]); } - for (int i = 1; i <= argct; ++i) { - free(arg[i]); + if (madeargs) { + for (int i = 1; i <= argct; ++i) { + free(arg[i]); + } } return; } diff --git a/commands.c b/commands.c index db7bea4..12e3cf1 100644 --- a/commands.c +++ b/commands.c @@ -2,9 +2,23 @@ if (chkCmdPtr[0] == '_') goto _cmd; if (chkCmd(2, "EXIT", "QUIT")) { if (argct > 1) {cerr = 3; goto cmderr;} cerr = 0; - if (argct == 1) {if (!solvearg(1)) goto cmderr; err = atoi(arg[1]);} - if (inProg) {inProg = false; goto cmderr;} - cleanExit(); + err = 0; + if (argct == 1) { + if (!solvearg(1)) goto cmderr; + if (runfile) { + err = retval = atoi(arg[1]); + } else { + err = atoi(arg[1]); + } + } + if (inProg) { + if (progindex > 0) unloadProg(); + else inProg = false; + retval = err; + } else { + cleanExit(); + } + goto cmderr; } if (chkCmd(1, "PUT")) { cerr = 0; @@ -19,13 +33,16 @@ if (chkCmd(2, "SET", "LET")) { if (!setVar(tmpargs[1], arg[2], argt[2], -1)) goto cmderr; goto noerr; } -if (chkCmd(2, "@", "LABEL")) { +if (chkCmd(3, "@", "LABEL", "LBL")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; int i = -1; for (int j = 0; j < gotomaxct; ++j) { if (!gotodata[j].used) {i = j; break;} - else if (!strcmp(gotodata[j].name, tmpargs[1])) {cerr = 28; goto cmderr;} + else if (!strcmp(gotodata[j].name, tmpargs[1])) { + if (gotodata[j].cp == cmdpos) {goto noerr;} + cerr = 28; goto cmderr; + } } if (i == -1) { i = gotomaxct; @@ -40,8 +57,9 @@ if (chkCmd(2, "@", "LABEL")) { gotodata[i].dlsp = dlstackp; gotodata[i].fnsp = fnstackp; gotodata[i].itsp = itstackp; + goto noerr; } -if (chkCmd(2, "%", "GOTO")) { +if (chkCmd(3, "%", "GOTO", "GO")) { if (argct != 1) {cerr = 3; goto cmderr;} cerr = 0; int i = -1; @@ -62,10 +80,11 @@ if (chkCmd(2, "%", "GOTO")) { itstackp = gotodata[i].itsp; gotodata[i].used = false; bool r = false; - while (gotomaxct > 0 && !gotodata[gotomaxct].used) {--gotomaxct; r = true;} + while (gotomaxct > 0 && !gotodata[gotomaxct - 1].used) {--gotomaxct; r = true;} if (r) gotodata = realloc(gotodata, gotomaxct * sizeof(cb_goto)); didloop = true; lockpl = true; + goto noerr; } if (chkCmd(1, "DIM")) { if (argct != 3) {cerr = 3; goto cmderr;} @@ -136,12 +155,13 @@ if (chkCmd(1, "COLOR")) { goto noerr; } if (chkCmd(1, "LOCATE")) { + if (argct > 2 || argct < 1) {cerr = 3; goto cmderr;} cerr = 0; int tmp = 0; - if (argct > 2 || argct < 1) {cerr = 3; goto cmderr;} if (!solvearg(1)) goto cmderr; - if (argt[1] == 0) {} else - if (argt[1] != 2) {cerr = 2; goto cmderr;} + getCurPos(); + if (argt[1] == 0) {} + else if (argt[1] != 2) {cerr = 2; goto cmderr;} else { tmp = atoi(arg[1]); if (tmp < 1) {cerr = 16; goto cmderr;} @@ -149,8 +169,8 @@ if (chkCmd(1, "LOCATE")) { } if (argct > 1) { if (!solvearg(2)) goto cmderr; - if (argt[2] == 0) {} else - if (argt[2] != 2) {cerr = 2; goto cmderr;} + if (argt[2] == 0) {} + else if (argt[2] != 2) {cerr = 2; goto cmderr;} else { tmp = atoi(arg[2]); if (tmp < 1) {cerr = 16; goto cmderr;} @@ -166,18 +186,32 @@ if (chkCmd(1, "LOCATE")) { goto noerr; } if (chkCmd(1, "CLS")) { - cerr = 0; if (argct > 1) {cerr = 3; goto cmderr;} + cerr = 0; uint8_t tbgc = bgc; + #ifndef _WIN_NO_VT + uint32_t ttbgc = truebgc; + #endif if (argct) { if (!solvearg(1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} + #ifndef _WIN_NO_VT + if (txt_truecolor) { + ttbgc = (uint32_t)atoi(arg[1]); + } else { + tbgc = (uint8_t)atoi(arg[1]); + } + #else tbgc = (uint8_t)atoi(arg[1]); + #endif } #ifndef _WIN_NO_VT - if (argct) printf("\e[48;5;%um", tbgc); + if (argct) { + if (txt_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); + } fputs("\e[H\e[2J\e[3J", stdout); - if (txt_bgc) printf("\e[48;5;%um", bgc); + updateTxtAttrib(); fflush(stdout); #else SetConsoleTextAttribute(hConsole, (fgc % 16) + (tbgc % 16) * 16); @@ -187,8 +221,8 @@ if (chkCmd(1, "CLS")) { goto noerr; } if (chkCmd(1, "WAITUS")) { - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} uint64_t d; @@ -197,34 +231,34 @@ if (chkCmd(1, "WAITUS")) { goto noerr; } if (chkCmd(1, "WAITMS")) { - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} - uint64_t d; - sscanf(arg[1], "%llu", (long long unsigned *)&d); + double d; + sscanf(arg[1], "%lf", &d); cb_wait(d * 1000); goto noerr; } if (chkCmd(1, "WAIT")) { - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} - uint64_t d; - sscanf(arg[1], "%llu", (long long unsigned *)&d); + double d; + sscanf(arg[1], "%lf", &d); cb_wait(d * 1000000); goto noerr; } if (chkCmd(1, "RESETTIMER")) { - cerr = 0; if (argct) {cerr = 3; goto cmderr;} + cerr = 0; resetTimer(); goto noerr; } if (chkCmd(2, "SRAND", "SRND")) { - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} double rs; @@ -233,8 +267,8 @@ if (chkCmd(2, "SRAND", "SRND")) { goto noerr; } if (chkCmd(1, "CALL")) { - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} inprompt = !runfile; @@ -246,8 +280,8 @@ if (chkCmd(1, "CALL")) { goto noerr; } if (chkCmd(1, "RUN")) { - cerr = 0; if (argct < 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} #ifndef _WIN32 @@ -270,7 +304,8 @@ if (chkCmd(1, "RUN")) { exit(0); } else if (pid > 0) { - while (wait(NULL) != pid) {} + while (wait(&retval) != pid) {} + retval = WEXITSTATUS(retval); } free(runargs); #else @@ -297,8 +332,8 @@ if (chkCmd(1, "RUN")) { goto noerr; } if (chkCmd(2, "$", "SH")) { - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} #ifndef _WIN_NO_VT @@ -317,7 +352,7 @@ if (chkCmd(2, "$", "SH")) { int duperr; duperr = dup(2); close(2); - cerr = system(arg[1]); + retval = WEXITSTATUS(system(arg[1])); dup2(duperr, 2); close(duperr); if (sh_restoreAttrib) updateTxtAttrib(); @@ -325,8 +360,8 @@ if (chkCmd(2, "$", "SH")) { goto noerr; } if (chkCmd(1, "EXEC")) { - cerr = 0; if (argct < 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} #ifndef _WIN_NO_VT @@ -356,10 +391,11 @@ if (chkCmd(1, "EXEC")) { if (pid < 0) cerr = -1; if (pid == 0) { execvp(runargs[0], runargs); - exit(0); + exit(127); } else if (pid > 0) { - while (wait(NULL) != pid) {} + while (wait(&retval) != pid) {} + retval = ((retval >> 8) & 0xFF); } else if (sh_silent) { dup2(stdout_dup, 1); @@ -391,8 +427,7 @@ if (chkCmd(1, "EXEC")) { dup2(fd, 1); dup2(fd, 2); } - int ret = system(tmpcmd); - (void)ret; + retval = WEXITSTATUS(system(tmpcmd)); if (sh_silent) { dup2(stdout_dup, 1); dup2(stderr_dup, 2); @@ -410,6 +445,12 @@ if (chkCmd(1, "FILES")) { if (argct) { if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} + int tmpret = isFile(arg[1]); + if (tmpret) { + if (tmpret == -1) {cerr = 15; seterrstr(arg[1]);} + else {cerr = 19;} + goto cmderr; + } olddn = malloc(CB_BUF_SIZE); getcwd(olddn, CB_BUF_SIZE); if (chdir(arg[1])) { @@ -420,8 +461,7 @@ if (chkCmd(1, "FILES")) { } } DIR* cwd = opendir("."); - if (!cwd) {if (argct) {free(olddn);} cerr = 20; goto cmderr;} - DIR* tmpdir; + if (!cwd) {if (argct) {chdir(olddn); free(olddn);} goto noerr;} struct dirent* dir; #ifdef _WIN32 #define DIRPFS "%s\\\n" @@ -431,14 +471,15 @@ if (chkCmd(1, "FILES")) { puts("./\n../"); #endif long dbegin = telldir(cwd); + struct stat pathstat; while ((dir = readdir(cwd))) { - if ((tmpdir = opendir(dir->d_name)) && strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..")) printf(DIRPFS, dir->d_name); - if (tmpdir) closedir(tmpdir); + stat(dir->d_name, &pathstat); + if (S_ISDIR(pathstat.st_mode) && strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..")) printf(DIRPFS, dir->d_name); } seekdir(cwd, dbegin); while ((dir = readdir(cwd))) { - if (!(tmpdir = opendir(dir->d_name))) puts(dir->d_name); - if (tmpdir) closedir(tmpdir); + stat(dir->d_name, &pathstat); + if (!(S_ISDIR(pathstat.st_mode))) puts(dir->d_name); } if (argct) { chdir(olddn); @@ -448,8 +489,8 @@ if (chkCmd(1, "FILES")) { goto noerr; } if (chkCmd(2, "CHDIR", "CD")) { - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} if (chdir(arg[1])) { @@ -459,12 +500,114 @@ if (chkCmd(2, "CHDIR", "CD")) { } goto noerr; } +if (chkCmd(1, "FCLOSE")) { + cerr = 0; + fileerror = 0; + if (argct != 1) {cerr = 3; goto cmderr;} + if (!solvearg(1)) {goto cmderr;} + if (argt[1] != 2) {cerr = 3; goto cmderr;} + if (!closeFile(atoi(arg[1]))) {cerr = 16; goto cmderr;} + goto noerr; +} +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 (argt[1] != 2 || argt[2] != 1) {cerr = 2; goto cmderr;} + int fnum = atoi(arg[1]); + if (fnum < 0 || fnum >= filemaxct) { + cerr = 16; + goto cmderr; + } else { + errno = 0; + fputs(arg[2], filedata[fnum].fptr); + fileerror = errno; + } + goto noerr; +} +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 (argt[1] != 2 || argt[2] != 2) {cerr = 2; goto cmderr;} + int fnum = atoi(arg[1]); + if (fnum < 0 || fnum >= filemaxct) { + cerr = 16; + goto cmderr; + } else { + errno = 0; + int32_t pos = atoi(arg[2]); + if (pos < 0) { + cerr = 16; + } else { + fseek(filedata[fnum].fptr, (pos > filedata[fnum].size) ? filedata[fnum].size : pos, SEEK_SET); + fileerror = errno; + } + } + goto noerr; +} +if (chkCmd(1, "FLUSH")) { + cerr = 0; + fileerror = 0; + if (argct != 1) {cerr = 3; goto cmderr;} + if (!solvearg(1)) {goto cmderr;} + if (argt[1] != 2) {cerr = 2; goto cmderr;} + int fnum = atoi(arg[1]); + if (fnum < 0 || fnum >= filemaxct) { + cerr = 16; + goto cmderr; + } + errno = 0; + fflush(filedata[fnum].fptr); + fileerror = errno; + goto noerr; +} +if (chkCmd(2, "MD", "MKDIR")) { + cerr = 0; + fileerror = 0; + if (argct != 1) {cerr = 3; goto cmderr;} + if (!solvearg(1)) {goto cmderr;} + if (argt[1] != 1) {cerr = 2; goto cmderr;} + errno = 0; + #ifndef _WIN32 + mkdir(arg[1], S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + #else + mkdir(arg[1]); + #endif + fileerror = errno; + goto noerr; +} +if (chkCmd(2, "RM", "REMOVE")) { + cerr = 0; + fileerror = 0; + if (argct != 1) {cerr = 3; goto cmderr;} + if (!solvearg(1)) {goto cmderr;} + if (argt[1] != 1) {cerr = 2; goto cmderr;} + cbrm(arg[1]); + goto noerr; +} +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 (argt[1] != 1 || argt[2] != 1) {cerr = 2; goto cmderr;} + errno = 0; + rename(arg[1], arg[2]); + fileerror = errno; + goto noerr; +} goto cmderr; _cmd: if (chkCmd(1, "_RESETTITLE")) { if (inProg) {cerr = 254; goto cmderr;} + if (argct) {cerr = 3; goto cmderr;} cerr = 0; - if (argct != 0) {cerr = 3; goto cmderr;} #ifndef _WIN_NO_VT if (!changedtitle) { if (changedtitlecmd) fputs("\e[23;0t", stdout); @@ -482,8 +625,8 @@ if (chkCmd(1, "_RESETTITLE")) { } if (chkCmd(1, "_TITLE")) { if (inProg) {cerr = 254; goto cmderr;} - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} #ifndef _WIN_NO_VT @@ -499,10 +642,35 @@ if (chkCmd(1, "_TITLE")) { #endif goto noerr; } +if (chkCmd(1, "_SETENV")) { + if (argct != 2) {cerr = 3; goto cmderr;} + cerr = 0; + if (!solvearg(1)) goto cmderr; + if (!solvearg(2)) goto cmderr; + if (argt[1] != 1 || argt[2] != 1) {cerr = 2; goto cmderr;} + #ifndef _WIN32 + setenv(arg[1], arg[2], 1); + #else + SetEnvironmentVariable(arg[1], arg[2]); + #endif + goto noerr; +} +if (chkCmd(1, "_UNSETENV")) { + if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; + if (!solvearg(1)) goto cmderr; + if (argt[1] != 1) {cerr = 2; goto cmderr;} + #ifndef _WIN32 + unsetenv(arg[1]); + #else + SetEnvironmentVariable(arg[1], ""); + #endif + goto noerr; +} if (chkCmd(1, "_PROMPT")) { if (inProg) {cerr = 254; goto cmderr;} - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} copyStr(tmpargs[1], prompt); @@ -510,23 +678,23 @@ if (chkCmd(1, "_PROMPT")) { } if (chkCmd(1, "_PROMPTTAB")) { if (inProg) {cerr = 254; goto cmderr;} - cerr = 0; if (argct != 1) {cerr = 3; goto cmderr;} + cerr = 0; if (!solvearg(1)) goto cmderr; if (argt[1] != 2) {cerr = 2; goto cmderr;} tab_width = atoi(arg[1]); } if (chkCmd(1, "_AUTOCMDHIST")) { if (inProg) {cerr = 254; goto cmderr;} + if (argct) {cerr = 3; goto cmderr;} cerr = 0; - if (argct != 0) {cerr = 3; goto cmderr;} autohist = true; goto noerr; } if (chkCmd(1, "_SAVECMDHIST")) { if (inProg) {cerr = 254; goto cmderr;} - cerr = 0; if (argct > 1) {cerr = 3; goto cmderr;} + cerr = 0; if (argct) { if (!solvearg(1)) goto cmderr; if (argt[1] != 1) {cerr = 2; goto cmderr;} @@ -545,8 +713,8 @@ if (chkCmd(1, "_SAVECMDHIST")) { } if (chkCmd(1, "_LOADCMDHIST")) { if (inProg) {cerr = 254; goto cmderr;} - cerr = 0; if (argct > 1) {cerr = 3; goto cmderr;} + cerr = 0; clear_history(); if (argct) { if (!solvearg(1)) goto cmderr; @@ -610,7 +778,7 @@ if (chkCmd(1, "_TXTATTRIB")) { if (!strcmp(arg[1], "UNDERLINE_COLOR")) attrib = 12; else if (!strcmp(arg[1], "FGC")) attrib = 13; else if (!strcmp(arg[1], "BGC")) attrib = 14; else - if (!strcmp(arg[1], "TRUECOLOR") || !strcmp(arg[1], "TRUE_COLOR") || !strcmp(arg[1], "24BIT_COLOR")) attrib = 15; else + if (!strcmp(arg[1], "TRUECOLOR") || !strcmp(arg[1], "TRUE_COLOR") || !strcmp(arg[1], "24BITCOLOR") || !strcmp(arg[1], "24BIT_COLOR")) attrib = 15; else {cerr = 16; goto cmderr;} } else { attrib = atoi(arg[1]); @@ -666,7 +834,8 @@ if (chkCmd(1, "_TXTATTRIB")) { case 6: txt_strike = (bool)val; break; case 7: txt_overln = (bool)val; break; case 8: txt_dim = (bool)val; break; - case 9: txt_hidden = (bool)val; break; + case 9: txt_blink = (bool)val; break; + case 10: txt_hidden = (bool)val; break; case 11: txt_reverse = (bool)val; break; case 12: txt_underlncolor = val; break; case 13: txt_fgc = (bool)val; break; diff --git a/docs/clibasic.man b/docs/clibasic.man new file mode 100644 index 0000000..08f3444 --- /dev/null +++ b/docs/clibasic.man @@ -0,0 +1,74 @@ +.TH CLIBASIC 1 "2021-09-09" "0.22" +.SH NAME +CLIBASIC \- Command Line Interface BASIC +.SH SYNOPSIS +\fBclibasic\fR [\fIOPTION\fR]... +.SH DESCRIPTION +A BASIC interpreter for the terminal (or console), written in C +.SH OPTIONS +.PP +.TP 7 +\fB\-\-help\fR +Shows the usage and option information. +.TP +\fB\-\-version\fR +Shows the version and license information. +.TP +\fB\-\-args\fR [\fI\,ARG\/\fR]... +Passes ARGs to the program. +.TP +\fB\-x\fR, \fB\-\-exec\fR \fI\,FILE\/\fR [\fI\,ARG\/\fR]... +Runs and passes ARGs to FILE. +.TP +\fB\-f\fR, \fB\-\-file\fR \fI\,FILE\/\fR +Runs FILE. +.TP +\fB\-c\fR, \fB\-\-command\fR \fI\,COMMAND\/\fR +Runs COMMAND and exits. +.TP +\fB\-k\fR, \fB\-\-keep\fR +Stops CLIBASIC from resetting text attributes. +.TP +\fB\-s\fR, \fB\-\-skip\fR +Skips searching for autorun programs. +.TP +\fB\-i\fR, \fB\-\-info\fR +Enables the info text. +.SH EXAMPLES +.TP +\fBclibasic\fR +Runs CLIBASIC in shell mode. +.TP +\fBclibasic\fR \-i +Runs CLIBASIC in shell mode and displays the info header like earlier versions of CLIBASIC. +.TP +\fBclibasic\fR examples/info.bas +Looks for ./examples/info.bas and if successful, loads and runs the file. CLIBASIC will exit once an error has occurred or execution completes successfully. +.TP +\fBclibasic\fR \-f \-bar\-.bas +In the case you want to run a file that starts with a hyphen, use the \-file or \-f option which will cause the next argument to be evaluated as a file name. +.TP +\fBclibasic\fR \-c 'PRINT "FOO"; "BAR"' +If you want to run a single command, use the \-\-command or \-c option which will interpret the next argument as if it were typed in during shell mode. +.SH EXIT STATUS +.TP +\fB0\fR +Success. +.TP +\fB1\fR +Error occurred. +.TP +\fBNOTE:\fR +Any exit status (0\-255) can be returned by the program or command via the 'EXIT' command. +.SH FILES +.TP +\fB\fI~/.clibasic_history\fR +History file for storing previously entered commands from shell mode. +.SH AUTHOR +.TP +PQCraft <0456523@gmail.com> +.SH COPYRIGHT +Copyright (C) 2021 PQCraft +.br +Licensed under the GNU General Public License version 3.0 + diff --git a/docs/clibasic_tmp_cmds.txt b/docs/clibasic_tmp_cmds.txt index 6188c1b..de19a0d 100644 --- a/docs/clibasic_tmp_cmds.txt +++ b/docs/clibasic_tmp_cmds.txt @@ -60,3 +60,5 @@ $txtlock:do:k$=inkey$():if asc(k$)<>0:print k$,"\n":endif:loop for i, 0, i < 4, 1: print "bruh": next for i, 0, i < 4, 1: print "bruh": for j, 0, j < 4, 1: print "__bruh__": next: next for i, 0, i < 4, 1: print "i", i: for j, 0, j < 4, 1: print "j", j: next: next +do: i = fread(0): if i <> -1: print chr$(i);: loop: endif: print +if i=0: print "zero": elseif i=1: print "one": else: print "other": endif diff --git a/docs/manual.odt b/docs/manual.odt index 41e6990..c457004 100644 Binary files a/docs/manual.odt and b/docs/manual.odt differ diff --git a/docs/manual.pdf b/docs/manual.pdf index 317cc23..529c180 100644 Binary files a/docs/manual.pdf and b/docs/manual.pdf differ diff --git a/examples/args.bas b/examples/args.bas index 34b3be1..ce94a06 100644 --- a/examples/args.bas +++ b/examples/args.bas @@ -1,6 +1,8 @@ PRINT "clibasic: {" + _STARTCMD$() + "}" +PRINT "file: {" + _ARG$(I) + "}" PRINT "cmdline: {" + _ARG$() + "}" -FOR I, 0, I < _ARGC(), 1 +PRINT "count: ["; _ARGC(); "]" +FOR I, 1, I <= _ARGC(), 1 print "arg [" + STR$(I) + "]" + ": {" + _ARG$(I) + "}" NEXT diff --git a/examples/bunkerbomb.bas b/examples/bunkerbomb.bas index 06e1ed9..f541ec8 100644 --- a/examples/bunkerbomb.bas +++ b/examples/bunkerbomb.bas @@ -1,20 +1,14 @@ -set e, 0 -dowhile e = 0 - set i$, input$("Bomb le bunker? [Y/n]: ") - if i$ = "": set e, 1: endif - set c, asc(i$) - set c$, chr$(c) - if c$ = "y": set e, 1: endif - if c$ = "Y": set e, 1: endif - if c$ = "n": set e, 2: endif - if c$ = "N": set e, 2: endif -loop +@ again +set i$, input$("Bomb le bunker? 💣 [Y/n]: ") +i$=ucase$(snip$(i$, 1)) +if i$ <> "" & i$ <> "Y" & i$ <> "N" + goto again +endif print "You have chosen..." -if e = 1 - print "Sending nukes..."; +if i$ <> "N" + print "☢️ Sending nukes..."; wait 3 - print "\nDone." + print "\nDone. 💥" else print "Le buker lives another day." endif -exit \ No newline at end of file diff --git a/examples/cat.bas b/examples/cat.bas new file mode 100644 index 0000000..1d6b17a --- /dev/null +++ b/examples/cat.bas @@ -0,0 +1,7 @@ +_txtattrib "fgc", "off" +if _argc() <> 1: print "Expected 1 argument, recieved "; _argc(); " arguments instead": exit 1: endif +del file +file = fopen(_arg$(1), "r") +if file = -1: print "Could not open '"; _arg$(1); "': "; _errnostr$(_fileerror()): endif +dowhile eof(file) = 0: put fread$(file): loop +file = fclose(file) diff --git a/examples/clock.bas b/examples/clock.bas new file mode 100644 index 0000000..ea98f9f --- /dev/null +++ b/examples/clock.bas @@ -0,0 +1,18 @@ +do + locate 1 + h = date("hr") + if h > 12 + h = h - 12 + m$ = "PM" + elseif h = 0 + h = 12 + m$ = "AM" + else + m$ = "AM" + endif + print pad$(h, 2); ":"; pad$(date("min"), 2); ":"; pad$(date("sec"), 2); m$; " "; pad$(date("year"), 4); "-"; pad$(date("mon"), 2); "-"; pad$(date("day"), 2) + s = date(0) + waitms 900 + while date(0) = s: loop + locate , cury() - 1 +loop diff --git a/examples/executable.bas b/examples/executable.bas index 634d57c..836c1e9 100644 --- a/examples/executable.bas +++ b/examples/executable.bas @@ -4,4 +4,6 @@ PRINT "args: " + _ARG$() FOR I, 1, I < _ARGC(), 1 print "arg #" + STR$(I) + ": " + _ARG$(I) NEXT - +PRINT "Press [ENTER] to continue..."; +DOWHILE INKEY$() <> "\n": LOOP + diff --git a/examples/factorial.bas b/examples/factorial.bas index fc0d4f1..2b0e62e 100644 --- a/examples/factorial.bas +++ b/examples/factorial.bas @@ -1,4 +1,9 @@ -str=INPUT$("Enter a factorial number: ") +IF _arg$() = "" + str=INPUT$("Enter a factorial number: ") +ELSE + str=_arg$() +ENDIF + num=CINT(VAL(str)) fact=1 diff --git a/examples/info.bas b/examples/info.bas index 583b09b..4620fa5 100644 --- a/examples/info.bas +++ b/examples/info.bas @@ -1,4 +1,3 @@ print "You are running CLIBASIC "; _VER$(); " on "; _OS$(); " "; _BITS$(); "-bit." call dirname$(_arg$(0)) + "color.bas" -'goto te diff --git a/examples/linenumbers.bas b/examples/linenumbers.bas new file mode 100644 index 0000000..f0bb491 --- /dev/null +++ b/examples/linenumbers.bas @@ -0,0 +1,3 @@ +10 PRINT "Hello World!" +20 GOTO 10 + diff --git a/examples/speedtestfast.bas b/examples/speedtestfast.bas index 4099b96..54a8aa9 100644 --- a/examples/speedtestfast.bas +++ b/examples/speedtestfast.bas @@ -1 +1 @@ -SCORE=0:RESETTIMER:DOWHILE TIMER()<5:SCORE=SCORE+1:LOOP:PRINT "Score: ";SCORE \ No newline at end of file +SCORE=0:RESETTIMER:DOWHILE TIMER()<5:SCORE=SCORE+1:LOOP:PRINT "Score: ";SCORE diff --git a/examples/test.bas b/examples/test.bas index 9ca5f6e..cac8617 100644 --- a/examples/test.bas +++ b/examples/test.bas @@ -1,12 +1,18 @@ 'clibasic test program print "test" -color 21 +if _vt() = 1 + color 21 +else + color 12 +endif print "blue" _txtattrib 1, 1 set E, 0 do -set E, E+1 -print E, ""; -loopwhile e < 256 \ No newline at end of file + set E, E+1 + print E, ""; +loopwhile e < 256 + +print diff --git a/functions.c b/functions.c index c1cf040..88e0cc4 100644 --- a/functions.c +++ b/functions.c @@ -115,7 +115,7 @@ if (chkCmd(1, "SH")) { int duperr; duperr = dup(2); close(2); - sprintf(outbuf, "%d", system(farg[1])); + sprintf(outbuf, "%d", (retval = system(farg[1]))); dup2(duperr, 2); close(duperr); if (sh_restoreAttrib) updateTxtAttrib(); @@ -156,7 +156,7 @@ if (chkCmd(1, "EXEC")) { } else if (pid > 0) { while (wait(&status) != pid) {} - sprintf(outbuf, "%d", (status >> 8) & 0xFF); + sprintf(outbuf, "%d", (retval = WEXITSTATUS(status))); } else if (sh_silent) { dup2(stdout_dup, 1); @@ -186,8 +186,7 @@ if (chkCmd(1, "EXEC")) { dup2(fd, 1); dup2(fd, 2); } - int ret = system(tmpcmd); - (void)ret; + retval = WEXITSTATUS(system(tmpcmd)); if (sh_silent) { dup2(stdout_dup, 1); dup2(stderr_dup, 2); @@ -210,7 +209,7 @@ if (chkCmd(1, "SH$")) { FILE* p = popen(farg[1], "r"); if (p) { outbuf[fread(outbuf, 1, CB_BUF_SIZE - 1, p)] = 0; - pclose(p); + retval = WEXITSTATUS(pclose(p)); } dup2(duperr, 2); close(duperr); @@ -243,7 +242,8 @@ if (chkCmd(1, "EXEC$")) { exit(127); } else if (pid > 0) { - while (wait(NULL) != pid) {} + while (wait(&retval) != pid) {} + retval = WEXITSTATUS(retval); outbuf[read(fd[0], outbuf, CB_BUF_SIZE - 1)] = 0; } dup2(stdout_dup, 1); @@ -272,7 +272,7 @@ if (chkCmd(1, "EXEC$")) { FILE* p = popen(tmpcmd, "r"); if (p) { outbuf[fread(outbuf, 1, CB_BUF_SIZE, p)] = 0; - pclose(p); + retval = WEXITSTATUS(pclose(p)); } dup2(duperr, 2); close(duperr); @@ -795,6 +795,64 @@ if (chkCmd(1, "LINE$")) { if (outbuf[strlen(outbuf) - 1] == '\r') outbuf[strlen(outbuf) - 1] = 0; goto fexit; } +if (chkCmd(1, "DATE")) { + cerr = 0; + ftype = 2; + if (fargct != 1 || fargt[1] == 0) {cerr = 3; goto fexit;} + int element = -1; + if (fargt[1] == 2) { + element = atoi(farg[1]); + } else { + upCase(farg[1]); + chkCmdPtr = farg[1]; + if (chkCmd(2, "SEC", "SECOND")) {element = 0;} + else if (chkCmd(2, "MIN", "MINUTE")) {element = 1;} + else if (chkCmd(2, "HR", "HOUR")) {element = 2;} + else if (chkCmd(1, "DAY")) {element = 3;} + else if (chkCmd(2, "MON", "MONTH")) {element = 4;} + else if (chkCmd(1, "YEAR")) {element = 5;} + else if (chkCmd(2, "WDAY", "WEEKDAY")) {element = 6;} + else if (chkCmd(2, "YDAY", "YEARDAY")) {element = 7;} + else if (chkCmd(3, "DST", "DAYLIGHT", "DAYLIGHTSAVING")) {element = 8;} + } + if (element > 8 || element < 0) {cerr = 16; goto fexit;} + time_t rawtime; + time(&rawtime); + struct tm* timeinfo; + timeinfo = localtime(&rawtime); + int edata = -1; + switch (element) { + case 0: + edata = timeinfo->tm_sec; + break; + case 1: + edata = timeinfo->tm_min; + break; + case 2: + edata = timeinfo->tm_hour; + break; + case 3: + edata = timeinfo->tm_mday; + break; + case 4: + edata = timeinfo->tm_mon; + break; + case 5: + edata = 1900 + timeinfo->tm_year; + break; + case 6: + edata = timeinfo->tm_wday; + break; + case 7: + edata = timeinfo->tm_yday; + break; + case 8: + edata = timeinfo->tm_isdst; + break; + } + sprintf(outbuf, "%d", edata); + goto fexit; +} if (chkCmd(1, "CWD$")) { cerr = 0; ftype = 1; @@ -804,6 +862,7 @@ if (chkCmd(1, "CWD$")) { } if (chkCmd(1, "FILES$")) { cerr = 0; + fileerror = 0; ftype = 1; if (fargct > 1) {cerr = 3; goto fexit;} char* olddn = NULL; @@ -812,15 +871,14 @@ if (chkCmd(1, "FILES$")) { olddn = malloc(CB_BUF_SIZE); getcwd(olddn, CB_BUF_SIZE); if (chdir(farg[1])) { + fileerror = errno; free(olddn); - seterrstr(farg[1]); - cerr = 17; + outbuf[0] = 0; goto fexit; } } DIR* cwd = opendir("."); - if (!cwd) {if (fargct) {free(olddn);} cerr = 20; goto fexit;} - DIR* tmpdir; + if (!cwd) {if (fargct) {chdir(olddn); free(olddn);} outbuf[0] = 0; goto fexit;} struct dirent* dir; #ifdef _WIN32 #define FSC '\\' @@ -829,22 +887,23 @@ if (chkCmd(1, "FILES$")) { #define FSC '/' strcpy(outbuf, "./\n../"); #endif + struct stat pathstat; while ((dir = readdir(cwd))) { - if ((tmpdir = opendir(dir->d_name)) && strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..")) { + stat(dir->d_name, &pathstat); + if (S_ISDIR(pathstat.st_mode) && strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..")) { strApndChar(outbuf, '\n'); copyStrApnd(dir->d_name, outbuf); strApndChar(outbuf, FSC); } - if (tmpdir) closedir(tmpdir); } closedir(cwd); cwd = opendir("."); while ((dir = readdir(cwd))) { - if (!(tmpdir = opendir(dir->d_name))) { + stat(dir->d_name, &pathstat); + if (!(S_ISDIR(pathstat.st_mode))) { strApndChar(outbuf, '\n'); copyStrApnd(dir->d_name, outbuf); } - if (tmpdir) closedir(tmpdir); } if (fargct) { chdir(olddn); @@ -853,15 +912,259 @@ if (chkCmd(1, "FILES$")) { closedir(cwd); goto fexit; } -if (chkCmd(2, "CHDIR", "CD")) { +if (chkCmd(2, "CD", "CHDIR")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 1) {cerr = 2; goto fexit;} + outbuf[0] = '0' + !chdir(farg[1]); + outbuf[1] = 0; + goto fexit; +} +if (chkCmd(1, "FOPEN")) { cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 2) {cerr = 3; goto fexit;} + if (fargt[1] != 1 || fargt[2] != 1) {cerr = 2; goto fexit;} + if (!isFile(farg[1])) { + outbuf[0] = '-'; + outbuf[1] = '1'; + outbuf[2] = 0; + fileerror = EINVAL; + goto fexit; + } + sprintf(outbuf, "%d", openFile(farg[1], farg[2])); + goto fexit; +} +if (chkCmd(1, "FCLOSE")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 2) {cerr = 2; goto fexit;} + outbuf[0] = '0' + closeFile(atoi(farg[1])); + outbuf[1] = 0; + goto fexit; +} +if (chkCmd(1, "FSIZE")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 2) {cerr = 2; goto fexit;} + int fnum = atoi(farg[1]); + if (fnum < 0 || fnum >= filemaxct) { + outbuf[0] = '-'; + outbuf[1] = '1'; + outbuf[2] = 0; + fileerror = EINVAL; + goto fexit; + } + sprintf(outbuf, "%d", filedata[fnum].size); + goto fexit; +} +if (chkCmd(1, "EOF")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 2) {cerr = 2; goto fexit;} + int fnum = atoi(farg[1]); + if (fnum < 0 || fnum >= filemaxct) { + outbuf[0] = '-'; + outbuf[1] = '1'; + outbuf[2] = 0; + fileerror = EINVAL; + goto fexit; + } + int32_t prev = ftell(filedata[fnum].fptr); + fgetc(filedata[fnum].fptr); + errno = 0; + outbuf[0] = '0' + (feof(filedata[fnum].fptr) != 0); + fileerror = errno; + fseek(filedata[fnum].fptr, prev, SEEK_SET); + outbuf[1] = 0; + goto fexit; +} +if (chkCmd(1, "EOFD")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 2) {cerr = 2; goto fexit;} + int fnum = atoi(farg[1]); + if (fnum < 0 || fnum >= filemaxct) { + outbuf[0] = '-'; + outbuf[1] = '1'; + outbuf[2] = 0; + fileerror = EINVAL; + goto fexit; + } + errno = 0; + outbuf[0] = '0' + (ftell(filedata[fnum].fptr) >= filedata[fnum].size); + outbuf[1] = 0; + fileerror = errno; + goto fexit; +} +if (chkCmd(1, "FREAD$")) { + cerr = 0; + fileerror = 0; ftype = 1; if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 2) {cerr = 2; goto fexit;} + int fnum = atoi(farg[1]); + outbuf[1] = 0; + if (fnum < 0 || fnum >= filemaxct) { + outbuf[0] = 0; + fileerror = EINVAL; + goto fexit; + } + if (feof(filedata[fnum].fptr)) { + outbuf[0] = 0; + } else { + errno = 0; + int c = fgetc(filedata[fnum].fptr); + outbuf[0] = (c < 0) ? 0 : c; + fileerror = errno; + } + goto fexit; +} +if (chkCmd(1, "FREAD")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 2) {cerr = 2; goto fexit;} + int fnum = atoi(farg[1]); + int fc = -1; + if (fnum < 0 || fnum >= filemaxct) { + fileerror = EINVAL; + } else if (!feof(filedata[fnum].fptr)) { + errno = 0; + fc = fgetc(filedata[fnum].fptr); + if (fc < 0) fc = -1; + fileerror = errno; + } + sprintf(outbuf, "%d", fc); + goto fexit; +} +if (chkCmd(1, "FWRITE")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 2) {cerr = 3; goto fexit;} + if (fargt[1] != 2 || fargt[2] != 1) {cerr = 2; goto fexit;} + int fnum = atoi(farg[1]); + int32_t ret = -1; + if (fnum < 0 || fnum >= filemaxct) { + fileerror = EINVAL; + } else { + errno = 0; + ret = (fputs(farg[2], filedata[fnum].fptr) != EOF); + fileerror = errno; + } + sprintf(outbuf, "%d", ret); + goto fexit; +} +if (chkCmd(1, "FSEEK")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 2) {cerr = 3; goto fexit;} + if (fargt[1] != 2 || fargt[2] != 2) {cerr = 2; goto fexit;} + int fnum = atoi(farg[1]); + int32_t ret = 2; + if (fnum < 0 || fnum >= filemaxct) { + fileerror = EINVAL; + } else { + errno = 0; + int32_t pos = atoi(farg[2]); + if (pos < 0) { + fileerror = EINVAL; + } else { + ret = !fseek(filedata[fnum].fptr, (pos > filedata[fnum].size) ? filedata[fnum].size : pos, SEEK_SET); + fileerror = errno; + } + } + sprintf(outbuf, "%d", ret); + goto fexit; +} +if (chkCmd(1, "FLUSH")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 2) {cerr = 2; goto fexit;} + int fnum = atoi(farg[1]); + if (fnum < 0 || fnum >= filemaxct) { + outbuf[0] = '-'; + outbuf[1] = '1'; + outbuf[2] = 0; + fileerror = EINVAL; + goto fexit; + } + errno = 0; + outbuf[0] = (fflush(filedata[fnum].fptr) != EOF); + outbuf[1] = 0; + fileerror = errno; + goto fexit; +} +if (chkCmd(2, "MD", "MKDIR")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 1) {cerr = 2; goto fexit;} + errno = 0; + #ifndef _WIN32 + outbuf[0] = '0' + !mkdir(farg[1], S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + #else + outbuf[0] = '0' + !mkdir(farg[1]); + #endif + outbuf[1] = 0; + fileerror = errno; + goto fexit; +} +if (chkCmd(2, "RM", "REMOVE")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} if (fargt[1] != 1) {cerr = 2; goto fexit;} + outbuf[0] = '0' + cbrm(farg[1]); + outbuf[1] = 0; + goto fexit; +} +if (chkCmd(4, "MV", "MOVE", "REN", "RENAME")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 2) {cerr = 3; goto fexit;} + if (fargt[1] != 1 || fargt[2] != 1) {cerr = 2; goto fexit;} errno = 0; - int ret = chdir(farg[1]); - (void)ret; - sprintf(outbuf, "%d", errno); + outbuf[0] = '0' + !rename(farg[1], farg[2]); + outbuf[1] = 0; + fileerror = errno; + goto fexit; +} +if (chkCmd(1, "ISFILE")) { + cerr = 0; + fileerror = 0; + ftype = 2; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 1) {cerr = 2; goto fexit;} + struct stat pathstat; + if (stat(farg[1], &pathstat)) { + outbuf[0] = '-'; + outbuf[1] = '1'; + outbuf[2] = 0; + fileerror = errno; + goto fexit; + } + outbuf[0] = '0' + !(S_ISDIR(pathstat.st_mode)); + outbuf[1] = 0; goto fexit; } goto fexit; @@ -894,6 +1197,28 @@ if (chkCmd(1, "_ENVSET")) { outbuf[1] = 0; goto fexit; } +if (chkCmd(1, "_RET")) { + cerr = 0; + ftype = 2; + if (fargct) {cerr = 3; goto fexit;} + sprintf(outbuf, "%d", retval); + goto fexit; +} +if (chkCmd(1, "_ERRNOSTR$")) { + cerr = 0; + ftype = 1; + if (fargct != 1) {cerr = 3; goto fexit;} + if (fargt[1] != 2) {cerr = 2; goto fexit;} + copyStr(strerror(atoi(farg[1])), outbuf); + goto fexit; +} +if (chkCmd(1, "_FILEERROR")) { + cerr = 0; + ftype = 2; + if (fargct) {cerr = 3; goto fexit;} + sprintf(outbuf, "%d", fileerror); + goto fexit; +} if (chkCmd(1, "_PROMPT$")) { cerr = 0; ftype = 1; @@ -930,6 +1255,18 @@ if (chkCmd(1, "_OS$")) { copyStr(OSVER, outbuf); goto fexit; } +if (chkCmd(1, "_VT")) { + cerr = 0; + ftype = 2; + if (fargct) {cerr = 3; goto fexit;} + #ifdef _WIN_NO_VT + outbuf[0] = '0'; + #else + outbuf[0] = '1'; + #endif + outbuf[1] = 0; + goto fexit; +} if (chkCmd(1, "_STARTCMD$")) { cerr = 0; ftype = 1; @@ -962,6 +1299,6 @@ if (chkCmd(1, "_ARGC")) { cerr = 0; ftype = 2; if (fargct) {cerr = 3; goto fexit;} - sprintf(outbuf, "%d", progargc); + sprintf(outbuf, "%d", (progargc > 0) ? progargc - 1 : progargc); goto fexit; } diff --git a/logic.c b/logic.c index 7317da3..3a73ad1 100644 --- a/logic.c +++ b/logic.c @@ -13,31 +13,49 @@ if (chkCmd(2, "?", "PRINT")) { if (cmd[j] == 0) {putchar('\n'); return true;} else {j--;} bool inStr = false; + bool lookingForSpChar = false; + bool sawSpChar = false; int pct = 0, bct = 0; int32_t ptr = 0; int32_t i = j; while (cmd[i]) { i++; if (cmd[i] == '"') {inStr = !inStr;} - if (cmd[i] == '(' && !inStr) {pct++;} - if (cmd[i] == ')' && !inStr) {pct--;} - if (cmd[i] == '[' && !inStr) {bct++;} - if (cmd[i] == ']' && !inStr) {bct--;} - if (cmd[i] == ' ' && !inStr) {} else + if (!inStr) { + switch (cmd[i]) { + case '(': ++pct; break; + case ')': --pct; break; + case '[': ++bct; break; + case ']': --bct; break; + } + } if ((cmd[i] == ',' || cmd[i] == ';' || cmd[i] == 0) && !inStr && pct == 0 && bct == 0) { - ltmp[1][ptr] = 0; ptr = 0; + ltmp[1][ptr] = 0; + ptr = 0; int32_t len = strlen(ltmp[1]); int tmpt; if (!(tmpt = getVal(ltmp[1], ltmp[1]))) return true; if (cmd[j] == ',') { - if (tmpt != 255) {putchar('\t');} - else {putchar('\n');} + if (tmpt == 255) {putchar('\n');} + else {putchar('\t');} } fputs(ltmp[1], stdout); if (cmd[i] == 0 && len > 0) putchar('\n'); j = i; - } else - {ltmp[1][ptr] = cmd[i]; ptr++;} + lookingForSpChar = false; + sawSpChar = false; + } else { + if (!inStr) { + if (cmd[i] == ' ' && !sawSpChar && ptr > 0) {lookingForSpChar = true;} + if (isExSpChar(cmd[i])) {lookingForSpChar = false; sawSpChar = true;} + } + if (inStr || cmd[i] != ' ') { + if (!isExSpChar(cmd[i])) sawSpChar = false; + if (lookingForSpChar) {cerr = 1; return true;} + ltmp[1][ptr] = cmd[i]; + ptr++; + } + } } if (pct || bct || inStr) {cerr = 1; return true;} fflush(stdout); @@ -64,7 +82,7 @@ if (chkCmd(1, "DO")) { dlstack[dlstackp].itsp = itstackp; return true; } -if (chkCmd(1, "DOWHILE")) { +if (chkCmd(2, "WHILE", "DOWHILE")) { if (dlstackp >= CB_PROG_LOGIC_MAX - 1) {cerr = 12; return true;} dlstackp++; if (itstackp > ((progindex > -1) ? minitstackp[progindex] : -1)) { @@ -78,7 +96,7 @@ if (chkCmd(1, "DOWHILE")) { } copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); uint8_t testval = logictest(ltmp[1]); - if (testval != 1 && testval) return true; + if (testval == 255) return true; if (testval == 1) { dlstack[dlstackp].pl = progLine; dlstack[dlstackp].cp = cmdpos; @@ -129,7 +147,7 @@ if (chkCmd(1, "LOOPWHILE")) { } copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); uint8_t testval = logictest(ltmp[1]); - if (testval != 1 && testval) return true; + if (testval == 255) return true; if (testval == 1) { if (inProg) { cp = dlstack[dlstackp].cp; @@ -160,8 +178,9 @@ if (chkCmd(1, "IF")) { } copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); uint8_t testval = logictest(ltmp[1]); - if (testval != 1 && testval) return true; + if (testval == 255) return true; itdcmd[itstackp] = (bool)!testval; + didelseif = !itdcmd[itstackp]; return true; } if (chkCmd(1, "ELSE")) { @@ -176,10 +195,29 @@ if (chkCmd(1, "ELSE")) { if (fndcmd[fnstackp]) return true; } if (didelse) {cerr = 11; return true;} + if (didelseif) {itdcmd[itstackp] = true; return true;} didelse = true; itdcmd[itstackp] = !itdcmd[itstackp]; return true; } +if (chkCmd(1, "ELSEIF")) { + if (itstackp <= -1) {cerr = 8; return true;} + if (itstackp > ((progindex > -1) ? minitstackp[progindex] + 1 : 0)) { + if (itdcmd[itstackp - 1]) return true; + } + if (dlstackp > ((progindex > -1) ? mindlstackp[progindex] : -1)) { + if (dldcmd[dlstackp]) return true; + } + if (fnstackp > ((progindex > -1) ? minfnstackp[progindex] : -1)) { + if (fndcmd[fnstackp]) return true; + } + copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); + uint8_t testval = logictest(ltmp[1]); + if (testval == 255) return true; + itdcmd[itstackp] = (bool)(!testval); + if (!didelseif) didelseif = !itdcmd[itstackp]; + return true; +} if (chkCmd(1, "ENDIF")) { if (itstackp <= -1) {cerr = 7; return true;} itstackp--; @@ -191,6 +229,7 @@ if (chkCmd(1, "ENDIF")) { } itdcmd[itstackp + 1] = false; didelse = false; + didelseif = false; return true; } if (chkCmd(1, "FOR")) { @@ -224,7 +263,7 @@ if (chkCmd(1, "FOR")) { setVar(fnvar, forbuf[0], 2, -1); } int testval = logictest(forbuf[2]); - if (testval == -1) return true; + if (testval == 255) return true; fndcmd[fnstackp] = !(bool)testval; if (!(fninfor[fnstackp] = (bool)testval)) {cerr = 0; return true;} if (!fninfor[fnstackp] && fnstack[fnstackp].cp == -1) { diff --git a/package.sh b/package.sh index 770c1ae..95213a2 100644 --- a/package.sh +++ b/package.sh @@ -1,39 +1,30 @@ -# makes clibasic release files +# clibasic release packager -# erase old versions -rm -f clibasic-linux-x64.zip -rm -f clibasic-linux-x86.zip -rm -f clibasic-windows-x64.zip -rm -f clibasic-windows-x86.zip -rm -f examples.zip +# mkrel function to reduce sloc +mkrel() { + echo "Making $1..." + rm -f "$1" + make $3 1> /dev/null || exit 1 + zip "$1" $2 1> /dev/null || exit 1 + make $4 1> /dev/null +} # backup built executables mv clibasic clibasic.tmp 2> /dev/null mv clibasic.exe clibasic.exe.tmp 2> /dev/null # package the examples -zip -r examples.zip examples +echo "Packaging examples..." +rm -f examples.zip +zip -r examples.zip examples 1> /dev/null || exit 1 # build -rm -f clibasic -make build 1> /dev/null -zip clibasic-linux-x64.zip clibasic -make clean 1> /dev/null - -rm -f clibasic -make build32 1> /dev/null -zip clibasic-linux-x86.zip clibasic -make clean 1> /dev/null - -rm -f clibasic.exe -make cross build 1> /dev/null -zip clibasic-windows-x64.zip clibasic.exe *.dll -make cross clean 1> /dev/null - -rm -f clibasic.exe -make cross build32 1> /dev/null -zip clibasic-windows-x86.zip clibasic.exe *.dll -make cross clean 1> /dev/null +mkrel "clibasic-linux-x64.zip" "clibasic" "clean build" "clean" +mkrel "clibasic-linux-x86.zip" "clibasic" "clean build32" "clean" +mkrel "clibasic-windows-vt-x64.zip" "clibasic.exe *.dll" "cross clean vt build" "cross clean" +mkrel "clibasic-windows-vt-x86.zip" "clibasic.exe *.dll" "cross clean vt build32" "cross clean" +mkrel "clibasic-windows-x64.zip" "clibasic.exe *.dll" "cross clean build" "cross clean" +mkrel "clibasic-windows-x86.zip" "clibasic.exe *.dll" "cross clean build32" "cross clean" # clean up mv clibasic.tmp clibasic 2> /dev/null