gno/bin/gsh/history.asm
tribby e7f2691599 Changes for gsh version 2.0d7:
Fixed several memory leaks.

Prefix command without any parameter (to list the prefixes) would cause
memory corruption when prefix had been invoked previously with a parameter.

Sourcing a command file from within an exec file could cause gsh to
wait forever, depending upon the commands executed in the sourced file.

All built-in commands return appropriate status: 1 for error, 0 for no error.

Fixed several cases where incorrect value was set in $status.

Added usage strings for tset, hash, commands, and history.

Fixed memory corruption error when edit command had no parameters.

When system() is called with pointer = NULL or with a command string that
causes gsh to detect an error (e.g., incompatibility with | and <), return
status of -1. In other cases, return process's status rather than always 0.

System would crash when output from a non-forked command was piped to
another process; for example   clear | cat > /tmp/list
1998-12-21 23:57:08 +00:00

670 lines
10 KiB
NASM

**************************************************************************
*
* The GNO Shell Project
*
* Developed by:
* Jawaid Bazyar
* Tim Meekins
*
* $Id: history.asm,v 1.7 1998/12/21 23:57:06 tribby Exp $
*
**************************************************************************
*
* HISTORY.ASM
* By Tim Meekins
* Modified by Dave Tribby for GNO 2.0.6
*
* Routines for dealing with history buffers.
*
* History Data Structures:
*
* HistoryPtr -> historyRec [HistoryPtr is the most recent history]
*
* Where historyRec is:
*
* [+0] NextHistory: pointer to historyRec
* [+4] HistoryCmd: string of characters
*
* Note: text set up for tabs at col 16, 22, 41, 49, 57, 65
* | | | | | |
* ^ ^ ^ ^ ^ ^
**************************************************************************
*
* Interfaces defined in this file:
*
* InsertHistory
*
* PrevHistory
*
* NextHistory
*
* SaveHistory
*
* ReadHistory
*
* InitHistory
*
* PrintHistory
*
**************************************************************************
mcopy /obj/gno/bin/gsh/history.mac
dummyhistory start ; ends up in .root
end
setcom 60
histNext gequ 0
histCmd gequ 4
;=========================================================================
;
; Add a C string to the head of the history buffer.
;
;=========================================================================
InsertHistory START
using HistoryData
using global
ptr2 equ 0
ptr equ ptr2+4
len equ ptr+4
histvalptr equ len+2
space equ histvalptr+4
subroutine (4:cmd),space
pei (cmd+2)
pei (cmd)
jsr cstrlen
sta len
pea 0
clc
adc #4+1
pha
~NEW
sta ptr
stx ptr+2
ora ptr+2
beq putdone
inc lasthist
inc numhist
lda historyptr ;Set up linked list pointers
sta [ptr]
ldy #histNext+2
lda historyptr+2
sta [ptr],y
mv4 ptr,historyptr
pei (cmd+2)
pei (cmd)
pei (ptr+2)
clc
lda ptr
adc #4
pha
jsr copycstr
;
; Now, find out what the maximum history is and prune to that value
;
putdone anop
;
; Get value of $HISTORY environment variable
;
ph4 #historyStr
jsl getenv
sta histvalptr Save pointer to GS/OS result buffer.
stx histvalptr+2
ora histvalptr+2 If buffer wasn't allocated,
jeq goback all done.
;
; Call Dec2Int to convert value of string into an integer
;
pha Reserve room on stack for result.
lda histvalptr Get pointer to $HISTORY value.
ldx histvalptr+2
clc Add 4 to address to skip
adc #4 over length words.
bcc pushaddr
inx
pushaddr phx Push address onto stack.
pha
ldy #2
lda [histvalptr],y
pha Push length.
pea 0 Push signedFlag = 0 (unsigned)
Tool $280b Dec2Int.
pla Get result.
sta size
beq alldone
;
; Follow linked list until we reach size histories
;
mv4 historyptr,ptr
ldy #histNext+2
follow lda [ptr]
tax
ora [ptr],y
beq alldone ;not enough
dec size
beq prune
lda [ptr],y
sta ptr+2
stx ptr
bra follow
;
; we have enough, start pruning
;
prune lda [ptr]
sta ptr2
lda [ptr],y
sta ptr2+2
lda #0
sta [ptr]
sta [ptr],y ;terminate last history
;
; Dispose remaining
;
dispose lda ptr2
ora ptr2+2
beq alldone
dec numhist
lda [ptr2]
sta ptr
lda [ptr2],y
sta ptr+2
pei (ptr2+2)
pei (ptr2)
jsl nullfree
lda ptr
sta ptr2
lda ptr+2
sta ptr2+2
ldy #histNext+2
bra dispose
alldone pei (histvalptr+2)
pei (histvalptr)
jsl nullfree
goback return
size ds 2
END
;=========================================================================
;
; Places the previous history into the command buffer, called when pressing
; UP-ARROW.
;
;=========================================================================
PrevHistory START
using HistoryData
using global
using termdata
ora2 historyptr,historyptr+2,@a ;If no history, then skip
jeq ctl5a
ldx cmdloc ;Move cursor to beginning of line
jsr moveleft
lda cdcap
ora cdcap
beq ctl5b0
tputs (cdcap,#0,#outc)
bra ctl5g
ctl5b0 ldx cmdlen ;clear line
ctl5b dex
bmi ctl5c
phx
lda #' '
jsr putchar
plx
bra ctl5b
ctl5c ldx cmdlen
jsr moveleft
ctl5g ora2 currenthist,currenthist+2,@a
bne ctl5i ;If not set up for current hist then
lda historyptr+2 ;Set up at start.
ldx historyptr
ldy #2
bra ctl5j
ctl5i mv4 currenthist,0 ;Otherwise move to previous history
stz cmdlen
stz cmdloc
ldy #HistNext+2
lda [0]
tax
lda [0],y
ctl5j sta 0+2 ;Save some pointers
stx 0
sta currenthist+2
stx currenthist
ora 0 ;If ptr is 0 then at end, quit
beq ctl5a
ldx #0 ;Display and store command
iny2
ctl5h lda [0],y
and #$FF
sta cmdline,x
beq ctl5ha
inx
iny
bra ctl5h
ctl5ha stx cmdlen
stx cmdloc
ldx #^cmdline
lda #cmdline
jsr puts
ctl5a rts
END
;=========================================================================
;
; Places the next history into the command buffer, called when pressing
; DOWN-ARROW.
;
;=========================================================================
NextHistory START
using HistoryData
using global
using termdata
ora2 historyptr,historyptr+2,@a ;No hist, then skip
jeq ctl6a
stz 4 ;Walk through linked list searching
stz 4+2 ; for hist prior to last hist.
mv4 historyptr,0
ctl6i if2 0,ne,currenthist,ctl6j
if2 0+2,eq,currenthist+2,ctl6k
ctl6j mv4 0,4
ldy #HistNext+2
lda [0]
tax
lda [0],y
sta 0+2
stx 0
bra ctl6i
ctl6k ldx cmdloc ;Move cursor to left
jsr moveleft
lda cdcap
ora cdcap
beq ctl6b0
tputs (cdcap,#0,#outc)
bra ctl6g
ctl6b0 ldx cmdlen ;clear line
ctl6b dex
bmi ctl6c
phx
lda #' '
jsr putchar
plx
bra ctl6b
ctl6c ldx cmdlen
jsr moveleft
ctl6g stz cmdlen ;Get hist info.
stz cmdloc
mv4 4,currenthist
ora2 4,4+2,@a
beq ctl6a ;Whoops, back to end, quit
ldx #0 ;Output the new command
ldy #4
ctl6h lda [4],y
and #$ff
sta cmdline,x
beq ctl6ha
iny
inx
bra ctl6h
ctl6ha stx cmdlen
stx cmdloc
ldx #^cmdline
lda #cmdline
jsr puts
ctl6a rts
END
;=========================================================================
;
; Save History if variable set
;
;=========================================================================
SaveHistory START
using HistoryData
using global
svhisvalptr equ 0
space equ svhisvalptr+4
subroutine ,space
lda historyFN
sta DestroyParm+2
sta CreateParm+2
sta OpenParm+4
lda historyFN+2
sta DestroyParm+4
sta CreateParm+4
sta OpenParm+6
;
; Get value of $SAVEHISTORY environment variable
;
ph4 #savehistStr
jsl getenv
sta svhisvalptr Save pointer to GS/OS result buffer.
stx svhisvalptr+2
ora svhisvalptr+2 If buffer wasn't allocated,
jeq goback all done.
;
; Call Dec2Int to convert value of string into an integer
;
pha Reserve room on stack for result.
lda svhisvalptr Get pointer to $HISTORY value.
ldx svhisvalptr+2
clc Add 4 to address to skip
adc #4 over length words.
bcc pushaddr
inx
pushaddr phx Push address onto stack.
pha
ldy #2
lda [svhisvalptr],y
pha Push length.
pea 0 Push signedFlag = 0 (unsigned)
Tool $280b Dec2Int
pla Get result.
sta size
jeq done
;
; Create and write history to file
;
Destroy DestroyParm
Create CreateParm
jcs done
Open OpenParm
bcs done
mv2 OpenRef,(WriteRef,WriteCRRef,CloseRef)
loop1 mv4 historyptr,0
mv2 size,count
ldy #histNext+2
loop2 lda 0
ora 0+2
beq next
lda [0]
tax
dec count
beq write
lda [0],y
sta 0+2
stx 0
bra loop2
write clc
lda 0
adc #4
tax
sta WriteBuf
lda 0+2
adc #0
sta WriteBuf+2
pha
phx
jsr cstrlen
sta WriteReq
Write WriteParm
bcs doneclose
Write WriteCR
bcs doneclose
next dec size
bne loop1
doneclose Close CloseParm
done pei (svhisvalptr+2) Free $SAVEHISTORY value buffer
pei (svhisvalptr)
jsl nullfree
goback return
DestroyParm dc i2'1'
dc a4'historyFN'
CreateParm dc i2'3'
dc a4'historyFN'
dc i2'$C3'
dc i2'0'
OpenParm dc i2'2'
OpenRef ds 2
dc a4'historyFN'
WriteParm dc i2'4'
WriteRef ds 2
WriteBuf dc a4'buffer'
WriteReq ds 4
ds 4
WriteCR dc i2'4'
WriteCRRef ds 2
dc a4'CRBuf'
dc i4'1'
ds 4
CRBuf dc i1'13'
CloseParm dc i2'1'
CloseRef ds 2
size ds 2
count ds 2
END
;=========================================================================
;
; Read History file
;
;=========================================================================
ReadHistory START
using HistoryData
using global
lda historyFN
sta OpenParm+4
lda historyFN+2
sta OpenParm+6
lda #0
sta historyptr
sta historyptr+2
Open OpenParm
bcs done
mv2 OpenRef,(ReadRef,NLRef,CloseRef)
NewLine NLParm
bcs doneclose
loop anop
Read ReadParm
bcs doneclose
ldy ReadTrans
beq doneclose
dey
lda #0
sta buffer,y
ph4 #buffer
jsl InsertHistory
bra loop
doneclose Close CloseParm
done rts
OpenParm dc i2'2'
OpenRef ds 2
dc a4'historyFN'
NLParm dc i2'4'
NLRef ds 2
dc i2'$7F'
dc i2'1'
dc a4'NLTable'
NLTable dc i1'13'
ReadParm dc i2'4'
ReadRef ds 2
dc a4'buffer'
dc i4'1024'
ReadTrans ds 4
CloseParm dc i2'1'
CloseRef ds 2
size ds 2
END
;=========================================================================
;
; Init History
;
;=========================================================================
InitHistory START
using HistoryData
ph4 #histName Create string
jsl AppendHome $HOME/history
stx historyFN+2 Store pointer to it
sta historyFN in historyFN
rts
END
;=========================================================================
;
; Print History (this is the history command)
;
;=========================================================================
PrintHistory START
using HistoryData
using global
ptr equ 0
status equ ptr+4
space equ status+2
subroutine (4:argv,2:argc),space
stz status
lda argc
dec a
beq chkptr
ldx #^usage
lda #usage
jsr errputs
inc status Return status = 1.
bra done
chkptr lda historyptr
ora historyptr+2
beq done
lda numhist
sta num
loop1 mv4 historyptr,ptr
lda num
bmi done
sta count
loop2 lda count
beq print
ldy #histNext+2
lda [ptr]
tax
lda [ptr],y
sta ptr+2
stx ptr
ora ptr
beq next
dec count
bra loop2
print sub2 lasthist,num,@a
Int2Dec (@a,#numbstr,#4,#0)
ldx #^numbstr
lda #numbstr
jsr puts
clc
ldx ptr+2
lda ptr
adc #4
ok jsr puts
jsr newline
next dec num
bra loop1
done return 2:status
numbstr dc c'0000: ',h'00'
num ds 2
count ds 2
usage dc c'Usage: history',h'0d00'
END
;=========================================================================
;
; History Data
;
;=========================================================================
HistoryData DATA
lasthist dc i2'0'
numhist dc i2'0'
currenthist ds 4
historyptr dc i4'0'
historyStr gsstr 'HISTORY'
savehistStr gsstr 'SAVEHIST'
histName dc c'/history',i1'0'
historyFN ds 4
END