home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
list
/
ep-src.ark
/
NDEFF.MAC
< prev
next >
Wrap
Text File
|
1988-05-21
|
20KB
|
1,342 lines
include BDS.LIB
lod macro
mov e,m
inx h
mov d,m
endm
sto macro
mov m,e
inx h
mov m,d
endm
ind macro
mov a,m
inx h
mov h,m
mov l,a
endm
.comment `
functions ALLOC, FREE, and FREEALL
/*
* Storage allocation data, used by "alloc" and "free"
*/
struct _header {
struct _header *_ptr;
unsigned _size;
};
struct _header _base; /* declare this external data to */
struct _header *_allocp; /* be used by alloc() and free() */
`
._ptr equ 0
._size equ 2
.comment `
/*
Storage allocation functions:
*/
char *alloc(nbytes)
unsigned nbytes;
{
struct _header *p, *q, *cp;
int nunits;
nunits = 1 + (nbytes + (sizeof (_base) - 1)) / sizeof (_base);
if ((q = _allocp) == NULL) {
_base._ptr = _allocp = q = &_base;
_base._size = 0;
}
for (p = q -> _ptr; ; q = p, p = p -> _ptr) {
if (p -> _size >= nunits) {
_allocp = q;
if (p -> _size == nunits)
_allocp->_ptr = p->_ptr;
else {
q = _allocp->_ptr = p + nunits;
q->_ptr = p->_ptr;
q->_size = p->_size - nunits;
p -> _size = nunits;
}
return p + 1;
}
if (p == _allocp) {
if ((cp = sbrk(nunits * sizeof (_base))) == ERROR)
return NULL;
cp -> _size = nunits;
free(cp+1); /* remember: pointer arithmetic! */
p = _allocp;
}
}
}
`
alloc::
; pop d
; pop h
; push h
; push d
; push b ;(not yet used)
; shld nbytes
; nunits = 1 + (nbytes + (sizeof (_base) - 1)) / sizeof (_base);
; lhld nbytes
; + (4 - 1)
inx h
inx h
inx h
; lxi d,4
; xchg
; call usdiv
mvi e,2
call shlrbe
inx h ;1 +
shld nunits
; if ((q = _allocp) == NULL) {
lhld _allocp
shld a$q
mov a,h
ora l
jnz .alc1
; _base._ptr = _allocp = q = &_base;
lxi h,_base
shld a$q
shld _allocp
shld _base+._ptr
; _base._size = 0;
; }
lxi h,0
shld _base+._size
; for (p = q -> _ptr; ; q = p, p = p -> _ptr) {
.alc1:
lhld a$q
ind
shld a$p
; if (p -> _size >= nunits) {
.alc2:
lhld a$p
inx h
inx h
lod
lhld nunits
call albu
jc .alc5
; _allocp = q;
lhld a$q
shld _allocp
; if (p -> _size == nunits)
lhld a$p
inx h
inx h
lod
lhld nunits
call eqwel
jnz .alc3
; _allocp->_ptr = p->_ptr;
lhld a$p
lod
lhld _allocp
sto
jmp .alc4
; else {
; q = _allocp->_ptr = p + nunits;
.alc3:
lhld a$p
xchg
lhld nunits
dad h
dad h ;4 bytes per _header
dad d
shld a$q ;q =
xchg ;_allocp->_ptr =
lhld _allocp
sto
; q->_ptr = p->_ptr;
lhld a$p
lod
lhld a$q
sto
; q->_size = p->_size - nunits;
lhld a$p
inx h
inx h
lod
lhld nunits
call cmh
dad d
xchg
lhld a$q
inx h
inx h
sto
; p -> _size = nunits;
lhld nunits
xchg
lhld a$p
inx h
inx h
sto
; }
; return p + 1;
; }
.alc4:
lhld a$p
inx h
inx h
inx h
inx h
; jmp .alc8
ret
; if (p == _allocp) {
.alc5:
lhld a$p
xchg
lhld _allocp
call eqwel
jnz .alc7
; if ((cp = sbrk(nunits * sizeof (_base))) == ERROR)
lhld nunits
;*4
dad h
dad h
; push h
call sbrk
; pop d
shld a$cp
inx h
mov a,h
ora l
rz
; jnz .alc6
; return NULL;
; lxi h,0
; jmp .alc8
; cp -> _size = nunits;
.alc6:
lhld nunits
xchg
lhld a$cp
inx h
inx h
sto
; free(cp+1); /* remember: pointer arithmetic! */
lhld a$cp
inx h
inx h
inx h
inx h
;; push h
call free
;; pop d
; p = _allocp;
; }
; }
;}
lhld _allocp
shld a$p
;(end for-loop action)
; for (p = q -> _ptr; ; q = p, p = p -> _ptr) {
.alc7:
lhld a$p
shld a$q
; lhld a$p
ind
shld a$p
jmp .alc2
;.alc8:
; pop b
; ret
.comment `
free(ap)
struct _header *ap;
{
struct _header *p, *q;
p = ap - 1; /* No need for the cast when "ap" is a struct ptr */
for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr)
if (q >= q -> _ptr && (p > q || p < q -> _ptr))
break;
if (p + p -> _size == q -> _ptr) {
p -> _size += q -> _ptr -> _size;
p -> _ptr = q -> _ptr -> _ptr;
}
else p -> _ptr = q -> _ptr;
if (q + q -> _size == p) {
q -> _size += p -> _size;
q -> _ptr = p -> _ptr;
}
else q -> _ptr = p;
_allocp = q;
}
`
free::
; pop d
; pop h
; push h
; push d
; shld f$ap
; push b
; p = ap - 1; /* No need for the cast when "ap" is a struct ptr */
; lhld f$ap
dcx h
dcx h
dcx h
dcx h
shld f$p
;
; for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr)
lhld _allocp
shld f$q
.fr1:
lhld f$p
xchg
lhld f$q
call agbu
jnc .fr2
lhld f$q
lod
lhld f$p
xchg
call albu
jc .fr5
; if (q >= q -> _ptr && (p > q || p < q -> _ptr))
; break;
.fr2:
lhld f$q
lod
xchg
call albu
jc .fr4
lhld f$p
xchg
lhld f$q
call agbu
jc .fr5
lhld f$q
lod
lhld f$p
xchg
call albu
; jnc .fr4
;
;.fr3: jmp .fr5
JC .fr5
;(end for-loop action)
; for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr)
.fr4:
lhld f$q
ind
shld f$q
jmp .fr1
; if (p + p -> _size == q -> _ptr) {
.fr5:
lhld f$p
push h
; lhld f$p
inx h
inx h
ind
dad h
dad h
pop d
dad d
xchg
lhld f$q
ind
call eqwel
jnz .fr6
; p -> _size += q -> _ptr -> _size;
lhld f$p
inx h
inx h
push h
lod
push d
lhld f$q
;q
ind
;q -> _ptr
inx h
inx h
ind
;q -> _ptr -> _size
pop d
dad d
xchg
pop h
sto
; p -> _ptr = q -> _ptr -> _ptr;
; }
lhld f$q
;q
ind
;q -> _ptr
ind
;q -> _ptr -> _ptr
xchg
lhld f$p
sto
jmp .fr7
; else p -> _ptr = q -> _ptr;
.fr6:
lhld f$q
lod
lhld f$p
sto
;
; if (q + q -> _size == p) {
.fr7:
lhld f$q
push h
; lhld f$q
inx h
inx h
ind
dad h
dad h
pop d
dad d
xchg
lhld f$p
call eqwel
jnz .fr8
; q -> _size += p -> _size;
lhld f$q
inx h
inx h
push h
lod
lhld f$p
inx h
inx h
ind
dad d
xchg
pop h
sto
; q -> _ptr = p -> _ptr;
; }
lhld f$p
lod
lhld f$q
sto
jmp .fr9
; else q -> _ptr = p;
.fr8:
lhld f$p
xchg
lhld f$q
sto
;
; _allocp = q;
;}
.fr9:
lhld f$q
shld _allocp
; pop b
ret
freeall::
lxi h,0
shld _allocp
lhld freram
shld allocp
ret
;formerly external
_base: dw 0,0
_allocp: dw 0
;alloc arg
;nbytes: dw 0 not needed
;alloc locals
a$p: dw 0
a$q: dw 0
a$cp: dw 0
nunits: dw 0
;free arg
;f$ap: dw 0 not needed
;free locals
f$p: dw 0
f$q: dw 0
sbrk::
; call ma1toh ;get # of bytes needed in HL
; xchg ;put into DE
; pop h
; pop d
; push d
; push h
xchg
lhld allocp ;get current allocation pointer
push h ;save it
dad d ;get tentative last address of new segment
jc brkerr ;better not allow it to go over the top!
dcx h
xchg ; now last addr is in DE
lhld alocmx ;get safety factor
call cmh
dad sp ;get HL = (SP - alocmx)
XCHG
CALL CMPHD
; call cmpdh ;is DE less than HL?
jnc brkerr ;if not, can't provide the needed memory.
; xchg ;else OK.
inx h
shld allocp ;save start of next area to be allocated
pop h ;get pointer to this area
ret ;and return with it.
brkerr: pop h ;clean up stack
jmp error ;and return with -1 to indicate can't allocate.
;cmpdh: mov a,d
; cmp h
; rc
; rnz
; mov a,e
; cmp l
; ret
.comment `
puts(s)
char *s;
{
while (*s) putchar(*s++);
}
`
puts::
; pop d
; pop h
; push h
; push d
.pts1:
mov a,m
ora a
rz
push h
; mov l,a
; mvi h,0
; push h
call putchar
; pop d
pop h
inx h
jmp .pts1
.comment `
char *strcat(s1,s2)
char *s1, *s2;
{
char *temp; temp=s1;
while(*s1) s1++;
do *s1++ = *s2; while (*s2++);
return temp;
} `
strcat::
; push b
; pop b
;
; pop b
; pop d
; pop b
; lxi h,-8
; dad sp
; sphl
;s1 in DE
;s2 in BC
;NO -- now s1 in HL and s2 in DE
; mov h,d ;save s1 for return
; mov l,e
;NO -- no return used
.sct1:
mov a,m
inx h
ora a
jnz .sct1
dcx h
;DE points to 0 at end of s1
.sct2:
ldax d
mov m,a
inx d
inx h
ora a
jnz .sct2
ret
.comment `
int strcmp(s1, s2)
char *s1, *s2;
{
while (*s1 == *s2++)
if (*s1++ == '\0')
return 0;
return (*s1 - *--s2);
} `
strcmp::
.comment `
push b
pop b
pop b
pop d
pop b
lxi h,-8
dad sp
sphl
;s1 in DE
;s2 in BC
mov h,b
mov l,c
;s2 in HL
pop b ;restore mark stack
`
XCHG
.1:
ldax d
ora a
jz .2 ;end of s1?
cmp m
inx h
inx d
jz .1
;here char's differ, and neither is nul
;A still has current char from s1
dcx h ;back to current char of s2
.2: sub m ;*s1 - *s2
mov l,a
mvi h,0
rnc
dcr h ;maybe negative sign
ret
.comment `
char *strcpy(s1,s2)
char *s1, *s2;
{
char *temp; temp=s1;
while (*s1++ = *s2++);
return temp;
} `
strcpy::
.comment `
push b
pop b
pop b
pop d
pop b
lxi h,-8
dad sp
sphl
;s1 in DE
;s2 in BC
`
;NO -- s1 in HL, s2 in DE
; push d ;for return s1
;get s1 in HL
; xchg
;NO -- return not used
.scpy1:
ldax d
mov m,a
inx d
inx h
ora a
jnz .scpy1
ret
;
;
; Functions appearing in this file:
;
; getchar kbhit ungetch putchar gets
; exit
;
getchar::
lda ungetl ;any character pushed back?
ora a
mov l,a
jz gch2
xra a ;yes. return it and clear the pushback
sta ungetl ;byte in C.CCC.
mvi h,0
ret
gch2: push b
mvi c,conin
call .bdos
pop b
cpi cntrlc ;control-C ?
jz .exit ;if so, exit the program.
cpi 1ah ;control-Z ?
lxi h,-1 ;if so, return -1.
rz
mov l,a
cpi cr ;carriage return?
jnz gch3
push b
mvi c,conout ;if so, also echo linefeed
mvi e,lf
call .bdos
pop b
mvi l,newlin ;and return newline (linefeed)..
gch3: mvi h,0
ret
kbhit::
lda ungetl ;any character ungotten?
mvi h,0
mov l,a
ora a
rnz ;if so, return true
push b
mvi c,cstat ;else interrogate console status
call .bdos
pop b
ora a ;0 returned by BDOS if no character ready
lxi h,0
rz ;return 0 in HL if no character ready
inr l ;otherwise return 1 in HL
ret
putchar::
; call ma1toh ;get character in A
; pop d
; pop h
; push h
; push d
; mov a,l
push b
mvi c,conout
cpi newlin ;newline?
jnz put1 ;if not, just go put out the character
mvi e,cr ;else...put out CR-LF
call .bdos
mvi c,conout
mvi a,lf
put1: mov e,a
call .bdos
put2: mvi c,cstat ;now, is input present at the console?
call .bdos
ora a
jnz put3
pop b ;no...all done.
ret
put3: mvi c,conin ;yes. sample it (this will always echo the
call .bdos ; character to the screen, alas)
cpi cntrlc ;is it control-C?
jz .exit ;if so, abort and reboot
pop b ;else ignore it.
ret
gets::
; call ma1toh ;get destination address
; pop d
; pop h
; push h
; push d
push b ;save BC
push h
push h
lxi h,-150 ;use space below stack for reading line
dad sp
push h ;save buffer address
mvi m,88h ;Allow a max of about 135 characters
mvi c,getlin
xchg ;put buffer addr in DE
call .bdos ;get the input line
mvi c,conout
mvi e,lf ;put out a LF
call .bdos
pop h ;get back buffer address
inx h ;point to returned char count
mov b,m ;set B equal to char count
inx h ;HL points to first char of line
pop d ;DE points to start destination area
copyl: mov a,b ;copy line to start of buffer
ora a
jz gets2
mov a,m
stax d
inx h
inx d
dcr b
jmp copyl
gets2: xra a ;store terminating null
stax d
pop h ;return buffer address in HL
pop b
ret
;exit::
; jmp .exit
;
;
; Functions appearing in this file:
; open creat unlink
; read write
; execl
;
;
; Open:
; int open(filename,mode)
; char *filename;
;
; Open a file for read (mode == 0), write (mode == 1) or both (mode = 2),
; and detect a user-number prefix. Returns a file descriptor.
;
open::
call arghak
xra a
call fgfcb ;any fcb's free?
jnc open2 ;if not, error
mvi a,10 ;"no more file slots"
jmp error
open2: sta tmp
xchg
lhld arg1
xchg
push b
call setfcu ;parse name and set usenum
lda usrnum
call setusr ;set new user number
mvi c,openc
call .bdos
cpi errorv ;successful open?
pop b
mvi a,11 ; set error code in case of error
jz oerror ;if error, go abort
lda tmp
call fgfd ;get HL pointing to fd table entry
lda arg2
ora a ;open for read?
mvi d,3
jz open4
dcr a
mvi d,5
jz open4 ;write?
dcr a
mvi a,12 ;"bad mode" for open operation...
jnz oerror ;...if not mode 2
mvi d,7 ;else must be mode 2.
open4: lda usrnum ;get user number for the file
add d ;add r/w bit codes
mov m,a ;and store in fd table
inx h ;clear max sector number field of fd entry
xra a
mov m,a
inx h
mov m,a
lda tmp ;get back fd
mov l,a
mvi h,0
call rstusr ;reset user number
ret
oerror: call rstusr ;reset user number
sta errnum ;store error code number
jmp error ;and return general error condition
;
; Close:
; close(fd);
;
; Close a file opened via "open" or "creat":
;
;close::
; jmp .close ;jump to the close routine in C.CCC
;
; Creat:
; int creat(filename)
; char *filename;
; Creates the named file, first deleting any old versions, and opens it
; for both read and write. Returns a file descriptor.
;
; ext unlink,open
creat::
pop d
pop h
push h
push d
push b
push h
; push h
call unlink ;erase any old versions of file
; pop d
lda usrnum ;set to appropriate user area computed by "unlink"
call setusr
mvi c,creatc ;create the file
lxi d,fcb ;assume fcb has been set by "unlink"
call .bdos
call rstusr ;restore previous user number
cpi errorv
pop h
pop b
jnz creat0 ;if no error, go open
mvi a,13 ;"can't create file" error code
sta errnum
jmp error
creat0: lxi d,2 ;now open for read/write
push d
; lhld arg1
push h
call open
pop d
pop d
ret
;
; Unlink:
; unlink(filename)
; char *filename;
;
; Deletes the named file. User number prefixes are recognized:
;
unlink:
; call ma1toh
push b
xchg
lxi h,fcb
call setfcu ;parse for fcb and compute user number
lda usrnum
call setusr ;set to correct user number
mvi c,delc ;delete
call .bdos
call rstusr ;restore original user number
lxi h,0
pop b ;restore BC
cpi errorv ;was BDOS able to find the file?
rnz ;if so, all done.
mvi a,11 ;set error code for "file not found"
sta errnum
dcx h ;return -1
ret
;
; Fabort:
; fabort(fd);
; Abort all operations on file fd. Has no effect under MP/M II.
;
fabort::
; pop d
; pop h
; push h
; push d
; mov a,l
call fgfd
jnc abrt2 ;legal fd?
mvi a,7
sta errnum ;set "bad fd" error code
jmp error
abrt2:
IF NOT MPM2
mvi m,0 ;clear entry in fd table
ENDIF
lxi h,0
ret
;
; Read:
;
; i = read(fd, buf, n);
;
; Read a number of sectors using random-record I/O.
;
; The return value is either the number of sectors successfully
; read, 0 for EOF, or -1 on error with errno() returning the error
; code (or errmsg(n) returning a pointer to an error message).
;
; The Random Record Field is incremented following each successful
; sector is read, just as if the normal (sequential) read function
; were being used. "seek" must be used to go back to a previous
; sector.
;
read::
call arghak
lda arg1
call fgfd
mov d,m ;save fdt entry in D
mvi a,7 ;prepare for possible "bad fd"
jc rerror
mov a,d
ani 2
mvi a,8 ;prepare for possible "no read permission"
jz rerror
push b
mov a,d ;get fd table entry
call setusr ;set user area to that of the file
lda arg1 ;get fd
call fgfcb
shld tmp2 ;save fcb address
lxi h,0 ;clear sector count
shld tmp2a
r2: lhld arg3 ;get countdown
mov a,h
ora l ;done?
r2aa: lhld tmp2a
jnz r2a
r2done: call rstusr ;reset user number
pop b ;yes. return with success count in HL
ret
r2a: lhld arg2 ;get transfer addr in DE
xchg
mvi c,sdma ;set DMA there
call .bdos
lhld tmp2
xchg
mvi c,readr ;code for BDOS random read
push d ;save DE so we can fudge nr field if
call .bdos ;we stop reading on extent boundary...
pop d
ora a
jz r4 ;go to r4 if no problem
sta errnum ;otherwise save error code
cpi 1 ;ok, we have SOME kind of hangup...
jz r2b ;check for EOF condition:
cpi 4 ; error codes 1 and 4 both indicate reading
jz r2b ; unwritten data..treat as EOF
lxi h,-1 ;put ERROR value in HL
jmp r2done
r2b: lhld tmp2a ;return count
jmp r2done
r4: lhld arg3 ;decrement countdown
dcx h
shld arg3
lhld arg2 ;bump DMA address
lxi d,128
dad d
shld arg2
lhld tmp2a ;bump success count
inx h
shld tmp2a
lhld tmp2 ;get address of fcb
lxi b,33 ;get addr of random record field
dad b
mov c,m ;bump
inx h ; value
mov b,m ; of
inx b ; random
mov m,b ; field
dcx h ; by one
mov m,c
mov a,b ;overflow past 16-bit record count?
ora c
jnz r2 ; go for next sector if no overflow
inx h ;else set 3rd byte of random sector count
inx h
mvi m,1
mvi a,14 ;"seek past 65536th record of file"
sta errnum
jmp r2aa ;and don't read any more.
rerror: sta errnum
jmp error
;
; Write:
; i = write(fd, buf, n);
;
; The random sector write function. Returns either the number
; of sectors successfully written, or -1 on hard error. Any return
; value other than n (the third arg) should be considered an error,
; after which errno() can tell you the error condition and errmsg()
; can return a pointer to an appropriate error message text.
;
write::
call arghak
lda arg1
call fgfd
shld arg5 ;save pointer to fd table entry
mov d,m ;save fd table entry in D
mvi a,7 ;prepare for possible "bad fd"
jc werror
mov a,d
ani 4
mvi a,9 ;prepare for possible "no write permission"
jz werror
push b
mov a,d ;set user number
call setusr
lda arg1 ;get fd
call fgfcb ;compute fcb address
shld tmp2 ;save it away
lxi h,0 ;clear success count
shld tmp2a
writ1: lhld arg3 ;done yet?
mov a,h
ora l
jnz writ2
;take care of maximum sector count for cfsize:
lhld tmp2 ;get fcb address
lxi d,33 ;point to random record field
dad d
mov e,m
inx h
mov d,m ;DE now holds random record number for next rec
push d ;save it
lhld arg5 ;get fd table pointer
inx h ;point to max value
mov e,m ;get in DE
inx h
mov d,m ;now DE is old max value, HL points to end of entry
xthl ;DE = old max, HL = current sector, STACK = tab ptr
xchg ;HL = old max, DE = current sector
call cmphd ;is old max less than current sector?
pop h ;get tab ptr in HL
jnc writ1a ;if old max not < current sector, don't update max
mov m,d ;else update max value with new sector number
dcx h
mov m,e
writ1a: lhld tmp2a ;if so, return count
wrdone: call rstusr ;reset user number
pop b
ret
writ2: lhld arg2 ;else get transfer address
push h ;save on stack
xchg ;put in DE
mvi c,sdma ;set DMA there
call .bdos
pop h ;get back transfer address
lxi d,128 ;bump by 128 bytes for next time
dad d
shld arg2 ;save -> to next 128 bytes
lhld tmp2 ;get addr of fcb
xchg
mvi c,writr ;write random sector
call .bdos
lhld tmp2a ;get success count in HL
ora a ;error?
jz writ3 ;if not, go do bookkeeping
sta errnum ;else save error code
jmp wrdone
writ3: inx h ; else bump successful sector count,
shld tmp2a
lhld arg3 ; debump countdown,
dcx h
shld arg3
lhld tmp2 ; get address of fcb
lxi b,33 ; get address of random field
dad b
mov c,m ; bump 16-bit value at random
inx h ; record
mov b,m ; field
inx b ; of
mov m,b ; fcb
dcx h ; by one
mov m,c
mov a,b ;overflow past 16-bit record count?
ora c
jnz writ1 ; go for next sector if no overflow
inx h ;else set 3rd byte of random sector count
inx h
mvi m,1
mvi a,14 ;set "past 65536th sector" error code
sta errnum
jmp writ1a ;and don't read any more.
werror: sta errnum
jmp error
end