Category : Word Processors
Archive   : FMAC16AS.ZIP
Filename : MINTFORM.ASM

 
Output of file : MINTFORM.ASM contained in archive : FMAC16AS.ZIP
;History:401,1
;Tue Sep 12 23:49:09 1989 Add the find_string entry point.
;10-01-88 14:45:52 make get_mint_space return four numbers.
;12-06-87 00:51:14 finish adding 256K of mint space.
;12-06-87 00:26:46 start adding support for 256K of mint space.
;11-16-87 23:18:00 call new_buffer from init_forms.
page ,132

.xlist
include mintform.def
include mint.def
.list

comment /

The forms:

Forms are laid out as a linear list of forms. formStore points to the
beginning, and [topbot] points to the end. The most recently defined forms are
placed at the beginning of the list. The forms consists of three elements: a
header, the name, and the data. The header contains the link to the next
form, the length of the name, the length of the data, and the form pointer
(which is always <= the length of the data). The form structure is defined in
the file 'mintform.def'.
When a form is to be looked up in form storage, the form is first
hashed. Then the form is looked up in the list of hash links. A linear search
is performed for all the forms that hash to that value.

formhash is the hashing table for form names. It is a list of
pointers to forms. Each form, in turn, has a pointer to the next form
whose name hashes to the same entry in formhash. To add a new form, we
must add the name to the proper place in the table. To delete a form, the
form name must be removed from formhash. Their links in formhash and each
of the forms must be updated, then the remaining forms get moved up in
memory.

Also, whenever a form gets looked up, it is placed at the head of
the chain of hash pointers. The assumption is that it will be looked up
again shortly.

/


formSeg segment byte public

define_buffer form_

public syntax_table
syntax_table dw NIL
;don't put anything here.
formhashsize equ 256
formhash dw formhashsize dup(NIL)

formStore label byte


formSeg ends


segmoffs struc
offs dw ?
segm dw ?
segmoffs ends


data segment byte public

public syntax_seg
syntax_seg dw formSeg ;segment holding syntax table.

this_segment dw ? ;points to next formSegments to get.
this_form dd ? ;current form while enumerating.

public formSeg0, formSeg1, formSeg2, formSeg3
formSegments label word
formSeg0 dw ?
formSeg1 dw ?
formSeg2 dw ?
formSeg3 dw ?

extrn data_bottop: word

data ends


code segment byte public

assume cs:code

extrn buffer_free: near
extrn new_buffer: near
extrn put_number: near

public init_forms
init_forms:
mov cx,4
mov bx,offset formSegments
init_forms_0:
assume ds:data, es:data
push bx
push cx
mov cx,offset formStore
call new_buffer
pop cx
pop bx
jc init_forms_1
xchgdses
assume ds:data, es:formSeg
mov [bx],es ;remember this form segment.
add bx,2
push cx
mov di,offset syntax_table ;null out the hash table.
xor ax,ax
mov cx,256 + 1
rep stosw
mov ax,offset formStore ;->end of forms.
mov form_topbot,ax
mov form_bottop,ax
mov form_botbot,ax
esdata
pop cx
loop init_forms_0
clc
init_forms_1:
ret


public get_mint_space
get_mint_space:
;enter with di -> place to put numbers.
;return four numbers giving the bytes of mint space available,
; di ->end of strings.
mov dx,ds ;start with ds.
mov cx,4 ;do four segments.
get_mint_space_1:
push ds ;get the next segment
mov ds,dx
assume ds:formseg
mov dx,form_next_buffer
mov ds,dx
mov ax,form_bottop ;get the free space for this buffer.
sub ax,form_topbot
pop ds
assume ds:data

push dx
push cx
mov cx,0 ;use only as many digits as is needed.
mov bx,10
call put_number
mov al,',' ;seperate them by commas.
stosb
pop cx
pop dx
loop get_mint_space_1
ret


;first_form sets us up to enumerate the forms (in no particular order).
; Returns es:bx ->next form, zr if there is no next form. Do not assume
; that es will remain the same from one call to the next.
public first_form, next_form
first_form:
assume ds:data, es:data
mov this_segment,offset formSegments
next_segment:
assume ds:data, es:nothing
mov bx,this_segment
add this_segment,2 ;postincrement to the next seg.
cmp bx,offset formSegments + 4*2 ;last form segment?
jz next_last ;yes - we're done.
mov ax,[bx] ;get the formSegment.
mov this_form.segm,ax
mov this_form.offs,offset formStore ;->beginning of forms.
next_form:
les bx,this_form
assume es:formSeg
mov ax,formSeg:[bx].form_length ;postincrement to the next form.
add this_form.offs,ax
cmp bx,form_topbot ;go if we have no more forms.
je next_segment
next_last:
ret


;enter with ds:bx -> a form. Make that form be the syntax table.

public store_syntax_table
store_syntax_table:
assume ds:formSeg, es:data
mov syntax_table,bx
mov syntax_seg,ds
ret


;define a form. Enter with:
; si => name
; cx = name length
; di => data
; dx = data length
; bx = form pointer.

public define_form
define_form:
assume ds:data, es:data
push bx ;save the form pointer.
call find_form ;see if it already exists.
jc define_form_1 ;it doesn't.
assume es:formSeg
;check to see if the form is already big enough.
cmp dx,formSeg:[bx].data_length
ja define_form_3 ;it isn't.
pop formSeg:[bx].form_pointer ;set the form pointer.
mov si,di ;prepare to move the data.
lea di,formSeg:[bx].name_offset ;->name.
add di,cx ;->data.
mov formSeg:[bx].data_length,dx ;set the data length.
mov cx,dx ;copy the new data in.
rep movsb
esdata
ret
define_form_3:
assume es:formSeg
push di ;delete the form pointed to by es:bx
push si
push cx
call delete_form
pop cx
pop si
pop di
esdata
define_form_1:
pop bx ;restore form pointer.
push di
push bx
push si
push cx
call hash_func ;exit with es:[bx]->hash entry.
assume es:formSeg
add cx,(size form_struc) ;compute amount of space needed.
add cx,dx
push cx ;push the size
mov ax,es
call buffer_free
jc define_form_2 ;go if we can't get enough mem.
mov di,form_topbot
pop formSeg:[di].form_length ;get the total size. (pushed as cx)
pop cx ;we have to pop into cx, because we
mov formSeg:[di].name_length,cx ; need it later for the movsb.
mov formSeg:[di].data_length,dx
pop si ;restore ->name
pop formSeg:[di].form_pointer
mov ax,formSeg:[bx] ;get current formhash
mov formSeg:[bx],di ;make formhash point to us.
mov formSeg:[di].hash_link,ax ;make us point to current formhash.
add di,name_offset ;lea di,[di].name_offset
rep movsb
pop si ;restore ->data
mov cx,dx
rep movsb
mov form_topbot,di ;remember the new end.
esdata
ret
define_form_2:
call nomem


;Find a form. Enter with:
; si -> name
; cx = name length
;Preserve di
;Exit with:
; nc if form found, es:bx -> form
; cy if form not found, es=data
public find_form
find_form:
assume ds:data, es:data
push dx
push di
call hash_func
assume es:formSeg
push bx ;remember the formhash pointer.
xor dx,dx
mov bx,formSeg:[bx] ;get ->first form that hashes here.
find_form_1:
cmp bx,NIL ;end of list?
je find_form_2 ;yes, we didn't find it.
cmp cx,formSeg:[bx].name_length ;lengths equal?
jne find_form_3 ;no, go to next.
lea di,formSeg:[bx].name_offset ;compare names.
push si
push cx
rep cmpsb
pop cx
pop si
jne find_form_3 ;names not equal.
pop di ;restore the formhash pointer.
or dx,dx ;did we find it first?
je find_form_4 ;yes - that's where we want it.
mov ax,formSeg:[di]
mov formSeg:[di],bx ;make head -> found.
xchg ax,formSeg:[bx].hash_link ;make found -> old head.
mov di,dx
mov formSeg:[di].hash_link,ax ;make pred(found) -> succ(found).
find_form_4:
clc ;found the form!
pop di
pop dx
ret
find_form_3:
assume es:formSeg
mov dx,bx
mov bx,formSeg:[bx].hash_link
jmp find_form_1
find_form_2:
pop bx ;restore the formhash pointer.
esdata
stc ;didn't find the form!
pop di
pop dx
ret


;delete a form. Enter with:
; es:bx=>form

public delete_form
delete_form:
;delete the form from the hashing table.
assume ds:data, es:formSeg
mov di,bx ;make a copy of the pointer to the form.
mov cx,formSeg:[bx].name_length
lea si,formSeg:[bx].name_offset
xchgdses
assume ds:formSeg, es:data
call hash_func
assume es:formSeg
sub bx,hash_link ;pretend that formhash is a form itself.
delete_form_1:
cmp formSeg:[bx].hash_link,di ;does this form point to us?
je delete_form_2 ;yes.
mov bx,formSeg:[bx].hash_link ;no - go to the next form.
jmp delete_form_1
delete_form_2:
mov ax,formSeg:[di].hash_link ;unlink us from the list.
mov formSeg:[bx].hash_link,ax
;check for deletion of the syntax table.
cmp di,syntax_table
jne delete_form_7
mov syntax_table,NIL ;if we're deleting it, put NIL in.
delete_form_7:
;now adjust the hash links in formhash.
mov ax,formSeg:[di].form_length
mov bx,offset syntax_table
mov cx,formhashsize+1 ;add one for the syntax table.
delete_form_3:
cmp formSeg:[bx],di ;do we need to adjust this one?
jbe delete_form_4 ;no.
sub formSeg:[bx],ax ;yes - do it.
delete_form_4:
add bx,2
loop delete_form_3
;now adjust all the hash links in the forms. Notice that we are adjusting
; the hash link in the form we are about to delete, but it doesn't hurt.
; We can also presume the existence of at least one form at this point.
mov bx,offset formStore ;->beginning of forms.
delete_form_5:
cmp formSeg:[bx].hash_link,di ;do we need to adjust this one?
jbe delete_form_6 ;no.
sub formSeg:[bx].hash_link,ax ;yes - do it.
delete_form_6:
add bx,formSeg:[bx].form_length ;compute the form after this one.
cmp bx,form_topbot ;no forms after this one.
jb delete_form_5
mov si,di ;now move every form after this one down.
add si,ax
mov cx,form_topbot
sub cx,si
rep movsb
mov form_topbot,di ;remember the new form_topbot.
dsdata
esdata
ret


;find the form whose name is given in arg1. Return the form pointer in
;ds:si, and the number of bytes remaining in the form in cx.
public find_arg1
find_arg1:
mov cx,1
;fall through to find_arg

;find the form whose name is given in the argument specified in cx. Return
; the form pointer in ds:si, and the number of bytes remaining in the form in
; cx, and the pointer to the form in bx.
public find_arg
find_arg:
assume ds:data, es:data
call getarg
public find_string
find_string:
call find_form
jc find_arg1_1 ;if form doesn't exist, exit.
xchgdses
assume ds:formSeg, es:data
lea si,formSeg:[bx].name_offset ;make si => form.data
add si,formSeg:[bx].name_length
add si,formSeg:[bx].form_pointer
mov cx,formSeg:[bx].data_length ;make cx = number of bytes left.
sub cx,formSeg:[bx].form_pointer
clc ;remember that form was found.
find_arg1_1:
ret


hash_func:
;enter with si,cx ->name to be hashed.
;exit with entry into hash table in ds:bx
;preserve dl.
assume ds:nothing
push si
push cx
xor bx,bx ;start with zero.
jcxz hash_func_1
xor ah,ah
hash_func_2:
lodsb
add bx,ax
loop hash_func_2
hash_func_1:
mov al,bl ;save the low byte
mov bl,bh
mov bh,0
and bl,3 ;four segments = two bits.
add bx,bx ;we're accessing words.
mov es,formSegments[bx] ;get the correct segment.
mov bl,al ;get the low byte back. No need to
;zero bh again.
add bx,bx
add bx,offset formhash
pop cx
pop si
ret


;Adjust the form pointer after building a value which affects the
; form pointer. The new form pointer is derived from the count
; of characters left in cx. The form is pointed to by bx.
public return_form
return_form:
assume ds:formSeg, es:data
mov ax,formSeg:[bx].data_length
sub ax,cx
mov formSeg:[bx].form_pointer,ax
dsdata
jmp return_tos


extrn return_tos: near
extrn getarg: near
extrn nomem: near
code ends

end



  3 Responses to “Category : Word Processors
Archive   : FMAC16AS.ZIP
Filename : MINTFORM.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/