diff --git a/.gitignore b/.gitignore index 87fb9e5ba..8b3dbabd4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ internal/c/qbx[2-9].cpp *.ttf /run_qb64.sh /qb64 -.fake \ No newline at end of file +.fake +.vscode diff --git a/findcurl.cmd b/findcurl.cmd new file mode 100755 index 000000000..54673b32e --- /dev/null +++ b/findcurl.cmd @@ -0,0 +1,30 @@ +@echo off +rem This script breaks when the version gets updated. +rem Can someone else work a way around that? +rem This script does not handle failure to make a directory +rem nor a failure to download the curl.cab +rem It also assumes that curl is downloaded to the users Desktop + +set DLPAGE=http://skanthak.homepage.t-online.de/download +set CURLVERSION=curl-7.64.1.cab +set LINK=%DLPAGE%/%CURLVERSION% +rem grab the arch. We'll need this to extract files. +reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set ARCH=i386|| set ARCH=amd64 + +rem Check if curl exists +curl --version 2>NUL 1>&2 + + +if %ERRORLEVEL == 9009 ( + mkdir internal\curl >NUL + echo Fetching %LINK% + explorer %LINK% + + rem we should wait until the file is downloaded, because explorer returns straight away + "%SystemRoot%\system32\expand.exe" "%USERPROFILE%\Desktop\%CURLVERSION%" /F:%ARCH%\* internal\curl + + rem Add to path + PATH=%PATH%;%~dp0\internal\curl +) ELSE ( + echo "Found curl, continuing" +) diff --git a/reset.cmd b/reset.cmd index 39349ef40..dd53dd850 100644 --- a/reset.cmd +++ b/reset.cmd @@ -52,4 +52,7 @@ if exist internal\version.txt del internal\version.txt echo Remove qb64.exe if exist qb64.exe del qb64.exe +echo Remove qb64-dev.exe +if exist qb64-dev.exe del qb64-dev.exe + pause diff --git a/source/.gitignore b/source/.gitignore new file mode 100644 index 000000000..369237bc2 --- /dev/null +++ b/source/.gitignore @@ -0,0 +1 @@ +!*.bas diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index 883122024..3dd40c940 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -228,10 +228,10 @@ FUNCTION ide2 (ignore) COLOR 1, 7: _PRINTSTRING ((idewx - 8) / 2, idewy - 4), " Status " COLOR 15, 1 - IF os$ = "LNX" THEN - _PRINTSTRING (2, idewy - 3), "Creating executable file named " + CHR$(34) + f$ + extension$ + CHR$(34) + "..." - ELSE + IF os$ = "WIN" THEN _PRINTSTRING (2, idewy - 3), "Creating .EXE file named " + CHR$(34) + f$ + extension$ + CHR$(34) + "..." + ELSE + _PRINTSTRING (2, idewy - 3), "Creating executable file named " + CHR$(34) + f$ + extension$ + CHR$(34) + "..." END IF PCOPY 3, 0 @@ -331,6 +331,7 @@ FUNCTION ide2 (ignore) m = m + 1: i = 0: RunMenuID = m menu$(m, i) = "Run": i = i + 1 menu$(m, i) = "#Start F5": i = i + 1 + menu$(m, i) = "Run only (No exe)": i = i + 1 menuDesc$(m, i - 1) = "Compiles current program and runs it" menu$(m, i) = "Modify #COMMAND$...": i = i + 1 menuDesc$(m, i - 1) = "Sets string returned by COMMAND$ function" @@ -1707,7 +1708,7 @@ FUNCTION ide2 (ignore) LOCATE , , 0 clearStatusWindow 0 - + If NoExeSaved then idecompiled = 0: GOTO mustGenerateExe IF idecompiled THEN IF iderunmode = 2 AND _FILEEXISTS(lastBinaryGenerated$) THEN @@ -2274,7 +2275,9 @@ FUNCTION ide2 (ignore) ' removing the "View on Wiki" - @dualbrain IF 1=0 AND (mY = idewy AND (mX >= idewx - 17 AND mX <= idewx - 4)) THEN 'view on wiki launchWiki: - url$ = StrReplace$(wikiBaseAddress$ + "/" + Back$(Help_Back_Pos), " ", "%20") + url$ = wikiBaseAddress$ + "/" + Back$(Help_Back_Pos) + url$ = StrReplace$(url$, " ", "%20"): url$ = StrReplace$(url$, "&", "%26") + url$ = StrReplace$(url$, "+", "%2B") IF INSTR(_OS$, "WIN") = 0 THEN url$ = StrReplace$(url$, "$", "\$") url$ = StrReplace$(url$, "&", "\&") @@ -2311,7 +2314,7 @@ FUNCTION ide2 (ignore) Help_sy = Help_Back(Help_Back_Pos).sy Help_cx = Help_Back(Help_Back_Pos).cx Help_cy = Help_Back(Help_Back_Pos).cy - a$ = Wiki(Back$(Help_Back_Pos)) + a$ = Wiki$(Back$(Help_Back_Pos)) WikiParse a$ GOTO newpageparsed END IF @@ -2569,7 +2572,7 @@ FUNCTION ide2 (ignore) Help_sy = Help_Back(Help_Back_Pos).sy Help_cx = Help_Back(Help_Back_Pos).cx Help_cy = Help_Back(Help_Back_Pos).cy - a$ = Wiki(Back$(Help_Back_Pos)) + a$ = Wiki$(Back$(Help_Back_Pos)) WikiParse a$ GOTO newpageparsed END IF @@ -2592,54 +2595,75 @@ FUNCTION ide2 (ignore) NEXT l2 = INSTR(l1, Help_Link$, Help_Link_Sep$) - 1 l$ = MID$(Help_Link$, l1, l2 - l1 + 1) - 'assume PAGE - l$ = RIGHT$(l$, LEN(l$) - 5) IF mCLICK OR K$ = CHR$(13) THEN mCLICK = 0 - IF Back$(Help_Back_Pos) <> l$ THEN - Help_Select = 0: Help_MSelect = 0 - 'COLOR 7, 0 - - Help_Back(Help_Back_Pos).sx = Help_sx 'update position - Help_Back(Help_Back_Pos).sy = Help_sy - Help_Back(Help_Back_Pos).cx = Help_cx - Help_Back(Help_Back_Pos).cy = Help_cy - - top = UBOUND(back$) - - IF Help_Back_Pos < top THEN - IF Back$(Help_Back_Pos + 1) = l$ THEN - GOTO usenextentry + IF LEFT$(l$, 5) = "EXTL:" THEN + IF (K$ = CHR$(13)) OR (mY = Help_cy - Help_sy + Help_wy1 AND mX = Help_cx - Help_sx + Help_wx1) THEN + l$ = RIGHT$(l$, LEN(l$) - 5) + l$ = StrReplace$(l$, " ", "%20") + l$ = StrReplace$(l$, "&", "%26") + IF INSTR(_OS$, "WIN") = 0 THEN + l$ = StrReplace$(l$, "$", "\$") + l$ = StrReplace$(l$, "&", "\&") + l$ = StrReplace$(l$, "(", "\(") + l$ = StrReplace$(l$, ")", "\)") + END IF + IF INSTR(_OS$, "WIN") THEN + SHELL _HIDE _DONTWAIT "start " + l$ + ELSEIF INSTR(_OS$, "MAC") THEN + SHELL _HIDE _DONTWAIT "open " + l$ + ELSE + SHELL _HIDE _DONTWAIT "xdg-open " + l$ END IF END IF + GOTO specialchar + ELSEIF LEFT$(l$, 5) = "PAGE:" THEN + l$ = RIGHT$(l$, LEN(l$) - 5) + IF Back$(Help_Back_Pos) <> l$ THEN + Help_Select = 0: Help_MSelect = 0 + 'COLOR 7, 0 - top = top + 1 - REDIM _PRESERVE Back(top) AS STRING - REDIM _PRESERVE Help_Back(top) AS Help_Back_Type - REDIM _PRESERVE Back_Name(top) AS STRING - 'Shuffle array upwards after current pos - FOR x = top - 1 TO Help_Back_Pos + 1 STEP -1 - Back_Name$(x + 1) = Back_Name$(x) - Back$(x + 1) = Back$(x) - Help_Back(x + 1).sx = Help_Back(x).sx - Help_Back(x + 1).sy = Help_Back(x).sy - Help_Back(x + 1).cx = Help_Back(x).cx - Help_Back(x + 1).cy = Help_Back(x).cy - NEXT - usenextentry: - Help_Back_Pos = Help_Back_Pos + 1 - Back$(Help_Back_Pos) = l$ - Back_Name$(Help_Back_Pos) = Back2BackName$(l$) - Help_Back(Help_Back_Pos).sx = 1 - Help_Back(Help_Back_Pos).sy = 1 - Help_Back(Help_Back_Pos).cx = 1 - Help_Back(Help_Back_Pos).cy = 1 - Help_sx = 1: Help_sy = 1: Help_cx = 1: Help_cy = 1 - a$ = Wiki(l$) - WikiParse a$ - GOTO newpageparsed + Help_Back(Help_Back_Pos).sx = Help_sx 'update position + Help_Back(Help_Back_Pos).sy = Help_sy + Help_Back(Help_Back_Pos).cx = Help_cx + Help_Back(Help_Back_Pos).cy = Help_cy + + top = UBOUND(back$) + + IF Help_Back_Pos < top THEN + IF Back$(Help_Back_Pos + 1) = l$ THEN + GOTO usenextentry + END IF + END IF + + top = top + 1 + REDIM _PRESERVE Back(top) AS STRING + REDIM _PRESERVE Help_Back(top) AS Help_Back_Type + REDIM _PRESERVE Back_Name(top) AS STRING + 'Shuffle array upwards after current pos + FOR x = top - 1 TO Help_Back_Pos + 1 STEP -1 + Back_Name$(x + 1) = Back_Name$(x) + Back$(x + 1) = Back$(x) + Help_Back(x + 1).sx = Help_Back(x).sx + Help_Back(x + 1).sy = Help_Back(x).sy + Help_Back(x + 1).cx = Help_Back(x).cx + Help_Back(x + 1).cy = Help_Back(x).cy + NEXT + usenextentry: + Help_Back_Pos = Help_Back_Pos + 1 + Back$(Help_Back_Pos) = l$ + Back_Name$(Help_Back_Pos) = Back2BackName$(l$) + Help_Back(Help_Back_Pos).sx = 1 + Help_Back(Help_Back_Pos).sy = 1 + Help_Back(Help_Back_Pos).cx = 1 + Help_Back(Help_Back_Pos).cy = 1 + Help_sx = 1: Help_sy = 1: Help_cx = 1: Help_cy = 1 + a$ = Wiki$(l$) + WikiParse a$ + GOTO newpageparsed + END IF END IF END IF @@ -2742,7 +2766,7 @@ FUNCTION ide2 (ignore) Help_Back(Help_Back_Pos).cy = 1 Help_sx = 1: Help_sy = 1: Help_cx = 1: Help_cy = 1 - a$ = Wiki(lnk$) + a$ = Wiki$(lnk$) IF idehelp = 0 THEN IF idesubwindow THEN PCOPY 3, 0: SCREEN , , 3, 0: GOTO ideloop @@ -2806,10 +2830,13 @@ FUNCTION ide2 (ignore) LOOP IF UCASE$(n$) = a2$ THEN - a$ = "'''" + backupn$ + "''' is a symbol that is used in your program as follows:" + a$ = "{{DISPLAYTITLE:agp@" + backupn$ + "}}" + CHR$(10) + a$ = a$ + "This is a subroutine or function that is used in your program as follows:" + CHR$(10) a$ = a$ + CHR$(10) + CHR$(10) + "{{PageSyntax}}" + CHR$(10) - a$ = a$ + ": " + sf$ + "'''" + backupn$ + "''' " + args$ - a$ = a$ + CHR$(10) + "{{PageNavigation}}" + a$ = a$ + ": [[" + LEFT$(sf$, LEN(sf$) - 1) + "]] '''" + backupn$ + "''' " + args$ + CHR$(10) + a$ = a$ + CHR$(10) + CHR$(10) + "{{PageSeeAlso}}" + CHR$(10) + a$ = a$ + "* [[Sub (explanatory)]]" + CHR$(10) + a$ = a$ + "* [[Function (explanatory)]]" + CHR$(10) IdeContextHelpSF = -1 @@ -5281,12 +5308,12 @@ FUNCTION ide2 (ignore) END IF IF menu$(m, s) = "Keyword #Index" THEN PCOPY 3, 0: SCREEN , , 3, 0 - lnk$ = "Keyword Reference (Alphabetical)" + lnk$ = "Keyword Reference - Alphabetical" GOTO OpenHelpLnk END IF IF menu$(m, s) = "#Keywords by Usage" THEN PCOPY 3, 0: SCREEN , , 3, 0 - lnk$ = "Keyword Reference (Usage)" + lnk$ = "Keyword Reference - By usage" GOTO OpenHelpLnk END IF @@ -5318,8 +5345,8 @@ FUNCTION ide2 (ignore) IF idehelp THEN Help_IgnoreCache = 1 a$ = Wiki$(Back$(Help_Back_Pos)) + WikiParse a$ 'reparse updated page incl. plugin templates Help_IgnoreCache = 0 - WikiParse a$ END IF GOTO ideloop END IF @@ -5396,10 +5423,18 @@ FUNCTION ide2 (ignore) ' removing the "View on Wiki" - @dualbrain IF 1=0 AND menu$(m, s) = "Update All #Pages..." THEN PCOPY 2, 0 - q$ = ideyesnobox("Update Help", "This can take up to 10 minutes.\nRedownload all cached help content from the wiki?") + q$ = ideyesnobox("Update Help", "This can take up to 20 minutes.\nRedownload all cached help content from the wiki?") PCOPY 2, 0 - IF q$ = "Y" THEN ideupdatehelpbox - PCOPY 3, 0: SCREEN , , 3, 0 + IF q$ = "Y" THEN + Help_Recaching = 1: Help_IgnoreCache = 1 + uerr = ideupdatehelpbox + Help_Recaching = 0: Help_IgnoreCache = 0 + PCOPY 3, 0: SCREEN , , 3, 0 + IF uerr THEN + lnk$ = "Update All" + GOTO OpenHelpLnk + END IF + END IF GOTO ideloop END IF @@ -5774,6 +5809,15 @@ FUNCTION ide2 (ignore) GOTO idemrun END IF + IF menu$(m, s) = "Run only (No exe)" THEN + PCOPY 3, 0: SCREEN , , 3, 0 + NoExeSaved = -1 + startPaused = 0 + GOTO idemrun + END IF + + + IF menu$(m, s) = "Modify #COMMAND$..." THEN PCOPY 2, 0 ModifyCOMMAND$ = " " + ideinputbox$("Modify COMMAND$", "#Enter text for COMMAND$", _TRIM$(ModifyCOMMAND$), "", 60, 0, 0) @@ -6492,8 +6536,8 @@ HelpAreaShowBackLinks: LOCATE idewy, (idewx - (LEN(Document_Title$) + 8)) \ 2 : PRINT " HELP: " + Document_Title$ + " " END IF IF 1=0 THEN ' removing the "View on Wiki" - @dualbrain - 'COLOR 7, 0: _PRINTSTRING (idewx - 18, idewy), CHR$(180) - 'COLOR 15, 3: _PRINTSTRING (idewx - 17, idewy), " View on Wiki " + COLOR 7, 0: _PRINTSTRING (idewx - 18, idewy), CHR$(180) + COLOR 15, 3: _PRINTSTRING (idewx - 17, idewy), " View on Wiki " END IF RETURN @@ -10286,22 +10330,7 @@ FUNCTION idechange$ a2$ = idefindtext END IF - 'retrieve search history - ln = 0 - fh = FREEFILE - OPEN ".\internal\temp\searched.bin" FOR BINARY AS #fh: a$ = SPACE$(LOF(fh)): GET #fh, , a$ - CLOSE #fh - a$ = RIGHT$(a$, LEN(a$) - 2) - DO WHILE LEN(a$) - ai = INSTR(a$, CRLF) - IF ai THEN - f$ = LEFT$(a$, ai - 1): IF ai = LEN(a$) - 1 THEN a$ = "" ELSE a$ = RIGHT$(a$, LEN(a$) - ai - 3) - ln = ln + 1 - REDIM _PRESERVE SearchHistory(1 TO ln) - SearchHistory(ln) = f$ - END IF - LOOP - ln = 0 + RetrieveSearchHistory SearchHistory() i = 0 idepar p, 60, 14, "Change" @@ -11141,22 +11170,7 @@ FUNCTION idefind$ a2$ = idefindtext END IF - 'retrieve search history - ln = 0 - fh = FREEFILE - OPEN ".\internal\temp\searched.bin" FOR BINARY AS #fh: a$ = SPACE$(LOF(fh)): GET #fh, , a$ - CLOSE #fh - a$ = RIGHT$(a$, LEN(a$) - 2) - DO WHILE LEN(a$) - ai = INSTR(a$, CRLF) - IF ai THEN - f$ = LEFT$(a$, ai - 1): IF ai = LEN(a$) - 1 THEN a$ = "" ELSE a$ = RIGHT$(a$, LEN(a$) - ai - 3) - ln = ln + 1 - REDIM _PRESERVE SearchHistory(1 TO ln) - SearchHistory(ln) = f$ - END IF - LOOP - ln = 0 + RetrieveSearchHistory SearchHistory() i = 0 idepar p, 60, 11, "Find" @@ -12848,6 +12862,7 @@ SUB ideshowtext 'Restore BG color in case a matching bracket was printed with different BG IF l = idecy THEN COLOR , 6 IF isKeyword > 0 THEN isKeyword = isKeyword - 1 + IF isKeyword = 0 AND checkKeyword$ = "REM" THEN comment = -1 IF isKeyword = 0 THEN checkKeyword$ = "": metacommand = 0: is_Number = 0: isCustomKeyword = 0 NEXT m @@ -14635,6 +14650,7 @@ FUNCTION idezfilelist$ (path$, method, mask$) 'method0=*.bas, method1=*.*, metho DO UNTIL EOF(150) LINE INPUT #150, a$ IF LEN(a$) THEN 'skip blank entries + IF path$ = "internal/help" THEN a$ = LEFT$(a$, (LEN(a$) - 5) \ 2) + ".txt" 'remove spelling label IF filelist$ = "" THEN filelist$ = a$ ELSE filelist$ = filelist$ + sep + a$ END IF LOOP @@ -14674,6 +14690,7 @@ FUNCTION idezfilelist$ (path$, method, mask$) 'method0=*.bas, method1=*.*, metho EXIT FOR END IF NEXT + IF path$ = "internal/help" THEN a$ = LEFT$(a$, (LEN(a$) - 5) \ 2) + ".txt" 'remove spelling label IF filelist$ = "" THEN filelist$ = a$ ELSE filelist$ = filelist$ + sep + a$ LOOP CLOSE #150 @@ -15051,11 +15068,6 @@ FUNCTION idelayoutbox LOOP END FUNCTION - - - - - FUNCTION idebackupbox a2$ = str2$(idebackupsize) v$ = ideinputbox$("Backup/Undo", "#Undo buffer limit (10-2000MB)", a2$, "0123456789", 50, 4, 0) @@ -15275,12 +15287,6 @@ FUNCTION ideadvancedbox ideadvancedbox = 0 END FUNCTION - - - - - - FUNCTION idemessagebox (titlestr$, messagestr$, buttons$) '-------- generic dialog box header -------- @@ -17584,7 +17590,7 @@ SUB Help_ShowText IF setup = 0 AND UBOUND(back$) = 1 THEN setup = 1 IF IdeContextHelpSF = 0 THEN - a$ = Wiki(Back$(1)) + a$ = Wiki$(Back$(1)) WikiParse a$ END IF END IF @@ -17709,23 +17715,11 @@ FUNCTION idesearchedbox$ ln = 0 l$ = "" - fh = FREEFILE - OPEN ".\internal\temp\searched.bin" FOR BINARY AS #fh: a$ = SPACE$(LOF(fh)): GET #fh, , a$ - a$ = RIGHT$(a$, LEN(a$) - 2) - DO WHILE LEN(a$) - ai = INSTR(a$, CRLF) - IF ai THEN - f$ = LEFT$(a$, ai - 1): IF ai = LEN(a$) - 1 THEN a$ = "" ELSE a$ = RIGHT$(a$, LEN(a$) - ai - 3) - IF LEN(l$) THEN l$ = l$ + sep + f$ ELSE l$ = f$ - ln = ln + 1 - END IF - LOOP - CLOSE #fh - - IF ln = 0 THEN - l$ = sep - END IF - + REDIM SearchHistory(0) AS STRING + RetrieveSearchHistory SearchHistory() + FOR i = 1 to UBOUND(SearchHistory) + l$ = SearchHistory(i) + sep + l$ + NEXT '72,19 h = idewy + idesubwindow - 9 @@ -18643,7 +18637,7 @@ FUNCTION removeDoubleSlashes$(f$) END FUNCTION SUB IdeAddSearched (s2$) - s$ = CRLF + s2$ + CRLF + s$ = s2$ + CRLF fh = FREEFILE OPEN ".\internal\temp\searched.bin" FOR BINARY AS #fh: a$ = SPACE$(LOF(fh)): GET #fh, , a$ x = INSTR(UCASE$(a$), UCASE$(s$)) @@ -18656,7 +18650,15 @@ SUB IdeAddSearched (s2$) CLOSE #fh END SUB -SUB ideupdatehelpbox +FUNCTION ideupdatehelpbox + ideupdatehelpbox = 0 'all good, getting 1 on error + IF Help_Recaching = 2 THEN + DIM FullMessage$(1 TO 2) + UpdateStep = 1 + Help_ww = 78 + GOTO startMainLoop + END IF + '-------- generic dialog box header -------- PCOPY 0, 2 PCOPY 0, 1 @@ -18698,8 +18700,9 @@ SUB ideupdatehelpbox FOR i = 1 TO 100: o(i).par = p: NEXT 'set parent info of objects '-------- end of generic init -------- + startMainLoop: DO 'main loop - + IF Help_Recaching = 2 GOTO updateRoutine '-------- generic display dialog box & objects -------- idedrawpar p @@ -18804,15 +18807,20 @@ SUB ideupdatehelpbox END IF 'end of custom controls + updateRoutine: '-------- update routine ------------------------------------- SELECT CASE UpdateStep CASE 1 'Create a list of all files to be recached - f$ = CHR$(0) + idezfilelist$("internal/help", 1, "") + CHR$(0) - IF LEN(f$) = 2 THEN f$ = CHR$(0) + IF Help_Recaching < 2 THEN + f$ = CHR$(0) + idezfilelist$("internal/help", 2, "*.txt") + CHR$(0) + IF LEN(f$) = 2 THEN f$ = CHR$(0) + ELSE + f$ = CHR$(0) 'no dir scan for 'qb64 -u' (build time update) + END IF 'Prepend core pages to list - f$ = CHR$(0) + "Keyword-Reference---(Usage).txt" + f$ + f$ = CHR$(0) + "Keyword_Reference_-_By_usage.txt" + f$ f$ = CHR$(0) + "QB64_Help_Menu.txt" + f$ f$ = CHR$(0) + "QB64_FAQ.txt" + f$ UpdateStep = UpdateStep + 1 @@ -18821,10 +18829,9 @@ SUB ideupdatehelpbox CASE 3 'Download and PARSE alphabetical index to build required F1 help links FullMessage$(1) = "Regenerating keyword list..." - Help_Recaching = 1: Help_IgnoreCache = 1 - a$ = Wiki$("Keyword Reference (Alphabetical)") - Help_Recaching = 0: Help_IgnoreCache = 0 - WikiParse a$ + a$ = Wiki$("Keyword Reference - Alphabetical") + IF INSTR(a$, "{{PageInternalError}}") > 0 THEN ideupdatehelpbox = 1: EXIT DO + WikiParse a$ 'update links.bin and check for plugin templates UpdateStep = UpdateStep + 1 CASE 4 'Add all linked pages to download list (if not already in list) @@ -18833,21 +18840,25 @@ SUB ideupdatehelpbox DO UNTIL EOF(fh) LINE INPUT #fh, l$ IF LEN(l$) THEN - c = INSTR(l$, ","): PageName2$ = RIGHT$(l$, LEN(l$) - c) - DO WHILE INSTR(PageName2$, " ") - ASC(PageName2$, INSTR(PageName2$, " ")) = 95 - LOOP - DO WHILE INSTR(PageName2$, "&") - i = INSTR(PageName2$, "&") - PageName2$ = LEFT$(PageName2$, i - 1) + "%26" + RIGHT$(PageName2$, LEN(PageName2$) - i) - LOOP - DO WHILE INSTR(PageName2$, "/") - i = INSTR(PageName2$, "/") - PageName2$ = LEFT$(PageName2$, i - 1) + "%2F" + RIGHT$(PageName2$, LEN(PageName2$) - i) - LOOP - PageName2$ = PageName2$ + ".txt" - IF INSTR(f$, CHR$(0) + PageName2$ + CHR$(0)) = 0 THEN - f$ = f$ + PageName2$ + CHR$(0) + c = INSTR(l$, ","): l$ = RIGHT$(l$, LEN(l$) - c) + IF Help_Recaching < 2 OR LEFT$(l$, 3) <> "_gl" THEN 'ignore _GL pages for 'qb64 -u' (build time update) + 'Escape all invalid and other critical chars in filenames + PageName2$ = "" + FOR i = 1 TO LEN(l$) + c = ASC(l$, i) + SELECT CASE c + CASE 32 ' '(space) + PageName2$ = PageName2$ + "_" + CASE 34, 36, 38, 42, 43, 47, 58, 60, 62, 63, 92, 124 '("$&*+/:<>?\|) + PageName2$ = PageName2$ + "%" + HEX$(c) + CASE ELSE + PageName2$ = PageName2$ + CHR$(c) + END SELECT + NEXT + PageName2$ = PageName2$ + ".txt" + IF INSTR(f$, CHR$(0) + PageName2$ + CHR$(0)) = 0 THEN + f$ = f$ + PageName2$ + CHR$(0) + END IF END IF END IF LOOP @@ -18878,13 +18889,15 @@ SUB ideupdatehelpbox f2$ = LEFT$(f2$, LEN(f2$) - 4) n = n + 1 FullMessage$(2) = "Page title: " + f2$ - Help_IgnoreCache = 1: Help_Recaching = 1: ignore$ = Wiki(f2$): Help_Recaching = 0: Help_IgnoreCache = 0 + ignore$ = Wiki$(f2$) + WikiParse ignore$ 'just check for plugin templates END IF ELSE UpdateStep = UpdateStep + 1 END IF CASE 6 stoprecache: + IF Help_Recaching = 2 THEN EXIT DO FullMessage$(1) = "All pages updated." FullMessage$(2) = "" idetxt(o(ButtonID).txt) = "#Close" @@ -18895,7 +18908,7 @@ SUB ideupdatehelpbox mousedown = 0 mouseup = 0 LOOP -END SUB +END FUNCTION FUNCTION ideASCIIbox$(relaunch) @@ -19857,10 +19870,30 @@ FUNCTION findHelpTopic$(topic$, lnks, firstOnly AS _BYTE) 'check if topic$ is in help links ' - returns a list of help links separated by CHR$(0) ' - returns the total number of links found by changing 'lnks' - a2$ = UCASE$(topic$) - fh = FREEFILE - OPEN "internal\help\links.bin" FOR BINARY AS #fh lnks = 0: lnks$ = CHR$(0) + fh = FREEFILE + '---------- + linksFileExist = _FILEEXISTS("internal\help\links.bin") + IF linksFileExist THEN + OPEN "internal\help\links.bin" FOR INPUT AS #fh + linksFileEmpty = (LOF(fh) = 0): CLOSE #fh + END IF + IF (NOT linksFileExist) OR linksFileEmpty THEN + q$ = ideyesnobox("Help problem", "The help system is not yet initialized,\ndo it now? (Make sure you're online.)") + PCOPY 3, 0: SCREEN , , 3, 0 + IF q$ = "N" GOTO noLinksFile + Help_IgnoreCache = 1 + a$ = Wiki$("Keyword Reference - Alphabetical") + Help_IgnoreCache = 0 + IF INSTR(a$, "{{PageInternalError}}") THEN + lnks = 1: lnks$ = lnks$ + "Initialize" + CHR$(0) + GOTO noLinksFile + END IF + Help_ww = 78: WikiParse a$ 'assume standard IDE width for parsing + END IF + '---------- + a2$ = UCASE$(topic$) + OPEN "internal\help\links.bin" FOR INPUT AS #fh DO UNTIL EOF(fh) LINE INPUT #fh, l$ c = INSTR(l$, ","): l1$ = LEFT$(l$, c - 1): l2$ = RIGHT$(l$, LEN(l$) - c) @@ -19877,6 +19910,7 @@ FUNCTION findHelpTopic$(topic$, lnks, firstOnly AS _BYTE) END IF LOOP CLOSE #fh + noLinksFile: findHelpTopic$ = lnks$ END FUNCTION @@ -20045,6 +20079,24 @@ FUNCTION GetBytes$(__value$, numberOfBytes&) getBytesPosition& = getBytesPosition& + numberOfBytes& END FUNCTION +SUB RetrieveSearchHistory (SearchHistory() AS STRING) + fh = FREEFILE + OPEN ".\internal\temp\searched.bin" FOR BINARY AS #fh + REDIM _PRESERVE SearchHistory(1 to 10000) AS STRING + IF LOF(fh) THEN + Do UNTIL EOF(fh) + ln = ln + 1 + IF ln > UBOUND(SearchHistory) THEN REDIM _PRESERVE SearchHistory(1 to ln + 10000) AS STRING + LINE INPUT #fh, SearchHistory(ln) + Loop + REDIM _PRESERVE SearchHistory(1 TO ln) AS STRING + ELSE + REDIM SearchHistory(1) AS STRING + SearchHistory(1) = "" + END IF + CLOSE #fh +END SUB + 'FUNCTION Download$ (url$, outputVar$, lookFor$, timelimit) STATIC ' 'as seen on http://www.qb64.org/wiki/Downloading_Files ' 'adapted for use in the IDE diff --git a/source/ide/wiki/wiki_global.bas b/source/ide/wiki/wiki_global.bas index 5bf5463ec..35713a62b 100644 --- a/source/ide/wiki/wiki_global.bas +++ b/source/ide/wiki/wiki_global.bas @@ -12,6 +12,7 @@ DIM SHARED Help_ww, Help_wh 'width & height of text region DIM SHARED help_h, help_w 'width & height DIM SHARED Help_Txt$ '[chr][col][link-byte1][link-byte2] DIM SHARED Help_Txt_Len +DIM SHARED Help_Pos, Help_Wrap_Pos DIM SHARED Help_Line$ 'index of first txt element of a line DIM SHARED Help_Link$ 'the link info [sep][type:]...[sep] DIM SHARED Help_Link_Sep$: Help_Link_Sep$ = CHR$(13) @@ -20,7 +21,6 @@ DIM SHARED Help_NewLineIndent DIM SHARED Help_Underline 'Link Types: ' PAGE:wikipagename -DIM SHARED Help_Pos, Help_Wrap_Pos DIM SHARED Help_BG_Col DIM SHARED Help_Col_Normal: Help_Col_Normal = 7 DIM SHARED Help_Col_Link: Help_Col_Link = 9 diff --git a/source/qb64.bas b/source/qb64.bas index 89ead847b..bf4c8fd7b 100644 --- a/source/qb64.bas +++ b/source/qb64.bas @@ -10,6 +10,17 @@ $CONSOLE 'Initially the "SCREEN" will be hidden, if the -x option is used it will never be created $SCREENHIDE +$EXEICON:'./qb64.ico' + +$VERSIONINFO:CompanyName=QB64 +$VERSIONINFO:FileDescription=QB64 IDE and Compiler +$VERSIONINFO:InternalName=qb64.bas +$VERSIONINFO:LegalCopyright=MIT +$VERSIONINFO:LegalTrademarks= +$VERSIONINFO:OriginalFilename=qb64.exe +$VERSIONINFO:ProductName=QB64 +$VERSIONINFO:Comments=QB64 is a modern extended BASIC programming language that retains QB4.5/QBasic compatibility and compiles native binaries for Windows, Linux and macOS. + '$INCLUDE:'global\version.bas' '$INCLUDE:'global\settings.bas' '$INCLUDE:'global\constants.bas' @@ -26,6 +37,8 @@ REDIM SHARED PL(1000) AS INTEGER 'Priority Level REDIM SHARED PP_TypeMod(0) AS STRING, PP_ConvertedMod(0) AS STRING 'Prepass Name Conversion variables. Set_OrderOfOperations +DIM SHARED NoExeSaved AS INTEGER + DIM SHARED vWatchOn, vWatchRecompileAttempts, vWatchDesiredState, vWatchErrorCall$ DIM SHARED vWatchNewVariable$, vWatchVariableExclusions$ vWatchErrorCall$ = "if (stop_program) {*__LONG_VWATCH_LINENUMBER=0; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);};if(new_error){bkp_new_error=new_error;new_error=0;*__LONG_VWATCH_LINENUMBER=-1; SUB_VWATCH((ptrszint*)vwatch_global_vars,(ptrszint*)vwatch_local_vars);new_error=bkp_new_error;};" @@ -1060,7 +1073,37 @@ IF C = 9 THEN 'run 'execute program + + + IF iderunmode = 1 THEN + IF NoExeSaved THEN + 'This is the section which deals with if the user selected to run the program without + 'saving an EXE file to the disk. + 'We start off by first running the EXE, and then we delete it from the drive. + 'making it a temporary file when all is said and done. + IF os$ = "WIN" THEN + SHELL QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) + ModifyCOMMAND$ 'run the newly created program + SHELL _HIDE _DONTWAIT "del " + QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) 'kill it + END IF + IF path.exe$ = "" THEN path.exe$ = "./" + IF os$ = "LNX" THEN + IF LEFT$(lastBinaryGenerated$, LEN(path.exe$)) = path.exe$ THEN + SHELL QuotedFilename$(lastBinaryGenerated$) + ModifyCOMMAND$ + KILL lastBinaryGenerated$ + ELSE + SHELL QuotedFilename$(path.exe$ + lastBinaryGenerated$) + ModifyCOMMAND$ + KILL path.exe$ + lastBinaryGenerated$ + END IF + END IF + IF path.exe$ = "./" THEN path.exe$ = "" + NoExeSaved = 0 'reset the flag for a temp EXE + sendc$ = CHR$(6) 'ready + GOTO sendcommand + END IF + + + IF os$ = "WIN" THEN SHELL _DONTWAIT QuotedFilename$(CHR$(34) + lastBinaryGenerated$ + CHR$(34)) + ModifyCOMMAND$ IF path.exe$ = "" THEN path.exe$ = "./" IF os$ = "LNX" THEN @@ -3340,18 +3383,22 @@ DO ELSE IF LEN(ideprogname) THEN IconPath$ = idepath$ + pathsep$ END IF + ExeIconFile$ = IconPath$ + MID$(ExeIconFile$, 3) ELSEIF INSTR(ExeIconFile$, "/") OR INSTR(ExeIconFile$, "\") THEN FOR i = LEN(ExeIconFile$) TO 1 STEP -1 IF MID$(ExeIconFile$, i, 1) = "/" OR MID$(ExeIconFile$, i, 1) = "\" THEN IconPath$ = LEFT$(ExeIconFile$, i) - ExeIconFile$ = MID$(ExeIconFile$, i + 1) - IF _DIREXISTS(IconPath$) = 0 THEN a$ = "File '" + ExeIconFile$ + "' not found": GOTO errmes + ExeIconFileOnly$ = MID$(ExeIconFile$, i + 1) + + IF _DIREXISTS(IconPath$) = 0 THEN a$ = "File '" + ExeIconFileOnly$ + "' not found": GOTO errmes + currentdir$ = _CWD$ CHDIR IconPath$ IconPath$ = _CWD$ CHDIR currentdir$ - ExeIconFile$ = IconPath$ + pathsep$ + ExeIconFile$ + + ExeIconFile$ = IconPath$ + pathsep$ + ExeIconFileOnly$ EXIT FOR END IF NEXT @@ -13617,28 +13664,6 @@ FUNCTION Type2MemTypeValue (t1) Type2MemTypeValue = t END FUNCTION -FUNCTION FileHasExtension (f$) - FOR i = LEN(f$) TO 1 STEP -1 - a = ASC(f$, i) - IF a = 47 OR a = 92 THEN EXIT FOR - IF a = 46 THEN FileHasExtension = -1: EXIT FUNCTION - NEXT -END FUNCTION - -FUNCTION RemoveFileExtension$ (f$) 'returns f$ without extension - FOR i = LEN(f$) TO 1 STEP -1 - a = ASC(f$, i) - IF a = 47 OR a = 92 THEN EXIT FOR - IF a = 46 THEN RemoveFileExtension$ = LEFT$(f$, i - 1): EXIT FUNCTION - NEXT - RemoveFileExtension$ = f$ -END FUNCTION - - - - - - 'udt is non-zero if this is an array of udt's, to allow examining each udt element FUNCTION allocarray (n2$, elements$, elementsize, udt) dimsharedlast = dimshared: dimshared = 0 @@ -24313,17 +24338,6 @@ FUNCTION lineinput3$ END IF END FUNCTION -FUNCTION getfilepath$ (f$) - FOR i = LEN(f$) TO 1 STEP -1 - a$ = MID$(f$, i, 1) - IF a$ = "/" OR a$ = "\" THEN - getfilepath$ = LEFT$(f$, i) - EXIT FUNCTION - END IF - NEXT - getfilepath$ = "" -END FUNCTION - FUNCTION eleucase$ (a$) 'this function upper-cases all elements except for quoted strings 'check first element @@ -24426,19 +24440,6 @@ FUNCTION GDB_Fix$ (g_command$) 'edit a gcc/g++ command line to include debugging GDB_Fix$ = c$ END FUNCTION - -SUB PATH_SLASH_CORRECT (a$) - IF os$ = "WIN" THEN - FOR x = 1 TO LEN(a$) - IF ASC(a$, x) = 47 THEN ASC(a$, x) = 92 - NEXT - ELSE - FOR x = 1 TO LEN(a$) - IF ASC(a$, x) = 92 THEN ASC(a$, x) = 47 - NEXT - END IF -END SUB - 'Steve Subs/Functins for _MATH support with CONST FUNCTION Evaluate_Expression$ (e$) t$ = e$ 'So we preserve our original data, we parse a temp copy of it @@ -24908,19 +24909,20 @@ FUNCTION EvaluateNumbers$ (p, num() AS STRING) EXIT FUNCTION END IF CASE "\" - IF VAL(num(2)) <> 0 THEN - n1 = VAL(num(1)) \ VAL(num(2)) - ELSE + IF FIX(VAL(num(2))) = 0 THEN EvaluateNumbers$ = "ERROR - Division By Zero" EXIT FUNCTION END IF + + n1 = VAL(num(1)) \ FIX(VAL(num(2))) CASE "MOD" - IF VAL(num(2)) <> 0 THEN - n1 = VAL(num(1)) MOD VAL(num(2)) - ELSE + IF FIX(VAL(num(2))) = 0 THEN EvaluateNumbers$ = "ERROR - Division By Zero" EXIT FUNCTION END IF + + n1 = VAL(num(1)) MOD FIX(VAL(num(2))) + CASE "+": n1 = VAL(num(1)) + VAL(num(2)) CASE "-": n1 = VAL(num(1)) - VAL(num(2)) @@ -26298,6 +26300,7 @@ SUB increaseUDTArrays END SUB '$INCLUDE:'utilities\strings.bas' +'$INCLUDE:'utilities\file.bas' '$INCLUDE:'subs_functions\extensions\opengl\opengl_methods.bas' '$INCLUDE:'utilities\ini-manager\ini.bm' diff --git a/source/utilities/build.bas b/source/utilities/build.bas new file mode 100644 index 000000000..38f21bd3d --- /dev/null +++ b/source/utilities/build.bas @@ -0,0 +1,38 @@ +''' Removes all the temporary build files. +''' (Various .o, .a, and ./internal/temp, etc.) +SUB PurgeTemporaryBuildFiles (os AS STRING, mac AS LONG) + ' Legacy style... + IF os = "WIN" THEN + CHDIR "internal\c" + SHELL _HIDE "cmd /c purge_all_precompiled_content_win.bat" + CHDIR "..\.." + ELSEIF os = "LNX" THEN + CHDIR "./internal/c" + IF mac THEN + SHELL _HIDE "./purge_all_precompiled_content_osx.command" + ELSE + SHELL _HIDE "./purge_all_precompiled_content_lnx.sh" + END IF + CHDIR "../.." + END IF + ' Make style... + ' make$ = GetMakeExecutable$ + ' IF os = "WIN" THEN + ' SHELL _HIDE "cmd /c " + make$ + " OS=win clean" + ' ELSEIF os = "LNX" THEN + ' IF mac THEN + ' SHELL _HIDE make$ + " OS=osx clean" + ' ELSE + ' SHELL _HIDE make$ + " OS=lnx clean" + ' END IF + ' END IF +END SUB + +''' Returns the make executable to use, with path if necessary. +FUNCTION GetMakeExecutable$ () + IF os$ = "WIN" THEN + GetMakeExecutable$ = "internal\c\c_compiler\bin\mingw32-make.exe" + ELSE + GetMakeExecutable$ = "make" + END IF +END FUNCTION diff --git a/source/utilities/file.bas b/source/utilities/file.bas new file mode 100644 index 000000000..a8e9fb703 --- /dev/null +++ b/source/utilities/file.bas @@ -0,0 +1,77 @@ +''' Duplicates the contents of one file into another. +''' Returns: 0 on success, 1 on error. +FUNCTION CopyFile& (sourceFile$, destFile$) + + DIM sourcefileNo, destFileNo + DIM fileLength AS _INTEGER64 + + result = 0 + sourceFileNo = FREEFILE + OPEN sourceFile$ FOR BINARY AS #sourceFileNo + if result = 1 THEN GOTO errorCleanup + + fileLength = LOF(sourceFileNo) + + destFileNo = FREEFILE + OPEN destFile$ FOR BINARY AS #destFileNo + if result = 1 THEN GOTO errorCleanup + + ' Read the file in one go + buffer$ = SPACE$(fileLength) + + GET #sourceFileNo, , buffer$ + PUT #destFileNo, , buffer$ + +ErrorCleanup: + IF sourceFileNo <> 0 THEN CLOSE #sourceFileNo + IF destFileNo <> 0 THEN CLOSE #destFileNo + CopyFile& = result + +END FUNCTION + +''' Splits the filename from its path and returns the path. +''' Returns: The path or empty if no path. +FUNCTION GetFilePath$ (f$) + FOR i = LEN(f$) TO 1 STEP -1 + a$ = MID$(f$, i, 1) + IF a$ = "/" OR a$ = "\" THEN + GetFilePath$ = LEFT$(f$, i) + EXIT FUNCTION + END IF + NEXT + GetFilePath$ = "" +END FUNCTION + +''' Checks if a filename has an extension on the end. +''' Returns: True if provided filename has an extension. +FUNCTION FileHasExtension (f$) + FOR i = LEN(f$) TO 1 STEP -1 + a = ASC(f$, i) + IF a = 47 OR a = 92 THEN EXIT FOR + IF a = 46 THEN FileHasExtension = -1: EXIT FUNCTION + NEXT +END FUNCTION + +''' Removes the extension off of a filename. +''' Returns: Provided filename without extension on the end. +FUNCTION RemoveFileExtension$ (f$) + FOR i = LEN(f$) TO 1 STEP -1 + a = ASC(f$, i) + IF a = 47 OR a = 92 THEN EXIT FOR + IF a = 46 THEN RemoveFileExtension$ = LEFT$(f$, i - 1): EXIT FUNCTION + NEXT + RemoveFileExtension$ = f$ +END FUNCTION + +''' Fixes the provided filename and path to use the correct path separator. +SUB PATH_SLASH_CORRECT (a$) + IF os$ = "WIN" THEN + FOR x = 1 TO LEN(a$) + IF ASC(a$, x) = 47 THEN ASC(a$, x) = 92 + NEXT + ELSE + FOR x = 1 TO LEN(a$) + IF ASC(a$, x) = 92 THEN ASC(a$, x) = 47 + NEXT + END IF +END SUB diff --git a/source/utilities/strings.bas b/source/utilities/strings.bas index f1a9aed53..e68ab0071 100644 --- a/source/utilities/strings.bas +++ b/source/utilities/strings.bas @@ -1,11 +1,7 @@ -' -' String manipulation functions -' - -FUNCTION StrRemove$ (myString$, whatToRemove$) 'noncase sensitive +''' String manipulation functions +FUNCTION StrRemove$ (myString$, whatToRemove$) ' noncase sensitive DIM a$, b$ DIM AS LONG i - a$ = myString$ b$ = LCASE$(whatToRemove$) i = INSTR(LCASE$(a$), b$) @@ -16,7 +12,7 @@ FUNCTION StrRemove$ (myString$, whatToRemove$) 'noncase sensitive StrRemove$ = a$ END FUNCTION -FUNCTION StrReplace$ (myString$, find$, replaceWith$) 'noncase sensitive +FUNCTION StrReplace$ (myString$, find$, replaceWith$) ' noncase sensitive DIM a$, b$ DIM AS LONG basei, i IF LEN(myString$) = 0 THEN EXIT FUNCTION @@ -31,3 +27,91 @@ FUNCTION StrReplace$ (myString$, find$, replaceWith$) 'noncase sensitive LOOP StrReplace$ = a$ END FUNCTION + +FUNCTION AddQuotes$ (s$) + AddQuotes$ = CHR$(34) + s$ + CHR$(34) +END FUNCTION + +' Convert a boolean value to 'True' or 'False'. +FUNCTION BoolToTFString$ (b AS LONG) + IF b THEN + BoolToTFString$ = "True" + ELSE + BoolToTFString$ = "False" + END IF +END FUNCTION + +' Convert 'True' or 'False' to a boolean value. +' Any string not 'True' or 'False' is returned as -2. +FUNCTION TFStringToBool% (s AS STRING) + DIM s2 AS STRING + s2 = _TRIM$(UCASE$(s)) + IF s2 = "TRUE" THEN + TFStringToBool% = -1 + ELSEIF s2 = "FALSE" THEN + TFStringToBool% = 0 + ELSE + TFStringToBool% = -2 + END IF +END FUNCTION + +''' Reads the bool setting at section:setting. +''' If it is not there or invalid, writes the default value to it. +FUNCTION ReadWriteBooleanSettingValue% (section AS STRING, setting AS STRING, default AS INTEGER) + + DIM checkResult AS INTEGER + DIM value AS STRING + DIM result AS INTEGER + + result = ReadConfigSetting(section, setting, value) + + checkResult = TFStringToBool%(value) + + IF checkResult = -2 THEN + WriteConfigSetting section, setting, BoolToTFString$(default) + ReadWriteBooleanSettingValue% = default + ELSE + ReadWriteBooleanSettingValue% = checkResult + END IF + +END FUNCTION + +''' Reads the string setting at section:setting. +''' If it is not there or invalid, writes the default value to it. +FUNCTION ReadWriteStringSettingValue$ (section AS STRING, setting AS STRING, default AS STRING) + + DIM value AS STRING + DIM result AS INTEGER + + result = ReadConfigSetting(section, setting, value) + + IF result = 0 THEN + WriteConfigSetting section, setting, default + ReadWriteStringSettingValue$ = default + ELSE + ReadWriteStringSettingValue$ = value + END IF + +END FUNCTION + +''' Reads the integer setting at section:setting. +''' If it is not there or invalid, writes the default value to it. +''' Verifies the value is positive and non-zero. +FUNCTION ReadWriteLongSettingValue& (section AS STRING, setting AS STRING, default AS LONG) + + DIM value AS STRING + DIM result AS INTEGER + DIM checkResult AS LONG + + result = ReadConfigSetting(section, setting, value) + + checkResult = VAL(value) + + IF result = 0 OR checkResult <= 0 THEN + WriteConfigSetting section, setting, str2$(default) + ReadWriteLongSettingValue& = default + ELSE + ReadWriteLongSettingValue& = checkResult + END IF + +END FUNCTION