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