diff --git a/README.md b/README.md index 52c5490..d0fc74b 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ To build CLIBASIC with support for VT escape codes, add `vt` before the rest of - 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. +- Most terminals cannot handle input while processing a cursor position request and INKEY$() will not reflect keys that were pressed during that time. The effect is more noticeable on terminals that are slow to respond such as Alacritty, Gnome Terminal, and Termux. A terminal that is fast to respond such as Konsole is recommended. - 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. - CLIBASIC will look for `~/.clibasicrc`, `~/autorun.bas`, then `~/.autorun.bas` in this order in the user's home directory and run the first file found. - The development scripts are `build.sh` which is for testing if CLIBASIC compiles correctly for Linux and Windows, `package.sh` which creates the zip files for making a CLIBASIC release, `commit.sh` which automates the build and push process, and `release-text.sh` which generates the text for making a CLIBASIC release. diff --git a/clibasic.c b/clibasic.c index 7f40356..60b90cb 100644 --- a/clibasic.c +++ b/clibasic.c @@ -10,6 +10,11 @@ #define CB_PROG_LOGIC_MAX 256 // Change the value to change how far logic commands can be nested #endif +#ifndef GCP_TIMEOUT // Avoids redefinition error if '-DGCP_TIMEOUT=' is used + /* Sets the timeout for getCurPos() before resending the escape code (slower terminals may require a higher value) */ + #define GCP_TIMEOUT 50000 // Change how long getCurPos() waits in microseconds until resending the cursor position request +#endif + /* Uses strcpy and strcat in place of copyStr and copyStrApnd */ #define BUILT_IN_STRING_FUNCS // Comment out this line to use CLIBASIC string functions @@ -116,7 +121,7 @@ // Base defines -char VER[] = "0.27"; +char VER[] = "0.27.1"; #if defined(__linux__) char OSVER[] = "Linux"; @@ -1055,10 +1060,16 @@ int main(int argc, char** argv) { if (tmpt != 1) strcpy(pstr, "CLIBASIC> "); getCurPos(); #ifndef _WIN32 - curx--; - int32_t ptr = strlen(pstr); - while (curx > 0) {pstr[ptr] = 22; ptr++; curx--;} - pstr[ptr] = 0; + struct winsize max; + ioctl(0, TIOCGWINSZ, &max); + if (curx == max.ws_col) { + putchar('\n'); + } else { + curx--; + int32_t ptr = strlen(pstr); + while (curx > 0) {pstr[ptr] = 22; ptr++; curx--;} + pstr[ptr] = 0; + } #else if (curx > 1) putchar('\n'); #endif @@ -1097,21 +1108,6 @@ int main(int argc, char** argv) { if (strcmp(tmpstr, cmpstr)) {add_history(tmpstr); copyStr(tmpstr, cmpstr);} copyStr(tmpstr, conbuf); nfree(tmpstr); - bool inStr = false; - bool sawCmd = false; - for (int32_t i = 0; conbuf[i]; ++i) { - switch (conbuf[i]) { - case 'a' ... 'z':; - if (!inStr) conbuf[i] = conbuf[i] - 32; - break; - case '"':; - inStr = !inStr; - break; - case ' ':; - if (!sawCmd) {sawCmd = true; inStr = false;} - break; - } - } cmdint = false; } if (runc) runc = false; @@ -1157,6 +1153,7 @@ int main(int argc, char** argv) { } else { if (!inStr && (conbuf[concp] == '\'' || conbuf[concp] == '#')) comment = true; if (!inStr && conbuf[concp] == '\n') comment = false; + if (!inStr) {conbuf[concp] = ((conbuf[concp] >= 'a' && conbuf[concp] <= 'z') ? conbuf[concp] - 32 : conbuf[concp]);} if (conbuf[concp] == '"') {inStr = !inStr; cmdl++;} else if ((conbuf[concp] == ':' && !inStr) || conbuf[concp] == 0) { while (conbuf[concp - cmdl] == ' ' && cmdl > 0) {cmdl--;} @@ -1173,7 +1170,12 @@ int main(int argc, char** argv) { if (chkinProg) goto fchkint; } else {cmdl++;} - if (!didloop) {if (comment) {conbuf[concp] = 0;} concp++;} else {didloop = false;} + if (!didloop) { + if (comment) {conbuf[concp] = 0;} + //else if (!inStr) {conbuf[concp] = (conbuf[concp] >= 'a' || conbuf[concp] <= 'z') ? conbuf[concp] - 32 : conbuf[concp];} + concp++; + } + else {didloop = false;} } } brkproccmd:; @@ -1249,7 +1251,7 @@ static inline void getCurPos() { fputs("\e[6n", stdout); fflush(stdout); uint64_t tmpus = usTime(); - while (!kbhit()) {if (usTime() - tmpus > 50000) {goto resend;}} + while (!kbhit()) {if (usTime() - tmpus > GCP_TIMEOUT) {goto resend;}} while (kbhit()) { if (kbhit()) { int ret = read(0, &buf[i], 1); @@ -1451,7 +1453,7 @@ bool loadProg(char* filename) { while (j < fsize && !feof(prog)) { int tmpc = fgetc(prog); if (tmpc == '"') inStr = !inStr; - if (!sawCmd && tmpc == ' ') {sawCmd = true; inStr = false;} + if (!inStr && !sawCmd && tmpc == ' ') {sawCmd = true; inStr = false;} if (!inStr && (tmpc == '\'' || tmpc == '#')) comment = true; if (tmpc == '\n') {comment = false; inStr = false;} if (tmpc == '\r' || tmpc == '\t') tmpc = ' '; @@ -1581,6 +1583,7 @@ static inline bool isValidVarChar(char c) { case ']':; case '_':; case '~':; + case '.':; return true; break; default:; @@ -3165,9 +3168,9 @@ int loadExt(char* path) { } cb_extargs extargs = { VER, BVER, OSVER, + &cerr, &retval, &fileerror, &varmaxct, vardata, - &retval, - &filemaxct, filedata, &fileerror, + &filemaxct, filedata, &chkCmdPtr, &txtattrib, &curx, &cury, @@ -3213,18 +3216,18 @@ bool unloadExt(int e) { if (e == -1) { for (int i = extmaxct - 1; i > -1; --i) { if (!extdata[i].inuse) continue; + if (extdata[i].deinit) extdata[i].deinit(); extdata[i].inuse = false; nfree(extdata[i].name); dlclose(extdata[i].lib); - if (extdata[i].deinit) extdata[i].deinit(); } extmaxct = 0; } else { if (e < -1 || e >= extmaxct || !extdata[e].inuse) {cerr = 16; return false;} + if (extdata[e].deinit) extdata[e].deinit(); extdata[e].inuse = false; nfree(extdata[e].name); dlclose(extdata[e].lib); - if (extdata[e].deinit) extdata[e].deinit(); for (int i = extmaxct - 1; i > -1; --i) { if (extdata[i].inuse) break; --extmaxct; diff --git a/clibasic.h b/clibasic.h index 3ab0dd9..c3be883 100644 --- a/clibasic.h +++ b/clibasic.h @@ -99,12 +99,13 @@ typedef struct { char* VER; // CLIBASIC version char* BVER; // bits ("64"/"32"/"?") char* OSVER; // os name ("Linux", "Windows", ...) + int* cerr; // pointer to the variable storing the error number + int* retval; // pointer to the variable read by the CLIBASIC function _RET() + int* fileerror; // pointer to the variable read by the CLIBASIC function _FILEERROR() int* varmaxct; // pointer to the amount of variable spots allocated cb_var* vardata; // pointer to the variable spots - int* retval; // pointer to the variable read by the CLIBASIC function _RET() int* filemaxct; // pointer to the amount of file spots allocated cb_file* filedata; // pointer to the file spots - int* fileerror; // pointer to the variable read by the CLIBASIC function _FILEERROR() char** chkCmdPtr; // pointer to a pointer of the char array to be compared by chkCmd() cb_txt* txtattrib; // pointer to the struct that stores text attributes int* curx; // pointer to the text cursor x position @@ -133,7 +134,7 @@ typedef struct { uint8_t (*getVar)(char*, char*); // puts the value of the variable specified by argument 1 in argument 2 and returns the type (1 = string, 2 = number) bool (*setVar)(char*, char*, uint8_t, int32_t); // sets the variable specified by argument 1 to the value specified by argument 2 and sets the type to argument 3 and size to argument 4 bool (*delVar)(char*); // deletes a variable - uint8_t (*getVal)(char*, char*); // gets the value of the raw input supplied by argument and returns the type (1 = string, 2 = number, 255 = blank) or 0 on failure + uint8_t (*getVal)(char*, char*); // solves raw input in argument 1, writes the value into argument 2, and returns the type (1 = string, 2 = number, 255 = blank) or 0 on failure bool (*solvearg)(int); // solves an argument for commands as some commands may want to read from raw input uint8_t (*logictest)(char*); // takes raw input, tests it, and returns -1 on failure, 0 if false, and 1 if true void (*printError)(int); // prints a built-in error string diff --git a/commands.c b/commands.c index 8ce4502..11c80d5 100644 --- a/commands.c +++ b/commands.c @@ -340,13 +340,18 @@ if (chkCmd(1, "LOCATE")) { cerr = 0; int tmp = 0; if (!solvearg(1)) 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;} - else {curx = tmp;} + else { + #ifndef _WIN_NO_VT + printf("\e[%dG", tmp); + #else + curx = tmp; + #endif + } } if (argct > 1) { if (!solvearg(2)) goto cmderr; @@ -356,13 +361,20 @@ if (chkCmd(1, "LOCATE")) { else { tmp = atoi(arg[2]); if (tmp < 1) {cerr = 16; goto cmderr;} - else {cury = tmp;} + else { + #ifndef _WIN_NO_VT + --tmp; + fputs("\e[32767A", stdout); + if (tmp) printf("\e[%dB", tmp); + #else + cury = tmp; + #endif + } } } #ifdef _WIN_NO_VT SetConsoleCursorPosition(hConsole, (COORD){curx - 1, cury - 1}); #else - printf("\e[%d;%dH", cury, curx); fflush(stdout); #endif goto noerr; @@ -372,22 +384,26 @@ if (chkCmd(1, "RLOCATE")) { cerr = 0; int tmp = 0; if (!solvearg(1)) goto cmderr; + #ifndef _WIN_NO_VT getCurPos(); + #endif if (argt[1] == 0) {} else if (argt[1] != 2) {cerr = 2; goto cmderr;} else { tmp = atoi(arg[1]); if (tmp == 0) {} else if (tmp < 0) { - curx += tmp; - if (curx < 0) curx = 0; #ifndef _WIN_NO_VT printf("\e[%dD", -tmp); + #else + curx += tmp; + if (curx < 0) curx = 0; #endif } else { - curx += tmp; #ifndef _WIN_NO_VT printf("\e[%dC", tmp); + #else + curx += tmp; #endif } } @@ -400,23 +416,26 @@ if (chkCmd(1, "RLOCATE")) { tmp = atoi(arg[2]); if (tmp == 0) {} else if (tmp < 0) { - cury += tmp; - if (cury < 0) cury = 0; #ifndef _WIN_NO_VT printf("\e[%dA", -tmp); + #else + cury += tmp; + if (cury < 0) cury = 0; #endif } else { - cury += tmp; #ifndef _WIN_NO_VT printf("\e[%dB", tmp); + #else + cury += tmp; #endif } } } #ifdef _WIN_NO_VT SetConsoleCursorPosition(hConsole, (COORD){curx - 1, cury - 1}); - #endif + #else fflush(stdout); + #endif goto noerr; } if (chkCmd(1, "CLS")) { diff --git a/examples b/examples index 672f4f4..44b58a2 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 672f4f4287a8ded0bc20e89c48fdab9c6937d8d1 +Subproject commit 44b58a24f7526ae768810357d89a7d629af5184f diff --git a/functions.c b/functions.c index 60f3338..0bbe136 100644 --- a/functions.c +++ b/functions.c @@ -833,7 +833,7 @@ if (chkCmd(1, "WIDTH")) { if (fargct) {cerr = 3; goto fexit;} #ifdef __unix__ struct winsize max; - ioctl(0, TIOCGWINSZ , &max); + ioctl(0, TIOCGWINSZ, &max); sprintf(outbuf, "%d", max.ws_col); #else CONSOLE_SCREEN_BUFFER_INFO csbi; @@ -850,7 +850,7 @@ if (chkCmd(1, "HEIGHT")) { if (fargct) {cerr = 3; goto fexit;} #ifdef __unix__ struct winsize max; - ioctl(0, TIOCGWINSZ , &max); + ioctl(0, TIOCGWINSZ, &max); sprintf(outbuf, "%d", max.ws_row); #else CONSOLE_SCREEN_BUFFER_INFO csbi; diff --git a/logic.c b/logic.c index 5eae5ee..7d48eb8 100644 --- a/logic.c +++ b/logic.c @@ -105,8 +105,8 @@ if (chkCmd(1, "DO")) { dldcmd[dlstackp] = false; dlstack[dlstackp].cp = cmdpos; dlstack[dlstackp].pl = progLine; - dlstack[dlstackp].fnsp = fnstackp; - dlstack[dlstackp].itsp = itstackp; + //dlstack[dlstackp].fnsp = fnstackp; + //dlstack[dlstackp].itsp = itstackp; dlstack[dlstackp].brkinfo = brkinfo; brkinfo.block = 1; #ifdef _WIN32 @@ -133,8 +133,8 @@ if (chkCmd(2, "WHILE", "DOWHILE")) { if (testval == 1) { dlstack[dlstackp].pl = progLine; dlstack[dlstackp].cp = cmdpos; - dlstack[dlstackp].fnsp = fnstackp; - dlstack[dlstackp].itsp = itstackp; + //dlstack[dlstackp].fnsp = fnstackp; + //dlstack[dlstackp].itsp = itstackp; dlstack[dlstackp].brkinfo = brkinfo; brkinfo.block = 1; #ifdef _WIN32 @@ -169,8 +169,8 @@ if (chkCmd(1, "LOOP")) { concp = dlstack[dlstackp].cp; } progLine = dlstack[dlstackp].pl; - fnstackp = dlstack[dlstackp].fnsp; - itstackp = dlstack[dlstackp].itsp; + //fnstackp = dlstack[dlstackp].fnsp; + //itstackp = dlstack[dlstackp].itsp; brkinfo = dlstack[dlstackp].brkinfo; lockpl = true; } @@ -208,8 +208,8 @@ if (chkCmd(1, "LOOPWHILE")) { concp = dlstack[dlstackp].cp; } progLine = dlstack[dlstackp].pl; - fnstackp = dlstack[dlstackp].fnsp; - itstackp = dlstack[dlstackp].itsp; + //fnstackp = dlstack[dlstackp].fnsp; + //itstackp = dlstack[dlstackp].itsp; brkinfo = dlstack[dlstackp].brkinfo; lockpl = true; } @@ -335,8 +335,8 @@ if (chkCmd(1, "FOR")) { cerr = 0; fnstack[fnstackp].cp = cmdpos; fnstack[fnstackp].pl = progLine; - fnstack[fnstackp].dlsp = dlstackp; - fnstack[fnstackp].itsp = itstackp; + //fnstack[fnstackp].dlsp = dlstackp; + //fnstack[fnstackp].itsp = itstackp; brkinfo.block = 2; #ifdef _WIN32 updatechars(); @@ -365,13 +365,14 @@ if (chkCmd(1, "NEXT")) { concp = fnstack[fnstackp].cp; } progLine = fnstack[fnstackp].pl; - dlstackp = fnstack[fnstackp].dlsp; - itstackp = fnstack[fnstackp].itsp; + //dlstackp = fnstack[fnstackp].dlsp; + //itstackp = fnstack[fnstackp].itsp; lockpl = true; didloop = true; } else { fnstack[fnstackp].cp = -1; brkinfo.type = 0; + fndcmd[dlstackp] = false; } fnstackp--; brkinfo = fnstack[fnstackp].brkinfo;