Tuesday, January 19, 2016

Copying a folder full of files in Liberty BASIC

Over on the Liberty BASIC forum at conforums.com one member was asking how to copy all the files in a folder for a database.

The hard way is to use the FILES statement and to write a bunch of code that tests and loops.

But is there an easier way?

One solution is to use the SHFileOperationA API call.

CallDLL #shell32, "SHFileOperationA", SHFILEOPSTRUCT as struct, CopyFolder as long
Chris Iverson shows how in his post.  That and more in this thread.  Click to read.



Friday, January 15, 2016

Date is between function in Liberty BASIC

Someone recently asked me if Liberty BASIC can answer the question about whether a date is between two other dates.  Yes it can!

The following is my quick solution to his question.

answer = isDateBetween("12/21/2015", "12/15/2015", "12/30/2015")
if answer then print "yes" else print "no"


answer = isDateBetween("11/21/2015", "12/15/2015", "12/30/2015")
if answer then print "yes" else print "no"


function isDateBetween(aDate$, firstDate$, lastDate$)
    aDays = date$(aDate$)
    firstDays = date$(firstDate$)
    lastDays = date$(lastDate$)
    isDateBetween = firstDays < aDays and aDays < lastDays
end function


Enjoy!

Thursday, January 14, 2016

Tiny BASIC part 5 - Adding color to PSET

It's much more fun to draw in color than with only a black pen, so let's add a third parameter to the PSET statement for color, for example:
PSET x, y, "color"
To do this we need to add some code to our  case "pset"  block:
 CASE "pset"
  IF GWINOPEN = 0 THEN
    E$ = "PSET error - Graphic window is not open"
    GOTO [Ready]
  END IF
  GOSUB [GetExpression]
  IF E$<>"" THEN [Ready]
  PSETX = N
  GOSUB [GetChar]
  IF C$ <> "," THEN
   E$= "Comma expected after x parameter"
   GOTO [Ready]
  END IF
  C = C + 1
  GOSUB [GetExpression]
  IF E$<>"" THEN [Ready]
  PSETY = N
  PSETCOLOR$ = "black"
  GOSUB [GetChar]
  IF C$ = "," THEN
   C = C + 1
   GOSUB [GetStringLiteral]
   IF E$ <> "" THEN [Ready]
   PSETCOLOR$ = B$
  END IF
  #GWIN "color "; PSETCOLOR$

  #GWIN "down ; set "; PSETX; " "; PSETY
  GOTO [FinishStatement]

The way this works is that it will look for a comma and a string expression after it sets PSETX and PSETYIf there is no comma it will skip over the part that gets a color parameter, so the default color will be black in that case.

The string will be the name of a valid Liberty BASIC color, for example red, blue, green, black, etc.    The following code is stolen from the routine that parses for the PRINT statement.  In a later post we will incorporate this into the PRINT code by calling it as a subroutine so that we won't have the same code twice.
[GetStringLiteral]
  GOSUB [SkipSpace]
  GOSUB [GetChar]
  IF C$=G$ THEN
   B$=""
[NextStringMember]
   C = C + 1 : C$=MID$(A$,C,1)
   IF C$="" THEN
    E$="Unterminated string"
    RETURN
   ELSE
   IF C$<>G$ THEN
    B$=B$+C$
    GOTO [NextStringMember]
   END IF
  END IF
  C = C + 1 : C$=MID$(A$,C,1)
  IF C$=G$ THEN
   B$=B$+C$
   GOTO [NextStringMember]
  END IF
 END IF
 RETURN

So we call the [GetStringLiteral] subroutine and check E$ for an error.  If there is none then we set PSETCOLOR$ to the value of B$ as shown here.

   GOSUB [GetStringLiteral]
   IF E$ <> "" THEN [Ready]
   PSETCOLOR$ = B$
  END IF
  #GWIN "color "; PSETCOLOR$


Then we add a drawing command like so to set the color:

  #GWIN "color "; PSETCOLOR$

Here is a sample that uses PSET with color!


5 graphicwin
10 pset x, y, "red"
20 pset x + 10, y, "blue"
30 pset x + 20, y, "green"
40 x = x + 1
50 y = y + 2
60 if x < 100 then goto 10

And here is a screenshot!



Wednesday, January 13, 2016

Liberty BASIC file type association

Liberty BASIC doesn't map the BAS file extension to itself when it is installed.  This is because I didn't want to be so presumptuous as to steal a common file type away from another version of BASIC that might be installed.

So, because there is a bug in Windows which makes it really hard to remap a file extension and there have been discussions about this in the Liberty BASIC forum at conforums.com one of our member Chris Iverson (thanks Chris!) has contributed some Liberty BASIC code to solve this problem.

  Click to see thread in the forum

Enjoy!

Sunday, January 10, 2016

Lunar lander revisited

Liberty BASIC comes with a nice introduction to video games called lander.bas.
  • It's a good example of a timer driven game.
  • It uses sprites which are actually generated on the fly using turtle graphics.
  • It also shows proper technique of structured programming.
So I have some ideas that I am thinking about implementing to update it and make it an even more complete video game example:
  • Add sound effects including ambient sounds, rocket motor noise and crash explosion.
  • Animate the rocket motor so you can see rocket exhaust coming out.
  • Add some flying space junk sprites that you need to avoid while trying to land.
  • Add a colored starfield in the background.
Looking forward to this!  Check back for updates!

Friday, January 08, 2016

Tiny BASIC part 4 - Adding a PSET statement


Okay, now we are ready to add a PSET statement for drawing pixels.  Today we will simply add the ability to draw a single black pixel at a time.  Next time we will add color!

Here is the code to accomplish this.  This is just another SELECT CASE block to add after the one we added for the GRAPHICWIN command.
 CASE "pset"
  IF GWINOPEN = 0 THEN
    E$ = "PSET error - Graphic window is not open"
    GOTO [Ready]
  END IF
  GOSUB [GetExpression]
  IF E$<>"" THEN [Ready]
  PSETX = N
  GOSUB [GetChar]
  IF C$ <> "," THEN
   E$= "Comma expected after x parameter"
   GOTO [Ready]
  END IF
  C = C + 1
  GOSUB [GetExpression]
  IF E$<>"" THEN [Ready]
  PSETY = N
  #GWIN "down ; set "; PSETX; " "; PSETY
  GOTO [FinishStatement]
This was a bit tricky to write because there isn't really any documentation with the original Tiny BASIC source code, but by looking at the code for the other statements I think I figured it out correctly.  It does seem to work.

The syntax for the new statement is PSET x, y

Let me explain what it does.
  • First check to see if the graphic window is open.  If it isn't then set E$ to be an error string.  Then GOTO [Ready].  This will display the error.
  • Then get the next expression using GOSUB [GetExpression].  This unleashes the expression parser which is easily the largest and most complex part of the Tiny BASIC source code.  Then it checks for an error using IF E$<>"".  If E$ does contain an error, then GOTO [Ready].
  • Okay so got this far, so set PSETX to be what was in N, which is the result of the call to [GetExpression].
  • Now get the next character, which we expect to be a comma to separate the x and y values.  If the next character is not a comma, set E$ to be an error and GOTO [Ready].
  • Now advance C one character by adding 1 to it.  We do this because we found the expected comma, and now we need to skip over that so that we can get the next expression for our y value.
  • Get the next expression using GOSUB [GetExpression].  Test E$ for an error and GOTO [Ready] if there is one.
  • Get the value of N and put it into the variable PSETY.
  • Finally, draw the pixel in the graphics window!
Here is the sample Tiny BASIC program that uses the PSET statement:

10 graphicwin
20 pset x, y
30 x = x + 1
40 y = y + 2
50 if x < 200 then goto 20

And here is the output of the program!

Thursday, January 07, 2016

Run BASIC Revisited - The easiest web development system on Earth

I got an inquiry yesterday about Run BASIC asking about what is special about it.  The essential concept is that it is an all-in-one BASIC web application server.  You can use it to create a dynamic web site, or to host in-house applications for your business or school, or use it to control your home.  The possibilities are pretty much endless.

Here is a link to a white paper about Run BASIC.
    http://www.libertybasic.com/RunBASICBreakthrough.pdf

Here is a link to the Run BASIC community forum.
    http://runbasic.proboards.com/

Wednesday, January 06, 2016

Tiny BASIC part 3 - Adding GRAPHICWIN statement


We are going to add GRAPHICWIN and PSET statements to Tiny BASIC.

Let's start with the really easy one.  We will add a  case "graphicwin"  block to the end of the select case blocks that we examined in the last post.  Here is what it looks like.  The new code is in bold red.
 CASE "let"
  GOSUB [GetLabel]
  IF E$<>"" THEN [Ready]
 CASE "graphicwin"
  IF GWINOPEN = 1 THEN
    PRINT "Graphics window is already open."
  ELSE
    GWINOPEN = 1
    OPEN "Graphics" FOR graphics AS #GWIN
  END IF
  GOTO [FinishStatement]

 END SELECT
So when you run Tiny BASIC and type the command graphicwin and press Enter it will open a small graphics window.  When it does this it also sets the GWINOPEN flag to 1 to that we can check it if the program tries to open another graphics window.  Only one graphics window will be allowed at a time.

The other thing that we want to do it close the graphics window and reset GWINOPEN to 0 if the program is started using the RUN statement.

So, we need to add the following code into the  case "run"  block.  Here is how that code should look.  The new code is in bold red.

 CASE "run"
  IF GWINOPEN = 1 THEN
    CLOSE #GWIN
    GWINOPEN = 0
  END IF

  FOR I=27 TO 52 : A(I)=0 : NEXT I
  L=27 : C=1
  GOTO [FinishStatement2]
So now the program will always start off in a clean state each time it is run!

In our next post we will figure out how to add a PSET statement so we can draw some graphics!


Monday, January 04, 2016

Tiny BASIC part 2 - Adding new statements

This is part 2 of a series on extending tiny basic.bas which is an example that comes with Liberty BASIC v4.5.0.

In order to add some graphics capability I want to suggest two new commands just to start.

GRAPHICWIN width, height     and    PSET x, y, color$

These will enable us to open a window to draw in, and also to draw pixels of a specific color at a given x, y position.  This will be a crude start, but it will be instructive because it will show the reader how to extend Tiny BASIC to do what is desired.

The first thing to do is figure out where in the code Tiny BASIC parses commands so we can add some more.  The code below is the routine that does this.  If you look carefully you will see a SELECT CASE statement and then a CASE statement for each Tiny BASIC command.

More later.
[NextStatement]
 GOSUB [GetLabel]
 IF E$<>"" THEN [Ready]
 SELECT CASE D$
 CASE "if"
  GOSUB [GetExpression]
  IF E$<>"" THEN [Ready]
  IF N<1 font="" then="">
   B$=A$(L) : C=LEN(B$)+1
   GOTO [FinishStatement]
  END IF
  GOSUB [GetLabel]
  IF E$<>"" THEN [Ready]
  IF D$<>"then" THEN
   E$="'THEN' expected"
   GOTO [Ready]
  END IF
  GOTO [NextStatement]
 CASE "rem"
  B$=A$(L) : C=LEN(B$)+1
  GOTO [FinishStatement]
 CASE "input"
  GOSUB [GetVar]
  IF E$<>"" THEN [Ready]
  INPUT N : A(V)=N
  GOTO [FinishStatement]
 CASE "print"
[Print]
  GOSUB [SkipSpace]
  GOSUB [GetChar]
  IF C$=G$ THEN
   B$=""
[NextChar]
   C = C + 1 : C$=MID$(A$,C,1)
   IF C$="" THEN
    E$="Unterminated string"
    GOTO [Ready]
   ELSE
    IF C$<>G$ THEN
     B$=B$+C$
     GOTO [NextChar]
    END IF
   END IF
   C = C + 1 : C$=MID$(A$,C,1)
   IF C$=G$ THEN
    B$=B$+C$
    GOTO [NextChar]
   END IF
   PRINT B$;
  ELSE
   GOSUB [GetExpression]
   IF E$<>"" THEN [Ready]
   B=N1
   IF B=N THEN
    PRINT N;"*";
   ELSE
    PRINT N;
   END IF
  END IF
  GOSUB [SkipSpace]
  GOSUB [GetChar]
  IF C$="," THEN C = C + 1 : GOTO [Print]
  GOSUB [SkipSpace]
  GOSUB [GetChar]
  IF C$<>";" THEN
   PRINT
  ELSE
   C = C + 1
  END IF
  GOTO [FinishStatement]
 CASE "clear"
  FOR I=27 TO 52 : A(I)=0 : NEXT I
  GOTO [FinishStatement]
 CASE "run"
  FOR I=27 TO 52 : A(I)=0 : NEXT I
  L=27 : C=1
  GOTO [FinishStatement2]
 CASE "goto"
  GOSUB [GetExpression]
  IF E$<>"" THEN [Ready]
  IF E>=N THEN L=27
  C=1 : T=N
[NextGoto]
  IF L=126 THEN
   E$="Line not found"
   GOTO [Ready]
  END IF
  GOSUB [GetNumber]
  IF N=T THEN E=N : GOTO [NextStatement]
  L = L + 1 : C=1
  GOTO [NextGoto]
 CASE "new"
  FOR I=27 TO 125 : A$(I)="" : NEXT I
  FOR I=27 TO 52 : A(I)=0 : NEXT I
  IF E=0 THEN [FinishStatement]
  GOTO [Ready]
 CASE "cls"
  CLS : GOTO [FinishStatement]
 CASE "help"
  FOR I=9 TO 18
   B$=A$(I) : PRINT B$
  NEXT I
  GOTO [FinishStatement]
 CASE "mem"
  B=126
  FOR I=27 TO 125
   diffI = 152 - I  'Cheating here
   B$=A$(diffI) : IF B$="" THEN B=diffI
  NEXT I
  B=126-B : PRINT B;"*";
  PRINT " lines free"
  GOTO [FinishStatement]
 CASE "end"
  GOTO [Ready]
 CASE "bye"
  GOTO [ExitTinyBAS]
 CASE "list"
  GOSUB [GetNumber] : T=N : A=L : I=C
  IF T=0 THEN
   GOSUB [GetLabel]
   IF E$="" AND D$="pause" THEN I=C
   E$=""
  END IF
  FOR L=27 TO 125
   C=1 : GOSUB [GetNumber]
   B=(T=0) OR (N=T)
   IF B=TRUE THEN
    IF A$<>"" THEN
     PRINT A$
     IF D$="pause" THEN
      B = (L-26) mod 10
      IF B=0 THEN PRINT "Pause..."; : INPUT AAA$
     END IF
    END IF
   END IF
  NEXT L
  L=A : C=I
  GOTO [FinishStatement]
 CASE "save"
 PRINT "SAVE, TBD"
 CASE "load"
 PRINT "LOAD, TBD"
 CASE "let"
  GOSUB [GetLabel]
  IF E$<>"" THEN [Ready]
 END SELECT