diff --git a/clibasic.c b/clibasic.c index 1833198..f237d0c 100644 --- a/clibasic.c +++ b/clibasic.c @@ -115,7 +115,7 @@ // Base defines -char VER[] = "0.22.5.1"; +char VER[] = "0.22.6"; #if defined(__linux__) char OSVER[] = "Linux"; @@ -332,7 +332,7 @@ static inline void* setsig(int sig, void* func) { 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 @@ -483,6 +483,7 @@ void forceExit() { txtqunlock(); tcsetattr(0, TCSANOW, &kbhterm); #endif + putchar('\n'); exit(0); } @@ -500,6 +501,8 @@ bool closeFile(int); static inline void upCase(char*); uint8_t logictest(char*); +bool checknl = false; + void cleanExit() { txtqunlock(); if (inprompt) { @@ -540,6 +543,10 @@ void cleanExit() { while (i > 0) {getchar(); i--;} tcsetattr(0, TCSANOW, &kbhterm); #endif + if (checknl) { + getCurPos(); + if (curx != 1) putchar('\n'); + } freeBaseMem(); exit(err); } @@ -548,7 +555,8 @@ void cmdIntHndl() { setsig(SIGINT, cmdIntHndl); if (cmdint) setsig(SIGINT, cleanExit); int i = kbhit(); - while (i > 0) {getchar(); i--;} + if (i) {read(0, &gpbuf, i);} + if (kbhit()) read(0, &gpbuf, kbhit()); cmdint = true; } @@ -623,6 +631,18 @@ static inline void ttycheck() { if (!isatty(STDOUT_FILENO)) {fputs("CLIBASIC does not support STDOUT redirection.\n", stderr); exit(1);} } +static inline void readyTerm() { + ttycheck(); + #ifndef _WIN32 + tcgetattr(0, &kbhterm); + kbhterm2 = kbhterm; + kbhterm2.c_lflag &= ~ICANON; + tcsetattr(0, TCSANOW, &kbhterm2); + sigemptyset(&intmask); + sigaddset(&intmask, SIGINT); + #endif +} + int main(int argc, char** argv) { #if defined(GUI_CHECK) && defined(__unix__) if (system("tty -s 1> /dev/null 2> /dev/null")) { @@ -678,6 +698,7 @@ int main(int argc, char** argv) { puts(" -s, --skip Skips searching for autorun programs."); puts(" -i, --info Displays an info string when starting in shell mode."); puts(" -r, --redirection Allows for redirection (this may cause issues)."); + puts(" -n, --newline Prints a newline if the cursor is not at the beginning of the line."); 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);} @@ -689,7 +710,6 @@ int main(int argc, char** argv) { } else if (!strcmp(argv[i], "--exec") || !strcmp(argv[i], "-x")) { if (runc) {fputs("Cannot run command and file.\n", stderr); exit(1);} if (runfile) {fputs("Program already loaded, use --args.\n", stderr); exit(1); unloadAllProg();} - ttycheck(); if (runfile) {unloadProg(); fputs("Incorrect number of options passed.\n", stderr); exit(1);} i++; if (!argv[i]) {fputs("No filename provided.\n", stderr); exit(1);} @@ -717,9 +737,13 @@ int main(int argc, char** argv) { if (redirection) {fputs("Incorrect number of options passed.\n", stderr); exit(1);} redirection = true; if (shortopt) goto chkshortopt; + } else if (!strcmp(argv[i], "--newline") || (shortopt && argv[i][shortopti] == 'n')) { + if (checknl) {fputs("Incorrect number of options passed.\n", stderr); exit(1);} + checknl = true; + if (shortopt) goto chkshortopt; } else if (!strcmp(argv[i], "--command") || !strcmp(argv[i], "-c")) { if (runfile) {fputs("Cannot run file and command.\n", stderr); exit(1);} - ttycheck(); + readyTerm(); if (runc) {fputs("Incorrect number of options passed.\n", stderr); exit(1);} i++; if (!argv[i]) {fputs( "No command provided.\n", stderr); exit(1);} @@ -752,7 +776,7 @@ int main(int argc, char** argv) { } } else { if (runc) {fputs("Cannot run command and file.\n", stderr); exit(1);} - ttycheck(); + readyTerm(); if (runfile) {unloadProg(); fputs("Incorrect number of options passed.\n", stderr); exit(1);} if (!strcmp(argv[i], "--file") || !strcmp(argv[i], "-f")) { i++; @@ -764,15 +788,7 @@ 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 + readyTerm(); rl_readline_name = "CLIBASIC"; char* rl_tmpptr = calloc(1, 1); rl_completion_entry_function = rl_get_tab; @@ -1009,7 +1025,10 @@ int main(int argc, char** argv) { if (inProg) { if (progbuf[progindex][cp] == '"') {inStr = !inStr; cmdl++;} else if ((progbuf[progindex][cp] == ':' && !inStr) || progbuf[progindex][cp] == '\n' || progbuf[progindex][cp] == 0) { - if (progbuf[progindex][cp - cmdl - 1] == '\n' && !lockpl) progLine++; + if (progbuf[progindex][cp - cmdl - 1] == '\n') { + if (!lockpl) progLine++; + if (inStr) inStr = false; + } if (lockpl) lockpl = false; while (progbuf[progindex][cp - cmdl] == ' ' && cmdl > 0) {cmdl--;} cmd = (char*)realloc(cmd, cmdl + 1); @@ -1098,32 +1117,13 @@ static inline int isFile(char* path) { return !(S_ISDIR(pathstat.st_mode)); } -#ifndef _WIN32 -int gcpret, gcpi; -void (*gcpoldsigh)(int); -bool gcpint = false; - -void gcpsigh() { - setsig(SIGINT, gcpsigh); - gcpoldsigh(0); - gcpint = true; - if (gcpret < gcpi + 1) getCurPos(); - txtqunlock(); - return; -} - -bool gcp_sig = true; -#endif - static inline void getCurPos() { fflush(stdout); cury = 0; curx = 0; #ifndef _WIN32 - char buf[16]; - register int i; - if (gcp_sig) sigprocmask(SIG_SETMASK, &intmask, &oldmask); - i = kbhit(); - while (i > 0) {getchar(); i--;} + static char buf[16] = {0}; + for (int i = 0; i < 16; ++i) {buf[i] = 0;} + register int i = 0; if (!textlock) { sneaktextlock = true; tcgetattr(0, &term); @@ -1131,22 +1131,36 @@ static inline void getCurPos() { term.c_lflag &= ~(ICANON|ECHO); tcsetattr(0, TCSANOW, &term); } - fputs("\e[6n", stdout); - fflush(stdout); - i = 0; - gcpi = 0; - while (!gcpi) {gcpi = kbhit();} - while (i) {gcpi += i = kbhit();} - gcpret = read(1, &buf, gcpi + 1); + i = kbhit(); + while (i > 0) {getchar(); --i;} + for (int r = 0; r < 2; ++r) { + i = 0; + fputs("\e[6n", stdout); + fflush(stdout); + int j = 0; + while (!(j = kbhit())) {} + while (1) { + buf[i] = getchar(); + if (buf[i] == 'R' || buf[i] == '\n' || i >= j - 1) {++i; goto gcplexit;} + ++i; + } + gcplexit: + buf[i] = 0; + i = kbhit(); + while (i > 0) {getchar(); --i;} + } if (!textlock) { tcsetattr(0, TCSANOW, &restore); sneaktextlock = false; } i = kbhit(); - while (i > 0) {getchar(); i--;} - if (gcpret != gcpi) {gcp_sig = false; getCurPos(); gcp_sig = true;} - else {sscanf(buf, "\e[%d;%dR", &cury, &curx);} - if (gcp_sig) sigprocmask(SIG_SETMASK, &oldmask, NULL); + while (i > 0) {getchar(); --i;} + if (buf[0] == '\e') { + sscanf(buf, "\e[%d;%dR", &cury, &curx); + } else { + sscanf(buf, "[%d;%dR", &cury, &curx); + } + if (curx == 0 || cury == 0) {getCurPos();} #else CONSOLE_SCREEN_BUFFER_INFO con; GetConsoleScreenBufferInfo(hConsole, &con); @@ -1277,13 +1291,19 @@ bool loadProg(char* filename) { progLine = 1; didelse = false; didelseif = false; + #ifdef _WIN_NO_VT getCurPos(); int tmpx = curx, tmpy = cury; + #else + fputs("\e[s", stdout); + fflush(stdout); + #endif int32_t fsize = (uint32_t)ftell(prog); uint64_t time2 = usTime(); fseek(prog, 0, SEEK_SET); #ifndef _WIN_NO_VT - printf("\e[%d;%dH", tmpy, tmpx); + fputs("\e[u\e[s", stdout); + fflush(stdout); #else SetConsoleCursorPosition(hConsole, (COORD){tmpx - 1, tmpy - 1}); #endif @@ -1294,7 +1314,8 @@ bool loadProg(char* filename) { bool comment = false; bool inStr = false; #ifndef _WIN_NO_VT - printf("\e[%d;%dH", tmpy, tmpx); + fputs("\e[u\e[s", stdout); + fflush(stdout); #else SetConsoleCursorPosition(hConsole, (COORD){tmpx - 1, tmpy - 1}); #endif @@ -1304,14 +1325,15 @@ bool loadProg(char* filename) { int tmpc = fgetc(prog); if (tmpc == '"') inStr = !inStr; if (!inStr && (tmpc == '\'' || tmpc == '#')) comment = true; - if (tmpc == '\n') comment = false; + if (tmpc == '\n') {comment = false; inStr = false;} if (tmpc == '\r' || tmpc == '\t') tmpc = ' '; 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 - printf("\e[%d;%dH", tmpy, tmpx); + fputs("\e[u\e[s", stdout); + fflush(stdout); #else SetConsoleCursorPosition(hConsole, (COORD){tmpx - 1, tmpy - 1}); #endif @@ -1320,7 +1342,8 @@ bool loadProg(char* filename) { } } #ifndef _WIN_NO_VT - printf("\e[%d;%dH", tmpy, tmpx); + fputs("\e[u\e[s", stdout); + fflush(stdout); #else SetConsoleCursorPosition(hConsole, (COORD){tmpx - 1, tmpy - 1}); #endif @@ -1585,6 +1608,7 @@ static inline void getStr(char* str1, char* str2) { case 'v': c = '\v'; break; case 'b': c = '\b'; break; case 'e': c = '\e'; break; + case 'a': c = '\a'; break; case '[': c = 1; break; case ']': c = 2; break; case 'x': diff --git a/commands.c b/commands.c index 9ccffe7..deb35e0 100644 --- a/commands.c +++ b/commands.c @@ -166,13 +166,27 @@ if (chkCmd(1, "LOCATE")) { cerr = 0; int tmp = 0; if (!solvearg(1)) goto cmderr; + #ifdef _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 < 1) {cerr = 16; goto cmderr;} - curx = tmp; + if (tmp == 0) {cerr = 16; goto cmderr;} + else if (tmp < 0) { + curx += tmp; + if (curx < 0) curx = 0; + printf("\e[%dD", -tmp); + } else { + curx = tmp; + #ifndef _WIN_NO_VT + --curx; + printf("\e[9999D"); + if (curx) printf("\e[%dC", curx); + ++curx; + #endif + } } if (argct > 1) { if (!solvearg(2)) goto cmderr; @@ -180,13 +194,23 @@ if (chkCmd(1, "LOCATE")) { else if (argt[2] != 2) {cerr = 2; goto cmderr;} else { tmp = atoi(arg[2]); - if (tmp < 1) {cerr = 16; goto cmderr;} - cury = tmp; + if (tmp == 0) {cerr = 16; goto cmderr;} + else if (tmp < 0) { + curx += tmp; + if (cury < 0) cury = 0; + printf("\e[%dA", -tmp); + } else { + cury = tmp; + #ifndef _WIN_NO_VT + --cury; + printf("\e[9999A"); + if (cury) printf("\e[%dB", cury); + ++cury; + #endif + } } } - #ifndef _WIN_NO_VT - printf("\e[%d;%dH", cury, curx); - #else + #ifdef _WIN_NO_VT SetConsoleCursorPosition(hConsole, (COORD){curx - 1, cury - 1}); #endif fflush(stdout); diff --git a/docs/clibasic.man b/docs/clibasic.man index 41a7e35..6f60f87 100644 --- a/docs/clibasic.man +++ b/docs/clibasic.man @@ -37,6 +37,9 @@ Enables the info text. .TP \fB\-r\fR, \fB\-\-redirection\fR Enables support for redirecting STDIN, STDOUT, and STDERR. +.TP +\fB\-n\fR, \fB\-\-newline\fR +Prints a newline if the cursor is not at the beginning of the line before exiting. .SH EXAMPLES .TP \fBclibasic\fR diff --git a/docs/manual.odt b/docs/manual.odt index e162b7b..230db28 100644 Binary files a/docs/manual.odt and b/docs/manual.odt differ diff --git a/docs/manual.pdf b/docs/manual.pdf index feb2081..60e18d7 100644 Binary files a/docs/manual.pdf and b/docs/manual.pdf differ diff --git a/examples/clock.bas b/examples/clock.bas index ea98f9f..4171146 100644 --- a/examples/clock.bas +++ b/examples/clock.bas @@ -1,3 +1,4 @@ +_txtlock do locate 1 h = date("hr") @@ -14,5 +15,5 @@ do s = date(0) waitms 900 while date(0) = s: loop - locate , cury() - 1 + locate , -1 loop diff --git a/examples/hello.bas b/examples/hello.bas index f3b4ce7..e645c2e 100644 --- a/examples/hello.bas +++ b/examples/hello.bas @@ -2,14 +2,14 @@ _TXTLOCK _TXTATTRIB "TRUECOLOR", 1 OC = FGC() R = CINT(RAND(255)): G = CINT(RAND(255)): B = CINT(RAND(255)) -X = 3: Y = RAND(0.5, 1): X = X - Y: Z = RAND(0.5, 1): X = X -Z +X = 2: Y = RAND(0.5, 1): X = X - Y: Z = RAND(0.5, 1): X = X -Z IF CINT(RAND(1)) = 1: X = X * -1: ENDIF IF CINT(RAND(1)) = 1: Y = Y * -1: ENDIF IF CINT(RAND(1)) = 1: Z = Z * -1: ENDIF @ LOOP RESETTIMER COLOR RGB(LIMIT(R, 0, 255), LIMIT(G, 0, 255), LIMIT(B, 0, 255)) -PRINT "Hello, World!",, PAD$(CINT(R), 3), PAD$(CINT(G), 3), PAD$(CINT(B), 3),, PAD$(X, 9, " "), PAD$(Y, 9, " "), PAD$(Z, 9, " "); +PRINT "Hello, World!"; COLOR OC PRINT R = R + X @@ -24,5 +24,5 @@ IF B < 0: Z = Z * -1: ENDIF WAITMS LIMIT(10 - TIMERMS(), 0, 10) RESETTIMER PUT "\r" -LOCATE , CURY() - 1 +LOCATE , -1 GOTO LOOP diff --git a/examples/input.bas b/examples/input.bas index c99f335..d36ed36 100644 --- a/examples/input.bas +++ b/examples/input.bas @@ -3,18 +3,38 @@ DO K$ = INKEY$() L = LEN(K$) IF ASC(K$) <> 0 - P = 0 - IF _OS$ = "Windows" - LOCATE 16 - ELSE - PUT "\r\t\t" - ENDIF + LOCATE 16 IF ASC(K$, LEN(K$) - 1) = 10: LOCATE , CURY() - 1: ENDIF - PUT " [", LEN(K$), "]" - DOWHILE P < L - PUT ", ", ASC(K$, P) - P = P + 1 - LOOP + PUT LEN(K$), ": [" + FOR P, 0, P < L, 1 + IF P > 0: PUT ", ": ENDIF + PUT ASC(K$, P) + NEXT + PUT "]" + STR$ = "" + FOR I, 0, ASC(K$, I) <> 0, 1 + C$ = SNIP$(K$, I, I + 1) + IF C$ = "\n" + STR$ = STR$ + "\\n" + ELSEIF C$ = "\r" + STR$ = STR$ + "\\r" + ELSEIF C$ = "\f" + STR$ = STR$ + "\\f" + ELSEIF C$ = "\t" + STR$ = STR$ + "\\t" + ELSEIF C$ = "\v" + STR$ = STR$ + "\\v" + ELSEIF C$ = "\b" + STR$ = STR$ + "\\b" + ELSEIF C$ = "\e" + STR$ = STR$ + "\\e" + ELSEIF C$ = "\a" + STR$ = STR$ + "\\a" + ELSE + STR$ = STR$ + C$ + ENDIF + NEXT + PUT ": {", STR$, "}" PUT "\n" ENDIF LOOP diff --git a/examples/test5.bas b/examples/test5.bas new file mode 100644 index 0000000..1017beb --- /dev/null +++ b/examples/test5.bas @@ -0,0 +1,8 @@ +_txtattrib "bgc", 1 +_txtlock +do + locate cint(rand(1, width())), cint(rand(1, height())) + color cint(rand(255)), cint(rand(255)) + _txtattrib cint(rand(1, 11)), cint(rand(1)) + put chr$(rand(32, 126)) +loop diff --git a/logic.c b/logic.c index df391f4..e560588 100644 --- a/logic.c +++ b/logic.c @@ -76,8 +76,7 @@ if (chkCmd(1, "DO")) { if (fnstackp > ((progindex > -1) ? minfnstackp[progindex] : -1)) { if (fndcmd[fnstackp]) return true; } - int32_t p = j; - while (cmd[p]) {if (cmd[p] != ' ') {cerr = 1; return true;} p++;} + while (cmd[j]) {if (cmd[j] != ' ') {cerr = 3; return true;} ++j;} dldcmd[dlstackp] = false; dlstack[dlstackp].cp = cmdpos; dlstack[dlstackp].pl = progLine; @@ -101,6 +100,7 @@ if (chkCmd(2, "WHILE", "DOWHILE")) { if (fndcmd[fnstackp]) return true; } copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); + if (getArgCt(ltmp[1]) != 1) {cerr = 3; return true;} uint8_t testval = logictest(ltmp[1]); if (testval == 255) return true; if (testval == 1) { @@ -127,6 +127,7 @@ if (chkCmd(1, "LOOP")) { if (fnstackp > ((progindex > -1) ? minfnstackp[progindex] : -1)) { if (fndcmd[fnstackp]) return true; } + while (cmd[j]) {if (cmd[j] != ' ') {cerr = 3; return true;} ++j;} if (inProg) { cp = dlstack[dlstackp].cp; } else { @@ -138,8 +139,6 @@ if (chkCmd(1, "LOOP")) { lockpl = true; dldcmd[dlstackp] = false; dlstackp--; - int32_t p = j; - while (cmd[p]) {if (cmd[p] != ' ') {cerr = 1; return true;} p++;} didloop = true; return true; } @@ -155,6 +154,7 @@ if (chkCmd(1, "LOOPWHILE")) { if (fndcmd[fnstackp]) return true; } copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); + if (getArgCt(ltmp[1]) != 1) {cerr = 3; return true;} uint8_t testval = logictest(ltmp[1]); if (testval == 255) return true; if (testval == 1) { @@ -186,6 +186,7 @@ if (chkCmd(1, "IF")) { if (fndcmd[fnstackp]) return true; } copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); + if (getArgCt(ltmp[1]) != 1) {cerr = 3; return true;} uint8_t testval = logictest(ltmp[1]); if (testval == 255) return true; itdcmd[itstackp] = (bool)!testval; @@ -203,6 +204,7 @@ if (chkCmd(1, "ELSE")) { if (fnstackp > ((progindex > -1) ? minfnstackp[progindex] : -1)) { if (fndcmd[fnstackp]) return true; } + while (cmd[j]) {if (cmd[j] != ' ') {cerr = 3; return true;} ++j;} if (didelse) {cerr = 11; return true;} if (didelseif) {itdcmd[itstackp] = true; return true;} didelse = true; @@ -221,6 +223,7 @@ if (chkCmd(1, "ELSEIF")) { if (fndcmd[fnstackp]) return true; } copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); + if (getArgCt(ltmp[1]) != 1) {cerr = 3; return true;} uint8_t testval = logictest(ltmp[1]); if (testval == 255) return true; itdcmd[itstackp] = (bool)(!testval); @@ -236,6 +239,7 @@ if (chkCmd(1, "ENDIF")) { if (fnstackp > ((progindex > -1) ? minfnstackp[progindex] : -1)) { if (fndcmd[fnstackp]) return true; } + while (cmd[j]) {if (cmd[j] != ' ') {cerr = 3; return true;} ++j;} itdcmd[itstackp + 1] = false; didelse = false; didelseif = false; @@ -256,17 +260,17 @@ if (chkCmd(1, "FOR")) { copyStrSnip(cmd, j + 1, strlen(cmd), ltmp[1]); if (getArgCt(ltmp[1]) != 4) {cerr = 3; return true;} cerr = 2; - getArg(0, ltmp[1], fnvar); + if (getArg(0, ltmp[1], fnvar) == -1) return true; if (getVar(fnvar, forbuf[0]) != 2) return true; - getArg(1, ltmp[1], forbuf[1]); + if (getArg(1, ltmp[1], forbuf[1]) == -1) return true; if (getVal(forbuf[1], forbuf[1]) != 2) return true; - getArg(3, ltmp[1], forbuf[3]); + if (getArg(3, ltmp[1], forbuf[3]) == -1) return true; if (getVal(forbuf[3], forbuf[3]) != 2) return true; setVar(fnvar, forbuf[1], 2, -1); if (fnstack[fnstackp].cp == -1) { copyStr(forbuf[1], forbuf[0]); } - getArg(2, ltmp[1], forbuf[2]); + if (getArg(2, ltmp[1], forbuf[2]) == -1) return true; if (fninfor[fnstackp]) { sprintf(forbuf[0], "%lf", atof(forbuf[0]) + atof(forbuf[3])); setVar(fnvar, forbuf[0], 2, -1); @@ -299,6 +303,7 @@ if (chkCmd(1, "NEXT")) { if (dldcmd[dlstackp]) {return true;} } fnstackp++; + while (cmd[j]) {if (cmd[j] != ' ') {cerr = 3; return true;} ++j;} if (fninfor[fnstackp]) { if (inProg) { cp = fnstack[fnstackp].cp;