pagesize 86 include mintdefs.a86 data dseg byte public extrn formb: word extrn forme: word extrn fend: word extrn actptr: word ; 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. After the remaining forms have been moved up in ;memory, their links in formhash and each of the forms must be updated. ; We use -1 for NIL because is above any legal address that a form may ;take on. When we adjust the hash links, we won't adjust any NILs because they ;seem to be a form which is above the one being moved. public syntax_table syntax_table dw NIL ;don't put anything here. formhashsize equ 256 public formhash ;formhash is public for debugging purposes only. formhash dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil dw nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil hash_value rw 1 ;data ends code cseg byte public ;*** assume cs:code, ds: data, es: data ;define a form. Enter with: ; si => name ; cx = name length ; di => data ; dx = data length ; bx = form pointer. ;this is what is accomplished: (a=active string, n=new form, o=old forms) ; aaaa nnnnnnnn ooooooo oooooooo ; ^ ^ ^ ;actptr formb forme ; ^<------>^ ; di cx si public define_form define_form: push bx ;save the form pointer. call find_form ;see if it already exists. jnc define_form_1 ;it doesn't. ;check to see if the form is already big enough. cmp dx,data_length[bx] ja define_form_3 ;it isn't. pop form_pointer[bx] ;set the form pointer. mov si,di ;prepare to move the data. lea di,name_offset[bx] ;->name. add di,cx ;->data. mov data_length[bx],dx ;set the data length. jmps define_form_4 define_form_3: push di push si push cx call delete_form pop cx pop si pop di define_form_1: pop bx ;restore form pointer. push di push si push cx add cx,size_form ;compute amount of space needed. add cx,dx push cx ;push the size mov si,actptr mov di,si sub di,cx mov ax,di ;see if we have that much space. sub ax,free_space cmp ax,fend jb define_form_2 ;no, go show no mem mov cx,formb ;compute the number of bytes to move. sub cx,actptr mov actptr,di ;update actptr rep movsb ;di points to the free space. Leave it alone. mov formb,di pop form_length[di] ;get the total size. (pushed as cx) mov form_pointer[di],bx pop cx ;we have to pop into cx, because we mov name_length[di],cx ; need it later for the movsb. mov data_length[di],dx pop si ;restore ->name call hash_func mov ax,[bx] ;get current formhash mov [bx],di ;make formhash point to us. mov hash_link[di],ax ;make us point to current formhash. add di,name_offset ;lea di,[di].name_offset rep movsb pop si ;restore ->data define_form_4: ;here with dx=data size, si->data, di->data area in form. mov cx,dx rep movsb ret define_form_2: jmp nomem ;Find a form. Enter with: ; si => name ; cx = name length ;Preserve di ;Exit with: ; bx => form ; cy if form found, ; nc if form not found. public find_form find_form: push dx push di call hash_func mov hash_value,bx ;remember the formhash pointer. xor dx,dx mov bx,[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,name_length[bx] ;lengths equal? jne find_form_3 ;no, go to next. lea di,name_offset[bx] ;compare names. push si push cx rep cmpsb pop cx pop si jne find_form_3 ;names not equal. or dx,dx ;did we find it first? je find_form_4 ;yes - that's where we want it. mov di,hash_value ;get the head of the list. mov ax,[di] mov [di],bx ;make head -> found. xchg ax,hash_link[bx] ;make found -> old head. mov di,dx mov hash_link[di],ax ;make pred(found) -> succ(found). find_form_4: stc ;found the form! pop di pop dx ret find_form_3: mov dx,bx mov bx,hash_link[bx] jmps find_form_1 find_form_2: clc ;didn't find the form! pop di pop dx ret ;delete a form. Enter with: ; bx=>form ;this is what is accomplished: (a=active string, f=forms, d=deleted form) ; aaaa ffffffff ddddddddddd ffffffff ; ^ ^ ^ ^^^^^^^ ^ ;actptr formb bx delete forme ; <-------------->^ ^ ; cx si di public delete_form delete_form: ;delete the form from the hashing table. mov di,bx ;make a copy of the pointer to the form. mov cx,name_length[bx] lea si,name_offset[bx] call hash_func sub bx,hash_link ;pretend that formhash is a form itself. delete_form_1: cmp hash_link[bx],di ;does this form point to us? je delete_form_2 ;yes. mov bx,hash_link[bx] ;no - go to the next form. jmps delete_form_1 delete_form_2: mov ax,hash_link[di] ;unlink us from the list. mov hash_link[bx],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,form_length[di] mov bx,offset syntax_table mov cx,formhashsize+1 ;add one for the syntax table. delete_form_3: cmp [bx],di ;do we need to adjust this one? jae delete_form_4 ;no. add [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,formb delete_form_5: cmp hash_link[bx],di ;do we need to adjust this one? jae delete_form_6 ;no. add hash_link[bx],ax ;yes - do it. delete_form_6: add bx,form_length[bx] ;compute the form after this one. cmp bx,forme ;no forms after this one. jb delete_form_5 add formb,ax mov si,di ;now move everything up. add di,ax mov cx,si sub cx,actptr dec si dec di std ;reverse move rep movsb cld inc di ;update actptr mov actptr,di ret ;find the form whose name is given in arg1. Return the form pointer in ;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 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: call getarg call find_form jnc find_arg1_1 ;if form doesn't exist, exit. mov si,bx ;make si => form.data add si,name_offset add si,name_length[bx] add si,form_pointer[bx] mov cx,data_length[bx] ;make cx = number of bytes left. sub cx,form_pointer[bx] stc ;remember that form was found. find_arg1_1: ret ;rehash is used when the hash structure is garbage, i.e., when a file has ; been bulk-loaded. public rehash rehash: mov di,offset formhash ;kill all of the current pointers. mov cx,formhashsize mov ax,NIL rep stosw mov di,formb rehash_1: lea si,name_offset[di] ;->name. mov cx,name_length[di] call hash_func mov ax,[bx] ;get current formhash mov [bx],di ;make formhash point to us. mov hash_link[di],ax ;make us point to current formhash. add di,form_length[di] cmp di,forme jb rehash_1 ret hash_func: ;enter with si,cx ->name to be hashed. ;the particular function we will use is: ; value=(((char*2+char)*2+char)*2+char)*2+char ... ;of course, most of the chars will be in the range [A-Za-z], so this ; may not be the best hashing function. Time will tell. ;exit with entry into hash table in bx. ;preserve dl. push si push cx xor bl,bl ;start with zero. jcxz hash_func_1 hash_func_2: add bl,bl ;*2 adc bl,0 lodsb sub al,'a' ;subtract off the most probable char. add bl,al ;+char adc bl,0 loop hash_func_2 hash_func_1: mov bh,0 add bx,bx lea bx,formhash[bx] ;don't 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 set_form_pointer set_form_pointer: mov ax,data_length[bx] sub ax,cx mov form_pointer[bx],ax ret public return_form return_form: call set_form_pointer jmp return_tos extrn return_tos: near extrn getarg: near extrn nomem: near ;code ends end