
macro VERSION_STRING setting
 {
   VERSION_STRING setting,' + listing'
 }

macro continue_line anything
 {
	test	byte [eax+7],80h
	jnz	continue_line
	mov	[eax+12],edi
      continue_line:
 }

macro output_written anything
 {
      output_written:
	call	close
	call	make_listing
	ret

      make_listing:
	mov	edx,_listing
	or	edx,edx
	jz	no_listing
	mov	[current_line],0
	mov	[counter],0
	mov	word [value],0A0Dh
	call	create
	jc	no_listing
	mov	eax,[code_start]
	add	eax,[code_size]
	cmp	eax,[last_offset]
	jae	last_offset_ok
	mov	[last_offset],eax
      last_offset_ok:
	mov	esi,[memory_start]
	mov	edi,[code_start]
      check_offsets:
	cmp	esi,[source_start]
	jae	check_last_offset
	test	byte [esi+7],80h
	jnz	offset_ok
	mov	eax,[code_start]
	cmp	eax,[esi+12]
	ja	fix_stub_offset
	mov	eax,edi
	mov	edi,[esi+12]
	cmp	eax,edi
	jbe	offset_ok
	call	fix_virtual_offsets
      offset_ok:
	add	esi,16
	call	skip_line_data
	jmp	check_offsets
      fix_stub_offset:
	mov	[esi+12],eax
	jmp	offset_ok
      check_last_offset:
	cmp	[last_offset],edi
	jae	all_offsets_ok
	mov	edi,[last_offset]
	call	fix_virtual_offsets
      all_offsets_ok:
	mov	esi,[memory_start]
      listing_server:
	cmp	esi,[source_start]
	jae	listing_done
	test	byte [esi+7],80h
	jnz	go_for_next_line
	call	list_line
      go_for_next_line:
	add	esi,16
	call	skip_line_data
	jmp	listing_server
      listing_done:
	xchg	esi,[current_line]
	mov	ecx,[last_offset]
	sub	ecx,[esi+12]
	call	make_listing_line
	call	flush_remaining_code
	call	close
      formatter_done:
	ret
      skip_line_data:
	lods	byte [esi]
	or	al,al
	jz	line_data_skipped
	cmp	al,1Ah
	je	skip_symbol_data
	cmp	al,3Bh
	je	skip_symbol_data
	cmp	al,22h
	jne	skip_line_data
	lods	dword [esi]
	add	esi,eax
	jmp	skip_line_data
      skip_symbol_data:
	lods	byte [esi]
	movzx	eax,al
	add	esi,eax
	jmp	skip_line_data
      line_data_skipped:
	ret
      fix_virtual_offsets:
	mov	edx,esi
	mov	esi,[memory_start]
      fix_offsets:
	cmp	esi,edx
	je	offsets_fixed
	cmp	edi,[esi+12]
	jae	fix_next
	mov	[esi+12],edi
      fix_next:
	add	esi,16
	call	skip_line_data
	jmp	fix_offsets
      offsets_fixed:
	mov	esi,edx
      no_listing:
	ret

      list_line:
	mov	ecx,[esi+12]
	xchg	esi,[current_line]
	or	esi,esi
	jz	listing_line_ok
	sub	ecx,[esi+12]
      make_listing_line:
	jz	line_without_code
	call	flush_remaining_code
	mov	[counter],ecx
	mov	edx,[esi+12]
	mov	[current_offset],edx
	sub	edx,[code_start]
	add	edx,[code_offset]
	mov	edi,buffer
	mov	ecx,8
      write_file_offset:
	xor	al,al
	shld	eax,edx,4
	cmp	al,10
	sbb	al,69h
	das
	stos	byte [edi]
	shl	edx,4
	loop	write_file_offset
	mov	ax,': '
	stos	word [edi]
	mov	edx,buffer
	mov	ecx,10
	call	write
	call	list_code
	call	list_source
      listing_line_ok:
	mov	esi,[current_line]
	ret
      line_without_code:
	mov	edi,buffer
	mov	al,20h
	mov	ecx,10
	rep	stos byte [edi]
	mov	edx,buffer
	mov	ecx,10
	call	write
	call	list_code
	call	list_source
	jmp	listing_line_ok
      list_code:
	mov	edi,buffer
	mov	ecx,12
      .output:
	cmp	[counter],0
	je	.spaces
	mov	edx,[current_offset]
	inc	[current_offset]
	dec	[counter]
	mov	dl,[edx]
	mov	al,dl
	and	al,1111b
	cmp	al,10
	sbb	al,69h
	das
	mov	ah,al
	mov	al,dl
	shr	al,4
	cmp	al,10
	sbb	al,69h
	das
	stos	word [edi]
	mov	al,20h
	stos	byte [edi]
	jmp	.next
      .spaces:
	mov	ax,2020h
	stos	word [edi]
	stos	byte [edi]
      .next:
	loop	.output
	mov	ax,2020h
	stos	word [edi]
	mov	edx,buffer
	mov	ecx,12*3+2
	call	write
	ret
      list_source:
	mov	[next_pass_needed],0
	mov	[source_line_offset],0
	push	ebx
	mov	edx,[esi]
	call	open
	xor	al,al
	mov	edx,[esi+8]
	call	lseek
      .load_line:
	mov	edi,[additional_memory]
	mov	edx,edi
	mov	ecx,100h shr 2
	xor	eax,eax
	rep	stos dword [edi]
	mov	ecx,100h
	call	read
	mov	edx,[additional_memory]
	xor	ecx,ecx
	xor	ebp,ebp
      .cut_line:
	movzx	eax,byte [edx+ecx]
	inc	ecx
	cmp	al,1Ah
	je	.end
	or	al,al
	jz	.end
	cmp	al,0Dh
	je	.cr
	cmp	al,0Ah
	je	.lf
	cmp	ebp,3Bh
	je	.next
	cmp	ebp,27h
	je	.quoted
	cmp	ebp,22h
	je	.quoted
	cmp	al,3Bh
	je	.comment
	cmp	byte [characters+eax],0
	je	.symbol
	cmp	ebp,1Ah
	je	.neutral
	cmp	al,27h
	je	.quote
	cmp	al,22h
	je	.quote
      .neutral:
	mov	ebp,1Ah
	jmp	.next
      .quote:
	mov	ebp,eax
	jmp	.next
      .quoted:
	cmp	ebp,eax
	jne	.next
	xor	ebp,ebp
	jmp	.next
      .symbol:
	xor	ebp,ebp
	cmp	al,'\'
	jne	.next
	or	[next_pass_needed],-1
      .next:
	cmp	ecx,100h
	jb	.cut_line
	xchg	ebx,[esp]
	call	write
	add	[source_line_offset],100h
	xchg	ebx,[esp]
	jmp	.load_line
      .comment:
	mov	ebp,3Bh
	jmp	.next
      .one_more_byte:
	cmp	ecx,100h
	jb	.ok
	add	edx,ecx
	mov	byte [edx],0
	mov	ecx,1
	call	read
	mov	edx,[additional_memory]
	mov	ecx,100h
      .ok:
	ret
      .cr:
	lea	eax,[edx+ecx-1]
	mov	word [value],0Dh
	add	[source_line_offset],ecx
	call	.one_more_byte
	cmp	byte [edx+ecx],0Ah
	jne	.write_line
	inc	ecx
	inc	[source_line_offset]
	mov	byte [value+1],0Ah
	jmp	.write_line
      .lf:
	lea	eax,[edx+ecx-1]
	mov	word [value],0Ah
	add	[source_line_offset],ecx
	call	.one_more_byte
	cmp	byte [edx+ecx],0Dh
	jne	.write_line
	inc	ecx
	inc	[source_line_offset]
	mov	byte [value+1],0Dh
	jmp	.write_line
      .end:
	add	[source_line_offset],ecx
	mov	ax,word [value]
	mov	[edx+ecx-1],ax
	or	ah,ah
	jz	.write_line
	inc	ecx
      .write_line:
	xchg	ebx,[esp]
	call	write
	cmp	[next_pass_needed],0
	je	.source_listed
	mov	edi,buffer
	mov	al,20h
	mov	ecx,10
	rep	stos byte [edi]
	mov	edx,buffer
	mov	ecx,10
	call	write
	call	list_code
	xchg	ebx,[esp]
	xor	al,al
	mov	edx,[esi+8]
	add	edx,[source_line_offset]
	call	lseek
	mov	[next_pass_needed],0
	jmp	.load_line
      .source_listed:
	xchg	ebx,[esp]
	call	close
	pop	ebx
	ret
      flush_remaining_code:
	cmp	[counter],0
	je	remaining_code_ok
	push	ecx
	mov	edi,buffer
	mov	al,20h
	mov	ecx,10
	rep	stos byte [edi]
	mov	edx,buffer
	mov	ecx,10
	call	write
	call	list_code
	mov	edx,value
	mov	ecx,1
	cmp	byte [edx+1],0
	je	write_line_break
	inc	ecx
      write_line_break:
	call	write
	pop	ecx
	jmp	flush_remaining_code
      remaining_code_ok:
	ret
 }

macro close_pass anything
 {
      close_pass:
	mov	[last_offset],edi
 }

macro write_code anything
 {
      write_code:
	mov	eax,[written_size]
	mov	[code_offset],eax
 }

macro _counter [data]
 {
   common _counter data
   _listing db 'LISTING.TXT',0
 }

macro written_size anything
 {
   written_size dd ?
   code_offset dd ?
   last_offset dd ?
   source_line_offset dd ?
 }
