title ATOM - atom package include kernel.inc include gpfix.inc MAXINTATOM = 0C000h PRIME = 37 ACTION_FIND = 0 ACTION_ADD = 1 ACTION_DEL = 2 ATOMTABLE STRUC at_prime DW ? ; Hash modulus at_hashTable DW ? ; variable length array ATOMTABLE ENDS ATOM STRUC a_chain DW ? a_usage DW ? a_len DB ? a_name DB ? ATOM ENDS externW externFP externNP ifdef FE_SB externNP MyIsDBCSLeadByte endif sBegin MISCCODE assumes cs, misccode assumes ds, nothing assumes es, nothing ; ; This procedure should be called once by each new client program. It ; will initialize the atom table for the caller's DS and store a pointer ; to the atom table in a reserve location in the caller's DS. ; We expect return value to be in CX as well as AX. (jcxz!) ; cProc InitAtomTable, parmW tblSize cBegin mov ax,ds:[pAtomTable] ; Don't create if already exists or ax,ax jnz initdone mov bx,tblSize or bx,bx jnz gotsize mov bl,PRIME gotsize: push bx inc bx ; space for table size shl bx,1 mov ax,LA_ZEROINIT cCall LocalAlloc, pop dx jcxz initDone ; Failure mov ds:[pAtomTable],ax mov bx,ax mov ds:[bx].at_prime,dx ; First word in hash is hash modulus initDone: mov cx,ax cEnd sEnd MISCCODE sBegin CODE assumes CS,CODE assumes DS,NOTHING assumes ES,NOTHING labelFP mov cl,ACTION_DEL db 0BBh ; mov bx, labelVDO AddAtom mov cl,ACTION_ADD db 0BBh ; mov bx, labelVDO FindAtom mov cl,ACTION_FIND errn$ LookupAtom ; ; Common procedure to add, find or delete an atom table entry. Called ; with a far pointer to the name string and an action code in CL register ; Works in an SS != DS environment. ; cProc LookupAtom,, parmD pName localW hName localB action cBegin beg_fault_trap la_trap mov [action],cl mov cx,SEG_pName ; If segment value is zero ifdef FE_SB or cx,cx jne @F jmp haveIntAtom @@: else jcxz haveIntAtom ; ...then integer atom endif mov hName,cx les si,pName ; ES:SI = pName cmp byte ptr es:[si],'#' ; Check for integer atom je parseIntAtom xor ax,ax cmp ds:[pAtomTable],ax ; Make sure we have an atom table jne tblokay cCall InitAtomTable, jcxz fail1 notIntAtom: les si,pName ; ES:SI = pName tblokay: xor ax,ax ; c = 0 xor cx,cx ; size = 0 xor dx,dx ; hash = 0 cld loop1: ; while { lods byte ptr es:[si] ; c = *pName++ or al,al ; if (!c) break; jz xloop1 inc cl ; size++ jz fail1 ; if (size > 255) fail ifdef FE_SB call MyIsDBCSLeadByte ; Is first of 2byte DBCS char ? jnc loop1ax ; Yes. endif call MyUpper ifdef FE_SB jmp short loop1a ; go normal loop1ax: mov bx, dx ; caluculate hash value rol bx, 1 add bx, dx add bx, ax ror dx, 1 add dx, bx lods byte ptr es:[si] ; Get Next char or al, al ; end of strings ? jz xloop1 ; yes, break; inc cl ; jz fail1 ; (size > 255) error endif loop1a: mov bx,dx ; hash = rol bx,1 ; + hash << 1 add bx,dx ; + hash add bx,ax ; + c ror dx,1 ; + hash >> 1 add dx,bx jmp loop1 ; } end of while loop ; Here if pName points to string of the form: #nnnn parseIntAtom: inc si ; pName++ xor cx,cx ; sum = 0 xor ax,ax loop3: lods byte ptr es:[si] ; c = *pName++ or al,al ; if (!c) break; jz xloop3 sub al,'0' ; if (!isdigit(c)) cmp al,9 ja notIntAtom ; imul cx, cx, 10 ; sum = (sum * 10) + (c - '0') add cx, ax jmp loop3 haveIntAtom: mov cx,OFF_pName ; Get integer atom xloop3: jcxz fail1 cmp cx,MAXINTATOM jae fail1 mov ax,cx ; return sum jmp do_exit fail1: xor ax,ax ; Fail, return NULL jmp do_exit xloop1: jcxz fail1 ; if (size == 0) fail xchg ax,dx ; DX:AX = hash mov bx,ds:[pAtomTable] div ds:[bx].at_prime lea bx,ds:[bx].at_hashTable ; pp = &hashTable[ hash % PRIME ] shl dx,1 add bx,dx mov dx,cx ; size mov ax,ss ; Setup for cmpsb mov es,ax loop2: ; while { mov si,[bx] ; p = *pp or si,si ; if (!p) break jz xloop2 cmp [si].a_len,dl ; if (p->len != size) jne loop2a ; continue les di,pName ; s2 = pName lea si,[si].a_name ; s1 = &p->name mov cx,dx ; size loop4: jcxz loop4x dec cx lodsb ; c1 = *s1++ ifdef FE_SB call MyIsDBCSLeadByte ; first byte of 2byte ? jc loop4a ; No, go normal mov ah, al ; save char mov al, es:[di] ; get *s2 inc di ; s2++ cmp ah, al ; compare *s1, *s2 jne loop4x ; not same, do next strings jcxz loop4x ; not necessary but case of bad strings dec cx lodsb ; get next char ( this must be second mov ah, al ; of 2byte ) mov al, es:[di] inc di cmp ah, al je loop4 ; same, go next char jmp loop4x ; not same, go next strings loop4a: endif call MyUpper mov ah,al mov al,es:[di] call MyUpper inc di ; c2 = *s2++ cmp ah,al je loop4 loop4x: mov si,[bx] ; p = *pp je xloop2 loop2a: lea bx,[si].a_chain ; pp = &p->chain jmp short loop2 ; } end of while loop xloop2: ; Dispatch on command. xor cx,cx mov cl,[action] jcxz do_find errnz ACTION_FIND loop do_delete errnz ACTION_ADD-1 do_add: or si,si ; NULL? jz do_insert inc [si].a_usage ; Already in list. Increment reference count. jmp short do_find do_delete: or si,si ; NULL? jz short do_exit ; Return NULL for internal errors dec [si].a_usage jg do_delete1 xor di,di xchg [si].a_chain,di ; *pp = p->chain, p->chain = 0; mov [bx],di cCall LocalFree, ; LocalFree( p ) do_delete1: xor si,si ; p = NULL jmp short do_find do_insert: mov di,bx ; save pp push dx ; save size add dx,size ATOM ; p = LocalAlloc( sizeof( ATOM )+size ) mov bx,LA_ZEROINIT cCall LocalAlloc, ; LocalAlloc( ZEROINIT, size ) pop cx ; restore size mov si,ax or si,si jz do_find mov [di],si ; *pp = p inc [si].a_usage ; p->usage = 1 mov [si].a_len,cl ; p->len = size mov bx,si push ds ; ES = DS pop es lea di,[si].a_name ; strcpy( &p->name, pName ) xor cx,cx mov cl,[si].a_len ; CX = #bytes to move inc cx ; include terminating null lds si,pName cld rep movsb push es pop ds ; Restore DS mov si,bx do_find: mov ax,si ; return p shr ax,1 shr ax,1 jz do_exit or ax,MAXINTATOM end_fault_trap do_exit: cEnd la_trap: fault_fix_stack xor ax,ax ; return NULL/FALSE jmp do_exit cProc IDeleteAtom, parmW atom1 regPtr lpName,ds,bx cBegin mov bx,atom1 cmp bx,MAXINTATOM jb freeExit shl bx,2 lea bx,[bx].a_name cCall DelAtom, jmp short freeDone freeExit: xor ax,ax freeDone: cEnd cProc IGetAtomHandle, parmW atom2 cBegin mov ax,atom2 cmp ax,MAXINTATOM jae @F xor ax, ax @@: shl ax,2 cEnd cProc IGetAtomName,, parmW atom3 parmD pString parmW maxChars cBegin beg_fault_trap getn_trap cld les di,pString cmp maxChars,0 je getnFail xor cx,cx mov byte ptr es:[di],cl mov bx,atom3 cmp bx,MAXINTATOM jb getIntAtom shl bx,2 ; Parameter validation - is this a pointer to a valid local allocation ; block, and is the block in use? nfd = la_next - la_fixedsize ; given pointer to data, get mov si, [bx.nfd] ; pointer to 'next' allocation mov si, [si] ; p = p->prev and si, not (LA_BUSY + LA_MOVEABLE) sub si, bx cmp si, -la_fixedsize jnz getnFail test word ptr [bx-la_fixedsize], LA_BUSY jz getnFail ; The usage count must be >0 cmp [bx].a_usage,cx je getnFail ; Len must be >0 mov cl,[bx].a_len jcxz getnFail cmp maxChars,cx jg getnOkay mov cx,maxChars dec cx getnOkay: lea si,[bx].a_name mov ax,cx rep movsb mov byte ptr es:[di],0 jmps getnDone getn_trap: fault_fix_stack ; Yes, fault handler can be within range getnFail: mov ax, atom3 krDebugOut DEB_WARN, "GetAtomName(#AX,...) Can't find atom" xor ax, ax jmps getnDone getIntAtom: ; When a buffer of length "n" is passed, we must reserve space for ; the '#' character and a null terminator; ; Fixed Bug #6143 --SANKAR-- 11-9-89 mov cx, maxChars cmp cx, 2 ; one '#' and one '\0' are a must! jl getnFail ; If it is less we fail; sub cx, 2 ; Allow two char spaces for '#' and '\0' mov maxChars, cx or bx,bx jz getnFail mov al,'#' stosb mov ax,bx mov bx,10 mov cx, maxChars jcxz getIntDone getIntLoop: xor dx,dx div bx push dx dec cx or ax,ax jz gotIntAtom jcxz gotIntAtom jmp getIntLoop gotIntAtom: sub maxChars,cx mov cx,maxChars getIntChar: pop ax add al,'0' stosb loop getIntChar getIntDone: xor al,al stosb mov ax,maxChars inc ax ; For the '#' Character end_fault_trap getnDone: cEnd sEnd CODE end