; Warning! if you don't like the taste of spaghetti, don't read this file! LOCALS @@ SMART IDEAL P386N MODEL TINY CODESEG ORG 100h ; Flags ACTIVE EQU 01h ; tab-completer active? PROGRESS EQU 02h ; tab-completion in progress? LSHIFT EQU 04h ; lshift down? RSHIFT EQU 08h ; rshift down? SHIFT EQU 0Ch ; either shift down? LCTRL EQU 10h ; lctrl down? RCTRL EQU 20h ; rctrl down? CTRL EQU 30h ; either ctrl down? LALT EQU 40h ; lalt down? RALT EQU 80h ; ralt down? ALT EQU 0C0h ; either alt down? MODS EQU 0FCh ; any modifiers down? ; Flags2 EXT EQU 01h ; extended key? WILDLEN EQU 84 Start: jmp Install DTA db 128 dup(?) Wildcard db WILDLEN dup(?) ; storage for the wildcard FileSeg dw 0 ; file list FileLen dw 0 label Old9h dword OldOff dw 0 ; orig int 9h handler OldSeg dw 0 OldSP dw 0 ; saved stack pointer Index dw 0 ; current file index OCX db 0 ; original cursor X NCX db 0 ; cursor to erase to - 1 Flags db 01h ; some flags (see above) Flags2 db 04h NPOldExitR: jmp NPOldExit OldExitR: jmp OldExit Int9h: pusha ; save registers and set up DS push ds push es push cs pop ds mov [OldSP], sp @@chkext: in al, 60h ; read scancode cmp al, 224 ; regular extended? jne @@chkRel or [Flags2], EXT @@chkRel: test al, 80h ; key being released? jz Press ; nope, goto press handler test [Flags2], EXT ; extended key? jz @@chkNorm ; extended keys cmp al, 157 jne @@chkRA and [Flags], NOT RCTRL jmp OldExit @@chkRA: cmp al, 184 jne NPOldExit and [Flags], NOT RALT jmp OldExit @@chkNorm: ; normal key cmp al, 143 jne @@chkLC jmp Ret9h @@chkLC: cmp al, 157 ; LCTRL? jne @@chkLS and [Flags], NOT LCTRL jmp OldExit @@chkLS: cmp al, 170 ; LSHIFT? jne @@chkRS and [Flags], NOT LSHIFT jmp OldExit @@chkRS: cmp al, 182 ; RSHIFT? jne @@chkLA and [Flags], NOT RSHIFT jmp OldExit @@chkLA: cmp al, 184 ; LALT? jne short NPOldExitR and [Flags], NOT LALT jmp OldExit Press: ; key pressed test [Flags2], EXT ; extended? jz @@chkNorm ; extended keys cmp al, 29 ; RCTRL jne @@chkRA or [Flags], RCTRL jmp OldExit @@chkRA: ; RALT cmp al, 56 jne short NPOldExit or [Flags], RALT jmp OldExit @@chkNorm: ; not extended cmp al, 15 ; is it TAB? jne @@chkLC ; not tab test [Flags], MODS ; modifiers? jz @@RegTabR ; regular old tab test [Flags], SHIFT ; shift-tab? jz OldExit test [Flags], CTRL ; shift-ctrl-tab? jz @@noctrl xor [Flags], ACTIVE ; shift-ctrl-tab (toggle active) jmp NPOldExit @@RegTabR: jmp RegTab @@noctrl: ; shift-tab (prev. file) test [Flags], ACTIVE ; quit if inactive jz OldExit push ds ; go to prev. file mov ax, [FileSeg] mov bx, [Index] mov ds, ax call strlen add bx, ax mov bx, [bx+1] pop ds mov [Index], bx jmp ShowFile ; now show it ; non-tab @@chkLC: cmp al, 29 ; LCTRL? jne @@chkLS or [Flags], LCTRL jmp OldExit @@chkLS: cmp al, 42 ; LSHIFT? jne @@chkRS or [Flags], LSHIFT jmp short OldExit @@chkRS: cmp al, 54 ; RSHIFT? jne @@chkLA or [Flags], RSHIFT jmp OldExit @@chkLA: cmp al, 56 ; LALT? jne NPOldExit or [Flags], LALT jmp OldExit ; disables PROGRESS, falls into OldExit, writes string if necessary NPOldExit: test [Flags], PROGRESS ; if TC not in progress, just exit jz @@nowrite call Erase ; finished with tab completion, so write chosen string mov bx, OFFSET Wildcard call strlen ; remove *.* from wildcard sub ax, 3 add bx, ax mov [byte bx], 0 sub bx, ax pusha ; print wildcard push bx push ax mov ah, 0Fh int 10h mov ah, 03h int 10h mov ax, 1301h mov bl, 7 pop cx push ds pop es pop bp int 10h popa add bx, ax ; find last '\', if any @@loop: mov cl, [bx] cmp cl, '\' je @@found dec bx cmp bx, OFFSET Wildcard jae @@loop jmp @@writefile @@found: sub bx, OFFSET Wildcard inc bx sub ax, bx @@writefile: mov bx, [Index] ; write the file minus the wildcard add bx, ax push ds mov ax, [FileSeg] mov ds, ax call PushStr pop ds @@nowrite: and [Flags], NOT PROGRESS ; not in progress anymore ; Calls old handler, then exits OldExit: pushf call [Old9h] mov sp, [OldSP] pop es pop ds popa iret ; indicates that an error occured, then falls into Ret9h DoError: and [Flags], NOT PROGRESS ; Resets keyboard, restores regs and then irets Ret9h: mov al, 20h ; reset keyboard out 20h, al mov sp, [OldSP] pop es pop ds popa iret RegTab: ; regular tab(file complete) test [Flags], ACTIVE ; quit if inactive jz OldExit test [Flags], PROGRESS jnz NextFile call ReadWild ; fetch Wildcard from screen jc DoError ; an error occured mov bx, OFFSET Wildcard ; append a '*.*' onto the wildcard call strlen add bx, ax mov [word bx], '.'*256 + '*' mov [word bx+2], '*' call SearchFiles jc DoError or [Flags], PROGRESS NextFile: push ds ; advance to next file mov ax, [FileSeg] mov bx, [Index] mov ds, ax mov bx, [bx-2] pop ds mov [Index], bx ShowFile: call Erase ; erase old file from screen call WriteTemp ; write the new one jmp Ret9h ; and return ; searches for files that match Wildcard and stores them SearchFiles: mov bp, sp sub sp, 2 mov dx, OFFSET DTA ; tell dos where our DTA is mov ah, 1ah int 21h cmp [FileLen], 0 ; if(!FileLen) Filearr=malloc(FileLen=256); jne @@nomalloc mov cx, 256 call malloc mov [FileLen], cx jc @@return mov [FileSeg], ax @@nomalloc: mov ah, 4eh ; find first file dta = findfirst(wild); mov cx, 37h ; all files and dirs mov dx, OFFSET Wildcard int 21h jc @@return sub ax, ax ; len = sub di, di ; fpos = 0; @@loop: ; do { mov bx, OFFSET DTA + 30 ; len = strlen(dta.fn+5) mov dx, di ; dx = fpos call strlen add ax, 5 ; ax = len add dx, ax ; if(fpos+len >= filelen) dx = fpos+len cmp dx, [FileLen] ; { // resize FileSeg memory block jb @@nogrow pusha push ds mov bx, [FileLen] ; try to resize the current block shl bx, 1 mov [FileLen], bx shr bx, 4 mov cx, [FileSeg] mov ah, 4ah mov es, cx int 21h jnc @@goodalloc ; fall back on an alloc/copy/free if that fails mov ah, 48h ; alloc mov bx, [FileLen] shr bx, 4 int 21h jnc @@copy ; error? pop ds jmp @@return @@copy: ; copy sub si, si sub di, di mov cx, [FileLen] mov dx, [FileSeg] mov es, ax shr cx, 1 mov ds, dx mov [FileSeg], ax rep movsb mov es, dx ; free mov ah, 49h int 21h @@goodalloc: pop ds popa @@nogrow: push di ; save fpos(1) add dx, 2 ; dx = fpos+len+2 mov si, bx ; si = &dta.fn mov bx, [FileSeg] ; filearr[fpos] = fpos+len+2; bx = FileSeg mov es, bx mov [es:di], dx add di, 2 ; strcpy(filearr+fpos+2, dta.fn); di = fpos+2 call strcpy mov di, dx ; filearr[fpos+len-2] = oldfpos+2; di=fpos+len+2 sub di, 4 ; di = fpos+len-2 mov bx, [bp-2] ; bx = old fpos add bx, 2 ; bx = old fpos+2 mov [es:di], bx pop bx ; bx = fpos(0) mov di, bx ; fpos+=len; di = fpos mov [bp-2], di ; save old fpos add di, ax ; di = fpos+len bx = fpos-len mov ah, 4fh ; dta = nextfile(); int 21h jnc @@loop sub si, si ; filearr[filearr[0]-4] = fpos-len+2; si = 0 add bx, 2 ; bx = fpos-len+2 mov si, [es:si] ; si = filearr[0] sub si, 4 ; si = filearr[0]-4 mov [es:si], bx mov [Index], bx ; Index = fpos-len+2; sub bx, 2 ; filearr[fpos-len] = 2; bx = fpos-len mov [word es:bx], 2 @@return: mov sp, bp ret ; takes the string in DS:BX and returns length in AX strlen: push bx dec bx mov ax, -1 @@loop: inc bx inc ax cmp [byte bx], 0 jne @@loop pop bx ret ; reverses the string in DS:SI reverse: push ax push bx push dx mov si, bx call strlen cmp ax, 1 jle @@done add si, ax clc rcr ax, 1 adc ax, 0 @@loop: dec si mov dl, [bx] mov dh, [si] mov [bx], dh inc bx mov [si], dl dec ax jnz @@loop @@done: pop dx pop bx pop ax ret ; reads the wildcard from the screen into Wildcard and sets carry on error ReadWild: mov si, OFFSET Wildcard push si mov ah, 0Fh ; get display page int 10h mov ah, 03h ; get cursor pos int 10h mov [NCX], dl ; save end cursor @@loop: mov ah, 03h ; get cursor pos int 10h dec dl ; back a space js @@abort ; off left edge? if so, abort dec ah ; set cursor pos (02h) int 10h mov ah, 08h ; read character int 10h call ValidChar jc @@done mov [si], al inc si jmp @@loop @@done: inc dl mov [OCX], dl ; save cursor mov [byte si], 0 ; null terminate pop bx call reverse clc ret @@abort: mov dl, [OCX] mov ah, 02h int 10h pop bx stc ret ; sets carry if char in al is invalid ValidChar: cmp al, 32 ; control characters and ' ' jbe @@bad ;cmp al, '\' ;je @@bad cmp al, '/' je @@bad cmp al, ':' je @@bad cmp al, '<' je @@bad cmp al, '>' je @@bad cmp al, '|' je @@bad cmp al, '"' je @@bad clc ret @@bad: stc ret ; allocates CX bytes of mem, returns segment in AX, carry set on error malloc: push bx mov bx, cx mov ah, 48h add bx, 15 shr bx, 4 int 21h pop bx ret ; copies the string from ds:si to es:di strcpy: pusha cld @@loop: movsb cmp [byte si-1], 0 jne @@loop popa ret ; erases OCX to NCX and places cursor at OCX Erase: pusha mov ah, 0Fh ; get display page int 10h mov ah, 03h ; get cursor pos int 10h mov dl, [OCX] ; set cursor to OCX dec ah int 10h mov ax, 0E20h ; write space and advance cursor @@loop: cmp dl, [NCX] jae @@done int 10h inc dl jmp @@loop @@done: mov ah, 2 ; set cursor to OCX mov dl, [OCX] int 10h popa ret ; writes the current string and sets NCX WriteTemp: pusha push ds mov cx, [FileSeg] mov ah, 0Eh ; write and advance cursor mov dl, [OCX] mov bx, [Index] mov ds, cx @@loop: mov al, [bx] inc bx inc dl cmp al, 0 je @@done int 10h jmp @@loop @@done: dec dl pop ds mov [NCX], dl popa ret ; Pushes a string (ds:bx) into the keyboard buffer PushStr: pusha ;mov ch, 30 ; A's scancode mov ch, 0 @@loop: mov ah, 5h ; int 16h, func 5h - push keystroke mov cl, [bx] ; read char cmp cl, 0 ; we done? je @@done int 16h ; nope, push it inc bx ; next char cmp al, 0 ; success? je @@loop ; yep.. continue on @@done: popa ret Install: mov ax, 3509h ; install int 9h handler int 21h mov dx, es mov [OldOff], bx mov [OldSeg], dx mov ah, 25h mov dx, OFFSET Int9h int 21h mov bx, 2Ch ; free environment block mov bx, [bx] mov ah, 49h mov es, bx int 21h mov bx, OFFSET ProgEnd ; resize program's memory block add bx, 15 shr bx, 4 mov ah, 4ah push cs pop es int 21h mov dx, OFFSET Install ; TSR! inc dx int 27h ProgEnd: end Start