The Liberty Basic Newsletter - Issue #87 - MAR 2001

© 2003, http://groups.yahoo.com/group/lbnews/

All Rights Reserved

Individual authors retain copyrights to their works.

---------------------------------------------------------
The Liberty Basic Newsletter - Issue #87 - MAR 2001
---------------------------------------------------------
In this issue:
    From Carl:  A book about Liberty BASIC
    Using CommandLine$ with tokenized files
    Updating the Open Source Editor
        Using CommandLine$ 
        Removing the Icon Changer
        Adding an Array Maker
    Contest reminder
    List of attached files
---------------------------------------------------------

A book about Liberty BASIC:

Thanks for waiting so long. I am now able to speak some about the LB book coming out!

The book is called Beginning Programming for Dummies the 2nd Edition. This is a book from Hungry Minds (aka IDG Books) by Wallace Wang, a popular author and columnist. The first edition of this book focused on QBASIC, and this new edition uses Liberty BASIC v2.01 to bring us forward into Windows programming!

We are going to promote this book on the LB website (and the French one too)!! ;-)

Here is a URL for Amazon's listing of the new book. They are accepting orders in advance. The book won't be available for a few weeks yet, even though their listing says it's available in March.

http://www.amazon.com/exec/obidos/ASIN/0764508350/qid=983768743/sr=1-2/ref=sc_b_2/106-6101787-5108448

From the Dummies website:

Beginning Programming For Dummies, 2nd Edition explains programming to nonprogrammers using Liberty Basic for hands-on examples along with snippets of C, Pascal, and Java code as well as HTML, Perl, and Python scripts to show how different languages accomplish the same task. The book focuses on introducing you to the basics of programming and guides you step-by-step through the basic tools and software, explaining the advantages and disadvantages of each one. The book explains the workings of compilers, visual tools and environments, debugging, testing, and also discusses the basics of more advanced programming disciplines such as animation and sound, encryption, communications, and more.

Sprinkled throughout Beginning Programming For Dummies, 2nd Edition, are real-life stories highlighting various problems with programming -- such as the time NASA had to blow up a rocket because of a mistyped command in a FORTRAN program or the time WordStar Corporation’s programmers defected to form their own word processing company, leaving WordStar unable to update their product because nobody in the company understood the assembly language source code that made WordStar work. Also included are stories from actual programmers who have created successful programs without having a degree or any training in programming including TurboTax, ScriptThing (a screenwriting program), and others.

USING CommandLine$ WITH TOKENIZED FILES

Liberty BASIC's RUN command allows us to run external programs. We can run Notepad like this:

RUN "Notepad"

If we want to open Notepad with a particular file loaded we can do that also, like this:

RUN "Notepad c:\lb201w\newfor20.txt"

The filename, "c:\lb201w\newfor20.txt" is an example of a command line argument. We are commanding the program to run with this file displayed.

We can run Liberty BASIC from the command line. From another program, or from the DOS prompt, or the START button's run command we could do this:

run "c:\lb201w\liberty.exe"

Windows knows where to find components of its own like Notepad and Explorer. We must specify the path to other applications like Liberty BASIC as we did above with "c:\lb201w\liberty.exe".

In the Notepad example, we didn't use the "exe" extension and in this example we did use it. It is optional. We could just as easily have said

run "c:\lb201w\liberty"
run "notepad.exe"

We can also run Liberty BASIC itself with command line arguments. For instance, we can add the name of a file to load when Liberty BASIC opens, like this:

run "c:\lb201w\liberty.exe c:\lb201w\boxes.bas"

When running Liberty BASIC from an external program, we can also include some switches that tell Liberty BASIC how to work. It can be made to run or debug a loaded BAS file on startup. In the registered version it can be made to tokenize the loaded file, and to run the Liberty BASIC editor minimized, and even to close Liberty BASIC once the program has ended. Multiple switches can be used at once.

Run a BAS file on startup
Debug a BAS file on startup
following three are in the registered version only--------
Make a TKN file from a BAS file on startup
Automatically Exit LB on completion of BAS file
Minimize the Liberty BASIC editor on startup

Examples:

run "LIBERTY -R -M PROG.BAS" 'run PROG.BAS with editor minimized

run "LIBERTY -T -A PROG.BAS" 'create a TKN file from PROG.BAS then exit

run "LIBERTY -D PROG.BAS" 'run the debugger on PROG.BAS

Liberty BASIC has a special function that allows us to run a tkn, as well as an exe. We can do this:

run "myprog.tkn"

Liberty BASIC gives us the ability to accept command line arguments in our own programs. Any arguments passed to a tokenized file when it is run are contained in the variable CommandLine$. We can run a tkn with command line arguments like this:

run "myprog.tkn argument1 argument2 argument3"

For the world's shortest CommandLine$ demo, tokenize the following 2 line program and call it "shortest.tkn"

'*****************
print CommandLine$
end
'*****************

When we run this program, it will simply print the value of the CommandLine$ variable into the mainwindow. To run it from another program:

'*****************
run "shortest.tkn I like Liberty BASIC"
end
'*****************

The example above would run a program with a mainwindow that displayed the text, "I like Liberty BASIC". That was fun, but not very useful. The information passed in the command line can issue instructions to the tokenized program. Let's make a Notepad clone that will accept a text file name, in the same way as our Notepad example at the start of this article.

We'll set up a simple text window:

'*****************
nomainwin
WindowWidth=600:WindowHeight=400
UpperLeftX=20:UpperLeftY=10

open "LB Notepad Clone" for text as #n
print #n, "!trapclose [quit]"
'*****************

Okay. We can now check to see if this program was started with any command line arguments:

'*****************
if CommandLine$<>"" then
    open CommandLine$ for input as #t
    print #n, "!contents #t";
    print #n, "!origin 1 1";
    close #t
end if
'*****************

If there is a command line argument, we'll assume it is the name of a text file, which we will open and load into the text window. Just for the fun of it, let's give ourselves a NOTICE that tells us the CommandLine$:

notice "CommandLine$ was ";CommandLine$

In a real program we would want to do some data validation. In this case, we would want to check for the existence of the file before attempting to open it. For simplicity, this step has been skipped. Don't skip data validation in an actual program! Here is the complete code, which should be tokenized with the filename "textcmd.tkn".

'*****************
nomainwin
WindowWidth=600:WindowHeight=400
UpperLeftX=20:UpperLeftY=10

open "LB Notepad Clone" for text as #n
print #n, "!trapclose [quit]"

'if CommandLine$ contains information,
'assume it is a text file name, and
'open file to load into text window:

if CommandLine$<>"" then
    open CommandLine$ for input as #t
    print #n, "!contents #t";
    print #n, "!origin 1 1";
    close #t
end if

notice "CommandLine$ was ";CommandLine$
[loop]
wait

[quit]
close #n:end
'*****************

We can run this tokenized program from another program. The simplest form is like this:

run "textcmd.tkn"

It contains no command line arguments, so no text file will be displayed in the window when textcmd.tkn is run. We can specify a file to load like this;

'*****************
nomainwin
filedialog "Open text file...","*.txt",textfile$
run "textcmd.tkn ";textfile$ 
'*****************

The demo above allows the user to choose a text file, and then it sends the filename of the chosen file to textcmd.tkn. When it is run, the tokenized application will open a text window with the desired text file displayed.

CommandLine$ is a variable that contains a string of text. We can evaluate the text in different ways to discover what it contains. Liberty BASIC has a word$() function that breaks a string into words at the blank spaces. Word$(text$,3) would produce the third word in the string called "text$". We can use this feature when assessing multiple command line arguments. Here is a simple example that will use the first word$ in the CommandLine$ as the width of the window, and the second word$ will be the height.

'*****************
'tokenize to multi.tkn
nomainwin

if CommandLine$<>"" then
    WindowWidth=val(word$(CommandLine$, 1))
    WindowHeight=val(word$(CommandLine$, 2))
end if

statictext #w.s, "CommandLine$ is empty",5,5,300,30
open "Variable-sized Window" for window as #w
print #w, "trapclose [quit]"
print #w.s, "Window dimensions are:  ";WindowWidth;" ";WindowHeight

wait

[quit]
close #w:end
'*****************

Notice the use of the VAL() function. Since the CommandLine$ is a string variable, the arguments must be converted to numbers for use as WindowWidth and WindowHeight. Notice also that we have skipped the data validation step, for the sake of simplicity in this demo. In a real program, the values should be checked to make sure they are valid values for WindowWidth and WindowHeight. To run the tokenized program from another program:

'*****************
nomainwin
run "multi.tkn 600 100"
end
'*****************

This will open a window that is 600 pixels wide and 100 pixels high.

We can also parse strings with the INSTR() function. This allows us to check for information that might be contained within the CommandLine$ in any order, and to pick meaningful information from it even if it contains some garbage. In the following example, we'll check to see if the CommandLine$ string contains the color "red". If it does, we'll set a variable called color$ to be "red", but if it doesn't, we'll use a default color$ of "blue".

'*****************
CommandLine$=lower$(CommandLine$)
if instr(CommandLine$,"red")>1 then
    color$="red"
else
    color$="blue"
end if
'*****************

Here is the entire program, which fills a graphics window with the specified color$:

'*****************
'tokenize to cmdinstr.tkn
nomainwin

CommandLine$=lower$(CommandLine$)
if instr(CommandLine$,"red")>1 then
    color$="red"
else
    color$="blue"
end if

open "Instr() test" for graphics_nsb as #g
print #g, "trapclose [quit]"
print #g, "fill ";color$

wait

[quit]
close #g:end
'*****************

That was pretty straightforward. We can call it from another program with no command line arguments, like this:

run "cmdinstr.tkn"

We can also call it and specify the "red" argument"

run "cmdinstr.tkn RED"

We can ask for a red window, and also include other stuff in the CommandLine$. Our tkn program can find our "red" instruction, even though there is extra information in the CommmandLine$:

run "cmdinstr.tkn Hello World RED Whatever"

You might notice that we are passing the word "RED", but the program is looking for the word, "red". We solved this possible problem by using the lower$() function to convert the text in the CommandLine$ to all lower case before we checked for "red".

USING COMMANDLINE IN THE OPEN SOURCE EDITOR:

We've incorporated the method discussed earlier (that allows us to open an editor with a file loaded) into the Open Source Editor. In this case, we'll open a BAS file, not a TXT file as in the earlier example. When the Open Source Editor loads, we'll check the CommandLine$ and if it has a value, we'll trim$ it and change it to lower$ case to make it simpler to manipulate. Then we'll parse it, starting from the end and going to the start of the string, looking for a space character. When we encounter a space, or when we've reached the beginning of CommandLine$ without finding a space, we designate the right-most part of the CommandLine$ as a file name, and send it to our [loadFile] routine. That routine checks for the existence of a valid file and loads it into the editor. (See previous newsletters for more explanation.) To use this method, we must first tokenize Open16.bas to Open16.tkn.

'open16.bas - addition:
'** NEW **************************
[check.command]  'if CommandLine$ contains a filename, it will be loaded at startup
    if CommandLine$<>"" then
        CommandLine$=lower$(trim$(CommandLine$))
        if right$(CommandLine$,3)="bas" then
            i=len(CommandLine$)
            while mid$(CommandLine$,i,1)<>" " and i>1
                i=i-1
            wend
            file$=mid$(CommandLine$,i)
            goto [loadFile]
        end if
    end if

TO RUN THE OPEN SOUCE EDITOR FROM AN EXTERNAL PROGRAM:

Here is a small program that will run the tokenized Open Source Editor allowing the user to designate a BAS file to load. Notice that if no file is chosen, the editor will run with no file loaded. (This program must be in the same directory as the open16.tkn.)

'run16.bas -- a demo of running the
'open source editor from the commandline
'with a file loaded

nomainwin

filedialog "Open a BAS file...","*.bas",basfile$ 

if basfile$ = "" then
    notice "No file chosen. The open source editor will run with no file loaded."
end if

run "open16.tkn " + basfile$ 

REMOVING THE ICON CHANGER

Liberty BASIC 1.4x had a bug that made it difficult to change the runtime icon. For this reason, several people in the LB community wrote/improved an icon changer. The add-on icon changer is no longer needed, since LB2 includes a special utility to extract/edit/create icons and to write them into the module. Not only is the add-on icon changer not needed, it doesn't work with LB2! The code, and these variables have been removed from the

open source editor:

'** NEW **
'removed Runtime icon changer, and these vars,
'since icon changer no longer works for LB2:
'hicon              icon handle
'szFile$            runtime engine name
'runtime$           runtime engine name
'icon$              icon file name
'#1icon             icon file handle
'success=0
'ico                used for icon changer
'runpos             used for icon changer
'error              error flag in icon changer
'icopath$           path in icon changer
'hico               handle of icon window
'hicodc             dc of icon window
'hFile              icon file handle
'icont$             buffer for icon file input
'iconlength         length of icon buffer

ADDING AN ARRAY MAKER

It can be tedious to fill an array by typing one element at a time. Imagine typing like this to fill an array with a hundred elements:

array$(1)="Hello"

array$(2)="Goodbye"

The job can be shortened somewhat by doing a copy/paste

of part of the code, then filling in the blanks:

array$(

array$(

array$(

array$(

array$(

Using this method would eliminate some of the keystrokes, but the job would still be tedious. Liberty BASIC Workshop includes an array maker. Doyle Whisenant has written a clone of that array maker, and added the ability to load an array from a file. We'll add it to the open source editor, as a tool. Here is a list of the new variable names:

'** array variables
'bString            flag for array string
'bNumeric           flag for array numeric
'i                  index var for general use
'a                  index var for general use
'arrayName$         name of array
'arrayItem$         individual array items
'myarray$()         variable for generating array items
'ArrayFileName$     name of file opened for creating array
'line$              file input variable

We won't explain each line of code, but rather hit some of the important highlights. The first on is the fact that this is a dialog window. Why? Because a dialog window allows a user to do keyboard only entry. TAB will advance the input focus to the next control, so the mouse needn't be clicked in a textbox to make it

accept the typed input.

open "Array Maker" for dialog_nf_modal as #arraymake

The other great reason to use a dialog window for this purpose also has to do with keeping it "keyboard only" for the user. Giving a button the extension ".default" will cause it to be activated when ENTER is pressed by the user.

button #arraymake.default, "Add Item", [ArrayAdd], UL, 150, 86, 112, 25

This feature allows a user to type the desired array item, then press ENTER to have it added to the array. Filling an array this way simply requires typing a name, then hitting ENTER over and over again until the array is filled. It is not necessary to lift hands from the keyboard to click the mouse on a button.

We need to do just a bit of coding to make this possible. When the ADD button is pressed, the current content of the array item textbox is added to the array. To make it easy for the user, we then clear the text from this textbox and set the input focus back onto this textbox, so that the next typing done by the user adds a fresh array element name.

    print #arraymake.arrayItem, ""
    print #arraymake.arrayItem, "!setfocus"

When the ADD button is activated, the text contained in the array item textbox is added to an array within our program called "myarray$". When it is time to create the code for the user's array, this internal array will be accessed. If instead, the user chooses to fill his array from a disk file, the file is opened and used to load "myarray$" directly.

   OPEN ArrayFileName$ for input as #arrayFile
     while eof(#arrayFile) = 0
       line input #arrayFile, ArrayLine$
       myarray$(i)= ArrayLine$ 
       i = i + 1
     wend
     close #arrayFile

The array dialog has two radiobuttons that allow the user to choose a string array, or a numeric array.

    radiobutton #arraymake.string, "String$", [stringSet], [stringReset], 182, 31, 72, 20
    radiobutton #arraymake.numeric, "Numeric", [numericSet], [numericReset], 182, 56, 72, 20

We will make "numeric" the default array type, so when the window opens, we will "set" the numeric button:

    print #arraymake.numeric, "set" 

We will also "set" the flag that indicates that this is a numeric array:

    bNumeric = 1

Creating the array is easy. First, we need some error trapping. The user will probably enter a name for the array, but we should supply one if he doesn't:

    if arrayName$="" then arrayName$="MyArray"

We should also check the array type. If it is to be a string array (if the flag bString = 1) then we should check for the ( $ ) character at the end of the name. If it is not already there, we should add it:

    if bString=1 and right$(arrayName$,1)<>"$" then
        arrayName$=arrayName$+"$"
    end if

Doyle has created a hidden texteditor control by giving it a width and height of 0. He uses this invisible texteditor to write the array code that is created. After the code is all written, he selects all of the text in the texteditor, and copies it to the clipboard, giving the user a message to that effect:

    Print #arraymake.text, "!selectall";
    Print #arraymake.text, "!copy";
    Print #arraymake.text, "!cls";
    notice "Array is copied into clipboard. Paste into your application."

We will keep track of the number of elements in the array as they are added, with the counter variable "i". We then must DIM our created array so that it is large enough to hold all of the needed elements:

    print #arraymake.text, "Dim ";arrayName$;"(";i;")"

After setting up the array with a DIM statement, it only remains to write the code to fill the array. This is easily done in a for/next loop, counting from 0 to the number or elements minus 1. We do a check to see if it is to be a string or numeric array. String array elements are contained within quote marks, while numeric array elements are not. The way to print a quote mark into a textbox is to print chr$(34):

    For a = 0 to i-1
    if right$(arrayName$, 1) = "$" then
      Print #arraymake.text, arrayName$;"(";a;") = ";chr$(34);myarray$(a);chr$(34)
    else
      Print #arraymake.text, arrayName$;"(";a;") = ";myarray$(a)
    end if
    Next a

Once the array has been copied to the clipboard, the window closes. If the user presses the CANCEL button, the window closes without creating the array or copying anything to the clipboard.

Code for the array maker is excerpted from the open source editor here. The open source editor file is included in this package and is called open17.bas and open17.tkn.

*******************************************
'excerpt from open17.bas:
[makeArrays] 'based on original code by Doyle Whisenant
    DIM myarray$(1000)
    left=int((DisplayWidth-280)/2):top=int((DisplayHeight-215)/2)
    WindowWidth = 280
    WindowHeight = 215
    bString = 0
    bNumeric = 1
    i = 0
    statictext #arraymake.static1, "Array Name:", 6, 11, 88, 20
    statictext #arraymake.static2, "Item to Add:", 6, 71, 96, 20
    groupbox #arraymake.groupbox3, "Type", 150, 11, 110, 70
    radiobutton #arraymake.string, "String$", [stringSet],_
        [loop], 182, 31, 72, 20
    radiobutton #arraymake.numeric, "Numeric", [numericSet],_
        [loop], 182, 56, 72, 20
    button #arraymake.default, "Add Item", [ArrayAdd],_
        UL, 150, 86, 112, 25
    TEXTEDITOR #arraymake.text, 0, 0, 0, 0
    button #arraymake.file, "File", [ArrayFile],_
        UL, 150, 119, 112, 25
    button #arraymake.create, "Create and Exit", [create],_
        UL, 150, 151, 112, 25
    button #arraymake.cancel, "Cancel", [ArrayCancel],_
        UL, 14, 151, 112, 25
    textbox #arraymake.arrayName, 6, 31, 136, 25
    textbox #arraymake.arrayItem, 6, 86, 136, 25
    open "Array Maker" for dialog_nf_modal as #arraymake
    print #arraymake, "font ms_sans_serif 0 8"
    print #arraymake.numeric, "set" 'flag bNumeric = 1
    goto [loop]


[ArrayAdd]   'Perform action for the button named 'add'
    print #arraymake.arrayItem, "!contents?"
    input #arraymake.arrayItem, arrayItem$

    myarray$(i)= arrayItem$ 
    i = i + 1
    print #arraymake.arrayItem, ""
    print #arraymake.arrayItem, "!setfocus"
    goto [loop]

[ArrayFile]
   i = 0
   filedialog "Open file", "*.*", ArrayFileName$
   if ArrayFileName$ = "" then
     notice "You must input a valid file name!"
     goto [loop]
   end if
   print #arraymake.arrayName, "!contents?"
    input #arraymake.arrayName, arrayName$ 
    if bString = 1 and right$(arrayName$, 1) <> "$" then
       arrayName$ = arrayName$ + "$"
    end if
   OPEN ArrayFileName$ for input as #arrayFile
     while eof(#arrayFile) = 0
       line input #arrayFile, ArrayLine$
       myarray$(i)= ArrayLine$ 
       i = i + 1
     wend
     close #arrayFile


[create]   'Perform action for the button named 'create'
    print #arraymake.arrayName, "!contents?"
    input #arraymake.arrayName, arrayName$ 

    if arrayName$="" then arrayName$="MyArray"
    if bString=1 and right$(arrayName$,1)<>"$" then
        arrayName$=arrayName$+"$"
    end if

    print #arraymake.text, "!cls";
    print #arraymake.text, "Dim ";arrayName$;"(";i;")"
    For a = 0 to i-1
    if right$(arrayName$, 1) = "$" then
      Print #arraymake.text, arrayName$;"(";a;") = " ;chr$(34);myarray$(a);chr$(34)
    else
      Print #arraymake.text, arrayName$;"(";a;") = ";myarray$(a)
    end if
    Next a

    Print #arraymake.text, "!selectall";
    Print #arraymake.text, "!copy";
    Print #arraymake.text, "!cls";
    notice "Array is copied into clipboard. Paste into your application."
[ArrayCancel]   'Perform action for the button named 'cancel'
    close #arraymake
    goto [loop]

[stringSet]   'Perform action for the radiobutton named 'string'
    bString = 1
    bNumeric = 0
    goto [loop]

[numericSet]   'Perform action for the radiobutton named 'numeric'
    bNumeric = 1
    bString = 0
    goto [loop]

CONTEST REMINDER

Don't forget that contest entries and nominations are due in July. For details, visit the contest page on the coweb:

http://libertybasic.swiki.net/146

Prizes include registered versions of Liberty BASIC and Liberty BASIC merchandise. Programmers of all levels and abilities may enter, since categories include beginner, intermediate and advanced. Remember that there are categories for newsletter contributions, web sites, logos and more. Check it out today!

http://libertybasic.swiki.net/146

ATTACHED FILES:

cmdinstr.bas

cmdinstr.tkn

multi.bas

multi.tkn

runinstr.bas

runshort.bas

runtext.bas

shortest.bas

shortest.tkn

testcmd.bas

testcmd.tkn

runmult.bas

open16.bas

open16.tkn

run16.bas

open17.bas

open17.tkn