;*********************************************************************
;*   MLSHARED.ASM                                                    *
;*                                                                   *
;*   By:            Michael Devore                                   *
;*   Date:          12/21/92                                         *
;*   Model:         Small                                            *
;*   Version:       2.5                                              *
;*   Assembler:     MASM 5.0                                         *
;*   Environment:   MS-DOS 2.x+                                      *
;*                                                                   *
;*   routines shared by pass one and pass two                        *
;*                                                                   *
;*********************************************************************

;TITLE   WARPLINK mlshared
;PAGE    50,80

;.MODEL  SMALL

;*****************************
;* Include files             *
;*****************************

[list -]
%include "lmacros2.mac"
[list -]
%include "mlequate.mac"
%include "mldata.mac"
%include "mlerrmes.mac"
[list +]

;*****************************
;* Public declarations       *
;*****************************

; procedures
PUBLIC  perform_pass,get_name,get_hash,load_file
PUBLIC  error_bx_pos,error_read_buff_pos,get_curr_obj,print_link_info

; variables
PUBLIC  filename,pass_number,obj_block_ptr
PUBLIC  ems_first_avail,ems_pages_flushed,obj_handle

;*****************************
;* Data begins               *
;*****************************

.DATA

;*****************************
;* External declarations     *
;*****************************

; variables
EXTRN   lib_handle:WORD,lib_read_amt:WORD
EXTRN	is_local:BYTE

; initialized local variables

; byte values
use_ems_maps    DB  0       ; nonzero if object modules are, or can be, mapped to EMS pages
EVEN
ems_pages_flushed   DB  0   ; nonzero if EMS pages flushed to make room for ovl, temp file
EVEN

; word values
ems_first_avail DW  4       ; first available ems logical page -- updated as used

.DATA?

; uninitialized local variables

; byte values
EVEN                        ; maximize speed on 8086 and better
filename    DB  128 DUP (?) ; current object module file name
pass_number DB  ?           ; number of pass

; word values
EVEN
obj_handle  DW  ?           ; handle of currently open object file
obj_block_ptr   DW  ?       ; segment of current object module name block
pos_in_list DW  ?           ; position to read name in object name block namelist
ems_map_blk DW  ?           ; segment of block hold 4 word entries for each obj, with EMS page maps

;*****************************
;* Constant data             *
;*****************************

.CONST

proctext_len    DB  proctext_stop-proc_text
proc_text       DB  CR,LF,'*** Processing file: '
proctext_stop   equ   $

string_.end:
.:		db ".END"
.size equ $ - .

string_.amount:
.:		db ".AMOUNT"
.size equ $ - .

msg_used_prefix:counted 13,10,"Used wllist label: "

data_modend:
.:		db MODEND, 2, 0, 0, -(MODEND + 2 + 0 + 0)
.size equ $ - .

data_segdef_be_127:
.:		db SEGDEF
		dw .size - 3
		db 48h		; WORD, PUBLIC
.segmentlength:	dw 0
.segmentlname:	db 0
		db 1		; class name (empty)
		db 1		; overlay name (empty)
		db 0		; checksum
.size equ $ - .

data_segdef_ae_128:
.:		db SEGDEF
		dw .size - 3
		db 48h		; WORD, PUBLIC
.segmentlength:	dw 0
		db 80h		; high 7 bits of segment name lname index
.segmentlname:	db 0
		db 1		; class name (empty)
		db 1		; overlay name (empty)
		db 0		; checksum
.size equ $ - .

data_theadr:
.:		db THEADR
		dw .size - 3
		counted "(wllist)"
		db 0		; checksum
.size equ $ - .


;*****************************
;* Code begins               *
;*****************************

.CODE

;*****************************
;* External declarations     *
;*****************************

; procedures
EXTRN   link_error:NEAR,dos_error:NEAR,alloc_memory:NEAR
EXTRN   pass1_obj_proc:NEAR,pass2_obj_proc:NEAR
EXTRN   load_buffer:NEAR,read_to_ems:NEAR
EXTRN   decrypt:NEAR,setup_incinfo:NEAR,map_ems_page:NEAR,restore_ems_map:NEAR

;*****************************
;* PERFORM_PASS              *
;*****************************

; perform generic pass 1 and pass 2 object module processing, route to appropriate pass code
; al has number of linker pass (1 or 2) upon entry
; destroys all registers

perform_pass    PROC    NEAR
    mov [pass_number],al      ; save pass number to memory variable
    and word [current_obj],0       ; init current object module number
    mov ax,[first_objblk_ptr]
    mov [obj_block_ptr],ax    ; init current block pointer to first block

pp_loop:
    mov ax,[obj_count]        ; get total count of object modules
    cmp ax,[current_obj]      ; end loop when current equals total
    ja  pp_getobj           ; more object modules
    jmp NEAR PTR pp_ret     ; all done

pp_getobj:
	rol byte [is_wllist_enabled], 1
	jnc @F
    cmp byte [pass_number],1       ; see if pass one processing
    jne @F
	dec ax			; count minus 1
	cmp word [current_obj], ax
				; is it last ?
	jne @F			; no -->
	call process_wllist	; process before continuing
@@:
    call    get_curr_obj    ; get current object module in filename

    xor ax,ax
    mov WORD PTR [file_pos_adj],ax    ; init file position adjustment
    mov WORD PTR [file_pos_adj+2],ax

    call    print_link_info

pp_2:
    cmp byte [pass_number],1       ; see if pass one processing
    jne pp_pass2            ; no, assume pass two

    mov dx,OFFSET filename wrt DGROUP   ; DS:DX -> ASCIIZ file specification
    mov ax,3d00h            ; open file with read access
    int 21h
    call    restore_ems_map
    jnc pp_noerr            ; no errors
    jmp NEAR PTR dos_error  ; error opening file

pp_noerr:
    mov [obj_handle],ax       ; save object module file handle
    mov bx,ax               ; save handle in bx
    call    load_buffer     ; load the file in the i/o buffer

    cmp byte [is_clpinc],0         ; see if clipper incremental link specified
    je  pp_noinc            ; no
    call    setup_incinfo   ; setup incremental info for file

pp_noinc:
    call    pass1_obj_proc  ; perform pass 1 object module processing

; if using EMS, check if can map out page(s) used by i/o buffer
    call    ems_page_mapout
    jmp SHORT pp_closefile  ; skip over pass 2 code

pp_pass2:

; if using EMS, check if object modules have page(s) to map in
    call    ems_page_mapin
    or  al,al               ; nonzero return if page was successfully mapped in
    je  pp_loadfile         ; not mapped in, load file
    call    pass2_obj_proc  ; perform pass 2 object module processing
    jmp SHORT pp_bumpobj

pp_loadfile:
    mov dx,OFFSET filename wrt DGROUP   ; DS:DX -> ASCIIZ file specification
    mov ax,3d00h            ; open file with read access
    int 21h
    call    restore_ems_map
    jnc pp_noerr2           ; no errors
    jmp NEAR PTR dos_error  ; error opening file

pp_noerr2:
    mov [obj_handle],ax       ; save object module file handle
    mov bx,ax               ; save handle in bx
    call    load_buffer     ; load the file in the i/o buffer
    call    pass2_obj_proc  ; perform pass 2 object module processing

pp_closefile:
    mov bx,[obj_handle]       ; get file handle of open object module file
    mov ah,3eh              ; close file
    int 21h
    call    restore_ems_map

pp_bumpobj:
    inc word [current_obj]         ; bump number of current object module
    jmp NEAR PTR pp_loop    ; loop back for next object module

pp_ret:
    ret
perform_pass    ENDP

;*****************************
;* PRINT_LINK_INFO           *
;*****************************

; print linker files being processed, if option set
; upon entry filename holds the file name
; destroys ax,bx,cx,dx,si

print_link_info PROC
    cmp byte [is_linkinfo],0       ; see if linker information to be printed
    je  pli_ret             ; no

    mov bx,OFFSET proc_text wrt DGROUP
    mov cl,[bx-1]           ; get length of string to print
    mov dx,bx               ; ds:dx -> string
    xor ch,ch               ; zap high byte of cx
    mov bx,STDOUT           ; write to standard output device
    mov ah,40h              ; write to device
    int 21h

    mov si,OFFSET filename wrt DGROUP   ; print chars in filename one at a time

pli_filename:
    mov dx,si
    lodsb                   ; get char from filename
    or  al,al               ; see if null terminator
    je  pli_ret             ; done
    mov cx,1
    mov ah,40h              ; write to device
    int 21h
    jmp SHORT pli_filename

pli_ret:
    ret
print_link_info ENDP

;*****************************
;* EMS_PAGE_MAPOUT           *
;*****************************

; map pages out to EMS if possible
; if first object module, allocate block to hold object module mapped out pages
; destroys ax,bx,cx,dx,si,di,es

ems_page_mapout PROC
    xor ax,ax
    cmp [is_no_ems],al        ; see if EMS used
    jne eout_ret            ; no

    cmp [any_ddl],al          ; see if DDL's used
    jne eout_ret            ; yes

    cmp [is_inlib],al         ; see if processing library
    je  eout_1              ; no

eout_ret:
    ret

eout_1:
    cmp [current_obj],ax      ; see if first object module (== 0)
    jne eout_2              ; no

; first object module, each module will have 4 word entries to hold EMS pages
eout_first:
    mov bx,[obj_count]        ; get object module count
    add bx,1                ; round up for 8-byte to paragraph conversion
    shr bx,1                ; bx holds paragraphs to allocate
    call    alloc_memory
    mov [ems_map_blk],ax      ; save segment of ems map block for object modules
    mov byte [use_ems_maps],1      ; set ems maps used flag

eout_2:
    mov di,[current_obj]
    shl di,1
    shl di,1
    shl di,1                ; x8, di holds offset into ems map block for object module
    mov es,[ems_map_blk]      ; es:di -> proper obj ems map block entry
    mov ax,-1               ; init to all -1's to show unused
    stosw
    stosw
    stosw
    stosw                   ; all four entries init'ed
    sub di,8                ; point es:di back to beginning of entry

    mov ax,WORD PTR [file_pos_adj]
    or  ax,WORD PTR [file_pos_adj+2]  ; see if buffer wrapped
    jne eout_ret            ; yes, more than 4 pages used, cannot map out
    mov cx,1                ; init count of pages to map out

; si holds final byte used+1, used to compute number of pages to map out
eout_loop:
    sub si,16384            ; back off one page
    jbe eout_3              ; si ended on this page
    inc cx                  ; bump count of pages to map out
    jmp SHORT eout_loop     ; loop for next page check

eout_3:
    cmp word [ems_page_avail],4    ; must have over four free pages
    jbe eout_ret            ; not enough

    mov ax,[ems_page_avail]   ; get count of free pages
    sub ax,4                ; back off four free pages
    sub ax,cx               ; see if enough free pages to save this obj in ems
    jc  eout_ret            ; no

; map obj to ems pages, bring in free pages
    add ax,4                ; adjust back for four free pages
    mov [ems_page_avail],ax   ; save new count of free pages

    mov ax,cx               ; save count of pages mapped out
    mov si,OFFSET ems_currmap wrt DGROUP    ; ds:si -> physical page entries
    rep movsw               ; move all used physical pages

    mov cx,ax               ; restore count of pages mapped out
    xor al,al

eout_loop2:
    push    ax              ; save physical page
    mov bx,[ems_first_avail]  ; map in first available free page
    inc word [ems_first_avail]     ; bump first available page
    call    map_ems_page
    pop ax                  ; restore physical page
    inc al                  ; bump physical page
    loop    eout_loop2      ; loop until all free pages are mapped in

    ret
ems_page_mapout ENDP

;*****************************
;* EMS_PAGE_MAPIN            *
;*****************************

; returns al==0 if cannot map in from EMS, nonzero if page mapped from
; EMS and no file load required
; destroys ax,bx,cx,dx,si,es

ems_page_mapin  PROC
    cmp byte [is_no_ems],0         ; see if EMS used
    jne ein_usefile         ; no

    cmp byte [is_inlib],0          ; see if processing library
    jne ein_usefile         ; yes

    cmp byte [use_ems_maps],0      ; see if EMS maps used
    je  ein_usefile         ; no

    cmp byte [ems_pages_flushed],0 ; see if EMS pages flushed to store ovl, temporary file
    jne ein_usefile         ; yes

; it may be possible to map in page from EMS, check status
    mov si,[current_obj]
    shl si,1
    shl si,1
    shl si,1                ; x8, si holds offset into ems map block for object module
    mov es,[ems_map_blk]      ; es:si -> proper obj ems map block entry
    xor cl,cl               ; cl holds physical page

ein_loop:
    es lodsw   ; get map page
    cmp ax,-1               ; see if not used (if not used, then no following ones are either)
    je  ein_chksuccess      ; not used
    mov bx,ax               ; get logical page in bx
    mov al,cl               ; get physical page in al
    call    map_ems_page    ; map in used pages
    inc cl                  ; bump physical page
    cmp cl,4                ; see if all physical pages mapped
    jb  ein_loop            ; not yet

ein_chksuccess:
    or  cl,cl               ; if cl is zero then no pages mapped, not successful
    je  ein_usefile         ; no pages mapped in

; at least one page mapped in, success
    mov al,1                ; return one to show success
    ret

ein_usefile:
    xor al,al               ; return zero to show must load buffer from file
    ret
ems_page_mapin  ENDP

;*****************************
;* GET_CURR_OBJ              *
;*****************************

; get current object module name in filename
; destroys ax,si,di,es

get_curr_obj    PROC
    cmp word [current_obj],0       ; see if first object file, requires position initialization
    jne gco_2               ; nope

gco_5:
    mov word [pos_in_list],4       ; init position in name list to first position in block

gco_2:
    mov si,[pos_in_list]      ; si will offset into block
    mov ax,[obj_block_ptr]    ; get current object name block
    mov es,ax               ; point extra segment at object name block
    mov ax,OBJ_NAMBLK_BYSIZE    ; size of block in bytes
    sub ax,[es:0]           ; minus free space, ax == end of used namelist
    cmp ax,si               ; check that position in list is below end
    ja  gco_3               ; not at end yet, pull name from this block's namelist

    mov ax,[es:2]           ; get pointer to next block
    mov [obj_block_ptr],ax    ; save back to memory variable
    or  ax,ax               ; check that is not null
    jne gco_5               ; non-null, next block exists, loop back and try with it

; A WarpLink internal error has occurred, no more object names were
; available before the count of all object modules was complete
    mov ax,INTERNAL_ERR     ; put warplink error code in ax
    mov cx,2                ; internal error value
    jmp NEAR PTR link_error ; transfer control to error handler

gco_3:
	es lodsb	; get flag byte
    and al,0c0h             ; only get overlay bits
    mov [obj_ovl_flag],al     ; save overlay status for module
    and al,40h              ; get nonvector root call status
    mov [nonovl_rvect],al     ; save it to global variable
    mov di,es               ; get object name block segment in di
    mov ax,ds
    mov es,ax               ; es -> warplink data area
    mov ds,di               ; ds -> object name block
    mov di,OFFSET filename wrt DGROUP   ; es:di -> destination of object module name

gco_6:
    movsb                   ; transfer a char from the block to filename
    cmp BYTE PTR [si-1],0   ; zero byte signals end of transfer
    jne gco_6               ; nonzero, keep looping

    mov ax,es
    mov ds,ax               ; ds -> warplink data

    mov [pos_in_list],si      ; si points to next name or end, save back to memory
    ret
get_curr_obj    ENDP

;*****************************
;* GET_NAME                  *
;*****************************

; es:si -> string upon entry
; ds:di -> warplink data location to place string
; bp == buffer end (buffer_end)
; cx == length of current record
; is_local nonzero if local variable (mangle name to unique)
; destroys ax,dx,di
; updates si to point past string
; updates cx to record length after string

get_name        PROC
    mov dx,cx               ; save object record length in dx
    mov cl,[es:si]          ; get 1-byte length of name
    xor ch,ch               ; zap high byte
    push    cx              ; save number of bytes to transfer
    inc si                  ; point to first char of name
    dec dx                  ; decrement record length to parse
    jcxz    gn_out          ; zero length name, no name chars to transfer
    cmp si,bp               ; check boundary conditions
    jae gn_load1            ; out of bounds

gn_1:
    cmp byte [is_casesense],0      ; check to see if string should go to all caps
    mov ax,es
    mov ds,ax
    mov ax,DGROUP
    mov es,ax               ; swap es and ds for string operations
    je  gn_5                ; not case sensitive, convert string to caps

%IFNDEF DEMO
    mov ax,si
    add ax,cx               ; get final char position of string
    jc  gn_3                ; overflow, buffer end will be reached during transfer
    cmp ax,bp
    jae gn_3                ; buffer end will be reached during transfer

; names are case sensitive, no alteration (to all caps) of chars occurs
; buffer end will not be reached during transfer
; this allows a straight REP MOVS memory move
    shr cx,1                ; convert to words
    rep movsw               ; move the string
    rcl cx,1                ; pick up carry
    rep movsb               ; transfer leftover byte, if any
    jmp SHORT gn_seg_restore    ; bypass char by char transfer code

; transfer to destination, case sensitive, buffer end reached sometime during transfer
gn_3:
    movsb                   ; transfer a byte
    cmp si,bp               ; check boundary conditions
    jae gn_load3            ; out of bounds

gn_4:
    loop    gn_3            ; loop back for next char transfer
    jmp SHORT gn_seg_restore
%ENDIF

; case insensitive, convert lowercase to upper, check for boundary conditions
gn_5:
    lodsb                   ; get byte to transfer
    cmp al,'a'              ; check lowercase lower boundary
    jb  gn_6                ; not a lowercase letter
    cmp al,'z'              ; check lowercase upper boundary
    ja  gn_6                ; not a lowercase letter
    sub al,20h              ; convert to uppercase

gn_6:
    stosb                   ; transfer char
    cmp si,bp               ; check boundary conditions
    jae gn_load2            ; out of bounds

gn_7:
    loop    gn_5            ; loop back for next char transfer

gn_seg_restore:
    mov ax,es
    mov cx,ds
    mov ds,ax               ; restore ds -> warplink data
    mov es,cx               ; restore es

; 12/22/92
gn_out:
	cmp	byte [is_local],0			; see if local variable
	jne	gn_local			; yes

gn_nullit:
    mov BYTE PTR [di],0     ; null terminate the destination string
    mov cx,dx               ; restore remaining record length to cx
    pop ax                  ; get bytes transferred
    sub cx,ax               ; update record length
    ret

gn_load1:
    call    load_file       ; load next portion of file into buffer, at end position
    jmp SHORT gn_1

gn_load2:
    call    load_file
    jmp SHORT gn_7

%IFNDEF DEMO
gn_load3:
    call    load_file
    jmp SHORT gn_4
%ENDIF

; 12/22/92
; local variable, mangle name by adding unique identifier at end
gn_local:
	cmp	byte [is_inlib],0			; see if processing library
	jne	gn_loclib			; yes

; mangle based on current_obj word variable, set high word to 4001h
	mov	ax,[current_obj]		; (current_obj << 1) | 0x8001
	shl	ax,1
	or	ax,8001h
	mov	[di],ax
	add	di,2
	mov	word [di],4001h
	add	di,2
	jmp	SHORT gn_nullit

; mangle based on lib_id dword variable
gn_loclib:
	push	dx
	mov	ax,WORD PTR [lib_id]
	mov	dx,WORD PTR [lib_id+2]
	shl	ax,1
	rcl	dx,1				; high word picks up rolled off high bit low word
	shl	dx,1
	or	ax,8001h
	mov	[di],ax
	add	di,2
	or	dx,08001h			; set high bit with libraries
	mov	[di],dx
	add	di,2
	pop	dx
	jmp	SHORT gn_nullit

get_name        ENDP

;*****************************
;* GET_HASH                  *
;*****************************

; returns 10-bit hashcode value in ax
; ds:si -> string upon entry
; destroys ax,si

get_hash    PROC    NEAR
    push    dx              ; save critical registers
    xor dx,dx               ; dx==hashcode, init to zero
    mov ah,dl               ; zero high byte of char value

gh_2:
    lodsb                   ; get char from string
    or  al,al               ; check for null terminator in string
    je  gh_out              ; hashcode computed
    add dx,ax               ; add in character value byte, ignore overflow
    jmp SHORT gh_2          ; loop until end of string

gh_out:
    mov ax,dx               ; ax = hashcode
    and ax,03ffh            ; make 10-bit value
    pop dx
    ret
get_hash    ENDP

;*****************************
;* LOAD_FILE                 *
;*****************************

; load next chunk of file containing object records into file buffer
; updates si to point to first read in char
; updates bp to point to new buffer_tail
; destroys no other registers

load_file   PROC
    push    ax              ; save critical registers
    push    bx
    push    cx
    push    dx
    push    ds
    mov ax,DGROUP
    mov ds,ax               ; ds -> warplink data
    cmp si,[buffer_end]       ; see if buffer end overflow or buffer tail overflow
    jae lf_3                ; buffer end overflow

; current buffer position >= buffer_tail and <= buffer_end
    mov ax,[buffer_tail]
    cmp byte [prev_flag],0         ; see if previous record needs to be preserved
    je  lf_2                ; no
    cmp ax,[prev_read_ptr]    ; see if tail is at previous record position
    je  lf_mem              ; yes, out of memory

lf_2:
    mov [buffer_head],ax      ; update buffer head to old buffer tail
    mov ax,[buffer_end]       ; get buffer end as new tail position
    cmp byte [prev_flag],0         ; see if need to save previous record
    je  lf_2a               ; no
    mov bx,[prev_read_ptr]
    cmp bx,[buffer_head]      ; check previous record position against buffer head
    jb  lf_2a               ; below buffer head, no overwrite problem
    cmp bx,ax               ; check previous record position against new tail position
    jae lf_2a               ; above or equal to buffer tail, no overwrite
    mov ax,[prev_read_ptr]    ; set tail so that previous record won't be overwritten

lf_2a:
    cmp byte [is_inlib],0          ; see if processing library
    je  to_lf_shared        ; no
    cmp byte [udl_proc_pass],1     ; see if udl processing
    je  lf_noddl            ; yes
    cmp byte [any_ddl],0           ; see if creating/using DLL (all libraries treated as object modules)
    jne to_lf_shared		; yes

lf_noddl:
    mov bx,LIB_MAX_READ
    add [lib_read_amt],bx     ; reread on same library module, bump amount read this time by LIB_MAX_READ bytes
	jc	lf_overflow			; can't read that much
	cmp	word [lib_read_amt],0ff00h	; see if past max buffer
	jbe	lf_2b				; no

lf_overflow:
	sub	[lib_read_amt],bx		; adjust back

lf_2b:
    mov bx,[buffer_tail]      ; get old buffer tail
    add bx,[lib_read_amt]     ; add maximum buffer read for library
    jc  lf_shared           ; overflow, new tail position won't exceed lib_read_amt from old tail position
    cmp ax,bx               ; see if new tail position is more than lib_read_amt from old position
    jbe lf_shared           ; no
    mov ax,bx               ; use lib_read_amt from old tail position as new tail instead

to_lf_shared:
    jmp SHORT lf_shared     ; jump to shared code

; current buffer position >=buffer_end
lf_3:
    cmp byte [prev_flag],0         ; see if previous record needs to be preserved
    je  lf_4                ; no
    cmp word [prev_read_ptr],0     ; see if previous record started at beginning of file buffer
    jne lf_4                ; no

; previous record must be preserved and takes up remaining file buffer, out of memory
lf_mem:
    mov ax,8                ; force DOS out of memory error
    jmp NEAR PTR dos_error

lf_4:
    mov ax,[buffer_end]       ; add buffer end to file position adjustment variable
    add WORD PTR [file_pos_adj],ax    ; update low word
    adc WORD [file_pos_adj+2],0   ; carry to high word
    mov word [buffer_head],0       ; set buffer head to physical beginning of buffer
    mov ax,[read_buff_ptr]    ; get current beginning of record as new tail position

    cmp byte [prev_flag],0         ; see if previous record used
    je  lf_5                ; no
    mov ax,[prev_read_ptr]    ; use previous record position as tail

lf_5:
    cmp byte [is_inlib],0          ; see if processing library
    je  lf_shared           ; no
    cmp byte [udl_proc_pass],1     ; see if udl processing
    je  lf_noddl2           ; yes
    cmp byte [any_ddl],0           ; see if creating/using DLL (all libraries treated as object modules)
    jne lf_shared           ; yes

lf_noddl2:
    mov bx,LIB_MAX_READ
    add [lib_read_amt],bx     ; reread on same library module, bump amount read this time by LIB_MAX_READ bytes
	jc	lf_overflow2		; can't read that much
	cmp	word [lib_read_amt],0ff00h	; see if past max buffer
	jbe	lf_5b				; no

lf_overflow2:
	sub	[lib_read_amt],bx		; adjust back

lf_5b:
    mov bx,[lib_read_amt]     ; get maximum tail for library
    cmp ax,bx               ; see if new tail position is more than lib_read_amt from buffer start (at 0)
    jbe lf_shared           ; no
    mov ax,bx               ; use lib_read_amt from buffer start (at 0) as new tail

lf_shared:
    mov [buffer_tail],ax      ; update buffer tail
    mov bp,ax               ; update buffer_tail bp register value
    sub ax,[buffer_head]      ; get difference between head and tail for bytes to load
    cmp byte [is_inlib],0          ; see if processing library
    je  lf_7                ; no
    mov bx,[lib_handle]       ; use library file handle
    jmp SHORT lf_8

lf_7:
    mov bx,[obj_handle]       ; use object module handle

lf_8:
    mov cx,ax               ; get number of bytes to read
    mov dx,[buffer_head]
    mov si,dx               ; update si -> first read in char
    mov ax,[buffer_base]
    push    ds
    mov ds,ax               ; ds:dx -> buffer area to load into

    call    read_to_ems     ; read file, transfer to EMS if necessary

    pop ds

lf_ret:
    call    decrypt         ; decrypt if SmartMem library
    cmp cx,ax               ; see if all bytes were read
    je  lf_ret2             ; yes

    mov byte [eof_flag],1          ; set end of file flag

lf_ret2:
    pop ds                  ; restore critical registers
    pop dx
    pop cx
    pop bx
    pop ax
    ret
load_file   ENDP

;*****************************
;* ERROR_BX_POS              *
;*****************************

; linker error, file position of error in bx
; terminates WarpLink, all non-error reporting registers are trashable
; ax holds error code upon entry
; cx holds associated error value, if any
; ds:dx -> file name

error_bx_pos    PROC
    cmp si,bx               ; check if si is less than bx (buffer wrapped)
    jae er_2                ; no

; back buffer_end bytes off of file_pos_adj, error occurred before buffer wrap
    mov di,[buffer_end]
    sub WORD PTR [file_pos_adj],di    ; update low word
    sbb WORD [file_pos_adj+2],0   ; borrow to high word

er_2:
    mov si,bx               ; get proper record offset
    jmp NEAR PTR link_error ; transfer control to error handler
error_bx_pos    ENDP

;*****************************
;* ERROR_READ_BUFF_POS       *
;*****************************

; linker error, file position of error in read_buff_ptr
; terminates WarpLink, all non-error reporting registers are trashable
; ax holds error code upon entry
; cx holds associated error value, if any
; ds:dx -> file name

error_read_buff_pos PROC
    cmp si,[read_buff_ptr]    ; check if si is less than read_buff_ptr (buffer wrapped)
    jae erb_2               ; no

; back buffer_end bytes off of file_pos_adj, error occurred before buffer wrap
    mov di,[buffer_end]
    sub WORD PTR [file_pos_adj],di    ; update low word
    sbb WORD [file_pos_adj+2],0   ; borrow to high word

erb_2:
    mov si,[read_buff_ptr]    ; get proper record offset
    jmp NEAR PTR link_error ; transfer control to error handler
error_read_buff_pos ENDP


process_wllist:
	lframe
	lvar dword, seektemp
	lvar dword, seektempinner
	lvar fromwords(words(TEMPWLLIST_size)), buffer
	lvar word, length
	lvar word, nextfield
	lequ ?nextfield, repeatseen
	lvar word, lnameslength
	lequ ?lnameslength, collectfunction
	lvar word, currentindex
	lequ ?currentindex, ledataremaining
	lvar word, segmentlname
	lequ ?segmentlname, ledatabase
	lvar word, lnamemustexist
	lequ ?lnamemustexist, ledatadone
	lvar dword, seeklname
	lvar word, behindpartialrecord
	lvar word, ledata_next_offset
	lvar word, ledata_end_offset
	lvar word, ledata_skip_repeated
	lenter
	push ds
	pop es			; => DGROUP
	xor ax, ax
    mov word [buffer_head], ax       ; set buffer head equal to offset zero from buffer base
    mov ax,[buffer_end]       ; get physical end of buffer
    cmp ax, TEMPSTRINGWLLIST_size + GRPDEFBUFFER_size + 32
    jae @F
    mov cx,26                ; internal error value
.internal:
    mov ax,INTERNAL_ERR     ; put warplink error code in ax
    jmp NEAR PTR link_error ; transfer control to error handler

@@:
    ; mov [buffer_tail],ax      ; set tail to physical end of buffer

	mov dx, data_theadr
	mov cx, data_theadr.size
	call .checksum_dsdx
	call .writeobj_dsdx

 extern data_coment
 extern data_coment.size
	mov dx, data_coment
	mov cx, data_coment.size
	call .checksum_dsdx
	call .writeobj_dsdx

	call .prepare_lname
	xor cx, cx
	call .enter_lname

	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seektemp

.loop_get_lnames:
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 1		; current
	call .seektemp
	mov word [bp + ?seektemp], ax
	mov word [bp + ?seektemp + 2], dx

	mov cx, TEMPWLLIST_size
	call .readtemp0_maybe_eof
	je @F
	test ax, ax
	jz .end_get_lnames
.internal27:
    mov cx,27                ; internal error value
    jmp .internal

.internal28:
    mov cx,28                ; internal error value
    jmp .internal

@@:
	mov dx, cx
	mov cl, [twlLength]
	jcxz .internal28
	call .readtemp

	call .skipprefix
	cmp al, twlGroup
	je .loop_find_group_lname
	cmp al, twlNew
	je .loop_find_list_section_lname
	jmp .loop_get_lnames

.loop_find_group_lname:
	call .skipunder
	cmp al, twlGroup
	je @F
	mov cx, 33
	jmp .internal
@@:
	mov byte [bp + ?lnamemustexist], 0
	call .findlname

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0		; SOF
	call .seektemp
	lea dx, [bp + ?buffer]
	mov cx, TEMPWLLIST_size
	call .readtemp_ssdx

	mov cx, -1
	mov dx, - TEMPWLLIST_size
	mov al, 1		; current
	call .seektemp

	mov ax, word [bp + ?currentindex]
	test ah, ah
	jnz .internal32
	mov byte [bp + ?buffer + twlGroupIndex], al
	lea dx, [bp + ?buffer]
	mov cx, TEMPWLLIST_size
	call .writetemp_ssdx

	mov cl, byte [bp + ?buffer + twlLength]
	mov dx, TEMPWLLIST_size
	call .readtemp

	jmp .loop_get_lnames


.loop_find_list_section_lname:
	call .skipunder
	cmp al, twlSegment
	je .getsegment
	cmp al, twlList
	je .check_found_lnames
	mov cx, 31
	jmp .internal

.getsegment:
	mov byte [bp + ?lnamemustexist], 0
	call .findlname

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0		; SOF
	call .seektemp
	lea dx, [bp + ?buffer]
	mov cx, TEMPWLLIST_size
	call .readtemp_ssdx

	mov cx, -1
	mov dx, - TEMPWLLIST_size
	mov al, 1		; current
	call .seektemp

	mov ax, word [bp + ?currentindex]
	test ah, ah
	jnz .internal32
	mov byte [bp + ?buffer + twlSegmentIndex], al
	lea dx, [bp + ?buffer]
	mov cx, TEMPWLLIST_size
	call .writetemp_ssdx

	mov cl, byte [bp + ?buffer + twlLength]
	mov dx, TEMPWLLIST_size
	call .readtemp

	mov si, word [bp + ?nextfield]
	jmp .loop_find_list_section_lname

.findlname:
	call .skipunder
	dec si
 extern name_field
	mov di, name_field
	xor cx, cx
	db __TEST_IMM16		; skip stosb and inc
@@:
	stosb
	inc cx
	lodsb
	cmp al, '_'
	je @F
	cmp al, 0
	je @F
	cmp al, '?'
	jne @B
@@:
	xor ax, ax
	stosb
	dec si
	mov word [bp + ?nextfield], si
	mov word [bp + ?length], cx

	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seekobj
	mov word [bp + ?currentindex], 1

.find_existing_lname:
	mov cx, 3
	call .readobj0_maybe_eof
	je @F
	test ax, ax
	jz .new_lname
.internal32:
	mov cx, 32
	jmp .internal

@@:
	mov dx, word [1]
	cmp byte [0], LNAMES
	je @F
	xor cx, cx		; cx:dx = length of record
	mov al, 1		; current
	call .seekobj
	jmp .find_existing_lname

@@:
	mov word [bp + ?lnameslength], dx
.check_existing_lname:
	cmp word [bp + ?lnameslength], 1
	jbe .next_existing_lname
	mov cx, 1
	call .readobj0
	inc dx
	mov cl, [0]
	stc
	sbb word [bp + ?lnameslength], cx
	jc .internal32
	call .readobj

	cmp cx, word [bp + ?length]
	jne @F
	mov di, name_field
	mov si, 1
	repe cmpsb
	je .found_existing_lname
@@:
	inc word [bp + ?currentindex]
	jmp .check_existing_lname

.next_existing_lname:
	jne .find_existing_lname
	mov cx, 1
	call .readobj0
	jmp .find_existing_lname

.found_existing_lname:
	clc
@@:
	retn

.new_lname:
	rol byte [bp + ?lnamemustexist], 1
	jc @B

	push es
	pop ds
	mov dx, name_field
	mov cx, word [bp + ?length]
	call .enter_lname

	jmp .found_existing_lname

.prepare_lname:
	xor cx, cx
	xor dx, dx
	mov al, 1
	call .seekobj
	mov word [bp + ?seeklname], ax
	mov word [bp + ?seeklname + 2], dx

	mov ds, [es:buffer_base]
	mov di, TEMPSTRINGWLLIST_size
	mov al, LNAMES
	mov byte [di], al
	add di, 3
	mov word [bp + ?behindpartialrecord], di
	retn

.enter_lname:
	mov di, word [bp + ?behindpartialrecord]
	mov ax, di
	add ax, cx
	jc .enter_new_lname
	add ax, 2
	jc .enter_new_lname
	cmp ax, TEMPSTRINGWLLIST_size + 1024
	ja .enter_new_lname
	cmp ax, word [es:buffer_end]
	jbe .append_lname
.enter_new_lname:
	push cx
	push ds
	push dx
	call .dump_lname

	call .prepare_lname
	pop dx
	pop ds
	pop cx

.append_lname:
	push es
	mov es, [es:buffer_base]
	mov si, dx
	mov al, cl
	stosb
	rep movsb
	pop es
	mov word [bp + ?behindpartialrecord], di

.dump_lname:
	mov dx, word [bp + ?seeklname]
	mov cx, word [bp + ?seeklname + 2]
	mov al, 0
	call .seekobj

	mov ds, [es:buffer_base]
	mov cx, word [bp + ?behindpartialrecord]
	cmp cx, TEMPSTRINGWLLIST_size + 3
	jbe @F
	inc cx
	mov dx, TEMPSTRINGWLLIST_size
	sub cx, dx
	mov ax, cx
	sub ax, 3
	mov word [TEMPSTRINGWLLIST_size + 1], ax
	call .checksum_dsdx
	call .writeobj_dsdx
@@:
	xor cx, cx
	xor dx, dx
	mov al, 2
	call .seekobj

	retn


.check_found_lnames:
	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0		; SOF
	call .seektemp
	lea dx, [bp + ?buffer]
	mov cx, TEMPWLLIST_size
	call .readtemp_ssdx

	mov cl, byte [bp + ?buffer + twlLength]
	mov dx, TEMPWLLIST_size
	call .readtemp

	cmp byte [bp + ?buffer + twlSegmentIndex], 0
	je .no_section_error

	jmp .loop_get_lnames


.end_get_lnames:
	call .dump_lname

	mov word [bp + ?currentindex], 1
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seektemp

.loop_outer_get_segdef:
	mov word [bp + ?seektemp], ax
	mov word [bp + ?seektemp + 2], dx

	mov cx, TEMPWLLIST_size
	call .readtemp0_maybe_eof
	je @F
	test ax, ax
	jz .end_get_segdef
	jmp .internal27

@@:
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	cmp byte [twlSegmentIndex], 0
	je .loop_outer_get_segdef

	cmp byte [twlListUsed], twlUsedInitial
	jne .loop_outer_get_segdef

	mov ax, word [bp + ?currentindex]
	test ah, ah
	jnz .internal32

	xchg byte [twlSegmentIndex], al
	mov byte [twlListUsed], twlUsedNewSeg
	mov byte [bp + ?segmentlname], al

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0
	call .seektemp

	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 2		; EOF
	call .seekobj

	add ax, data_segdef_be_127.segmentlength - data_segdef_be_127
	adc dx, 0
	mov word [twlSegdefSizeOffset], ax
	mov word [twlSegdefSizeOffset + 2], dx
	push dx
	push ax

	push es
	pop ds
	mov al, byte [bp + ?segmentlname]
	mov byte [data_segdef_be_127.segmentlname], al
	mov byte [data_segdef_ae_128.segmentlname], al
	mov dx, data_segdef_be_127
	mov cx, data_segdef_be_127.size
	test al, al
	jns @F
	mov dx, data_segdef_ae_128
	mov cx, data_segdef_ae_128.size
@@:
	call .checksum_dsdx
	call .writeobj_dsdx

	mov cx, TEMPWLLIST_size
	call .writetemp0

	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

.loop_inner_get_segdef:
	mov word [bp + ?seektempinner], ax
	mov word [bp + ?seektempinner + 2], dx

	mov cx, TEMPWLLIST_size
	call .readtemp0_maybe_eof
	je @F
	test ax, ax
	jz .end_inner_get_segdef
	jmp .internal27

@@:
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	cmp byte [twlListUsed], twlUsedInitial
	jne .loop_inner_get_segdef

	mov cl, byte [bp + ?segmentlname]
	cmp byte [twlSegmentIndex], cl
	jne .loop_inner_get_segdef

	mov ax, word [bp + ?currentindex]
	mov byte [twlSegmentIndex], al
	mov byte [twlListUsed], twlUsedNewSeg

	mov dx, word [bp + ?seektempinner]
	mov cx, word [bp + ?seektempinner + 2]
	mov al, 0
	call .seektemp

	pop ax
	pop dx
	mov word [twlSegdefSizeOffset], ax
	mov word [twlSegdefSizeOffset + 2], dx
	push dx
	push ax

	mov cx, TEMPWLLIST_size
	call .writetemp0

	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	jmp .loop_inner_get_segdef

.end_inner_get_segdef:
	pop ax
	pop dx			; discard

	inc word [bp + ?currentindex]
				; done with this segdef

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .readtemp0
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	jmp .loop_outer_get_segdef


.end_get_segdef:

	mov word [bp + ?currentindex], 1
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seektemp

.loop_outer_get_grpdef:
	mov word [bp + ?seektemp], ax
	mov word [bp + ?seektemp + 2], dx

	mov cx, TEMPWLLIST_size
	call .readtemp0_maybe_eof
	je @F
	test ax, ax
	jz .end_get_grpdef
	jmp .internal27

@@:
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	cmp byte [twlGroupIndex], 0
	je .loop_outer_get_grpdef

	cmp byte [twlListUsed], twlUsedInitial
	jne .loop_outer_get_grpdef

	mov ax, word [bp + ?currentindex]
	test ah, ah
	jnz .internal32

	xchg byte [twlGroupIndex], al
	mov byte [twlListUsed], twlUsedNewGroup
	mov byte [bp + ?segmentlname], al

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .writetemp0

	mov dx, cx
	mov cl, byte [twlLength]
	call .readtemp

	push ds
	push es
	pop ds
	pop es			; swap
	mov di, TEMPSTRINGWLLIST_size
				; es:di -> buffer for grpdef record
	mov al, GRPDEF
	stosb
	scasw			; skip length
	mov al, byte [bp + ?segmentlname]
	test al, al
	jns @F
	mov byte [es:di], 80h
	inc di
@@:
	stosb
	push ds
	push es
	pop ds
	pop es			; swap back
	push di			; stack -> next grpdef entry

	call .skipprefix
	cmp al, twlGroup
	jne .internal34
	call .skipunder
	cmp al, twlGroup
	jne .internal34
	call .skipunder
	dec si
@@:
	lodsb
	cmp al, '_'
	je @F
	cmp al, 0
	je @F
	cmp al, '?'
	jne @B
@@:
	dec si
	jmp @F

.internal34:
	mov cx, 34
.internal_j1:
	jmp .internal

.internal35:
	mov cx, 35
	jmp .internal_j1

.internal37:
	mov cx, 37
	jmp .internal_j1

.grpdef_loop:
	mov si, word [bp + ?nextfield]
@@:
	call .skipunder
	cmp al, 0
	je .grpdef_done
	cmp al, '?'
	je .grpdef_done
	cmp al, twlSegment
	jne .internal35

	push word [bp + ?currentindex]
	mov byte [bp + ?lnamemustexist], -1
	call .findlname
	jc .group_unknown_section_error
	mov ax, [bp + ?currentindex]
	test ah, ah
	jnz .internal32
	mov word [bp + ?segmentlname], ax
	call .findsegdef
	mov ax, [bp + ?currentindex]
	test ah, ah
	jnz .internal32
	pop word [bp + ?currentindex]

	push ds
	push es
	pop ds
	pop es			; swap

	pop di			; es:di -> next grpdef entry
	lea dx, [di + 4]
	cmp dx, [buffer_end]
	ja .internal37
	mov word [es:di], 80FFh	; low byte = 0FFh, then high byte = 80h
	inc di
	test al, al
	jns @F
	; mov byte [es:di], 80h
	inc di
@@:
	stosb
	push di			; stack -> next grpdef entry

	push ds
	push es
	pop ds
	pop es			; swap back

	push ax

	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seektemp

.loop_inner_get_grpdef:
	mov word [bp + ?seektempinner], ax
	mov word [bp + ?seektempinner + 2], dx

	mov cx, TEMPWLLIST_size
	call .readtemp0_maybe_eof
	je @F
	test ax, ax
	jz .end_inner_get_grpdef
	jmp .internal27

@@:
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	cmp byte [twlListUsed], twlUsedNewSeg
	jne .loop_inner_get_grpdef

	pop cx
	cmp byte [twlSegmentIndex], cl
	push cx
	jne .loop_inner_get_grpdef

	cmp byte [twlGroupIndex], 0
	jne .group_multiple_error

	mov ax, word [bp + ?currentindex]
	mov byte [twlGroupIndex], al

	mov dx, word [bp + ?seektempinner]
	mov cx, word [bp + ?seektempinner + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .writetemp0

	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	jmp .loop_inner_get_grpdef

.end_inner_get_grpdef:
	pop ax			; discard

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .readtemp0

	mov dx, cx
	mov cl, byte [twlLength]
	call .readtemp

	jmp .grpdef_loop

.grpdef_done:

	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 2		; EOF
	call .seekobj

	pop di
    mov ds,[es:buffer_base]      ; DS => buffer area
	inc di			; -> past checksum byte
	mov cx, di		; -> past checksum byte
	mov dx, TEMPSTRINGWLLIST_size
				; -> prepared grpdef record
	sub cx, dx		; = length of record
	mov ax, cx
	sub ax, 3		; = length field
	mov word [TEMPSTRINGWLLIST_size + 1], ax
	call .checksum_dsdx
	call .writeobj_dsdx

	inc word [bp + ?currentindex]
				; done with this grpdef

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .readtemp0
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	jmp .loop_outer_get_grpdef


.end_get_grpdef:

	call .prepare_extdef
	mov word [bp + ?currentindex], 1
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seektemp

.loop_extdef:
	mov word [bp + ?seektemp], ax
	mov word [bp + ?seektemp + 2], dx

	mov cx, TEMPWLLIST_size
	call .readtemp0_maybe_eof
	je @F
	test ax, ax
	jz .end_extdef
	jmp .internal27

@@:
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	cmp byte [twlListUsed], twlUsedInitial
	jne .loop_extdef

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	add dx, TEMPWLLIST_size
	adc cx, 0
	mov al, 0
	call .seektemp

	xor cx, cx
	mov cl, [twlLength]
	mov dx, TEMPWLLIST_size
	call .readtemp

	mov si, dx
	mov cx, -1
@@:
	inc cx
	lodsb
	test al, al
	jnz @B

	mov di, word [bp + ?behindpartialrecord]
	mov ax, di
	add ax, cx
	jc .new_extdef
	add ax, 3
	jc .new_extdef
	cmp ax, TEMPSTRINGWLLIST_size + 1024
	ja .new_extdef
	cmp ax, word [es:buffer_end]
	jbe .append_extdef
.new_extdef:
	push cx
	push dx
	call .dump_extdef

	call .prepare_extdef
	pop dx
	pop cx

.append_extdef:
	push es
	 push ds
	 pop es
	mov si, dx
	mov al, cl
	stosb
	rep movsb
	mov al, 0
	stosb
	pop es
	mov word [bp + ?behindpartialrecord], di

	mov ax, word [bp + ?currentindex]
	mov word [twlExtdefIndex], ax

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .writetemp0

	mov dl, byte [twlLength]
	xor cx, cx
	mov al, 1
	call .seektemp

	inc word [bp + ?currentindex]
	jmp .loop_extdef

.prepare_extdef:
	mov ds, [es:buffer_base]
	mov di, TEMPSTRINGWLLIST_size
	mov al, EXTDEF
	mov byte [di], al
	add di, 3
	mov word [bp + ?behindpartialrecord], di
	retn

.dump_extdef:
	xor cx, cx
	xor dx, dx
	mov al, 2
	call .seekobj

	mov ds, [es:buffer_base]
	mov cx, word [bp + ?behindpartialrecord]
	cmp cx, TEMPSTRINGWLLIST_size + 3
	jbe @F
	inc cx
	mov dx, TEMPSTRINGWLLIST_size
	sub cx, dx
	mov ax, cx
	sub ax, 3
	mov word [TEMPSTRINGWLLIST_size + 1], ax
	call .checksum_dsdx
	call .writeobj_dsdx
@@:
	retn

.end_extdef:
	call .dump_extdef

	mov word [bp + ?currentindex], 1
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seektemp

.loop_outer_collect_items:
	mov word [bp + ?seektemp], ax
	mov word [bp + ?seektemp + 2], dx

	lea dx, [bp + ?buffer]
	mov cx, TEMPWLLIST_size
	call .readtemp_ssdx_maybe_eof
	je @F
	test ax, ax
	jz .end_collect_items
	jmp .internal27

@@:
	xor dx, dx
	mov dl, byte [bp + ?buffer + twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	cmp byte [bp + ?buffer + twlListUsed], twlUsedNewSeg
	jne .loop_outer_collect_items

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	add dx, TEMPWLLIST_size
	adc cx, 0
	mov al, 0
	call .seektemp

	xor cx, cx
	mov cl, [bp + ?buffer + twlLength]
	mov dx, TEMPWLLIST_size
	call .readtemp

	call .skipprefix
	cmp al, twlNew
	jne .invalid_new_segment_error
	call .skipunder
	cmp al, twlSegment
	jne .check_list		; not used because of .check_found_lnames
	call .skipunder
	dec si
@@:
	lodsb
	cmp al, '_'
	je @F
	cmp al, 0
	je @F
	cmp al, '?'
	jne @B
@@:
	dec si
	call .skipunder

.check_list:
	cmp al, twlList
	jne .invalid_new_segment_error
	call .skipunder
	dec si
 extern name_field
	mov di, name_field
	xor cx, cx
	db __TEST_IMM16		; skip stosb and inc
@@:
	stosb
	inc cx
	lodsb
		; do not check for underscore as a terminator !
	cmp al, 0
	je @F
	cmp al, '?'
	jne @B
@@:
	xor ax, ax
	stosb
	mov word [bp + ?length], cx

	call .get_size
	mov word [bp + ?ledatabase], ax

	call .prepare_one_pubdef
	call .index_one_pubdef
	mov cx, [bp + ?length]
	mov al, cl
	stosb			; string length
	mov si, name_field
	rep movsb		; string
	mov ax, word [bp + ?ledatabase]
	stosw			; offset
	call .finish_one_pubdef

	and word [bp + ?repeatseen], 0
	mov word [bp + ?collectfunction], .collect_size
	call .inner_collect

	call .get_size
	sub ax, [bp + ?ledatabase]
	jc .internal38
	push ax
	jnz @F
	rol byte [bp + ?repeatseen], 1
	jc @F
	jmp .no_ledata

@@:
	mov word [bp + ?ledataremaining], ax

	and word [bp + ?seektempinner], 0
	and word [bp + ?seektempinner + 2], 0
	and word [bp + ?ledata_skip_repeated], 0
				; initially, no partial repeated tempwllist

	call .emit_ledata
	jnc @F
	rol byte [bp + ?repeatseen], 1
	jc @F
	jmp .internal40

@@:
	call .prepare_fixupp

	mov word [bp ?collectfunction], .collect_list
	call .inner_collect

	call .dump_fixupp

	cmp word [bp + ?ledataremaining], 0
	je @F
.internal43:
	mov cx, 43
	jmp .internal

@@:
.no_ledata:

	call .prepare_one_pubdef
	call .index_one_pubdef
	mov cx, [bp + ?length]
	mov al, cl
	add al, string_.end.size
	stosb			; string length
	mov si, name_field
	rep movsb		; string
	mov si, string_.end
	mov cl, string_.end.size
	rep movsb
	mov ax, word [bp + ?ledatabase]
	stosw			; offset
	call .finish_one_pubdef

	call .prepare_one_pubdef

	xor ax, ax
	stosw			; group, segment
	stosw			; frame

	mov cx, [bp + ?length]
	mov al, cl
	add al, string_.amount.size
	stosb			; string length
	mov si, name_field
	rep movsb		; string
	mov si, string_.amount
	mov cl, string_.amount.size
	rep movsb
	pop ax
	shr ax, 1		; = count of entries
	stosw			; offset
	call .finish_one_pubdef

	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .readtemp0
	mov dl, [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	jmp .loop_outer_collect_items

.internal40:
	mov cx, 40
	jmp .internal_j2

.internal38:
	mov cx, 38
.internal_j2:
	jmp .internal

.get_size:
	mov dx, word [bp + ?buffer + twlSegdefSizeOffset]
	mov cx, word [bp + ?buffer + twlSegdefSizeOffset + 2]
	mov al, 0
	call .seekobj

	push ax
	mov dx, sp
	mov cx, 2
	call .readobj_ssdx
	pop ax
	retn

.prepare_one_pubdef:
	xor cx, cx
	xor dx, dx
	mov al, 2
	call .seekobj

	push es
	mov es, [es:buffer_base]
	mov di, TEMPSTRINGWLLIST_size
	mov dx, di
	mov al, PUBDEF
	stosb
	scasw
	pop ds			; => DGROUP
	retn

.index_one_pubdef:
	mov al, [bp + ?buffer + twlGroupIndex]
	test al, al
	jns @F
	mov byte [es:di], 80h
	inc di
@@:
	stosb			; group
	mov al, [bp + ?buffer + twlSegmentIndex]
	test al, al
	jns @F
	mov byte [es:di], 80h
	inc di
@@:
	stosb			; segment
	retn

.finish_one_pubdef:
	xor ax, ax
	stosb			; type
	inc di			; checksum
	push ds
	pop es			; => DGROUP
	mov ds, [es:buffer_base]
	mov cx, di
	sub cx, dx
	mov ax, cx
	sub ax, 3
	mov word [TEMPSTRINGWLLIST_size + 1], ax
	call .checksum_dsdx
	call .writeobj_dsdx
	retn

.collect_repeated_ledata:
	mov cx, [bp + ?ledata_skip_repeated]
	push cx
	xor ax, ax		; first item = 0
	sub bx, cx		; bx = how many remain
	jb .internal45
	jcxz @FF		; not a partial repeated tempwllist -->
@@:
	add ax, dx		; increase adjust for next item
	loop @B			; ax += cx * dx
@@:
	mov cx, bx		; number of items to do (at most)
	pop bx			; = how many to skip next
	mov di, word [bp + ?ledata_next_offset]
	push es
	mov es, word [es:buffer_base]
				; es:di -> ledata image next word
	jcxz @FF
@@:
	stosw			; store item adjust
	add ax, dx		; increase adjust
	inc bx			; processed 1 more, count how many to skip next
	mov word [bp + ?ledata_next_offset], di
				; store -> next
	cmp di, word [bp + ?ledata_end_offset]
				; are we done ?
	ja .internal44		; error -->
	je .collect_repeated_ledata_return_to_loop_caller
	loop @B			; loop for number of items
@@:
	mov word [bp + ?ledata_skip_repeated], cx
				; = 0, next call shouldn't skip partial rep
	pop es
	retn			; return to .inner_collect loop

.collect_repeated_ledata_return_to_loop_caller:
	mov word [bp + ?ledata_skip_repeated], bx
				; store how many to skip next time (if partial)
	loop @F			; branch if cx != 1
	mov word [bp + ?ledata_skip_repeated], cx
				; store a zero instead (no more partial rep)
@@:
	pop es
	pop ax			; discard a near return address so that
				;  we return to .inner_collect_partial caller
	retn

.internal44:
	mov cx, 44
	jmp .internal

.internal45:
	mov cx, 45
	jmp .internal

.collect_size:
	cmp bx, 1
	je @F
	mov byte [bp + ?repeatseen], -1
@@:
	push bx
	call .get_size
	pop bx
	add bx, bx
	add ax, bx		; count relocs (1 word per reloc)
	push ax
	mov dx, -2
	mov cx, -1
	mov al, 1
	call .seekobj
	mov dx, sp
	mov cx, 2
	call .writeobj_ssdx
	pop ax
	retn

.collect_list:
	push bx
	push ds

	 push es
	 pop ds
	cmp byte [_wllist_debug_flag], 1
	jb @F
	mov si, msg_used_prefix
 extern cmsg
	call cmsg
	pop ds
	mov si, TEMPWLLIST_size
 extern zmsg
	call zmsg
	db __TEST_IMM8		; skip pop

@@:
	pop ds
	pop bx

	test bx, bx
	jz .collect_list_empty
.collect_list_loop:
	push bx
		; first check if next LEDATA chunk needed
	cmp word [bp + ?ledatadone], LEDATA_LIMIT
	jb @F
.new_ledata:
	call .dump_fixupp
	call .emit_ledata
	jc .internal41

		; read back the tempwllist entry being processed
		;  as it could be overwritten by .emit_ledata
	mov dx, word [bp + ?seektempinner]
	mov cx, word [bp + ?seektempinner + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .readtemp0

	jmp .new_ledata_prepare_fixupp

.internal41:
	mov cx, 41
	jmp .internal

@@:
		; now get a pointer to prepared FIXUPP
		;  and find whether next part fits into this record
	mov di, word [bp + ?behindpartialrecord]
	mov ax, di
	add ax, 5 + 1		; EXTDEF >= 128 needs 5 bytes per fixup
	jc .new_fixupp
	cmp ax, TEMPSTRINGWLLIST_size + 1024
	ja .new_fixupp
	cmp ax, word [es:buffer_end]
	jbe .append_fixupp
.new_fixupp:
	call .dump_fixupp

.new_ledata_prepare_fixupp:
	call .prepare_fixupp

.append_fixupp:
	push es
	 push ds
	 pop es
%if 0

example: C4 38 56 01

9c FIXUPP16      5 bytes, checksum 0C (valid)
;   FIXUP  segment-relative, type 1 (16-bit offset)
          record offset 0038
          frame method F5 (TARGET index)
          target method T6 (EXTDEF) index 0001 'extlabel'
   0000: c4 38 56 01                                      :  .8V.

C4: 1100_0100 FIXUP, M=1 segment-relative, Location=1 (16-bit offset)
38		(steals bottom two bits of C4 as top bits, ie 038)
56: 0101_0110 F=0 Frame=5 T=0 P=1 Targt=2 (P+Targt=6)
01

%endif

	mov ax, word [bp + ?ledatadone]	; -> offset in last LEDATA
	add word [bp + ?ledatadone], 2	; increase for next user

	xchg al, ah			; get data record offset in order
	test al, 1111_1100b		; mustn't be > 10 bits
	jz @F
.internal39:
	mov cx, 39
	jmp .internal
@@:
	or al, 0C4h			; FIXUP, M=1, Location=1
	stosw				; store the data record offset + bits

	mov al, 56h
	stosb

	mov ax, word [twlExtdefIndex]
	test ax, 0FF80h
	jz @F
	xor ah, 80h
	jns .internal42
	mov byte [es:di], ah
	inc di
@@:
	stosb

	pop es
	mov word [bp + ?behindpartialrecord], di

	pop bx
	dec bx
	jnz .collect_list_loop
.collect_list_empty:

		; modify the tempwllist entry to mark it used
	mov byte [twlListUsed], twlUsedListItem

		; write the tempwllist entry to update it
	mov dx, word [bp + ?seektempinner]
	mov cx, word [bp + ?seektempinner + 2]
	mov al, 0
	call .seektemp

	mov cx, TEMPWLLIST_size
	call .writetemp0

		; seek past the label name
	mov dl, byte [twlLength]
	xor cx, cx
	mov al, 1
	call .seektemp

	retn

.internal42:
	mov cx, 42
	jmp .internal

.emit_ledata:
	and word [bp + ?ledatadone], 0

	sub word [bp + ?ledataremaining], LEDATA_LIMIT
	jb .last_ledata
.full_ledata:
	mov si, LEDATA_LIMIT
	jmp .write_ledata

.last_ledata:
	mov si, word [bp + ?ledataremaining]
	and word [bp + ?ledataremaining], 0
	add si, LEDATA_LIMIT
	jz .done_ledata

.write_ledata:
	xor dx, dx
	xor cx, cx
	mov al, 2
	call .seekobj

    mov ds,[es:buffer_base]      ; DS:DX -> segment:offset of buffer area
    push es
    push ds
    pop es
    pop ds			; swap
	mov di, TEMPSTRINGWLLIST_size
	mov al, LEDATA
	stosb
	scasw			; size
	mov al, byte [bp + ?buffer + twlSegmentIndex]
	test al, al
	jns @F
	mov byte [es:di], 80h
	inc di
@@:
	stosb
	mov ax, [bp + ?ledatabase]
	add word [bp + ?ledatabase], si
	stosw
@@:
	xor ax, ax
	mov cx, si

	rol byte [bp + ?repeatseen], 1
	jnc .ledata_no_repeat

	push di
	rep stosb
	mov word [bp + ?ledata_end_offset], di
	pop di
	mov word [bp + ?ledata_next_offset], di

    push es
    push ds
    pop es
    pop ds			; swap back

	xor cx, cx
	xor dx, dx
	mov al, 1
	call .seektemp
	push dx
	push ax			; stack current seek
	mov cx, word [bp + ?seektempinner + 2]
	mov dx, word [bp + ?seektempinner]
	push cx
	push dx			; stack currently saved seek
	mov al, 0
	call .seektemp		; seek to it too, and dx:ax = seek
	push word [bp + ?collectfunction]
	mov word [bp + ?collectfunction], .collect_repeated_ledata
	call .inner_collect_partial
	pop word [bp + ?collectfunction]
	pop word [bp + ?seektempinner]
	pop word [bp + ?seektempinner + 2]
				; reset saved seek
	pop dx
	pop cx
	mov al, 0
	call .seektemp		; and reset current seek

	mov di, word [bp + ?ledata_next_offset]
	inc di
	jmp @F

.ledata_no_repeat:
	rep stosb
	inc di			; -> past checksum byte

    push es
    push ds
    pop es
    pop ds			; swap back

@@:
	mov cx, di
	mov dx, TEMPSTRINGWLLIST_size
	sub cx, dx
	mov ax, cx
	sub ax, 3
	mov word [TEMPSTRINGWLLIST_size + 1], ax
	call .checksum_dsdx
	call .writeobj_dsdx
	clc
	retn

.done_ledata:
	stc
	retn


.prepare_fixupp:
	mov ds, [es:buffer_base]
	mov di, TEMPSTRINGWLLIST_size
	mov al, FIXUPP
	mov byte [di], al
	add di, 3
	mov word [bp + ?behindpartialrecord], di
	retn

.dump_fixupp:
	xor cx, cx
	xor dx, dx
	mov al, 2
	call .seekobj

	mov ds, [es:buffer_base]
	mov cx, word [bp + ?behindpartialrecord]
	cmp cx, TEMPSTRINGWLLIST_size + 3
	jbe @F
	inc cx
	mov dx, TEMPSTRINGWLLIST_size
	sub cx, dx
	mov ax, cx
	sub ax, 3
	mov word [TEMPSTRINGWLLIST_size + 1], ax
	call .checksum_dsdx
	call .writeobj_dsdx
@@:
	retn


.inner_collect:
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seektemp

.loop_inner_collect_items:
.inner_collect_partial:
	mov word [bp + ?seektempinner], ax
	mov word [bp + ?seektempinner + 2], dx

	mov cx, TEMPWLLIST_size
	call .readtemp0_maybe_eof
	je @F
	test ax, ax
	jz .end_inner_collect_items
	jmp .internal27

@@:
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	cmp byte [twlListUsed], twlUsedInitial
	jne .loop_inner_collect_items

	mov dx, word [bp + ?seektempinner]
	mov cx, word [bp + ?seektempinner + 2]
	add dx, TEMPWLLIST_size
	adc cx, 0
	mov al, 0
	call .seektemp

	xor cx, cx
	mov cl, [twlLength]
	mov dx, TEMPWLLIST_size
	call .readtemp

	mov bx, 1
	call .skipprefix
	mov dx, bx
	cmp al, twlRepeat
	jne @F
	push dx
 extern _wlcalc_parse_number
	call _wlcalc_parse_number
	jc .repeat_number_invalid_error
	test dx, dx
	jnz .repeat_number_overflow_error
	pop dx
	xchg bx, ax
	call .skipunder
@@:
	cmp al, twlWidth
	jne @F
	push bx
 extern _wlcalc_parse_number
	call _wlcalc_parse_number
	pop bx
	jc .width_number_invalid_error
	test dx, dx
	jnz .width_number_overflow_error
	xchg dx, ax
	call .skipunder
@@:
	cmp al, twlList
	jne .invalid_list_item_error
	call .skipunder
	dec si
	mov di, name_field
	mov cx, word [bp + ?length]
	test di, di
	repe cmpsb
@@:
	jne .next_inner_collect_items
	cmp byte [si], '?'
	je @F
	cmp byte [si], 0
	jne @B
@@:

	call near [bp + ?collectfunction]
.next_inner_collect_items:
	xor dx, dx
	xor cx, cx
	mov al, 1
	call .seektemp
	jmp .loop_inner_collect_items

.end_inner_collect_items:
	retn


.end_collect_items:

	mov word [bp + ?currentindex], 1
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seektemp

.loop_check_remaining:
	mov word [bp + ?seektemp], ax
	mov word [bp + ?seektemp + 2], dx

	mov cx, TEMPWLLIST_size
	call .readtemp0_maybe_eof
	je @F
	test ax, ax
	jz .end_check_remaining
	jmp .internal27

@@:
	mov dl, byte [twlLength]
	xor cx, cx		; cx:dx = length
	mov al, 1		; current
	call .seektemp

	cmp byte [twlListUsed], twlUsedInitial
	jne .loop_check_remaining
	jmp .unknown_list_error

.end_check_remaining:

	xor cx, cx
	xor dx, dx
	mov al, 0
	call .seekobj		; SOF

.loop_fix_segdef:
	push dx
	push ax			; preserve seek
	mov cx, 3
	call .readobj0_maybe_eof; read OMF record
	je @F
	test ax, ax		; EOF ?
	jz .end_fix_segdef	; yes -->
	jmp .internal27

@@:
	cmp byte [0], SEGDEF	; a segdef record ?
	je .do_fix_segdef	; yes -->

	pop dx
	pop dx			; discard seek on stack
	mov dx, word [1]	; length of record (not including header)
	xor cx, cx		; cx:dx = length
	mov al, 1
	call .seekobj		; seek past record
	jmp .loop_fix_segdef

.do_fix_segdef:
	mov cx, word [1]	; get record length
	cmp cx, 250		; validate
	jbe @F
	mov cx, 55		; internal error value
	jmp .internal

@@:
	mov dl, 3		; read so entire record is at buffer:0
	call .readobj

	pop dx
	pop ax			; ! ax:dx = seek
	xchg cx, ax		; cx:dx = seek
	add al, 3		; ax = length of record including header
	push ax
	mov al, 0
	call .seekobj		; seek back to start of record
	pop cx			; = length including header

	xor dx, dx
	call .checksum_dsdx	; do the checksum
	call .writeobj_dsdx	; rewrite record

	xor cx, cx
	xor dx, dx
	mov al, 1
	call .seekobj		; get current seek
	jmp .loop_fix_segdef

.end_fix_segdef:		; seek on stack left, lleave cleans it

.end_after_warning:
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 2		; EOF
	call .seekobj

	push es
	pop ds
	mov dx, data_modend
	mov cx, data_modend.size
	call .writeobj_dsdx

	mov ah, 3Eh
	int 21h			; close obj
	or word [_wllist_obj_handle], -1
	lleave code
	retn


.findsegdef:
	xor cx, cx
	xor dx, dx		; cx:dx = 0
	mov al, 0		; SOF
	call .seekobj
	mov word [bp + ?currentindex], 1

.find_existing_segdef:
	mov cx, 3
	call .readobj0_maybe_eof
	je @F
	test ax, ax
	jz .group_unknown_section_error
	jmp .internal32

@@:
	mov dx, word [1]
	cmp byte [0], SEGDEF
	je @F
	xor cx, cx		; cx:dx = length of record
	mov al, 1		; current
	call .seekobj
	jmp .find_existing_segdef

.internal36:
	mov cx, 36
	jmp .internal

@@:
	cmp dx, 7
	jb .internal36
	cmp dx, 8
	ja .internal36

	mov cx, dx
	call .readobj0
	cmp byte [0], 48h
	jne .internal36
	mov ax, word [bp + ?segmentlname]
	test ah, ah
	jnz .internal32
	test al, al
	js @F
	cmp byte [3], al
	jmp @FF

@@:
	mov ah, al
	mov al, 80h
	cmp word [3], ax
@@:
	je .found_existing_segdef
	inc word [bp + ?currentindex]
	jmp .find_existing_segdef

.found_existing_segdef:
	retn


.invalid_list_item_error:
	mov ax, _WLLIST_INVALID_LIST_ITEM_ERR
	jmp .inner_error

.width_number_invalid_error:
	mov ax, _WLLIST_WIDTH_NUMBER_INVALID_ERR
	jmp .inner_error

.width_number_overflow_error:
	mov ax, _WLLIST_WIDTH_NUMBER_OVERFLOW_ERR
	jmp .inner_error

.repeat_number_invalid_error:
	mov ax, _WLLIST_REPEAT_NUMBER_INVALID_ERR
	jmp .inner_error

.repeat_number_overflow_error:
	mov ax, _WLLIST_REPEAT_NUMBER_OVERFLOW_ERR
	; jmp .inner_error

		; INP:	ax = error code
.inner_error:
	mov dx, word [bp + ?seektempinner]
	mov cx, word [bp + ?seektempinner + 2]
	jmp .tempwllist_error

.no_section_error:
	mov ax, _WLLIST_NO_SECTION_ERR
	jmp .outer_error

.group_unknown_section_error:
	mov ax, _WLLIST_GROUP_UNKNOWN_SECTION_ERR
	jmp .outer_error

.unknown_list_error:
	mov ax, _WLLIST_UNKNOWN_LIST_ERR
	jmp .outer_error

.invalid_new_segment_error:
	mov ax, _WLLIST_INVALID_NEW_SEGMENT_ERR
	jmp .outer_error

.group_multiple_error:
	mov ax, _WLLIST_GROUP_MULTIPLE_ERR
	; jmp .outer_error

		; INP:	ax = error code
.outer_error:
	mov dx, word [bp + ?seektemp]
	mov cx, word [bp + ?seektemp + 2]

.tempwllist_error:
		; INP:	ax = error code
		;	cx:dx = seek in tempwllist file of erroneous entry
		;	es => DGROUP
		;	ds don't care
	push ax
	mov al, 0
	call .seektemp			; -> G label
	mov cx, TEMPWLLIST_size
	call .readtemp0			; read header

	mov ax, word [twlObjIndex]
	mov word [es:_wlcalc_obj_index], ax

	mov dx, cx
	mov cl, byte [twlLength]
	call .readtemp			; read label (ASCIZ)

	mov di, name_field		; es:di -> name field
	mov si, dx			; ds:si -> label
	mov cx, words(256)
	rep movsw			; copy over
 extern handle_wlcalc.get_object_filename
 extern _wlcalc_obj_index
	call handle_wlcalc.get_object_filename
	pop ax

	rol byte [es:is_wllist_error_as_warning], 1
	jnc @F
 extern link_warning
		; warning only
	mov di, name_field
	call link_warning	; give warning feedback
	jmp .end_after_warning
@@:
		; error on first unknown
    mov cx,OFFSET name_field wrt DGROUP ; cx -> symbol name for this error
    jmp NEAR PTR link_error	; transfer control to error handler

	lleave ctx


.skipprefix:
	mov si, dx
	cmp word [si], ".."
	jne @F
	cmp byte [si + 2], '@'
	jne @F
	add si, 3
@@:
 extern string_wllist
	mov di, string_wllist
@@:
	cmpsb
	jne .check
	cmp byte [si - 1], 0
	jne @B
.internal29:
    mov cx,29                ; internal error value
	jmp .internal
.check:
	cmp byte [es:di - 1], 0
	jne .internal29
.match:
	dec si
.skipunder:
@@:
	lodsb
	cmp al, '_'
	je @B
	retn


.checksum_dsdx:
	push cx
	push si
	mov si, dx
	xor ax, ax
	dec cx
	call .checksum_partial
	neg ah
	mov byte [si], ah
	pop si
	pop cx
	retn

.checksum_partial:
	jcxz @FF
@@:
	lodsb
	add ah, al
	loop @B
@@:
	retn

.seektemp:
	mov bx, word [es:_wllist_temp_handle]
	mov ah, 42h
	int 21h
    call    restore_ems_map
	jc .doserrortemp
	retn

.seekobj:
	mov bx, word [es:_wllist_obj_handle]
	mov ah, 42h
	int 21h
    call    restore_ems_map
	jc .doserrorobj
	retn

.readtemp0:
	call .readtemp0_maybe_eof
.temp_check_not_shortread:
	jne .shortreadtemp
	retn
.readtemp:
	call .readtemp_maybe_eof
	jmp .temp_check_not_shortread
.readtemp_dsdx:
	call .readtemp_dsdx_maybe_eof
	jmp .temp_check_not_shortread
.readtemp_ssdx:
	call .readtemp_ssdx_maybe_eof
	jmp .temp_check_not_shortread

.readtemp0_maybe_eof:
    xor dx,dx
.readtemp_maybe_eof:
    mov ds,[es:buffer_base]      ; DS:DX -> segment:offset of buffer area
.readtemp_dsdx_maybe_eof:
	db __TEST_IMM16		; skip push, pop
.readtemp_ssdx_maybe_eof:
	push ss
	pop ds
	mov bx, word [es:_wllist_temp_handle]
	mov ah, 3Fh
	int 21h
    call    restore_ems_map
	jc .doserror
	cmp ax, cx
	retn

.shortreadtemp:
	mov ax, -2		; short read code
	jmp .doserrortemp
.shortwritetemp:
	mov ax, 27h
.doserrortemp:
    mov dx,OFFSET _wllist_temp_file_name wrt DGROUP
.doserror:
    jmp dos_error		; error reading file


.writetemp0:
    xor dx,dx
.writetemp:
    mov ds,[es:buffer_base]      ; DS:DX -> segment:offset of buffer area
.writetemp_dsdx:
	db __TEST_IMM16		; skip push, pop
.writetemp_ssdx:
	push ss
	pop ds
	mov bx, word [es:_wllist_temp_handle]
	mov ah, 40h
	int 21h
    call    restore_ems_map
	jc .doserrortemp
	cmp ax, cx
	jne .shortwritetemp
.retn:
	retn

.writeobj0:
    xor dx,dx
.writeobj:
    mov ds,[es:buffer_base]      ; DS:DX -> segment:offset of buffer area
.writeobj_dsdx:
	db __TEST_IMM16		; skip push, pop
.writeobj_ssdx:
	push ss
	pop ds
	mov bx, word [es:_wllist_obj_handle]
	mov ah, 40h
	int 21h
    call    restore_ems_map
	jc .doserrorobj
	cmp ax, cx
	je .retn
.shortwriteobj:
	mov ax, 27h
	jmp .doserrorobj
.shortreadobj:
	mov ax, -2		; short read code
.doserrorobj:
    mov dx,OFFSET _wllist_obj_file_name wrt DGROUP
    jmp .doserror		; error writing file

.readobj0:
	call .readobj0_maybe_eof
.obj_check_not_shortread:
	jne .shortreadobj
	retn
.readobj:
	call .readobj_maybe_eof
	jmp .obj_check_not_shortread
.readobj_dsdx:
	call .readobj_dsdx_maybe_eof
	jmp .obj_check_not_shortread
.readobj_ssdx:
	call .readobj_ssdx_maybe_eof
	jmp .obj_check_not_shortread

.readobj0_maybe_eof:
    xor dx,dx
.readobj_maybe_eof:
    mov ds,[es:buffer_base]      ; DS:DX -> segment:offset of buffer area
.readobj_dsdx_maybe_eof:
	db __TEST_IMM16		; skip push, pop
.readobj_ssdx_maybe_eof:
	push ss
	pop ds
	mov bx, word [es:_wllist_obj_handle]
	mov ah, 3Fh
	int 21h
    call    restore_ems_map
	jc .doserrorobj
	cmp ax, cx
	retn

END
