include clib.inc
include io.inc
include dos.inc
include dir.inc
include conio.inc
include stdio.inc
include string.inc
include list.inc

	.data

cpinfo	db "LIST Version 1.00 BETA, "
%      	db "&@Date &@Time",10,10,0
cpusage	db "USAGE: LIST [-option] [<listfile>] <file(s)> [<format>] [-option] [@arg_file]",10
	db 10
	db " -a    append text to <listfile>",10
	db " -i    include directories in <listfile>",10
	db " -r    process subfolders",10
	db " -u    convert to unix",10
	db " -xd   exclude <drive> in location",10
	db " -xp   exclude <path> in location",10
	db " -y    assume Yes on all queries",10
	db " -q    quiet",10
	db " -v    verbose (no <listfile>)",10
	db " -h#   head text (start)",10
	db " -e#   exit text (end)",10
	db " @#    continue from file #",10,10
	db "Example:",10
	db " LIST -v -hhello *.* -egoodbye",10
	db ' LIST objs.rsp src\*.asm -hOBJS=\ "\t%%n.obj \\\n"',10
	db 10,0

crlf	db 13,10,0
ff_form	db '%f\n',0
	db WMAXPATH-5 dup(?)

	.data?

option_y db ?
option_v db ?
option_q db ?

ff_head db 256 dup(?)
ff_exit db 256 dup(?)
ff_name	db WMAXPATH dup(?)
ff_path	db WMAXPATH dup(?)
ff_mask	db WMAXPATH dup(?)
ff_fblk	S_WFBLK <?>
ff_list S_LIST <?>

	.code

do_file proc uses ebx directory:dword, ff:dword
local	fname[WMAXPATH]:byte
	mov ebx,ff
	mov ecx,directory
	.if ebx
	    lea ecx,[ebx].S_WFBLK.wf_name
	.endif
	.if func(cmpwarg,ecx,addr ff_mask)
	    .if ebx
	    	invoke strfcat,addr fname,directory,addr [ebx].S_WFBLK.wf_name
	    .else
	    	invoke strcpy,addr fname,directory
	    .endif
	    .if func(listadd,addr ff_list,addr fname)
		sub eax,eax
	    .endif
	.endif
	ret
do_file endp

do_directory proc directory:dword
	.if !func(scan_files,directory)
	    .if ff_list.li_flag & _LIST_INCDIR
		invoke do_file,directory,0
	    .endif
	.else
	    mov eax,-1
	.endif
	ret
do_directory endp

set_directory proc directory:dword
local	path[WMAXPATH]:byte
	invoke strfcat, addr path, addr ff_path, directory
	sub eax,eax
	.if ff_list.li_flag & _LIST_RECURSIV
	    invoke scan_directory,0,addr path
	.elseif ff_list.li_flag & _LIST_INCDIR
	    invoke do_file,addr path,0
	.endif
	ret
set_directory endp

readfiles proc uses esi ebx
local ffmask[256]:byte
	invoke strlen,addr ff_path
	.if eax
	    inc eax
	.endif
	mov ff_list.li_sublen,eax
	mov ebx,offset ff_fblk
	invoke strfcat,addr ffmask,addr ff_path,cstr("*.*")
	invoke wfindfirst,addr ffmask,ebx,_A_ALLFILES
	mov esi,eax
	.if eax == -1
	    sub eax,eax
	    jmp readwf_end
	.endif
	.if [ebx].S_WFBLK.wf_name == '.' && [ebx].S_WFBLK.wf_name[1] == 0
	    .if func(wfindnext,ebx,esi)
		jmp @F
	    .endif
	    .if [ebx].S_WFBLK.wf_name == '.' && [ebx].S_WFBLK.wf_name[2] == 0
		.if func(wfindnext,ebx,esi)
		    jmp @F
		.endif
	    .endif
	.endif
	.repeat
	    .if [ebx].S_WFBLK.wf_attrib & _A_SUBDIR
		.if func(set_directory,addr [ebx].S_WFBLK.wf_name)
		    .break
		.endif
	    .else
		invoke do_file,addr ff_path,ebx
	    .endif
	    invoke wfindnext,ebx,esi
	.until eax
      @@:
	invoke wcloseff,esi
	sub eax,eax
    readwf_end:
	ret
readfiles endp

putstring proc string:dword
	invoke strcat,string,addr crlf
	invoke strlen,eax
	mov ecx,eax
	invoke oswrite,ff_list.li_handle,string,ecx
	ret
putstring endp

arg_option_a:
	or ff_list.li_flag,_LIST_APPEND
	ret
arg_option_i:
	or ff_list.li_flag,_LIST_INCDIR
	ret
arg_option_r:
	or ff_list.li_flag,_LIST_RECURSIV
	ret
arg_option_u:
	or ff_list.li_flag,_LIST_UNIX
	ret
arg_option_y:
	or ff_list.li_flag,_LIST_TRUNC
	ret
arg_option_x:
	.if ah == 'd'
	    or ff_list.li_flag,_LIST_XDRIVE
	.elseif ah == 'p'
	    or ff_list.li_flag,_LIST_XPATH
	.endif
	ret
arg_option_q:
	inc option_q
	ret
arg_option_v:
	inc option_v
	ret

arg_option_h:
	add ebx,2
	invoke strcpy,addr ff_head,ebx
	inc cl
	ret
arg_option_e:
	add ebx,2
	invoke strcpy,addr ff_exit,ebx
	inc cl
	ret

read_args proc uses esi edi ebx
local	buf[512]:byte
	sub edi,edi
	mov eax,ebx
	inc eax
	.if func(fopen,eax,cstr("rt"))
	    mov esi,eax
	    lea ebx,buf
	    .repeat
	    	invoke fgets,ebx,512,esi
		.break .if !eax
		invoke strtrim,ebx
		call arg_option
		mov edi,eax
	    .until ZERO?
	    invoke fclose,esi
	.endif
	mov eax,edi
	ret
read_args endp

arg_option_?:
	invoke _print, addr cpinfo
	invoke _print, addr cpusage
	sub eax,eax
	ret

arg_option:
	mov eax,[ebx]
	.if al == '?'
	    jmp arg_option_?
	.endif
	.if al == '/' || al == '-'
	    shr eax,8
	    or  eax,202020h
	    mov edx,cstr("airuyxqveh")
	    mov ecx,edx
	  @@:
	    cmp al,[ecx]
	    je @F
	    inc ecx
	    cmp byte ptr [ecx],0
	    jne @B
	    jmp arg_option_?
	  @@:
	    sub ecx,edx
	    shl ecx,2
	    call option_label[ecx]
	.else
	    .if al == '@'
	    	.if !func(read_args)
		    ret
		.endif
	    .elseif !ff_name
		invoke strcpy,addr ff_name,ebx
	    .elseif !ff_path
		invoke strcpy,addr ff_path,ebx
	    .else
		invoke strcpy,addr ff_form,ebx
	    .endif
	.endif
	sub eax,eax
	inc eax
	ret

	.data

option_label label dword
	dd arg_option_a
	dd arg_option_i
	dd arg_option_r
	dd arg_option_u
	dd arg_option_y
	dd arg_option_x
	dd arg_option_q
	dd arg_option_v
	dd arg_option_e
	dd arg_option_h
	dd arg_option_?

	.code

main	proc c
	mov edi,_argc
	mov esi,_argv
	.if _argc == 1
	    call arg_option_?
	    jmp main_end
	.endif
	dec edi
	lodsd
	.repeat
	    lodsd
	    mov ebx,eax
	    call arg_option
	    jz main_end
	    dec edi
	.until !edi
	.if !option_q
	    invoke _print, addr cpinfo
	.endif
	.if option_v
	    .if ff_name
		.if ff_path
	    	    invoke strcpy, addr ff_form, addr ff_path
		.endif
	    	invoke strcpy, addr ff_path, addr ff_name
	    .endif
	.endif
	invoke strfn, addr ff_path
	push eax
	invoke strcpy, addr ff_mask, eax
	pop eax
	.if eax > offset ff_path && byte ptr [eax-1] == '\'
	    mov byte ptr [eax-1],0
	.else
	    mov byte ptr [eax],0
	.endif
	.if !ff_name || !ff_mask
	    invoke perror,cstr("Nothing to do..")
	    sub eax,eax
	    jmp main_end
	.endif
	.if !ff_path
	    .if !func(fullpath,addr ff_path, 0)
		invoke perror,cstr("Error init current path")
		mov eax,1
	    	jmp main_end
	    .endif
	.endif
	.if !option_v
	    or ff_list.li_flag,_LIST_USEFILE
	    mov eax,ff_list.li_flag
	    .if !(al & (_LIST_TRUNC or _LIST_APPEND))
	    	.if func(filexist,addr ff_name)
		    invoke _print, cstr("File %s exist. Delete ? (Y,N): "), addr ff_name
	    	    call getch
	    	    or  al,20h
	    	    .if al == 'y'
	    	    	or  ff_list.li_flag,_LIST_TRUNC
			mov eax,ff_list.li_flag
		    .else
	    	    	jmp @F
		    .endif
	    	.endif
	    .endif
	.endif
	.if !option_q
	    invoke _print, cstr(<10,"File(s):   %s",10>), addr ff_mask
	    invoke _print, cstr(<"Directory: %s",10,10>), addr ff_path
	.endif
	mov eax,offset ff_mask
	mov fp_maskp,eax
	mov eax,do_file
	mov fp_fileblock,eax
	mov eax,do_directory
	mov fp_directory,eax
	.if func(listopen, addr ff_list, addr ff_name, addr ff_form)
	    or ff_list.li_flag,_LIST_MACRO
	    .if ff_head
		invoke putstring, addr ff_head
	    .endif
	    invoke readfiles
	    .if ff_exit
		invoke putstring, addr ff_exit
	    .endif
	    invoke listclose, addr ff_list
	.endif
      @@:
	.if option_v
	    .if !option_q
		invoke _print, cstr(<10,"Total %d file(s)",10>), ff_list.li_total
	    .endif
	.endif
	xor eax,eax
    main_end:
    	ret
main	endp

	end
