
                         NEWAPP and DOSLIB

                         *** IMPORTANT ***

NEWAPP.SCR and DOSLIB.SCR are subject to change (really!)  There is
no guarantee - or intent - that future versions will remain backward
compatible.  When backing up or distributing application source code
that uses DOSLIB.SCR, it is important to include a copy as newer
versions of DOSLIB may no longer be compatible.

                           Introduction

NEWAPP is a skeletal program that allows users to quickly develop a
DOS application.  It provides often needed tasks including error
handling, command-line parsing, file operations, buffered I/O, help
screen, number and string functions.

NEWAPP comprises two parts:

  NEWAPP.SCR   skeletal main program
  DOSLIB.SCR   function library

NEWAPP is supplied as a functioning program which may be turnkeyed.
Styled as a typical DOS command-line application it demonstrates
how the various tasks are integrated to form a functioning program.
Making NEWAPP perform a useful task can be as easy as adding one
line.  In this instance it is line 6 of the definition (RUN) which
turns NEWAPP into a simple filecopy utility.

DOSLIB is a library of Forth and DOS functions in source form.
While the primary role is support for NEWAPP, DOSLIB may be used
by any application.  DOSLIB is organized as named modules.
1 FLOAD DOSLIB  loads the names of all the modules contained in
DOSLIB into the dictionary.  Executing the name of a module
loads the code for that module into memory.  NEWAPP automatically
loads DOSLIB and a default set of modules.

New users are encouraged to examine and understand how NEWAPP works
before attempting to create their own application.  The following
notes should help with some of the less obvious aspects.  Unless
otherwise stated screen references (numbered 0 onwards) refer to
NEWAPP.SCR.

First, an explanation of the function +IS which is used by NEWAPP.
+IS is similar to IS but instead of replacing the existing behaviour
of a DEFERed word, it appends a new action.  When the deferred word
is eventually executed, all actions in the chain will be performed
beginning with the most recently added.

1. Setting the options

   Screen 1 defines the title of the program, version, date and name
   for the turnkey executable.

   The programmer may optionally set the upper LIMIT of memory for
   turnkey applications (Screen 1 line 10).  The calculation assumes
   256 bytes for PAD and data stack, plus any bytes TALLY'd at
   compile-time.  Typically TALLY holds the total number of bytes the
   program will ALLOT or otherwise consume at run-time.  By default
   LIMIT is set to the maximum available memory i.e. the compiler's
   top of memory address (usually $FFF0 for MS-DOS or CCP/BDOS base
   for CP/M).

   Screen 2 loads the remainder of the application.  It also defines
   and sets the action for several deferred words which are explained
   below.

   ONSTART is a deferred word.  Its function is to perform any system
   initialization that may be required before the application begins.
   Typically these will be "run once" tasks such as alloting buffers
   or initializing memory management functions.  Actions are appended
   to ONSTART with +IS.

   CON-IO is a deferred word that sets the console input/output method.
   By default CON-IO is set to BIOS-IO.  Users needing DOS console I/O
   redirection can do so either by selectively surrounding words with
   DOS-IO ... CON-IO  pairs or by uncommenting the line:
   ' DOS-IO IS CON-IO.

   The DOSLIB disk read/write routines include a halt check.  If ESC
   CTRL-C or CTRL-BREAK keys are detected, the user is given the option
   to abort the program.  The feature may be disabled by commenting out
   the line: ' ?STOPKEY IS ?STOP.

   ONERROR is the application's top-level error handler.  It intercepts
   exceptions before the system's error handler deals with it.  ONERROR
   permits applications to perform any necessary 'clean-up' tasks before
   aborting.

   ONERROR is a deferred word whose action is modified with +IS.  An
   example is the DOSLIB files module which extends ONERROR to
   automatically close the default files should an error occur.

   Note: In general, functions executed by ONERROR should *not* be
   permitted to generate an exception as this will mask the original
   exception.

2. Loading DOSLIB modules

   Screen 3 of NEWAPP.SCR initializes the DOSLIB library then proceeds
   to load the named modules.  This screen contains the support modules
   typically needed by NEWAPP based applications.  If your application
   does not require a particular module and you wish to conserve space,
   then you may comment out the line on which the module's name appears.

3. Default files

   The default files module simplifies much of the drudgery associated
   with file handling e.g. display of filenames when opening, overwrite
   checking, error messages when reading or writing files etc.

   Handles for one input and one output file are supported which is
   sufficient for most applications.  The usual read/write functions
   are provided including file position and reposition.  Output file
   overwrite checking is enabled by default.  It may be turned off by
   uncommenting the line:  WRTCHK OFF  on screen 2.

   When an application aborts as a result of a fatal error, the default
   files will be automatically flushed and closed.  Optionally the
   default output file can be deleted on error by uncommenting the
   following line on screen 2:  ' DELOUTFILE +IS ONERROR

   FLUSHWRITE is a deferred function that works similarly to FLUSH-FILE.
   Data written to the default output file is forced to disk updating
   the directory.  Buffered output, if loaded, is also flushed.

4. Additional handles

   Additional file handles are created with the HANDLE command.  A
   simple example and usage is shown below.

   HANDLE PRNFILE                          \ create handle and name
   S" outfile.prn" PRNFILE !FNAME          \ assign a filename
   W/O PRNFILE (FMAKE)                     \ create disk file
   S" sample data" PRNFILE >FID FWRITELN   \ write some data
   PRNFILE FCLOSE DROP                     \ close handle

   Operations on new handles are performed using DOSLIB file commands.
   FOPEN (FOPEN) FMAKE (FMAKE) (?FMAKE) FCLOSE will require a file
   handle; whereas FREAD FWRITE FREADLN FWRITELN FPOS FREPOS FSIZE
   FRESIZE require a file-id (FID).  >FID takes a file handle and
   returns the file-id (-1 = file closed).  Additional handles can be
   automatically closed by adding them to CLOSEFILES e.g.

   : CLOSEPRNFILE ( -- )  prnfile fclose drop ;

   ' closeprnfile +is closefiles

5. Buffered files

   READCHAR and WRITECHAR functions are optional extensions to the
   default files which allow reading/writing data one character at a
   time.  For speed, buffers are used to hold the data.  Buffer refill
   and flushing is automatic.  FLUSHWRITE may be used to immediately
   flush the output buffer e.g. as a precedent to using WRITEDATA or
   WRITETEXT which write directly to the file.  The values returned by
   INFILEPOS and OUTFILEPOS are automatically adjusted for buffer
   contents.  Similarly REPOSINFILE and REPOSOUTFILE automatically
   reset/flush the buffers respectively and thus may be freely mixed
   with READCHAR and WRITECHAR.

   Default buffer size is 512 bytes and is given by #INBUF and #OUTBUF
   respectively.  For simplicity buffers are allocated at compile-time
   but can be changed to run-time if required as shown below.

   Example: Allocate the buffered output file at run-time and change
   the buffer size to 1024 bytes.

   Make the following changes to the copy of NEWAPP.SCR that will
   become your application.

   Step 1. Disable compile-time buffer allocation by setting #OUTFILE
   to zero prior to loading _Bufoutfile on the electives screen:

     ( modify Screen 3 )
     0 to #OUTFILE  _Bufoutfile      \ buffered output file

   Step 2. To allocate and initialize the output buffer at run-time,
   create a word to perform the function and append to deferred word
   ONSTART:

     ( append to Screen 2 )
     :noname ( -- )  #1024  dup to #OUTFILE  reserve to OUTFILE
     resetoutbuf ; +is ONSTART

   Note: Applications may apply the technique of run-time allocation
   to any large buffer used by the program.  It is useful for keeping
   turnkey executables small and/or allocating buffers that otherwise
   would not fit into memory at compile-time.

