[comp.sys.atari.st] A patch for wildcard expansion and stdout

RDROYA01@ULKYVX.BITNET (Robert Royar) (01/02/87)

The other day I wrote about trouble with wild card expansion on the command
line using the Alcyon runtime library.  Yesterday I spent the entire day
tracking down the problem and discovered a few loose ends in the operating
system and in the startup code.  The problem turned out to be three problems
all related to the spurious trap #2 vector.  The Alcyon library was
originally designed to work with CP/M-68K (note that's 68 not 86 as a number
of Atari users seem to believe).  That OS used trap #2 for all BDOS service
and trap #3 for the BIOS.  Apparently, GEM still uses the trap #2 vector for
some calls to the GSX, but none of these were supported in the original CP/M
system and none are used by gemlib.  The ones that are used by gemlib are
function 2 (conout), function 9 (print string), and 26 (set DMA, really a
set DTA call).  But when these functions go through trap #2, after about 6
branches all over the place, the trap routine simply RTEs.  What this means
is that calls to conout in ttyout.o, calls to print string in ttyout.o and
in xmain.o, and calls to set DMA in xmain.o are all big no ops.  Therefore,
the runtime lib cannot print its own startup error messages.  It cannot find
the names of files it has searched for with the Fsfirst() call (because the
DMA address it set with the set DMA command contains only garbage).  And,
chances are, any attempt to use stdout or any other standard TTY:/CON: file
will fail simply because the routine to output the characters are no ops.
Fixing these problems was relatively simple, rewrite the ___BDOS function in
gemstart.s.  Since the function numbers and parameters are the same (just
the trap vectors differ), all that was needed were some simple comparisons.
Below is the new __BDOS call in my revised gemstart.s:

*
* Surprise, the trap #2 vector is largely a do nothing routine.
* Redirecting the basic calls may help solve a few problems.
*
        .globl ___BDOS

___BDOS:
        link    A6,#-4
        cmpi.w  #9,$8(A6)       * print string
        beq     togem
        cmpi.w  #2,$8(A6)       * conout
        beq     togem
        cmpi.w  #1,$8(A6)       * conin (not called in gemlib)
        beq     togem
        cmpi.w  #26,$8(A6)      * set dma
        bne     bdos            * GSX uses some functions above # $C0
togem:
        move.l  $a(A6),(sp)     * value
        move.w  $8(A6),-(sp)    * function
        bsr     _gemdos
        addq.l  #2,sp
        bra     out
bdos:
        move.l  $a(A6),d1       * value
        move.w  $8(A6),d0       * function
        trap    #2              * Enter BDOS
        cmpa.l  __break,sp      * Check for stack ovf
        bcs     __sovf          * overflow! print msg and abort

out:    unlk    A6              * no error; return
        rts                     * Back to caller

_gemdos:
        move.l  (sp)+,biosret
        trap    #1
        move.l  biosret,-(sp)
        rts

Compiling with this startup file let me get "*.C No match" from the runtime
library as it tried to open all the C files on the drive.  Before the error
would not print.

The next problem is in the gemlib module xopen.o, the function ___open.
This is a low level IO function which is apparently only called to parse
and expand command line file names.  It uses gemdos for all service.  But
the problem in this part of the library is one I have discovered twice
before with the Alcyon library in other functions, an error that is either
a simple typo or one which signals a problem with the code parser.  Since
this error does not occur, or has not yet occurred, in files I've compiled,
I assume it was a typo in the original source, something that could easily
be corrected.  The problem is a `beq' instruction which should have been a
`bne.'  The test occurs twice in ___open, once after Fsfirst() at offset
$ae from the first address of the file and again after Fsnext() at offset
$c8.  In both cases these calls return -1 on error and 0 for success.  But
the code tests for the value in register D0 and if it is equal to 0,
branches to the error exit routine.  Changing the value of that instruction
fixed most of the wild card problems.  Here's how to do that:

1. using ar68, extract xopen.o from gemlib
2. start up sid
3. type r xopen.o at the sid `-' prompt
4. sid responds by reading the file and reporting the start and end addresses
5. type l<the start address sid reports>
6. the very first instruction is a "bra <absolute address>"
7. type l<that absolute address> (now we're alligned on the proper boundary)
8. use the l command to look for a "move.w #$4e,(sp)-" followed by a "jsr $0"
   (this is the search first command)
9. about three instructions down from the jsr is the beq.  Change this to
   a bne using the s command (beq=$67; bne=$66)
10. at offset $1a from the beq is another beq (right after the search next).
   again using the s command, change this to a bne.
11. after both changes are made, write the file by typing "w xopen.o"
12. replace the old xopen.o in gemlib with the new one (ar68 r gemlib xopen.o)

Sid preserves the relocation bits and symbols, so the file will still work
properly.

Now for the last problem.  With this patched gemlib, programs can finally
get at the expanded file lists created by wildcards, except for one
problem.  The search commands read the drive and path name for the files and
return only the name to the dta.  None of the startup routines bother with
paths or drive names (although they do extensive checking to assure they are
correct).  So the program's main() gets a list of file names without the
path or drive appended (again, only if wildcards are used).  It assumes that
these names are for files on the current disk and path, which they may not
be.  So, even though the startup routine has diligently expanded the
wildcards and assured that the files exist, if the logged in drive and
current directory do not match the default drive/directory, main() cannot
open the files.  If the logged in drive/directory does match that used to
expand the wildcards, then everything works OK.

Somewhere in ___main there needs to be code to strcat the drivecode and
directory (supplied on the command line) to the individula filenames before
passing the argv vector to main.  This is not the kind of thing which can
be patched.  So if Alcyon is listening or Atari, perhaps someone with
source could do this for those of us who grew up with command lines,
wildcards and all that hoopla.