Date: Fri, 22 Jan 93 15:10:58 -0500
From: "swensotc@ACQ" <swensotc@calando.acq.osd.mil>
Subject: QL Hacker's Journal #12
To: distribution:;@calando.acq.osd.mil (see end of body)

           Q L  H A C K E R ' S  J O U R N A L
----------------------------------------------------------
   Number 12                               Jan 1993
----------------------------------------------------------

   The QL Hacker's Journal (QHJ) is an amateur publication
published by Tim Swenson strictly as a hobby and as a
service to the QL Community.
   The QHJ is copyright by Tim Swenson and respective
contributers, but may be freely copied and distributed
(please do) to all QL users.
   The QHJ is always interested in article submissions.
If interested, please send mail to the address below
(Snail Mail or E-Mail).
   Electronic copies of the QHJ are available on disk
or via e-mail from:

        QL Hacker's Journal
            c/o Tim Swenson
        4773 W. Braddock Rd. #3
        Alexandria, VA 22311
        (703) 820-6657
        swensotc@calando.acq.osd.mil
        tswenson@dgis.dtic.dla.mil
         (Be aware that my address will be changing soon)

>From The Editor

   This issue is a smaller than I'd like.  As the new owner
of a Z88 I've been spending time playing with it.  Not
being good a soldering, I took me a while to make some
cables for it.  Plus, having a bad soldering pencil did not
help matters.

   This will be the last issue before I move to Dayton,
Ohio.  I now plan to move in mid-February.  Once I get
established I'll put out another issue with my new mailing
address on it (both e-mail and snail mail).

   Note to code submiters (what few there are):  When
submitting source code to the QHJ, remember that the line
length of the QHJ is 60 chars.  It would be appreciated if
your source code came formated that way.


QL to Z88 Data Transfer
   By Tim Swenson

   As the new owner of a Cambridge Z88 laptop, I needed a
way to transfer  files to and from the QL.  I did not have
enough memory to use Z88COM and I wanted to use the built
in Import/Export utility.

   Transfering files from the Z88 to the QL was easy.
Enter COPY SER2 TO RAM1_FILE_EXT, connect the Z88 on SER2,
and have the Z88 send the file.  Once the Z88 was done,
I'd just hit CTRL-SPACE to break the COPY.  Getting files
to the Z88 would be more difficult.

   A direct copy would not not work.  I was able to get a
SuperBasic  program from Dave Bennett that sort of worked.
I found that I had to  open the serial port as SER2IR.  I
did see that the program has a PAUSE  between sending
characters.  Since SuperBasic does not have a byte  input
command, the program would read in a string at a time
(ended  with a LF).  But files with no LF would cause
problems.  Time to move to C.

   The C program is fairly simple.  My first version only
prompted for a file name, the later version added the
ability to set the baud rate and convert all LF's to CR's
(the Z88 uses Cr's for EOL's).  Once the serial port is
opened right, the file is opened and, byte by byte, is
sent to the Z88.  I tried the program with out a pause
between bytes, but it did not work, hence the FOR loop for
a pause.

   In keeping with the Z88 Import/Export protocal, I send
an ESC for end of file and ESC for end of batch.  If the
file came from the Z88 it has the filename in the file.
One can then send the file to the Z88 in batch mode without
telling the Z88 what the file name is.  If it's not needed,
the ESC's will go to the bit bucket.

   The program was written for Small-C but should compile
fine with C68 with only a few modifications.

/* File:     QLtoZ88_c
   Author:   Timothy Swenson

   Send files to the Z88 from the QL

   This program will send any file to a Z88.
   It has an option to translate all Line Feeds (LF)
   (QL End-Of-Line markers) to Carriage Return (CR)
   (Z88 End-Of-Line markers).

   At the end of each file it will send an End Of File
   escape command.  It will the send an End of Batch
   escape sequence. Since Z88 files store the filename
   with in the file (when transfered out of Import-
   Export) the Batch Recieve can be used to send a
   file without explicitly telling the Z88 the
   filename.

*/

#define  TRUE    1
#define  FALSE   0
/* #define  CR      13  defined in STDIO_H */
/* #define  LF      10  defined in STDIO_H */
#define  ESC     27

#include <stdio_h>

main() {
   char  c, file[30];

   int   i, convert, baud_rate, fd1, fd2;

   printf("      QL To Z88 \n");
   printf("        By Tim Swenson\n\n");
   printf("Enter Input File Name : \n");
   gets(file);

   fd1 = fopen(file,"r");
   if (fd1 == NULL)  {
      printf("Did not open file: %s",file);
      abort(1);
   }

   printf("\nConvert LF to CR? (Y/N)");
   getchar(c);
   convert = FALSE;    /* default */
   if ( c == 'Y' || c == 'y' )
       convert = TRUE;

   printf("\nSelect Baud Rate: \n");
   printf("     1 -   300\n");
   printf("     2 -  1200\n");
   printf("     3 -  2400\n");
   printf("     4 -  9600\n");
   printf("Default of 1200\n");
   getchar(c);
   baud_rate = 1200;    /* default */
   if ( c == '1' )  baud_rate = 300;
   if ( c == '2' )  baud_rate = 1200;
   if ( c == '3' )  baud_rate = 2400;
   if ( c == '4' )  baud_rate = 9600;

   fd2 = fopen("ser2ir","w");
   if (fd2 == NULL) {
      printf("Could not open Serial 2\n");
      abort(1);
   }
   baud(baud_rate);

   while (( c = getc(fd1)) != EOF) {
          if ( convert == TRUE && c == LF )
             putc(CR,fd2);
          else
             putc(c,fd2);

          /* Pause in sending */
          for ( i = 1; i < 500; i++)
                 ;
   }

/* Send ESC E to signal End of File */
/*    ( Z88 Protocal ) */
   putc(ESC,fd2);
   putc('E',fd2);

/* add another pause */
   for ( i = 1; i < 500; i++ )
           ;

/* Send ESC Z to signal End of Batch */
   putc(ESC,fd2);
   putc('Z',fd2);

   fclose(fd1);
   fclose(fd2);
}

   One small problem with Z88 ASCII files on the QL was the
fact that the Z88 used CR instead of LF to mark EOL.  I
wrote a very short program that will read in a file, convert
all instances of CR to LF and output the file.  It's fairly
trivial but I've added here for the beginning C users out there.

/* File:     CRtoLF_c
   Author:   Timothy Swenson

   Converts all CR's to LF's

   This program will take a file that came
   from the Z88 with CR's for End-Of-Line
   markers and convert them to LF's (QL
   End-OF-Line markers).

*/

/* #define  CR      13  defined in STDIO_H */
/* #define  LF      10  defined in STDIO_H */

#include <stdio_h>

main() {
   char  c, file[30];

   int   fd1, fd2;

   printf("Enter Input File Name : \n");
   gets(file);

   fd1 = fopen(file,"r");
   if (fd1 == NULL)  {
      printf("Did not open input file: %s",file);
      abort(1);
   }

   printf("Enter Output File Name : \n");
   gets(file);

   fd2 = fopen(file,"w");
   if (fd2 == NULL) {
      printf("Could not open output file: %s\n",file);
      abort(1);
   }

   while (( c = getc(fd1)) != EOF) {
          if ( c == CR )
             putc(LF,fd2);
          else
             putc(c,fd2);
   }

   fclose(fd1);
   fclose(fd2);
}


MacPaint File Printing
   By Don Walterman

   Don Walterman has sent a program that reads a MacPaint
file and prints to an HP Deskjet printer.  Don claims that
this is his first C program.  If so, it's very ambitious.

   Don did not send an article describing his program, so
I'll present it as is.

   For formatting reasons, comments are below the lines that
they apply to.  I've inserted ^'s to emphasise the point.

/* Print_Mac305_c
   Author: Don Walterman
*/

char _PROG_NAME[] = "Print Mac";

#include <stdio_h>
#include <qlib_h>

#define  ESC  27
#define  FF   12

char macfile_name[50],answer,i;
unsigned short int bits,repeat_count,single_count,byte;
unsigned short int dot_column,single_byte,line_count;
long   tty_wait = 0;

FILE *mac_file, *printer;

main()
{
   if((tty_wait = isatty( fileno( stdout ))) &&
    !isnoclose( fileno(stdout )))
   {
      struct QLRECT rect;

      rect.q_width = 512;
      rect.q_height =200;
      rect.q_x = rect.q_y = 0;
      tty_wait = getchid( fileno(stdout) );
      sd_wdef( tty_wait, -1, RED_M4, 1, &rect);
      sd_clear( tty_wait, -1);
   }

   printf("Enter the readmac file to print \n(including the
    device name).   ");
   scanf("%s" , macfile_name);

   if ((mac_file = fopen(macfile_name,"r")) == NULL) {
      puts("\ncan't find file...please check disk and
       try again\n ");
      printf("System error returned..... %d %s", _oserr,"
       \n");
      if(tty_wait) {
         printf("Press any key to continue\n");
         io_fbyte( tty_wait, -1, &i);
      }
      main();
   }
   fseek(mac_file,640,SEEK_SET);
   /* ^ set file pointer to start of picture data  */

   printer = fopen("SER1","w");
     /* ^ open SER1_ for printing   */
   fprintf(printer,"%c%s", ESC, "*b0M");
     /* ^ select full graphics mode  */
   fprintf(printer,"%c%s", ESC,"*t75R");
     /* ^ select 75 dpi resolution   */
   fprintf(printer,"%c%s", ESC,"&a0C");
     /* ^ set printer's cursor to leftmost position */
   fprintf(printer,"%c%s", ESC,"&a+112H");
     /* ^ center the image on the page */
   fprintf(printer,"%c%s", ESC,"*r1A");
    /* ^ start printing at current printer(cursor)
     position */

   dot_column = 0;
   line_count = 0;

   fprintf(printer,"%c%s", ESC,"*b72W");
     /* ^ print 576 dots per line (standard Mac screen
      width)  */
     /* 72 dot_columns x 8 bits per dot_column        */
   do {
      byte = fgetc(mac_file);
      if (byte > 184 && byte < 256)
      {
         repeat_count = 257 - byte;
         byte = fgetc(mac_file);
         do {
            fputc(byte , printer);
        /* ^ this routine prints out the repeating data
         bytes  */
            dot_column++;
          /* ^ the first byte tells how many times to
           repeat the */
            if(dot_column > 71)
          /* ^ next byte    */
            {
               fprintf(printer,"%c%s", ESC,"*b72W");
               dot_column = 0;
               line_count++;
               update();
            }
            --repeat_count;
         } while (repeat_count > 0);
      }
      else {
        /* ^ this routine prints out the non-repeating  */
      if (byte < 128)
       /* ^ graphics bytes. the first byte tells how many */
      { /* non-repeating bytes follow                    */
         single_count = 0;
         do {
            single_byte = fgetc(mac_file);
            fputc(single_byte , printer);
            dot_column++;
            if(dot_column > 71)
            {
               fprintf(printer,"%c%s", ESC,"*b72W");
               dot_column = 0;
               line_count++;
               update();
            }
            single_count++;
         } while(single_count < (byte+1));
      }
   }

} while(!feof(mac_file) && (line_count < 720));
   /* ^ jump out at end of file  */
   /* the screen is 720 lines so skip the garbage   */
   if(dot_column < 72)
   /* ^ the file may have appended from the file transfer */
   {
      do {
      /* ^ this routine finishes off whatever graphics   */
         byte = 0;
      /* ^ line is started so that the next two commands */
         fputc(byte , printer);
     /* ^ are not mistaken for graphics data   */
         dot_column++;
      } while(dot_column < 72);
   }

   fprintf(printer,"%c%s", ESC,"*rB");
    /* ^ tell DeskJet end of graphics data */
   fprintf(printer,"%c", FF);

   fclose(printer);
   fclose(mac_file);

   printf("\nPrint another Readmac file ?  ");
   if(getchar() == 89 | getchar() == 121)
    /* ^ if 'y' or 'Y' start over      */
   {
      main();
   }
}
update()
{
   sd_pixp( tty_wait, -1,10,20);
   printf("printing line %d %s", line_count, "of 720
    lines....\n");
}


Maze Solution with CA
   By Tim Swenson

   I've been playing with Cellular Automata (CA) since
College. (See QHJ #4 for a more indepth discussion of CA)
I've seem some articles that talk about how CA can be used
in Physics and Chemistry to simulate various chemical
reactions and particle simulations.  I have not seen any
fairly practical applications that can be easy demonstrated
to show how useful CA can be.

   That was before I read an article in the most recent
issue of "Dr Dobb's Journal."  Basem Nayfeb of Stanford
University gives a fresh approach to finding the solution
to a maze.

   Past algorithms for solving mazes were brute force
approaches to solve the maze just like a mouse.  Be
recursivly searching all possible paths the solution will be
eventually found.  This takes time and lots of memory for
stack space.  Basem Nayfeb used CA to solve the problem with
no extra extra memory needed.

   Given a maze stored in an array.  Cells with a wall have
a value of 1, free cells are 0.  In the maze possible moves
are north, west, east, and south.  This translates to a
neighborhood of the 4 cells that share a side with a cell.
Basem defines a counting rule that states:  A free cell will
become a wall cell if there are three or more walls in its
neighborhood.  The only cells that have 3 or more walls
nearby are obviously dead-ends.  Over time all dead-ends
will convert to walls and only the true path(s) will stay
free of walls.

   By defining a simple neighborhood and that one simple
rule, Basem has defined a CA that will fairly quickly find
the solution to the maze.

   Below is the a SuperBasic program that implements the
algorithm.  You can see how short and simple it is.
Consider how much code it would take to solve the problem
the recursive way.

** Maze_ssb
**   Tim Swenson
**
**   Based on an algorithm by Basem A. Nayfeb
**    Dr Dobb's Journal  January 1993
**

wall = 1
free = 0

** My example maze is 16x16.  Change
**  to what ever you need.
maze_x = 16
maze_y = 16

DIM maze(maze_x,maze_y)

read_file
display

REPeat loop
   eval
   dislay
   IF change = 0 THEN EXIT loop
END REPeat loop


DEFine PROCedure read_file
  OPEN_IN #4,flp1_maze_data
  FOR y = 1 TO maze_y
    INPUT #4,in$
    FOR x = 1 TO maze_x
      maze(x,y) = in$(x)
    END FOR x
  END FOR y
  CLOSE #4
END DEFine read_file

DEFine PROCedure eval
  LOCal count

   change = 0
   FOR y = 2 TO maze_y-1
      FOR x = 2 TO maze_x-1
         count = 0
         IF maze(x,y+1) = wall THEN count=count+1
         IF maze(x+1,y) = wall THEN count=count+1
         IF maze(x,y-1) = wall THEN count=count+1
         IF maze(x-1,y) = wall THEN count=count+1
         IF count >= 3 THEN
            maze(x,y) = wall
            change = 1
         END IF
      END FOR x
   END FOR y

END DEFine eval

DEFine PROCedure display

   CLS
   FOR y = 1 TO maze_y
      FOR x = 1 TO maze_x
         IF maze(x,y) = wall THEN
            PRINT "*";
         ELSE
            PRINT " ";
         END IF
      END FOR x
      PRINT
   END FOR y
   PAUSE 4E4
END DEFine display

   Here is an example data file that I used in my testing of
the program:

1111111111111111
1000000010000101
1010111010110101
1010101010110101
1010101010110101
1010101010111101
1110101010110001
0000101000110100
1110101010110101
1010101010110101
1010101010110101
1010101010110101
1010100010110101
1011111110111101
1000000000000001
1111111111111111


QHJ Index

   Here is a listing of issues and articles for the first
two years of the QHJ.  Use as a quick reference to find what
issue a particular article is in.

QHJ #1  -  January 1991
   Structured SuperBasic
   Ratcliff/Obershelp Pattern Matching
   The Quebec Link
   Pursuit of a PD C Compiler
   Minix on the QL

QHJ #2  -  February 1991
   Find_c
   DiskInfo_bas
   C Beautifier

QHJ #3  -  April 1991
   Herb Schaaf's Small C Programs
   File Comparison
   Real Windows for SuperBasic
   C Compiler Comparison

QHJ #4  -  July 1991
   Rand_c
   Cellular Automata
   Iterated Function Systems

QHJ #5  -  August 1991
   News
   The Dutch Connection
   QHJ Print Formatter
   QROFF Postscript Formatter
   2D Arrays in Small C

QHJ #6  -  November 1991
   Italian Software
   Dutch Connection II
   RPN Calculator
   Substring Searching in C
   Levenstein Distance
   QDOS Rights
   Compiler Benchmarks

QHJ #7  -  January 1992
   Core Wars
   QLPatch
   The German Connection
   New QL

QHJ #8  -  March 1992
   ASCII Dump
   Check Bits for ASCII Files
   ANSI C to K&R C
   Strip_c

QHJ #9  -  June 1992
   New Public Domain/Freeware QL Software
   Software Engineering and OOPS on the QL?
   Random Dot Stereograms
   Infix to Postfix
   Fletcher's Checksum

QHJ #10  -  September 1992
   Programmer's Bookshelf
   Maus.sys.ql
   PGM & PBM to QL

QHJ #11  -  November 1992
   C68 Version 3.03
   Disk Eraser
   Random ASCII Stereograms
   LZW Compression
   Token Reconstruction



%%% overflow headers %%%
To: 100031.2312@compuserve.com, 70004.75@compuserve.com,
        70313.3522@compuserve.com, 71071.462@compuserve.com,
        71157.745@compuserve.com, 71650.605@compuserve.com,
        72047.2774@compuserve.com, 72267.3572@compuserve.com,
        72466.3716@compuserve.com, 73270.1444@compuserve.com,
        74405.1244@compuserve.com, 74435.135@compuserve.com,
        75206.1565@compuserve.com, 9021973@ul.ie, ac959@cleveland.freenet.edu,
        adamd@rhi.hi.is, agulbra@siri.unit.no, akayser@dnpap.et.tudelft.nl,
        andreas_bloetscher@bb.maus.de, beppe@alessia.dei.unipd.it,
        bj@cs.tu-berlin.de, bolli@matai.vuw.ac.nz, chris@bcl.co.nz,
        cs89ssg@brunel.ac.uk, dhembrow@eoe.co.uk, Dirk_Kutscher@hb2.maus.de,
        flight@vogon.mathi.uni-heidelb, gaylord@shannon.ee.wits.ac.za,
        geisler@namu01.gwdg.de, georg@bluemoon.gun.de,
        grimbert@aedi.insa-lyon.fr, groot@idca.tds.philips.nl,
        Hans_Hoelscher@hb.maus.de, hclase@morgan.ucs.mun.ca,
        henne@eana.f3.gmd.dbp.de, hlschaaf@brahms.udel.edu,
        j.c.vanderwal@research.ptt.nl, jeroen@cs.few.eur.nl,
        jfsenior@vax1.tcd.ie, jk@zarniwoop.pc-labor.uni-bremen.de,
        jmooring@mswe.dnet.ms.philips.nl, johnl@master.qpsx.oz.au,
        klamer@mi.eltn.utwente.nl, lorenz@alessia.dei.unipd.it,
        lsg001@cck.cov.ac.uk, martin@chemeng.ed.ac.uk,
        mauricio@gauss.aero.ufl.edu, mbppxgf@cms.mcc.ac.uk,
        mcj@moose.cccs.umn.edu, peter@opusc.csd.scarolina.edu,
        pfoley@cavebbs.welly.gen.nz, qltwirl@matai.vuw.ac.nz,
        Ralf_Tenbrink@bn.maus.de, rcarter@isis.cs.du.edu, rdw@ukc.ac.uk,
        rohde@namu01.gwdg.de, s.telford@ed.ac.uk, sander.plomp@cwi.nl,
        seje890@ucl.ac.uk, srwmpnm@wnv.grace.cri.nz, swh@eatl.co.uk,
        ts@uwasa.fi, UDAH054@oak.cc.kcl.ac.uk, umisef@mcshh.hanse.de,
        v882022@si.hhs.nl, wahl@ocf.berkeley.edu, woodman@bnr.ca,
        ztsindi@ubvmsb.cc.buffalo.edu, cc201jja01@trent-poly.ac.uk,
        dnash@chaos.demon.do.uk, ipi@cernvm.bitnet, dup@vax.ox.ac.uk,
        71071.462@compuserve.com, jockneyj@cs.man.ac.uk
%%% end overflow headers %%%
