From 6a134929a9fcd3391229010dd9fe68d9c82b06de Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Mon, 18 Jan 2021 00:19:33 -0300 Subject: [PATCH 1/7] Puts _ERRORMESSAGE$ to good use. --- source/ide/ide_methods.bas | 2 +- source/qb64.bas | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index 78ccc689d..2ac5bd23b 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -143,7 +143,7 @@ FUNCTION ide2 (ignore) 'report any IDE errors which have occurred IF ideerror THEN mustdisplay = 1 - IF ideerror = 1 THEN errorat$ = "IDE module error" + IF ideerror = 1 THEN errorat$ = _ERRORMESSAGE$ IF ideerror = 2 THEN errorat$ = "File not found" IF ideerror = 3 THEN errorat$ = "File access error": CLOSE #150 IF ideerror = 4 THEN errorat$ = "Path not found" diff --git a/source/qb64.bas b/source/qb64.bas index a50e2cbf3..9060df312 100644 --- a/source/qb64.bas +++ b/source/qb64.bas @@ -1101,7 +1101,7 @@ ideerror: IF INSTR(idemessage$, sp$) THEN 'Something went wrong here, so let's give a generic error message to the user. '(No error message should contain sp$ - that is, CHR$(13), when not in Debug mode) - idemessage$ = "Compiler error (check for syntax errors) (Reference:" + idemessage$ = "Compiler error (check for syntax errors) (" + _ERRORMESSAGE$ + ":" IF ERR THEN idemessage$ = idemessage$ + str2$(ERR) + "-" IF _ERRORLINE THEN idemessage$ = idemessage$ + str2$(_ERRORLINE) IF _INCLERRORLINE THEN idemessage$ = idemessage$ + "-" + _INCLERRORFILE$ + "-" + str2$(_INCLERRORLINE) @@ -12474,6 +12474,7 @@ IF Debug THEN 'A more in-your-face error handler PRINT "A QB error has occurred (and you have compiled in debugging support)." PRINT "Some key information (qb64.bas):" PRINT "Error"; ERR + PRINT "Description: "; _ERRORMESSAGE$ PRINT "Line"; _ERRORLINE IF _INCLERRORLINE THEN PRINT "Included line"; _INCLERRORLINE @@ -12491,7 +12492,10 @@ IF ideerror THEN 'error happened inside the IDE fh = FREEFILE OPEN "internal\temp\ideerror.txt" FOR OUTPUT AS #fh PRINT #fh, ERR + PRINT #fh, _ERRORMESSAGE$ PRINT #fh, _ERRORLINE + PRINT #fh, _INCLERRORLINE + PRINT #fh, _INCLERRORFILE$ CLOSE #fh sendc$ = CHR$(255) 'a runtime error has occurred RESUME sendcommand 'allow IDE to handle error recovery @@ -12507,7 +12511,7 @@ IF Debug THEN PRINT #9, "ERL="; ERL IF idemode AND qberrorhappenedvalue >= 0 THEN 'real qb error occurred ideerrorline = linenumber - idemessage$ = "Compiler error (check for syntax errors) (Reference:" + idemessage$ = "Compiler error (check for syntax errors) (" _ERRORMESSAGE$ + ":" IF ERR THEN idemessage$ = idemessage$ + str2$(ERR) + "-" IF _ERRORLINE THEN idemessage$ = idemessage$ + str2$(_ERRORLINE) IF _INCLERRORLINE THEN idemessage$ = idemessage$ + "-" + _INCLERRORFILE$ + "-" + str2$(_INCLERRORLINE) From f657fb24d96b23848d98ab7147baad0400e3811f Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Mon, 18 Jan 2021 00:48:28 -0300 Subject: [PATCH 2/7] Resets idefocusline when opening a file. --- source/ide/ide_methods.bas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index 2ac5bd23b..7c6ba1819 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -5786,7 +5786,7 @@ FUNCTION ide2 (ignore) END IF '"Y" END IF 'unsaved r$ = idefiledialog$("", 1) - IF r$ <> "C" THEN ideunsaved = -1: idechangemade = 1: idelayoutallow = 2: ideundobase = 0: QuickNavTotal = 0: ModifyCOMMAND$ = "" + IF r$ <> "C" THEN ideunsaved = -1: idechangemade = 1: idelayoutallow = 2: ideundobase = 0: QuickNavTotal = 0: ModifyCOMMAND$ = "": idefocusline = 0 PCOPY 3, 0: SCREEN , , 3, 0: idewait4mous: idewait4alt GOSUB redrawItAll: GOTO ideloop END IF From 7916be2e3ed9583496fd345fa7bcd2fb98e6f2dd Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Mon, 18 Jan 2021 02:25:38 -0300 Subject: [PATCH 3/7] Show eventual substitutions even if Find and Replace is canceled. --- source/ide/ide_methods.bas | 10 +++++++++- source/qb64.bas | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index 7c6ba1819..2be0c20c8 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -5478,7 +5478,15 @@ FUNCTION ide2 (ignore) idedeltxt PCOPY 3, 0: SCREEN , , 3, 0: idewait4mous: idewait4alt ideselect = 0 - IF r$ = "C" THEN idecx = oldcx: idecy = oldcy: GOTO ideloop + IF r$ = "C" THEN + idecx = oldcx: idecy = oldcy: GOTO ideloop + IF changed THEN + ideshowtext + SCREEN , , 0, 0: LOCATE , , 1: SCREEN , , 3, 0 + PCOPY 3, 0 + idechanged changed + END IF + END IF IF r$ = "Y" THEN l$ = idegetline(idecy) idechangemade = 1 diff --git a/source/qb64.bas b/source/qb64.bas index 9060df312..99b8be97a 100644 --- a/source/qb64.bas +++ b/source/qb64.bas @@ -12511,7 +12511,7 @@ IF Debug THEN PRINT #9, "ERL="; ERL IF idemode AND qberrorhappenedvalue >= 0 THEN 'real qb error occurred ideerrorline = linenumber - idemessage$ = "Compiler error (check for syntax errors) (" _ERRORMESSAGE$ + ":" + idemessage$ = "Compiler error (check for syntax errors) (" + _ERRORMESSAGE$ + ":" IF ERR THEN idemessage$ = idemessage$ + str2$(ERR) + "-" IF _ERRORLINE THEN idemessage$ = idemessage$ + str2$(_ERRORLINE) IF _INCLERRORLINE THEN idemessage$ = idemessage$ + "-" + _INCLERRORFILE$ + "-" + str2$(_INCLERRORLINE) From 2840adce9779cbed5b211c811a1b1f3c679e12bf Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Mon, 18 Jan 2021 02:25:58 -0300 Subject: [PATCH 4/7] Keeps "Change" dialog open after "Change all". --- source/ide/ide_methods.bas | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index 2be0c20c8..b750abfbc 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -6443,8 +6443,6 @@ FUNCTION idechange$ NEXT IF changed = 0 THEN idenomatch ELSE idechanged changed: idechangemade = 1 - EXIT FUNCTION - END IF 'change all From 525de822d155172237510b7207909ed2f86b7758 Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Mon, 18 Jan 2021 03:47:25 -0300 Subject: [PATCH 5/7] Add percentage bar to "Change All" (Change dialog). --- source/ide/ide_methods.bas | 73 +++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index b750abfbc..d9a7ea109 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -5479,13 +5479,14 @@ FUNCTION ide2 (ignore) PCOPY 3, 0: SCREEN , , 3, 0: idewait4mous: idewait4alt ideselect = 0 IF r$ = "C" THEN - idecx = oldcx: idecy = oldcy: GOTO ideloop + idecx = oldcx: idecy = oldcy IF changed THEN ideshowtext SCREEN , , 0, 0: LOCATE , , 1: SCREEN , , 3, 0 PCOPY 3, 0 idechanged changed END IF + GOTO ideloop END IF IF r$ = "Y" THEN l$ = idegetline(idecy) @@ -6234,6 +6235,7 @@ FUNCTION idechange$ o(i).sel = idefindonlystrings i = i + 1 + ButtonsID = i o(i).typ = 3 o(i).y = 14 o(i).txt = idenewtxt("Find and #Verify" + sep + "#Change All" + sep + "Cancel") @@ -6247,24 +6249,7 @@ FUNCTION idechange$ DO 'main loop '-------- generic display dialog box & objects -------- - - idedrawpar p - f = 1: cx = 0: cy = 0 - FOR i = 1 TO 100 - - IF o(i).typ THEN - - 'prepare object - o(i).foc = focus - f 'focus offset - - o(i).cx = 0: o(i).cy = 0 - - idedrawobj o(i), f 'display object - - IF o(i).cx THEN cx = o(i).cx: cy = o(i).cy - - END IF - NEXT i + GOSUB displayDialog lastfocus = f - 1 '-------- end of generic display dialog box & objects -------- @@ -6388,6 +6373,15 @@ FUNCTION idechange$ IF idefindcasesens = 0 THEN s$ = UCASE$(s$) FOR y = 1 TO iden + COLOR 0, 7 + maxprogresswidth = p.w - 4 + percentage = INT(y / iden * 100) + percentagechars = INT(maxprogresswidth * y / iden) + percentageMsg$ = STRING$(percentagechars, 219) + STRING$(maxprogresswidth - percentagechars, 176) + LOCATE p.y + 7, p.x + 2 + PRINT percentageMsg$; + PCOPY 1, 0 + l$ = idegetline(y) l2$ = "" @@ -6442,7 +6436,24 @@ FUNCTION idechange$ NEXT - IF changed = 0 THEN idenomatch ELSE idechanged changed: idechangemade = 1 + SCREEN , , 3, 0 + COLOR 7, 1: LOCATE idewy - 3, 2: PRINT SPACE$(idewx - 2);: LOCATE idewy - 2, 2: PRINT SPACE$(idewx - 2);: LOCATE idewy - 1, 2: PRINT SPACE$(idewx - 2); 'clear status window + idefocusline = 0 + ideshowtext + PCOPY 3, 0 + PCOPY 0, 2 + PCOPY 0, 1 + SCREEN , , 1, 0 + GOSUB displayDialog + PCOPY 1, 0 + + IF changed = 0 THEN + idenomatch + ELSE + idechanged changed: idechangemade = 1 + END IF + + idetxt(o(ButtonsID).txt) = "Find and #Verify" + sep + "#Change All" + sep + "Close" END IF 'change all @@ -6468,7 +6479,26 @@ FUNCTION idechange$ mousedown = 0 mouseup = 0 LOOP + EXIT FUNCTION + displayDialog: + idedrawpar p + f = 1: cx = 0: cy = 0 + FOR i = 1 TO 100 + IF o(i).typ THEN + + 'prepare object + o(i).foc = focus - f 'focus offset + + o(i).cx = 0: o(i).cy = 0 + + idedrawobj o(i), f 'display object + + IF o(i).cx THEN cx = o(i).cx: cy = o(i).cy + + END IF + NEXT i + RETURN END FUNCTION SUB FindQuoteComment (text$, __cursor AS LONG, c AS _BYTE, q AS _BYTE) @@ -6495,7 +6525,8 @@ SUB FindQuoteComment (text$, __cursor AS LONG, c AS _BYTE, q AS _BYTE) END SUB SUB idechanged (totalChanges AS LONG) - result = idemessagebox("Change Complete", LTRIM$(STR$(totalChanges)) + " substitutions.", "") + IF totalChanges > 1 THEN pl$ = "s" + result = idemessagebox("Change Complete", LTRIM$(STR$(totalChanges)) + " substitution" + pl$ + ".", "") END SUB FUNCTION idechangeit$ From 8fd038be443870fe9062c1d46cec3bcdfafb298b Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Mon, 18 Jan 2021 04:28:38 -0300 Subject: [PATCH 6/7] Shows search flags when no match is found (F3). --- source/ide/ide_methods.bas | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index d9a7ea109..72ba8304e 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -1674,7 +1674,7 @@ FUNCTION ide2 (ignore) GOSUB UpdateSearchBar IF KSHIFT THEN idefindinvert = 1 IdeAddSearched idefindtext - idefindagain + idefindagain -1 ELSE GOTO idefindjmp END IF @@ -5545,7 +5545,7 @@ FUNCTION ide2 (ignore) PCOPY 3, 0 result = idemessagebox("Search complete", "No changes made.", "") ELSE - idenomatch + idenomatch -1 END IF PCOPY 3, 0: SCREEN , , 3, 0: idewait4mous: idewait4alt GOTO ideloop @@ -6448,7 +6448,7 @@ FUNCTION idechange$ PCOPY 1, 0 IF changed = 0 THEN - idenomatch + idenomatch 0 ELSE idechanged changed: idechangemade = 1 END IF @@ -7144,7 +7144,7 @@ FUNCTION idefind$ s$ = idetxt(o(1).txt) idefindtext$ = s$ IdeAddSearched idefindtext - idefindagain + idefindagain 0 EXIT FUNCTION END IF @@ -7176,7 +7176,7 @@ FUNCTION idefind$ LOOP END FUNCTION -SUB idefindagain +SUB idefindagain (showFlags AS _BYTE) DIM comment AS _BYTE, quote AS _BYTE IF idefindinvert THEN @@ -7281,7 +7281,7 @@ SUB idefindagain IF idefindbackwards THEN y = y - 1 IF y = start - 1 AND looped = 1 THEN - idenomatch + idenomatch showFlags IF idefindinvert THEN IF idefindbackwards = 0 THEN idefindbackwards = 1 ELSE idefindbackwards = 0 idefindinvert = 0 @@ -7293,7 +7293,7 @@ SUB idefindagain ELSE y = y + 1 IF y = start + 1 AND looped = 1 THEN - idenomatch + idenomatch showFlags IF idefindinvert THEN IF idefindbackwards = 0 THEN idefindbackwards = 1 ELSE idefindbackwards = 0 idefindinvert = 0 @@ -7660,8 +7660,20 @@ FUNCTION idenewtxt (a$) idenewtxt = idetxtlast END FUNCTION -SUB idenomatch - result = idemessagebox("Search complete", "Match not found.", "") +SUB idenomatch (showFlags AS _BYTE) + msg$ = "Match not found." + c$ = ", " + IF showFlags THEN + IF idefindcasesens THEN flags$ = flags$ + "match case": flagset = flagset + 1 + IF idefindwholeword THEN flags$ = flags$ + LEFT$(c$, ABS(flagset) * 2) + "whole word": flagset = flagset + 1 + IF idefindnocomments THEN flags$ = flags$ + LEFT$(c$, ABS(flagset) * 2) + "no comments": flagset = flagset + 1 + IF idefindonlycomments THEN flags$ = flags$ + LEFT$(c$, ABS(flagset) * 2) + "only comments": flagset = flagset + 1 + IF idefindnostrings THEN flags$ = flags$ + LEFT$(c$, ABS(flagset) * 2) + "no strings": flagset = flagset + 1 + IF idefindonlystrings THEN flags$ = flags$ + LEFT$(c$, ABS(flagset) * 2) + "only strings": flagset = flagset + 1 + IF flagset > 1 THEN pl$ = "s" + IF flagset THEN msg$ = msg$ + "\n(Flag" + pl$ + ": " + flags$ + ")" + END IF + result = idemessagebox("Search complete", msg$, "") END SUB FUNCTION idefiledialog$(programname$, mode AS _BYTE) From d1acd48e32db92f25b8ce8b9e4369d386266845d Mon Sep 17 00:00:00 2001 From: FellippeHeitor Date: Mon, 18 Jan 2021 18:22:00 -0300 Subject: [PATCH 7/7] Adds version number to status bar. Also: Allows clicking the status bar Version and Line number to open the About and the "Go to line" dialogs. --- source/global/version.bas | 2 + source/ide/ide_global.bas | 1 + source/ide/ide_methods.bas | 79 +++++++++++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/source/global/version.bas b/source/global/version.bas index ccd0585bb..d268370ab 100644 --- a/source/global/version.bas +++ b/source/global/version.bas @@ -8,6 +8,8 @@ IF _FILEEXISTS("internal/version.txt") THEN versionfile = FREEFILE OPEN "internal/version.txt" FOR INPUT AS #versionfile LINE INPUT #versionfile, AutoBuildMsg + AutoBuildMsg = _TRIM$(AutoBuildMsg) + IF LEFT$(AutoBuildMsg, 9) <> "From git " THEN AutoBuildMsg = "" CLOSE #versionfile END IF diff --git a/source/ide/ide_global.bas b/source/ide/ide_global.bas index e1c27f980..204a7e1e4 100644 --- a/source/ide/ide_global.bas +++ b/source/ide/ide_global.bas @@ -159,6 +159,7 @@ DIM SHARED ActiveINCLUDELinkFile AS STRING DIM SHARED HideCurrentLineHighlight AS _BYTE, ShowLineNumbers AS _BYTE DIM SHARED SearchMenuEnableQuickNav AS INTEGER DIM SHARED idegotobox_LastLineNum AS LONG, maxLineNumberLength AS LONG +DIM SHARED versionStringStatus$, lineNumberStatus$ '-------------------------------------------------------------------------------- TYPE idedbptype diff --git a/source/ide/ide_methods.bas b/source/ide/ide_methods.bas index 72ba8304e..5bf9e6cd4 100644 --- a/source/ide/ide_methods.bas +++ b/source/ide/ide_methods.bas @@ -132,6 +132,7 @@ FUNCTION ide2 (ignore) STATIC wholeword.selecty1, wholeword.idecy STATIC ForceResize, IDECompilationRequested AS _BYTE STATIC QuickNavHover AS _BYTE, FindFieldHover AS _BYTE + STATIC VersionInfoHover AS _BYTE, LineNumberHover AS _BYTE ignore = ignore 'just to clear warnings of unused variables @@ -789,6 +790,7 @@ FUNCTION ide2 (ignore) 'status bar COLOR 0, 3: LOCATE idewy + idesubwindow, 1: PRINT SPACE$(idewx); + UpdateIdeInfo q = idevbar(idewx, idewy - 3, 3, 1, 1) q = idevbar(idewx, 3, idewy - 8, 1, 1) q = idehbar(2, idewy - 5, idewx - 2, 1, 1) @@ -1308,11 +1310,10 @@ FUNCTION ide2 (ignore) PCOPY 3, 0 - IF mB THEN + IF mCLICK THEN ideselect = 0 idecy = QuickNavHistory(QuickNavTotal) QuickNavTotal = QuickNavTotal - 1 - _DELAY .2 GOTO waitforinput END IF ELSE @@ -1358,6 +1359,51 @@ FUNCTION ide2 (ignore) END IF END IF + IF mY = idewy + idesubwindow AND mX >= idewx - 22 - LEN(versionStringStatus$) AND mX < idewx - 22 THEN + 'Highlight Version Number + IF VersionInfoHover = 0 THEN + LOCATE idewy + idesubwindow, idewx - 22 - LEN(versionStringStatus$) + COLOR 13, 6 + PRINT versionStringStatus$; + PCOPY 3, 0 + VersionInfoHover = -1 + END IF + IF mCLICK THEN PCOPY 0, 2: GOTO helpabout + ELSE + IF VersionInfoHover = -1 THEN + 'Restore "Find" bg + VersionInfoHover = 0 + LOCATE idewy + idesubwindow, idewx - 22 - LEN(versionStringStatus$) + COLOR 2, 3 + PRINT versionStringStatus$; + PCOPY 3, 0 + END IF + END IF + + IF mY = idewy + idesubwindow AND mX >= idewx - 20 AND mX =< idewx THEN + 'Highlight line number + IF LineNumberHover = 0 THEN + COLOR 13, 6 + LOCATE idewy + idesubwindow, idewx - 20: PRINT lineNumberStatus$; + PCOPY 3, 0 + LineNumberHover = -1 + END IF + IF mCLICK THEN + PCOPY 0, 2 + idegotobox + PCOPY 3, 0: SCREEN , , 3, 0: idewait4mous: idewait4alt + GOTO ideloop + END IF + ELSE + IF LineNumberHover = -1 THEN + 'Restore "Find" bg + LineNumberHover = 0 + COLOR 0, 3 + LOCATE idewy + idesubwindow, idewx - 20: PRINT lineNumberStatus$; + PCOPY 3, 0 + END IF + END IF + IF os$ = "WIN" OR MacOSX = 1 THEN IF _WINDOWHASFOCUS THEN @@ -5013,6 +5059,7 @@ FUNCTION ide2 (ignore) END IF IF menu$(m, s) = "#About..." THEN + helpabout: PCOPY 2, 0 m$ = "QB64 Version " + Version$ + CHR$(10) + BuildNum$ IF LEN(AutoBuildMsg$) THEN m$ = m$ + CHR$(10) + AutoBuildMsg$ @@ -5997,6 +6044,8 @@ FUNCTION ide2 (ignore) q = idevbar(idewx, 3, idewy - 8, 1, 1) q = idehbar(2, idewy - 5, idewx - 2, 1, 1) + UpdateIdeInfo + GOSUB UpdateTitleOfMainWindow DEF SEG = 0 @@ -8710,16 +8759,17 @@ SUB ideshowtext 'update cursor pos in status bar COLOR 0, 3 - LOCATE idewy + idesubwindow, idewx - 20: PRINT " : "; + a$ = SPACE$(10) + b$ = "" + RSET a$ = LTRIM$(STR$(idecy)) IF idecx < 100000 THEN - LOCATE idewy + idesubwindow, idewx - 9 - a$ = LTRIM$(STR$(idecx)) - PRINT a$; - IF cc <> -1 THEN PRINT "(" + str2$(cc) + ")"; + b$ = SPACE$(10) + c$ = LTRIM$(STR$(idecx)) + IF cc <> -1 THEN c$ = c$ + "(" + str2$(cc) + ")" + LSET b$ = c$ END IF - a$ = LTRIM$(STR$(idecy)) - LOCATE idewy + idesubwindow, (idewx - 10) - LEN(a$) - PRINT a$; + lineNumberStatus$ = a$ + ":" + b$ + LOCATE idewy + idesubwindow, idewx - 20: PRINT lineNumberStatus$; SCREEN , , 0, 0: LOCATE idecy - idesy + 3, maxLineNumberLength + idecx - idesx + 2: SCREEN , , 3, 0 @@ -14581,6 +14631,15 @@ SUB UpdateIdeInfo IF LEN(a$) < (idewx - 20) THEN a$ = a$ + SPACE$((idewx - 20) - LEN(a$)) COLOR 0, 3: LOCATE idewy + idesubwindow, 2 PRINT a$; + + COLOR 2, 3 + IF LEN(versionStringStatus$) = 0 THEN + versionStringStatus$ = "v" + Version$ + IF LEN(AutoBuildMsg$) THEN versionStringStatus$ = versionStringStatus$ + MID$(AutoBuildMsg$, _INSTRREV(AutoBuildMsg$, " ")) + END IF + LOCATE idewy + idesubwindow, idewx - 22 - LEN(versionStringStatus$) + PRINT versionStringStatus$; + PCOPY 3, 0 END SUB