gno/bin/gsh/shellutil.asm
tribby 6269a8ca25 Changes for gsh version 2.0d8:
Fixed several mutual exclusion problems, including a particularly nasty
one that would cause gsh to loop forever inside the memory manager. (You
could identify this one by the "BRA (-23)" at the bottom of the infinite
loop.)

Fixed the string vector print routine to properly handle all numbers of
entries in the hash table.  Previously, it would always print duplicate
entries if there were < 6 commands hashed, and would sometimes print
duplicates (depending on previous contents of an internal table) for
other numbers of commands.

gsh would wait on background processes started from an exec file
(executed, not sourced). Now the exec file does not wait on the process,
but the background process is not associated with the parent shell after
the exec file terminates.

Made gsh globbing work more like csh: if none of the requested patterns
are found, print "No match" and exit.

At startup, if /etc/glogin, $HOME/glogin, or $HOME/gshrc does not exist,
don't report a "file not found" error message. (PR#100)
1998-12-31 18:29:14 +00:00

687 lines
11 KiB
NASM

**************************************************************************
*
* The GNO Shell Project
*
* Developed by:
* Jawaid Bazyar
* Tim Meekins
*
* $Id: shellutil.asm,v 1.8 1998/12/31 18:29:14 tribby Exp $
*
**************************************************************************
*
* SHELLUTIL.ASM
* By Tim Meekins
* Modified by Dave Tribby for GNO 2.0.6
*
* Utility functions used by the shell. Mainly string functions.
*
* Note: text set up for tabs at col 16, 22, 41, 49, 57, 65
* | | | | | |
* ^ ^ ^ ^ ^ ^
**************************************************************************
*
* Interfaces defined in this file:
*
* tolower Convert the accumulator to lower case
* {accumulator = character}
* jsr tolower
* {if acc was uppercase it's now lowercase; else no change}
*
* toslash Convert ':' to '/'
* {accumulator = character}
* jsr toslash
* {if acc was ':', it's now '/'; otherwise no change}
*
* lowercstr Convert a c string to lower case
* {push address of c string on stack}
* jsr lowercstr
*
* cstrlen Get the length of a c string
* {push address of c string on stack}
* jsr cstrlen
* {return with len of string in acc}
*
* copycstr Copy one string to another. Assumes an alloccstr has been
* performed on destination.
*
* cmpcstr Compare two c strings. Return 0 if equal, -1 if less than,
* +1 if greater
*
* cmpdcstr Compare two downshifted c strings. Return 0 if equal,
* -1 if less than, +1 if greater
*
* c2gsstr Allocate memory, then convert a c string to a GS/OS string
* (caller must dispose when done)
*
* catcstr Takes two strings, concats into a newly created string.
*
* nullfree Call ~DISPOSE if pointer is not NULL
*
* newlineX Print a carriage return and a newline, unless "newline" shell
* var is set.
*
* getenv Get value of indicated environment variable; pass in addr of a
* GS/OS string, and pass back addr of allocated GS/OS result
* buffer (with null byte added at end).
* subroutine (4:var)
* return 4:ptr
*
* rmemcpy
* subroutine (2:num,4:src,4:dest)
*
**************************************************************************
mcopy /obj/gno/bin/gsh/shellutil.mac
dummyshellutil start ; ends up in .root
end
setcom 60
;=========================================================================
;
; Convert the accumulator to lower case.
;
;=========================================================================
tolower START
cmp #'A'
bcc done
cmp #'Z'+1
bcs done
adc #'a'-'A'
done rts
END
;=========================================================================
;
; Convert ':' to '/'
;
;=========================================================================
toslash START
cmp #':'
bne done
lda #'/'
done rts
END
;=========================================================================
;
; Convert a c string to lower case
;
;=========================================================================
lowercstr START
space equ 1
p equ space+2
end equ p+4
tsc
phd
tcd
short a
ldy #-1
loop iny
lda [p],y
beq done
cmp #'A'
bcc loop
cmp #'Z'+1
bcs loop
adc #'a'-'A'
sta [p],y
bra loop
done rep #$21
longa on
lda space
sta end-2
pld
tsc
adc #end-3
tcs
rts
END
;=========================================================================
;
; Get the length of a c string.
;
;=========================================================================
cstrlen START
space equ 1
p equ space+2
end equ p+4
tsc
phd
tcd
short a
ldy #0
loop lda [p],y
beq done
iny
bra loop
done rep #$21
longa on
lda space
sta end-2
pld
tsc
adc #end-3
tcs
tya
rts
END
;=========================================================================
;
; Copy one string to another. Assumes an alloccstr has been performed on
; destination.
;
;=========================================================================
copycstr START
space equ 1
q equ space+2
p equ q+4
end equ p+4
tsc
phd
tcd
short a
ldy #0
loop lda [p],y
beq done
sta [q],y
iny
bra loop
done sta [q],y
rep #$21
longa on
lda space
sta end-2
pld
tsc
adc #end-3
tcs
rts
END
;=========================================================================
;
; Compare two c strings. Return 0 if equal, -1 if less than, +1 greater
;
;=========================================================================
cmpcstr START
space equ 1
q equ space+2
p equ q+4
end equ p+4
tsc
phd
tcd
short a
ldx #0
ldy #0
strloop lda [p],y
beq strchk
cmp [q],y
bne notequal
iny
bra strloop
strchk lda [q],y
beq done
lessthan dex
bra done
notequal bcc lessthan
inx
done rep #$21
longa on
lda space
sta end-2
pld
tsc
adc #end-3
tcs
txa
rts
END
;=========================================================================
;
; Compare two downshifted c strings. Return 0 if ==, -1 if <, +1 >
;
;=========================================================================
cmpdcstr START
hold equ 1
space equ hold+2
q equ space+2
p equ q+4
end equ p+4
tsc
sec
sbc #space-1
tcs
phd
tcd
ldx #0
ldy #0
strloop lda [q],y
and #$FF
jsr tolower
sta hold
lda [p],y
and #$FF
beq strchk
jsr tolower
cmp hold
bne notequal
iny
bra strloop
strchk lda hold
beq done
lessthan dex
bra done
notequal bcc lessthan
inx
done anop
lda space
sta end-2
pld
tsc
clc
adc #end-3
tcs
txa
rts
END
;=========================================================================
;
; Convert a c string to a GS/OS string (don't forget to dispose when done)
;
;=========================================================================
c2gsstr START
len equ 1
gstr equ len+2
space equ gstr+4
cstr equ space+2
end equ cstr+4
tsc
sec
sbc #space-1
tcs
phd
tcd
pei (cstr+2)
pei (cstr)
jsr cstrlen
sta len
adc #3
pea 0
pha
~NEW
sta gstr
stx gstr+2
incad @xa
incad @xa
pei (cstr+2)
pei (cstr)
phx
pha
jsr copycstr
lda len
sta [gstr]
ldx gstr+2
ldy gstr
lda space
sta end-2
pld
tsc
adc #end-3
tcs
tya
rts
END
;=========================================================================
;
; Takes two strings, concats into a newly created string.
;
;=========================================================================
catcstr START
new equ 1
space equ new+4
q equ space+2
p equ q+4
end equ p+4
tsc
sec
sbc #space-1
tcs
phd
tcd
pei (p+2)
pei (p)
jsr cstrlen
pha
pei (q+2)
pei (q)
jsr cstrlen
adc 1,s
inc a
inc a
plx
pea 0
pha
~NEW
sta new
stx new+2
ldy #0
copy1 lda [p],y
and #$FF
beq copy2
sta [new],y
iny
bra copy1
copy2 lda [q]
and #$FF
sta [new],y
beq done
iny
incad q
bra copy2
done ldx new+2
ldy new
lda space
sta end-2
pld
tsc
clc
adc #end-3
tcs
tya
rts
END
;=====================================================================
;
; call ~DISPOSE if pointer is not NULL
;
;=====================================================================
nullfree START
lda 4,s Hold address
tay parameter in
lda 6,s X and Y registers.
tax
lda 2,s Move return
sta 6,s address on
lda 1,s the stack.
sta 5,s
tya Put address
sta 1,s parameter back
txa on the stack.
sta 3,s
ora 1,s If address is NULL,
bne ok
plx clean up stack
plx
rtl and return to caller.
ok ~DISPOSE NOTE: macro locks/unlocks mem mutex
rtl
END
;=====================================================================
;
; Data area that holds memory manager mutual exclusion key,
; which is referenced in the ~NEW and ~DISPOSE macros
;
;=====================================================================
memglobal DATA
memmutex key
END
;=====================================================================
;
; Print a carriage return and a newline, unless "newline" shell var
; is set.
;
;=====================================================================
newlineX START
using vardata
lda varnewline
beq newline
rts
;=====================================================================
;
; Print a carriage return and a newline
;
;=====================================================================
newline ENTRY
lda #13
jmp putchar
END
**************************************************************************
*
* Quick little routine for reading variables and converting to
* null terminated strings. We could probably just link the Orca/C
* library getenv(), but lets stay Orca-free, after all, that's why this
* is written in assembly! :)
*
* For gsh 2.0: pass in addr of a GS/OS string, and pass back addr of
* allocated GS/OS result buffer (with null byte added at end), not c-strings.
*
**************************************************************************
getenv START
len equ 1
retval equ len+2
space equ retval+4
var equ space+3
end equ var+4
; subroutine (4:var),space
tsc
sec
sbc #space-1
tcs
phd
tcd
lock mutex
;
; Get the variable's length using ReadVariableGS
; Set up parameter block:
mv4 var,RVname Addr of name, from user.
ld4 TempResultBuf,RVresult Use temporary result buf.
ReadVariableGS ReadVar Get length.
;
; Allocate memory for value string
;
lda TempRBlen Get length of value.
bne notnull Return null if 0.
sta retval
sta retval+2
bra exit
notnull inc2 a Add 4 bytes for result buf len words.
inc2 a
sta len Save result buf len.
inc a Add 1 more for terminating null byte.
pea 0
pha
~NEW Request the memory.
sta RVresult Store address in ReadVariable
stx RVresult+2 parameter block and
sta retval direct page pointer.
stx retval+2
ora retval+2 If address == NULL,
beq exit return NULL to user.
lda len Store result buffer length
sta [retval] at beginning of buf.
;
; Read the full value into the allocated memory
;
ReadVariableGS ReadVar
;
; Add null byte at end of text to make it work as a C string
;
ldy TempRBlen Get length of value,
iny4 + 4 (for length words at start)
lda #0 Store zero at end of string.
short a
sta [retval],y
long a
;
; All done.
;
exit unlock mutex
ldy retval
ldx retval+2
lda space+1
sta end-2
lda space
sta end-3
pld
tsc
clc
adc #end-4
tcs
tya
rtl
mutex key
; Parameter block for shell ReadVariableGS call (p 423 in ORCA/M manual)
ReadVar anop
dc i2'3' pCount
RVname ds 4 Pointer to name (passed by user)
RVresult ds 4 GS/OS Output buffer ptr
RVexpflag ds 2 export flag
; GS/OS result buffer for getting the full length of the PATH env var.
TempResultBuf dc i2'5' Only five bytes total.
TempRBlen ds 2 Value's length returned here.
ds 1 Only 1 byte for value.
END
**************************************************************************
*
* Copy src bytes to destination address
*
**************************************************************************
rmemcpy START
subroutine (2:num,4:src,4:dest),0
ldy num Get length of src.
beq done Done if == 0.
tya
dey
bit #1
bne odd
dey
bra lp1
odd short m
lda [src],y
sta [dest],y
long m
dey
dey
bmi done
lp1 lda [src],y
sta [dest],y
dey
dey
bpl lp1
done return
END