flat assembler
Message board for the users of flat assembler.

Index > DOS > 219-byte LFN dir lister (386+)

Author
Thread Post new topic Reply to topic
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 12 Oct 2006, 02:44
It only lists LFN filenames and their filesizes w/ commas (but > 4 GB works, if your filesystem supports it, e.g. NTFS). The default filespec is * (aka, *.*) but another can be specified at the cmdline. It assembles out of the box w/ NASM or YASM. FASM is supported by a .BAT that uses sed. Octasm also works w/ the included sed script.

I would post this under Windows except it works in pure DOS (w/ DOSLFN) plus it's a DOS .COM (not exactly a native Win32 format).

P.S. To manipulate LFN files under pure DOS w/ no TSR, use Odi's LFN tools (w/ src).

P.P.S. There's lots of good 256 byte demos (usually w/ src) at http://www.256b.com (e.g., selfdasm, tet, inv, wolf, smile256).

P.P.P.S. Don't whine about how useless it is because of cluster size: use ARK (comes w/ ASM src) to combine a lot of stray .COMs to save space! :)

Code:
; ----------------------------------------------------------------------
; LFNDIR.ASM (0.10)  --  simple 386+ LFN dir lister (names + fsizes only)
;
; Monday  June 11, 2007  5:35pm
;
; ======================================================================
; CRC32 = 406D2C10
;
; begin 644 lfndir.com
; MOH``C50"K(3`=07'1`$J`),P_X@XN$YQN?<`Z!P`<AF.X.@?`+A/<8SCZ`T`
; MZ!0`<_.XH7&,X\TAP[\)`KX!`/G-(<-R_;()Z(``]@40=`6R6^AV`(UU+.AC
; M`/8%$'0'LEWH9@#K4^AF`&8/MLIFBU4<9HM%(+_;`3'M9I)F4F8QTF;W\6:3
; M9EAF]_%FA].`RS!%B!V#_0-R!D?&!2PQ[4=FA=)UU6:%P'703X`]+'0!1ZJ-
; G=?[]Z`0`Z!,`PZR$P'0&DN@$`.OU_,.T`LTAP[(-Z/;_L@K-(<,`
; `
; end
; ======================================================================
;
; +-----------------+
; |  Requirements:  |
; +-----------------+
;
; Tested successfully on the following:
;
;      = Win XP Home SP2 (Intel P4 2.52 Ghz)
;      = DR-DOS 7.03 w/ DOSLFN 0.40e (Intel Pentium 166 Mhz w/o MMX)
;      = FreeDOS 1.0 (kernel 2036) w/ DOSLFN 0.40e (Intel 486 Sx/25)
;
; FASM   (use .BAT below)  :  219 bytes
; OCTASM (use .sed below)  :  219 bytes
; NASM or YASM             :  219/220 bytes (depending on version)
;
;    "nasm lfndir.asm -o lfndir.com -O5v"
;
; +------------+
; |  Credits:  |
; +------------+
;
; rugxulo AT gmail DOT com   (no spam, please!)
;
; public domain, free for any use, no credit necessary ("nenies proprajxo")
;
; with much grace from:
;   =  Our Lord Jesus Christ (seriously!)
;
; and a few nifty tips from:
;   =  Jason Hood (jadoxa)
;   =  brief look at some optimization texts (e.g. Agner Fog)
;   =  FASM forum (for being VERY helpful, in general, towards assembly)
;
; +---------------+
; |  Optimizing:  |
; +---------------+
;
;  = nothing else ... yet!   ;-)
;     = possibly using other instructions:  AAM, BSWAP, CMC ??
;
; +---------+
; |  Make:  |
; +---------+
; ----------------------------------------------------------------------
;
; @echo off
; REM Makes it w/ FASM (needs sed: e.g., SED15X.ZIP or SEDMOD10.ZIP)
;
; for %%a in (lfndir*.asm) do set L1=%%a
; set O1=lf.asm
; if not exist %L1% goto end
; sed "/sec.* \./d;/^bit/d;s/^.\(org.*h\)./\1/;s/res\([bw]\)/r\1/" %L1% >%O1%
; if not exist %O1% goto end
; REM cwsdpmi (for weird mem. manager situations, e.g. DOSBox)
; fasm %O1% lfndir-fasm.com >NUL
; for %%l in (lfndir-*.com) do set C1=%%l
; if "%C1%"=="" goto end
; %C1% %1
; :end
; REM !! this would delete it (to save space) !!
; REM for %%f in (%O1% %C1%) do if exist %%f del %%f
; for %%e in (O1 L1 C1) do set %%e=
;
; ----------------------------------------------------------------------
;
; # sed script for LFNDIR to work w/ Octasm
; #
; #     sed -f lfn-oct.sed lfndir.asm > lfn-oct.asm
; #     octasm \lfn-oct.asm file_out \lfn-oct.com
; #
; # N.B. Make sure to remove all trailing whitespace (or sed won't work!):
; #
; #     sed "s/ *$//" lfn-oct.sed > oct.sed
;
; 1s/..*/LANG OCTASM,0.1\
; &/
; s/jc find\.ret/jc <1/
; s/ equ /=/
; /^section \.text/d
; /^section \.data/d
; s/^section \.bss/virtual/
; $s/..*/&\
; code/
; s/.\(org 100h\)./\1/
; s/^bits /use/
; s/\(j[a-z][a-z]*\) \.ret/\1 >1/
; s/^\.ret:/#/
; s/^\([.a-zA-Z0-9_][.a-zA-Z0-9_]*\):/#\1/
; s/byte \[/b[/
; s/dword \[/d \[/
; s/word \[/w[/
; s/res\([bw]\)/r\1/
; s/^\.*[a-zA-Z0-9_][a-zA-Z0-9_]* [dr][bw]/#&/
; s/jmp short/jmp /
; /0\.1/!s/\.//g
; s/^;;;*/;/
;
; ----------------------------------------------------------------------
;
; +------------+
; |  Changes:  |
; +------------+
;
; 0.10: 219 bytes:  removed useless strlen (and more tweaks)
; 0.9 :  231 bytes:  yet more size optimizations
; 0.8 :  236 bytes:  more size optimizations!  ;-)
; 0.7 :  243 bytes:  tweaked a bit w/ some optimizations
; 0.6 :  255 bytes:  no code changes, only various text updates
; 0.5 :  255 bytes;  filespec can now be specified (default '*.*')
; 0.4 :  251 bytes;  fairly simple optimizations vs. previous
; 0.3 :  277 bytes:  now prints both names and filesizes
; 0.2 :  145 bytes:  minor optimizations vs. previous version
; 0.1 :  151 bytes:  initial version (filenames only)
;
; ----------------------------------------------------------------------
;
; +----------------+
; |  Misc. Notes:  |
; +----------------+
;
; P.S. You can shave more bytes if you're willing to compromise by
;      removing the filesize commas and/or adapting "call print_char"
;      to use int 29h (which isn't redirectable).
;
;      I wasn't willing to do so, and my goal was 256 bytes, so
;
;
; also, from Ralf Brown's interrupt list,
; (http://www.delorie.com/djgpp/doc/rbinter/id/16/32.html):
;
;    "only works when IFSMgr is running, not under bare MS-DOS 7"
;
;     BUT, it does work with DOSLFN 0.40e under pure DR-DOS 7.03!
;
;     http://www.geocities.com/jadoxa/  (DOSLFN, Jason Hood)
;
; ----------------------------------------------------------------------


CR equ 13
LF equ 10

ALL equ 0F7h                           ; everything but volume label (bit 3)
                                       ;   i.e., 0FFh and not 8
STDOUT equ 1
DIR equ 10000b                         ; bit 4 (aka, 10h)

COMMA equ 2Ch
SPACE equ 20h                          ; 20h = ' ' = bit 5 = 32
TAB equ 9

bits 16
section .text
[org 100h]                             ; works w/ old YASM 0.3.0, too

;--------------------------------------------------------------------

Komenco:
        mov si,80h
        lea dx,[si+2]
        lodsb
        test al,al
        jnz Filespec
        mov word [si+1],'*'            ; '*',0  is same as '*.*',0

Filespec:
        xchg ax,bx                     ; = 1 byte!  :-D
        xor bh,bh
        mov byte [bx+si],bh

Search:
        mov ax,714Eh                   ; LFN: find first
        mov cx,ALL
        call find
        jc Fino

;        mov word [find_handle],ax
        mov fs,ax

        call print_fileinfo
Next:
        mov ax,714Fh                   ; LFN: find next

;        mov bx,word [find_handle]
        mov bx,fs

        call find
        call print_fileinfo
        jnc Next
Adios:
        mov ax,71A1h                   ; close LFN find handle

;        mov bx,word [find_handle]
        mov bx,fs

        int 21h
Fino:

;        mov ax,4C00h
;        int 21h

;         int 20h
        ret                            ; oldest trick in the book
                                       ;  (saves a byte)

;--------------------------------------------------------------------

; find
find:
        mov di,finddata
        mov si,1                       ; DOS date/time format
        stc
        int 21h
.ret:
        ret

; print_fileinfo
print_fileinfo:
        jc find.ret

.begin:
        mov dl,TAB                     ; give us some space (to aide in
        call print_char                ;  telling the difference between
                                       ;  two lines of one filename or two
                                       ;  (compare listing of an 80+ length
                                       ;   fname via DIR /B and this .COM)

        test byte [di],DIR
        jz .fname

        mov dl,'['                     ; surround dirs w/ '[' and ']'
        call print_char                ;  e.g., '[My Documents]'

.fname:
        lea si,[di+2Ch]                ; LFN
        call print_str

        test byte [di],DIR
        jz .crlf

        mov dl,']'
        call print_char
        jmp short .crlf2
.crlf:
        call print_crlf

;;;        mov ecx,word [outbase]
;;        mov ecx,10                   ; = 6 bytes
;        lea ecx,[10]                  ; = 5 bytes
         movzx ecx,dl                  ; = 4 bytes

.fsize:
        mov edx,dword [di+1Ch]         ; filesize (qword)
        mov eax,dword [di+20h]

.bin2dec:
        mov di,buffer_start_nul+1      ; put ASCIIZ decimal string
        xor bp,bp                      ;  w/ commas in buffer (backwards)

.start:
        xchg eax,edx
        push edx
        xor edx,edx
        div ecx
        xchg eax,ebx
        pop eax
        div ecx
        xchg edx,ebx

        or bl,'0'                      ; this only works for dec numbers!
;        push eax                      ; this works for dec or hex nums
;        xchg bl,al
;        mov bx,asciihex
;        xlatb                         ; translate digit to ASCII
;        xchg bl,al
;        pop eax

        inc bp
        mov byte [di],bl

;        cmp bp,word [comma_number]

        cmp bp,3
        jb .no_comma                   ; comma_number = 3 (dec) or 4 (hex)

        inc di
        mov byte [di],COMMA
        xor bp,bp
.no_comma:
        inc di
        test edx,edx
        jnz .start
        test eax,eax
        jnz .start
        dec di                         ; now DX:AX = 0
        cmp byte [di],COMMA            ; this will allow 3-digit numbers
        jz .bye                        ;  not to be printed w/ a comma
        inc di
.bye:
;        mov byte [di],0
        stosb

        lea si,[di-2]

        std
        call print_str
.crlf2:
        call print_crlf
.ret:
        ret

; print_str
print_str:                             ; print string (redirectable)
        lodsb
        test al,al
        jz .bye2
        xchg ax,dx
        call print_char
        jmp short print_str
.bye2:
        cld
.ret:
        ret

; print_char
print_char:                            ; print char (redirectable)
        mov ah,2
        int 21h
.ret:
        ret

; print_crlf
print_crlf:                            ; print '\n' (redirectable)
        mov dl,CR
        call print_char
        mov dl,LF

;        call print_char
        int 21h                        ; this saves a byte
.ret:
        ret

;--------------------------------------------------------------------

;section .data                          ; this line increases .COM size ???
                                        ; (ah, NASM default: dword-aligned)

;asciihex db '0123456789ABCDEF',0

buffer_start_nul db 0

;--------------------------------------------------------------------

section .bss

;find_handle resb 2
buffer resb 45                         ; big enough for 64-bit no. w/ commas

finddata:
.attrib resb 4
.created_time resb 4
.accessed_time resb 4
.modified_time resb 4
.filesize_high resb 4                  ; 64-bit filesize
.filesize_low resb 4
.reserved resb 8                       ; unused
.long_name resb 260                    ; ASCIIZ
.short_name resb 14                    ; ASCIIZ

; EOF
    


Description: .ASM src, main .COM, textfile screenshot, LFN example, plus technical excerpt in .TXT about int 21h, 71..h functions used here (taken from Ralf Brown's list)
Download
Filename: lfndir10.zip
Filesize: 6.83 KB
Downloaded: 791 Time(s)



Last edited by rugxulo on 13 Jun 2007, 02:00; edited 15 times in total
Post 12 Oct 2006, 02:44
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 12 Oct 2006, 11:03
you can write "mov word [si+1],002Ah" simply as "mov word [si+1], '*'"
Post 12 Oct 2006, 11:03
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 12 Oct 2006, 21:03
vid, you are correct, sir! Yes, that's a nice readability tip, sorry I missed it! Smile

EDIT: Finally did it, too (dunno why it took so long either).


Last edited by rugxulo on 10 Jun 2007, 00:48; edited 4 times in total
Post 12 Oct 2006, 21:03
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 13 Oct 2006, 14:42
EDIT: ... (redundant post)


Last edited by rugxulo on 09 Jan 2007, 23:35; edited 2 times in total
Post 13 Oct 2006, 14:42
View user's profile Send private message Visit poster's website Reply with quote
Octavio



Joined: 21 Jun 2003
Posts: 366
Location: Spain
Octavio 15 Oct 2006, 13:46
rugxulo wrote:
It only lists LFN filenames and their filesizes (but > 4 GB works).

Fat 32 is limited to 4GB perhaps you mean >2GB.
But the problem is in showing the complete charset wich is 2^16 diferent letters ,this would require a graphics videomode + bmps to show all chars above 80h like: ñÇü²³§
Post 15 Oct 2006, 13:46
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 18 Oct 2006, 23:12
Octavio, yes, I meant > 2 GB (though in my head I was thinking in terms of the limitations of a 32-bit number ... my 16-bit DOS prog VDIR apparently shows > 3 GB filesizes on my Win XP NTFS C: drive using only 16-bit regs, mainly DX:AX, so I'm actually comparing LFNDIR to that).

Complete charset? I guess you mean Unicode (probably won't work) instead of extended ASCII (apparently works).
Post 18 Oct 2006, 23:12
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 06 Jan 2007, 03:01
And, for completeness' sake, here's a wimpy 16-bit DOS dir lister I've written (reassembles via a bunch of assemblers using sed, included). No flames, I know it ain't much, but whatever. Razz


Description: VDIR 0.49 (unfinished)
16-bit DOS dir lister
public domain
rugxulo AT bellsouth DOT net

Download
Filename: V49LITE.ZIP
Filesize: 75.96 KB
Downloaded: 798 Time(s)

Post 06 Jan 2007, 03:01
View user's profile Send private message Visit poster's website Reply with quote
ATV



Joined: 31 Aug 2004
Posts: 109
Location: Finland
ATV 08 Jan 2007, 13:06
rugxulo, you are very good with sed and using bat to convert source.
But then I found next line
Quote:
if "%CLEAN%"=="y" if exist %V%fasm.asm erase %V%fasm.asm

Why, why, why you are deleting v49fasm.asm

Any plans to add 24h time format? It's easier than am/pm +midnight stuff.
Post 08 Jan 2007, 13:06
View user's profile Send private message Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 09 Jan 2007, 05:09
ATV wrote:
rugxulo, you are very good with sed and using bat to convert source.
It is more efficient than manually editing a billion separate files. That would get tedious very quickly.

ATV wrote:

But then I found next line
Quote:
if "%CLEAN%"=="y" if exist %V%fasm.asm erase %V%fasm.asm

Why, why, why you are deleting v49fasm.asm


If you don't like that behavior, in V49OTHER.BAT go to ":begin" and type below it "set clean=n".

Because I use/edit only the main V49.ASM file, if I want to assemble via an assembler other than ArrowASM (default) or A86, I have to use sed. Now, most seds (except GNU sed -i, which I avoid because it's larger/slower/386-only) don't edit in-place. So, I have to create a second .ASM file (e.g., V49FASM.ASM) with suitable changes to allow it to be assembled in the target assembler's syntax. I see no reason to keep around the auxiliary .ASM by default because any changes made to it are not shared with the main V49.ASM source. Plus, it wastes storage space (e.g., on a floppy or RAM disk) to keep every little auxiliary .ASM if doing "V49OTHER all" for instance, so unless you "set CLEAN=n" before running V49OTHER.BAT (or type "V49OTH2 fasm notclean"), it deletes V49FASM.ASM.

ATV wrote:

Any plans to add 24h time format? It's easier than am/pm +midnight stuff.


I dunno, 00:05 just looks dumb to me, so I typically use 12-hour, but it'd be easy to change. More to do! Razz
Post 09 Jan 2007, 05:09
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 11 Feb 2007, 21:57
Okay, ATV, here's a quick diff that makes /T! use 24-hour file times when using /V (instead of default 12-hours). After this, you can either enable it manually each time you use it, reassemble with "suboptions dw 31 or MILITARY", or put "set VDIR=t!" in your AUTOEXEC.BAT (or FDAUTO.BAT or whatever). Enjoy (heh, yeah right!). Smile

Code:
565,566c569,571
< A_SUBOPT_X equ 1000h
< A_SUBOPT_N equ 2000h
---
> MILITARY equ 1000h
> A_SUBOPT_X equ 2000h
> A_SUBOPT_N equ 4000h
626,627c631,632
< ;        cmp al,'T'                     ; /Z:T would be useless!
< ;        jz env_var_next
---
> ;;        cmp al,'T'                     ; /Z:T would be useless!
> ;;        jz env_var_next                ;   but /t! wouldn't
701,702c706,707
<         cmp al,'T'                     ; /Z:T would be useless!
<         jz env_var2_next
---
> ;        cmp al,'T'                     ; /Z:T would be useless!
> ;        jz env_var2_next               ;   but /t! wouldn't
1787c1792,1798
<         mov ax,word ptr [dta+16h]      ; offset of file's time
---
>                                        ; offset of file's time
> 
>         mov si,offset buffer
>         mov word ptr [si],'  '         ; needed by /t!
>         mov word ptr [si+2],0
> 
>         mov ax,word ptr [dta+16h]
1792a1804,1807
> 
>         test word ptr [suboptions],MILITARY
>         jnz file_time_continue
> 
1850a1866
>         inc cx
1853d1868
<         mov byte ptr [di],0
3915c3930,3938
< option_t:                              ; /T will print time and date
---
> option_t:
>         call suboption_flag_check
> ;        cmp word ptr es:[si],2154h     ; '!T'
>         jnz option_t_begin
>         xor word ptr [suboptions],MILITARY
>         inc si                         ; /T! prints 24h times (default: 12h)
>         jmp short option_t_ret
> 
> option_t_begin:                        ; /T will print time and date
3959c3982
< ;        ret                            ; bogus 'ret' for .SED scripts!
---
>         ret
4089,4090c4112,4113
<         cmp byte ptr [si],'T'          ; ignore /T or /H or /? or /Z
<         jz option_z_load
---
> ;        cmp byte ptr [si],'T'          ; ignore /H or /? or /Z
> ;        jz option_z_load               ;    (keep /t for /t!)
4186c4209
< ;                nxCYJIRXHDatds         ; n=/A:N, x=/A:X
---
> ;               nxMCYJIRXHDatds         ; n=/A:N, x=/A:X, M = MILITARY
    
Post 11 Feb 2007, 21:57
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 13 Jun 2007, 02:21
Updated this, added .ZIP package

BTW, I spent a few hours poring over the code, so I seriously doubt I'll be decreasing it much, if at all, in the next few weeks (however, some of you obviously could, even though I doubt you will since DOS interest here seems to be low). Oh well.
Post 13 Jun 2007, 02:21
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 04 Mar 2008, 16:39
Sorry to bump the thread, but at least I found this interesting: Wink

Code:
.crlf2: 
;        call print_crlf 
        jmp print_crlf     ; saves a byte
.ret: 
        ret
    
Post 04 Mar 2008, 16:39
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.