Q L   H A C K E R ' S   J O U R N A L
      ===========================================
           Supporting  All  QL  Programmers
      ===========================================
         #30                       December 1998 
      
    The QL Hacker's Journal (QHJ) is published by Tim
Swenson as a service to the QL Community.  The QHJ is
freely distributable.  Past issues are available on disk,
via e-mail, or via the Anon-FTP server, garbo.uwasa.fi. 
The QHJ is always on the look out for article submissions.

        QL Hacker's Journal
     c/o Tim Swenson
     2455 Medallion Dr. 
     Union City, CA 94587
     swensont@geocities.com  swensont@jack.sns.com
     http://www.geocities.com/SiliconValley/Pines/5865/index.html




EDITOR'S FORUMN

In this issue I want to take a look at a couple of Unix
languages that have recently been ported to the QL.  In the
ql-users mailing list, I've seen some comments that
basically say "Why use these other languages on the QL?  All
development should be done in SuperBasic or C68 and use the
Pointer Environment."  As much as I agree with this, I don't
see Perl or AWK being used to do serious development on the
QL.  I see them being used to accomplish short personal
tasks.  There are some tasks that can be done much easier
with AWK or Perl than in SuperBasic or C68.  Of course,
there is the ability to use Perl/AWK programs from other
environments on the QL and the ability to learn Perl/AWK
even if you don't have access to a Unix system.  I've done
some Perl stuff at work because it is the best Unix language
to hack in, and now that I have Perl on the QL, I can run
the same programs at home.

West Coast Sinclair Show

Since the last US QL Show in Bedford, PA, there has been
some talk about having two shows in 1999, one on the East
Coast and one on the West Coast.  The vendors support the
idea, having one show right after another so they can hit
both in one trip.  I think they are just tired of the East
Coast and want to visit sunny California.

So, Don Walterman (who has recently moved out West) and I
are organizing the West Coast Sinclair Show.  This show will
encompass all Sincliar computers with most of the vendors
covering the QL and Z88, but we hope to have something of
interest to all Sinclair users.  At the moment the show is
only in the planning stages.  We are worried about getting
enough people to attend to make it work having a show.  We
would like to get about 20-30 people to show.

Here is what is being planned.  The show will be in Union
City, CA, on the east side of the San Francisco Bay, about
half way between Oakland and San Jose.  The show will be
held in the Mehran Banquet Hall, a store front used by a
Pakistani restaurant next door.  The Banquet Hall is within
walking distance of the Union City BART station (local
commuter rail) and only about 2 miles off I-880.  The show
will be held on 5 June.  For those coming from out of the
Bay Area, the South Hayward Motel 6 is the motel of choice.
It has a Denny's and McDonalds on the premisis and has a
Taco Bell within walking distance.  The motel has bus access
to the Union City BART station (and then to the show site).
The night before the show, I plan to have a Bar-B-Q at my
house (about 1.25 miles from the motel).  I'll supply the
hamburgers, hot dogs, chips, and soda (Jochem, there will be
2 kinds of Root Beer). 

For any Europeans coming to the show, I'm offering a limited
tourist service.  Let me know what you would like to see in
the Bay Area, how you plan to get around, and I will look
into maps, travel directions, and any transit costs.  If you
only know of a general category, say natural history or
aviation, I can provide a list of places of interest.  Since
there will be a week between the two shows, this will allow
plenty of time for sightseeing in the Bay Area.

If you are interested in coming to the show, please let me
know.  I am especially interested in hearing from those on
the West Coast.  I would hate to see most of the attendees
be from Europe.  


AWK

AWK has been ported to the QL by Peter Tillier and is a Unix
language that is used for all sorts of list processing
tasks.  The name comes from the three writers of the
language; Aho, Weinberger, and Kernighan.

AWK works very similar to grep.  For each line of input, it
searches for a given pattern.  If the pattern matches, then
an action is performed.  If there is no search pattern, then
it is assumed to match and the action is performed.  This is
the formal definition of what AWK does, in reality, the code
looks a lot like other languages, and each line usually does
not have a pattern and is therefore executed.  How this all
works will become clearer as you read the code below.

To give an example of how to use AWK, here is something that
I'm using AWK to do.  I keep a list of people that get the
QHJ via e-mail.  In the list is the persons last name, first
name and e-mail address.  From this list I want to generate
a e-mail address only list, for sending an issue, and a list
of people, sorted by last name.

I've created a text file with each field seperated by colons
and each record is a seperate line.  Here is an example
file:

test_data:

     Andrews:Bob:bob@mail.com
     Johnson:Ralph:rj@newmail.com
     Smith:John:john@oldmail.com
     Wilson:Ted:trw@mail.com

The first AWK script will print out only the 3rd field from
each line.  Here it is:

rep1_awk:

     { 
        FS = ":";
        print $3;
      }

And the output is:

     bob@mail.com
     rj@newmail.com
     john@oldmail.com 
     trw@mail.com

Basically all the script does is this: for each line, change
the Field Seperator to be a colon and then print out field
#3.

The second report is a little more complicated.  It will
have a header, then the e-mail addreses, and then a footer
giving a count of the e-mail addresses.  The BEGIN block
will only be executed at the beginning of a program, before
any work is done on the input file.  I'm using the BEGIN
block to print out a header for the report.  There is also
an END block, which will only be executed at the end of the
program.  Here is the 2nd AWK script:

rep2_awk:

     BEGIN {
        print "  Name           E-Mail Address"
        print "---------------------------------"
     }

     { 
        FS = ":"
        printf("%6s %10s    %s\n",$2,$1,$3)
      }

Here is the output:

       Name           E-Mail Address
     ---------------------------------
        Bob    Andrews    bob@mail.com
      Ralph    Johnson    rj@newmail.com
       John      Smith    john@oldmail.com
        Ted     Wilson    trw@mail.com

This time I've decided to use a printf statement, which is
very similar to the C version of printf.  The problem though
is that the output of the names is right justified and there
is too much space between the first and last name.  I want
one space between the first and last name.  Here is a 3rd
AWK script that uses a regular print instead of a printf and
gives me what I want:

rep3_awk:

     BEGIN {
        print "  Name           E-Mail Address"
        print "-----------------------------------"
        count = 0
     }

     { 
        FS = ":"
        print $2,$1,"\t",$3
        count = count + 1
      }

     END {
        print "-----------------------------------"
        print "      Total Addresses = ",count
     }

Here is the output:

       Name           E-Mail Address
     -----------------------------------
     Bob Andrews       bob@mail.com
     Ralph Johnson     rj@newmail.com
     John Smith        john@oldmail.com
     Ted Wilson        trw@mail.com
     -----------------------------------
           Total Addresses =  4

Now if I had to write this program in SuperBasic, I would
first have to write a section that splits out the individual
fields into different string variables.  With AWK it's
automatic and very easy to do.


PERL

Perl is a language that I started playing with back around
1989.  When I started using Perl for a project, a few people
wondered if this was a good idea, given that Perl was a
relatively obcure language and they worried about people
knowing Perl after I left.  Well, Perl has now become THE
language for Unix.  There are over 15 books available on
Perl, a Perl magazine, and many, many web sites.

Perl was designed to be a kitchen-sink language for Unix and
allows the programmer to get the same task done many ways.
Perl is more expansive than AWK and you can get a lot more
done, although some AWK programs will be shorter than Perl.
If you do program in AWK and wish to convert to Perl, there
is a nice AWK-to-Perl program that comes with the Perl
distribution.

To show how different AWK is from Perl, let's use the same
example programs as above, but write them in Perl.  The
first Perl program is the same as the first AWK program.
Note how many more lines it takes in Perl.  I'm sure this
Perl program is not the most optimal, but even an optimal
Perl program would be longer than the 2 line AWK program.
Here is the program in Perl:

rep1_pl:

     #!/usr/bin/perl

     # Read the file into an array
     open(FILE,"test_data");
     @array = ;
     close(FILE);

     foreach $line (@array) {
        @array2 = split(/:/,$line);
        print "$array2[2]";
     }

And the output is:

     bob@mail.com
     rj@newmail.com
     john@oldmail.com
     trw@mail.com

The first line of a Perl program starts with
#!/usr/bin/perl, or something like that.  This is not a partof the Perl program, but is used to tell the Unix shell to
run Perl and feed it the rest of the script.  It is not
needed for the QL version of Perl.

With the second report, I decided to use the 'format'
feature of Perl.  It allows you to define fields so that the
output can be formated into neat columns.  Left and right
justification and the decimal point can be handled for you.
It can take a while to get used to formats, but once you do
you find them usefull for all sorts of tasks.  Here is the
2nd script: 

     #!/usr/bin/perl

     #Define formated output
     format TOP =
       Name              E-Mail Address
     ------------------------------------------
     .

     format STDOUT =
     @<<<<<<<<<<<<<<<<<   @<<<<<<<<<<<<<<<
     $name, $email
     .

     format BOTTOM =
     ------------------------------------------
        Total Addresss = @<<<<
     $count
     .


     # Read the file into an array
     open(FILE,"test_data");
     @array = ;
     close(FILE);

     $^ = TOP;
     $~ = STDOUT;
     $count = 0;

     foreach $line (@array) {
        @array2 = split(/:/,$line);
        $name = $array2[1]." ".$array2[0];
        $email = $array2[2];
        write;
        $count = $count + 1;
     }

     $~ = BOTTOM;
     write;


       Name              E-Mail Address
     ------------------------------------------
     Bob Andrews          bob@mail.com
     Ralph Johnson        rj@newmail.com
     John Smith           john@oldmail.com
     Ted Wilson           trw@mail.com
     ------------------------------------------
        Total Addresss = 4


As another example, here is a program that I wrote to figure
out the odds on die rolls.

#!/usr/bin/perl
#
# dice_pl
#
# This program determines the percentages in rolling X
number
# of Y sided dice.  The simplest approach to doing this is
# to do a something like this (for 2 6-sided die):
#
#      FOR x = 1 to 6
#         FOR y = 1 to 6
#            roll = x + y
#         NEXT y
#      NEXT x
#
# But this means that the number of dice used is hard coded
# into the program.  This programs approach is like an 
# odometer.  An array is used that is equal to the number of
# die used.  The first die is incremented and each other 
# die is incremented when the one next to each reaches 7
# (still using the 2 6-sided die example).
#
# Here is a visual diagram:
#
#   ------------------------
#   |  1  |  1 |  1  |  1  |
#   ------------------------
#
#  Once the first "die" hits 7, it goes back to 1 and the
#  "die" next to hit rolls over to 2.  This continues until
#  all possible combinations have been made.
#
#  Output is :
#     Die Roll  -  the value of the die.
#     Possible  -  how many times this die roll can occur.
#     % of Roll -  Percentage of total rolls that this roll
#                  can occur.
#     To-Hit %  -  Percent chance of making rolling this
number
#                  or less.

 
format top =

Die Roll  Possible   % of Roll     To-Hit %
--------------------------------------------
.

format STDOUT = 
@###       @###       @###.##       @###.##
$x,$rolls,$indper,$totper
.

die "Usage: dice.pl die_sides num_die\n" if @ARGV < 2;

$num_die = $ARGV[1];
$sides   = $ARGV[0];

print "\n     Roll of $num_die $sides-Sided Die\n";

# set all dice to 1
for ( $x = 1; $x <= $num_die; $x++) {
    $array[$x] = 1;
}

$array[1] = 0;

for ( $y = 1; $y <= $sides**$num_die; $y++ ) {
    #Increment the first die
    $array[1] = $array[1] + 1;
    $total = 0;

    # Go through each die and see if they need to "rollover"
    # then calculate total of dice.
    for ($x = 1; $x <= $num_die; $x++) {
        if ( $array[$x] == $sides+1 ) {
           $array[$x] = 1;
           $array[$x+1] = $array[$x+1] + 1;
        }
        $total = $total + $array[$x];
    }
   
    $total_array[$total] = $total_array[$total] + 1;

}

# Report Section
# Output is
#      - Die Roll Of  (total of dice)
#      - Number of Times Possible
#      - % of that Roll
#      - % of To-Hit number

$total = 0;

for ($x = $num_die; $x <= $sides*$num_die; $x++) {

    $rolls = $total_array[$x];
    $indper = ($total_array[$x]/$sides**$num_die)*100;
    $total = $total + $total_array[$x];
    $totper = ($total/$sides**$num_die)*100;
    write;

#    print("Die Roll of $x,$total_array[$x], $temp1,
$temp2\n");
}

When using Perl, remember that there is no "shell" in QDOS.
In the standard Perl use, there are a couple of different
ways to have Perl run an OS command, like DEL in MS-DOS or
'rm' in Unix.  To do this, Perl executes the operating
system shell and passes to it the command to execute.  This
works for real executables or internal shell commands.  In
QDOS these "shell" calls work out to be really nothing more
than an EXEC, or EXEC_W call.  There is no way to have Perl
run a QDOS/SuperBasic imbedded command, like 'wdir'.

Here is an example:

     system("ls");

This works out the the QDOS command of:

     EXEC_W ls

The Perl command:

   system("unzip file_zip");

works out to the QDOS command of:

     EXEC_W unzip;"file_zip"

So if the following Perl command:

     system("dir flp1_");

works out to the QDOS command of:

     EXEC_W dir;"flp1_"

which is invalid.  

On the QL, the back tick character is really the Pound
Sterling symbol (which, for portablilty reasons I won't show
here).  This means that if you take a Perl program written
on another system and bring it to the QL, all of the back
tick characters will show up as the Pound Sterling
character.  This also means that if you are writting a Perl
program on the QL, use the Pound Sterling character and it
will be treated as a back tick.  Since the two characters
have the same ASCII value, you don't need to worry about
converting, by hand, the two characters, as it will happen
automatically.

Where this is important in Perl, is in the following
command:

     @array = `ls bin*`;

Having a string in back ticks (versus single or double
quotes), tells Perl to execute what is in between the back
ticks.  This is the same convention used in the Unix C Shell
scripting language.  

If you are looking for books on Perl, remember that Perl for
QDOS is Perl Version 4 and most books deal with Perl Version
5.  The first edition of "Programming Perl" and "Learning
Perl" (red binding) dealt with Perl Version 4.  There are
some major changes between Perl 4 and Perl 5, including some
syntax changes in common functions.


THE SHELL

While on the subject of Unix languages, Adrian Ives has
continued the work of P. J. Taylor with The Shell, a command
line shell for QDOS.  Given my Unix background, I would say
that The Shell is similar in functionality to Unix shells
(C, Bourne, T, Korn).  The Shell considers commands to be
programs to execute and handles command line arguments in
the standard way.  Pipes are created with the pipe ( | )
symbol, and executing programs in the background (like EXEC)
is done with the ampersand ( & ).

Given that 'grep' is available from the C68 distribution,
'wc' comes with the GNU Text Utilities distribution, and
that 'ls' is available with The Shell, you can execute the
following command line in The Shell:
     ls | grep _txt | wc -l

Another nice thing about The Shell is the way it handles
directories.  It treats level 2 directories as real
directories.  You can 'cd' to a directory, run 'ls' and see
only those files in the directory.  You can also 'cd /bin'
or 'cd ../man'.  The Shell understands both the MS-DOS and
Unix directory slashes.

The Shell also handles files with dots/periods in it
(file.txt).  So, if you are doing a lot of bringing programs
over from other environment and have lots of file with dot
extensions, The Shell is handles the files without having to
put the files in quotes.

The Shell version 1.10 is available from Adrian Ives web
page:

     www.angelfire.com/ab/4fac/

    Source: geocities.com/svenqhj