; Copyright 2005 Christopher Evans
; Website: http://nxdos.sourceforge.net/
;                                                                           ;
;       This program is copyrighted, but may be freely distributed          ;
;       under the terms of the Free Software Foundation's GNU General       ;
;       Public License v2 (or later.)  See the file COPYING for the         ;
;       legalities.  If you did not receive a copy of COPYING, you          ;
;       may request one from the Free Software Foundation, Inc.,            ;
;       59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           ;
;       ABSOLUTELY NO WARRANTY -- use it at your own risk!                  ;
;                                                                           ;

code            segment byte public
                assume  cs:code, ds:code

		org	100h

ProgramStart    EQU $    

slte            proc    far

start:          jmp     initialize
include         \nxdos\src\toolbox.asm
include         \nxdos\src\mem\mem.asm

initialize:
;                push cs
;                pop  es
;                mov  bx, ProgramEnd
;                call memresize
;                or   al, al
;                jnz  exitptr
                call cs:main
                

exitptr:        call dosexit
                int 20h      

slte            endp

updatecursor proc far
        mov  dl, curcol
        mov  dh, currow
        call gotoxy
        ret
updatecursor endp

incsize proc far
        inc  editpos
        mov  cx, editsize
        inc  cx
        mov  editsize, cx
        ret
incsize endp

decsize proc far
        dec  editpos
        mov  cx, editsize
        dec  cx
        mov  editsize, cx
        ret
decsize endp

drawmenus proc far
        mov  al, 07h
        call textcolor
        call clrscr
        mov  bh, 0

        mov  dl, 1
        mov  dh, 1
        call gotoxy
        mov  ax, 1
        call textbackground
        _newline 
        _print menubar, 1

        mov  dl, 1
        mov  dh, 25
        call gotoxy
        mov  ax, 1
        call textbackground
        _newline 
        _print helpbar, 1
          ret
drawmenus endp

showedit_buf proc far
        mov  dl, 1
        mov  dh, 2     
        call gotoxy

        mov  cx, 1838
        mov  si, 0  ; editpos

displaybuf:
        mov  al, editbuffer[si]
        call teletype
        inc  si
        loop displaybuf
          ret
showedit_buf endp

hr   db ?
min  db ?
sc   db ?
dst  db ?

; ===========================================================================
menubarinfo proc far
; This is a convenient debugging aid, as well is user inform
; ===========================================================================

        mov  dl, 70
        mov  dh, 1     
        call gotoxy
        mov  ah, 02h
        int  1ah
        jc   _aborttime
        mov  hr, ch
        mov  min, cl
        mov  sc,  dh
        mov  dst, dl

        mov  ax, 0
        mov  al, hr
        call bcd2num
        call putnum
        _echo ':'
        mov  ax, 0
        mov  al, min
        call bcd2num
        call putnum
        _echo ':'
        mov  ax, 0
        mov  al, sc
        call bcd2num
        call putnum
_aborttime:

        mov  dl, 70
        mov  dh, 25    
        call gotoxy

        mov  al, 7
        call textcolor
        mov  ax, editsize
        call putnum  

        mov  dl, 60
        mov  dh, 25    
        call gotoxy

        mov  al, 7
        call textcolor
        _echo '['
        mov  al, currow
        call putnum
        _echo ' '
        mov  al, curcol  
        call putnum
        _echo ']'

        mov  dl, 20
        mov  dh, 25
        call gotoxy
        mov  al, emsfound
        or   al, al
        jz   _showxmsinfo
        call cs:ems_Info
        _echo ' '
_showxmsinfo:
        mov  al, xmsfound
        or   al, al
        jz   _mbx
        call cs:XMS_Info
_mbx:   ret
menubarinfo endp

storechar proc far
        mov  si, editpos
        mov  byte ptr editbuffer[si], al
        ret
storechar endp

checkkeys proc far
; check for menu keys and such controls
        mov  key, al        
        cmp  al, 0
        jne  _notaextendedkey
        _readkey
        cmp  al, 77
        jne  chkrightarrow
        inc  curcol
        call incsize
        call updatecursor
        jmp  _extdn
chkrightarrow:
        cmp  al, 75
        jne  _extdn
        dec  curcol
        call decsize
        call updatecursor
_extdn: jmp  _keychkdone
_notaextendedkey:
        cmp  al, 27
        jne  _backspace
        mov  al, 1
        mov  done, al
_backspace:
        mov  al, key
        cmp  al, 08
        jne  __newline
        ; bound check 
        mov  ax, editsize
        or   ax, ax
        jz   _keychkdone
        ;
        mov  dl, curcol
        dec  dl
        mov  curcol, dl
        call updatecursor
        _echo ' '
        call updatecursor
        call decsize
        jmp  _keychkdone
__newline:
        cmp  al, 13   ; enter
        je   _nline     
        inc  curcol
        mov  dh, curcol
        cmp  dh, 79
        jb   _storechar
_nline:
        mov  dh, currow
        cmp  dh, 24
        jb   _goingtoanewline
_home_our_screen:    
        call drawmenus
        mov  dl, 1
        mov  currow, dl
_goingtoanewline:
        mov  dh, 1
        mov  curcol, dh
        mov  dl, currow
        inc  dl
        mov  currow, dl
_storechar:
        call incsize
        mov  al, key
        call storechar
        call teletype
_keychkdone:
        ret
key db ?
checkkeys endp


filehandle  dw ?
ReadError   db 'File Error on Read.',0
FileWriteerror   db 'File Error on Write. (Press any key)',0
OpenError   db 'FileName: ',0
OpenFileMsg db 'FileName: ',0
Filename    db 127 dup(0),0

; ===========================================================================
main proc far
; ===========================================================================
        call cs:ems_setup
        call cs:XMS_Setup

        _print OpenFileMsg, 1
        lea  di, filename
        mov  cx, 127
        call getdata
        mov  ah, 3dh
        mov  al, 00000010b  ; R/W
        lea  dx, filename
        int  21h
        jnc  opened
        mov  ah, 3ch
        mov  al, 00000010b  ; R/W
        lea  dx, filename
        mov  cx, 00100000b
        int  21h
        jnc  opened
        _print OpenError, 1
        ret
opened: mov  filehandle, ax
        ;
        ; read in file into buffer
        mov  ah, 3fh
        mov  bx, FileHandle
        mov  cx, EditBuf$
        lea  dx, editbuffer
        int  21h
        jnc  fileread  
        _print ReadError, 1
        jmp  closethefile
fileread:

        ;
        call drawmenus
editloop:
        call hidecursor
        call menubarinfo
        call showedit_buf
        call showcursor
        call updatecursor
        kbhit
        or   al, al
        jz   editloop
        call readkey
        call checkkeys
        mov  al, done      ; check to see if user is done editing
        or   al, al
        jz   editloop

        ; save file from buffer
savethefile:
        mov  ah, 40h
        mov  bx, FileHandle
        mov  cx, EditBuf$   ; edit size
        lea  dx, editbuffer
        int  21h
        jnc  filesaved
        _print Filewriteerror, 1
        _readkey
filesaved:

closethefile:
        ; close filename
        mov  ah, 3eh
        mov  bx, FileHandle 
        int  21h



        mov  al, 07h
        call textcolor
        call clrscr
        _print banner, 1
        _newline
        _print special, 1


     ret
main endp

menubar db '  (F)ile              * Simple Little Text Edit 1.0 * ',0
helpbar db '  F1=Help                                                         | ',0
banner     db 'Simple Little Text Editor (SLTE) v1.0 June, 2005',0ffh
           db 'Copyright (C) 2005 by Christopher R. Evans, all rights reserved',0ffh,0

special    db 'SLTE is designed to be the system text file editor for NX-DOS.',0ffh
           db 'If you use it, I encourage you to support the nxdos project. ',0ffh
           db 'By donating money to the project you will also be supporting Sourceforge,',0ffh
           db 'Electronic Frontier Foundation, and the Open Source Initiative.',0ffh,0ffh
           db 'The website is http://nxdos.sourceforge.net/',0ffh,0
eb         dw 0
toprow     db 2
currow     db 2 
curcol     db 1
bottomrow  db 24
done       db 0
editsize   dw 0
editpos    dw 0
EDITBUF$   EQU 32768
editbuffer db EDITBUF$ dup(0)

code            ends

ProgramEnd      EQU $-01h
		end	start




; dosedit
                _newline
                lea  di, filename
                mov  cx, 127
                call getdata

                lea  dx, filename
                mov  bx, 0
                xor  cx, cx
                call fopen
                cmp  ax, 0
                je   createfile
createfile:
                lea  dx, filename
                mov  bx, 1
                xor  cx, cx
                call fopen
                cmp  ax, 0
                je   exitptr
fileopened:     mov  filehandle, ax
                mov  bx, filehandle
                call filesize
                mov  word ptr file_size, ax
                mov  word ptr file_size+2, dx
                cmp  ax, 3fffh
                ja   close_this_file
                _fread  filehandle, txt, word ptr file_size

editloop:
                call displayscreen
                kbhit
                or  al, al
                jz  editloop
                call readkey

        ;        call teletype

                mov  si, txtptr
                mov  byte ptr [txt][si], al
                inc  si
                mov  txtptr, si
                inc  txtsize
                cmp  al, 27
                jne  editloop

                _fwrite filehandle, txt, txtsize
close_this_file:
                _fclose filehandle

exitptr:        call dosexit
                int 20h      

com             endp

displayscreen proc near
        call getxy
        mov  x, dh
        mov  y, dl

        xor  cx, cx
dispcont:
        lea  si, txt
        mov  bp, cx
        mov  al, byte ptr [si][bp]
        call teletype
        inc  cx
        cmp  cx, (80*24)
        jb   dispcont

        _gotoxy y, x, 0
        ret
        x db ?
        y db ?
displayscreen endp

filehandle dw ?
file_Size  dd 0
filename   db 127 dup(0),0
txt        db 3fffh dup(0)
txtptr     dw 0
txtsize    dw 0

code            ends

ProgramEnd      EQU $-01h

		end	start

; DOS-EDIT.ASM - Resdient Command Line Editor

Initialize:	Sub	AX,AX			; Make AX equal zero
		Mov	DS,AX			; To point to vector segment

		Les	BX,dword ptr DS:[21h * 4]; Get and save Int. 21h
		Mov	Word Ptr CS:[OldInterrupt21],BX
		Mov	Word Ptr CS:[OldInterrupt21 + 2],ES

		Les	BX,dword ptr DS:[16h * 4]; Get and save Int. 16h
		Mov	Word Ptr CS:[OldInterrupt16],BX
		Mov	Word Ptr CS:[OldInterrupt16 + 2],ES

		Push	CS			; Restore DS register
		Pop	DS			;   by setting to CS

		Mov	DX,Offset NewInterrupt21
		Mov	AX,2521h		; Set new Interrupt 21h
		Int	21h			;   through DOS

		Mov	DX,Offset NewInterrupt16
		Mov	AX,2516h		; Set new Interrupt 16h
		Int	21h			;   through DOS

		Mov	DX,Offset Initialize	; Number of bytes to stay
		Int	27h			; Terminate & remain resident
exitptr:
                int 20h      

;	Get Buffer Character
;	--------------------

GetBufferChar:	Push	BX		
		Mov	BX,CS:[BufferPointer]	; Get pointer to key buffer
		Mov	AL,CS:[BX]		; Get the key
		Sub	AH,AH			; Blank out scan code
		Pop	BX
		Ret

;	Full Screen Routine
;	-------------------

FullScreen:	Push	AX			; Save all these registers
		Push	BX
		Push	CX
		Push	DX
		Push	DI
		Push	DS
		Push	ES

		Mov	AX,CS			; Set AX to this segment
		Mov	DS,AX			; Do DS is this segment
		Mov	ES,AX			; And ES is also

		Mov	AH,0Fh			; Get Video State
		Int	10h			;   through BIOS
		Dec	AH			; Number of columns on screen
		Mov	[MaxCharCol],AH		; Save maximum column
						; BH = Page Number throughout
		Mov	AH,03h			; Get cursor in DX
		Int	10h			;   through BIOS
		Mov	[OriginalCursor],DX	; And save the cursor position

		Call	Up			; Move cursor up	

MainLoop:	Cmp	DH,Byte Ptr [OriginalCursor + 1]	; If at line
		Jz	TermFullScreen		; stated from, terminate

		Mov	AH,02h			; Set cursor from DX
		Int	10h			;   through BIOS

GetKeyboard:	Mov	AH,0			; Get the next key
		PushF				; By simulating Interrupt 16h
		Call	CS:[OldInterrupt16]	;   which goes to BIOS

		Cmp	AL,1Bh			; See if Escape key
		Jz	TermFullScreen		; If so, terminate full screen

;	Back Space
;	----------

		Cmp	AL,08h			; See if back space
		Jnz	NotBackSpace		; If not, continue test

		Or	DL,DL			; Check if cursor at left
		Jz	MainLoop		; If so, do nothing	

		Dec	DL			; Otherwise, move cursor back
		Call	ShiftLeft		; And shift line to the left

		Jmp	MainLoop		; And continue for next key

;	Carriage Return
;	---------------

NotBackSpace:	Cmp	AL,0Dh			; See if Carriage Return
		Jnz	NotCarrRet		; If not, continue test

                Call    EndLine                 ; Move line into buffer

		Mov	AL,0Dh			; Tack on a Carriage Return
		Stosb				; By writing to buffer
		Inc	[BufferCounter]		; One more character in buffer

		Jmp	MainLoop		; And continue

;	Normal Character
;	----------------

NotCarrRet:	Cmp	AL,' '			; See if normal character
		Jb	NotNormalChar		; If not, continue test

		Cmp	[InsertOn],0		; Check for Insert mode
		Jz	OverWrite		; If not, overwrite 

		Call	ShiftRight		; Shift line right for insert
		Jmp	Short NormalCharEnd	; And get ready to print

OverWrite:	Mov	CX,1			; Write one character
		Mov	AH,0Ah			; By calling BIOS
		Int	10h

NormalCharEnd:	Call	Right			; Cursor to right and print

		Jmp	MainLoop		; Back for another key

;	Cursor Key, Insert, or Delete Subroutine
;	----------------------------------------

NotNormalChar:	Xchg	AL,AH			; Put extended code in AL
		Sub	AX,71			; See if it's a cursor key
		Jc	GetKeyboard		; If not, no good

		Cmp	AX,12			; Another check for cursor
		Ja	GetKeyboard		; If not, skip it 

		Add	AX,AX			; Double for index
		Mov	DI,AX			;   into vector table

		Call	[KeyRoutine + DI]	; Do the routine

		Jmp	MainLoop		; Back for another key	

;	Terminate Full Screen Movement
;	------------------------------

TermFullScreen:	Mov	DX,[OriginalCursor]	; Set cursor to original
		Mov	AH,2			; And set it
		Int	10h			;   through BIOS

		Pop	ES			; Restore all registers
		Pop	DS
		Pop	DI
		Pop	DX
		Pop	CX
		Pop	BX
		Pop	AX

		Ret				; And return to New Int. 16h

;	Cursor Movement
;	---------------

Home:		Mov	DL,Byte Ptr [OriginalCursor]	; Move cursor to
		Ret				; to original column

Up:		Or	DH,DH			; Check if at top row
		Jz	UpEnd			; If so, do nothing
		Dec	DH			; If not, decrement row
UpEnd:		Ret

PgUp:		Sub	DL,DL			; Move cursor to far left 
		Ret

Left:		Or	DL,DL			; Check if cursor at far left
		Jnz	GoWest			; If not, move it left
		Mov	DL,[MaxCharCol]		; Move cursor to right
		Jmp	Up			; And go up one line
GoWest:		Dec	DL			; Otherwise, decrement column
		Ret

Right:		Cmp	DL,[MaxCharCol]		; Check if cursor at far right
		Jb	GoEast			; If not, move it right
		Sub	DL,DL			; Set cursor to left of screen
		Jmp	Down			; And go down one line
GoEast:		Inc	DL			; Otherwise, increment column
		Ret

EndLine:        Call    TransferLine            ; Move line to buffer
		Mov	DX,[OriginalCursor]	; Set cursor to original
		Ret

Down:		Inc	DH			; Move cursor down one row
		Ret

PgDn:		Mov	CL,[MaxCharCol]		; Get last column on screen
		Inc	CL			; Kick it up by one
		Sub	CL,DL			; Subtract current column
		Sub	CH,CH			; Set top byte to zero
		Mov	AL,' '			; Character to write
		Mov	AH,0Ah			; Write blanks to screen
		Int	10h			;   through BIOS
Dummy:		Ret

;	Insert and Delete
;	-----------------

Insert:		Xor	[InsertOn],-1		; Toggle the InsertOn flag
		Ret				;   and return	

Delete:		Call	ShiftLeft 		; Shift cursor line left
		Ret				;   and return

;	Transfer Line on Screen to Keyboard Buffer
;	------------------------------------------

TransferLine:	Sub	CX,CX			; Count characters in line
		Mov	DI,Offset KeyboardBuffer	; Place to store 'em
		Mov	[BufferPointer],DI	; Save that address
		Cld				; String direction forward

GetCharLoop:	Mov	AH,02h			; Set Cursor at DX
		Int	10h			;   through BIOS

		Mov	AH,08h			; Read Character & Attribute
		Int	10h			;   through BIOS

		Stosb				; Save the character

		Inc	CX			; Increment the counter
		Inc	DL			; Increment the cursor column
		Cmp	DL,[MaxCharCol]		; See if at end of line yet
		Jbe	GetCharLoop		; If not, continue

		Dec	DI			; Points to end of string
		Mov	AL,' '			; Character to search through
		Std				; Searching backwards
		Repz	Scasb			; Search for first non-blank
		Cld				; Forward direction again
		Jz	SetBufferCount		; If all blanks, skip down

		Inc	CL			; Number of non-blanks
		Inc	DI			; At last character
SetBufferCount:	Inc	DI			; After last character
		Mov	[BufferCounter],CL	; Save the character count

		Ret				; Return from routine

;	Shift Line One Space Right (For Insert)
;	---------------------------------------

ShiftRight:	Push	DX			; Save original cursor
		Mov	DI,AX			; Character to insert

ShiftRightLoop:	Call	ReadAndWrite		; Read character and write

		Inc	DL			; Kick up cursor column 
		Cmp	DL,[MaxCharCol]		; Check if it's rightmost
		Jbe	ShiftRightLoop		; If not, keep going

		Pop	DX			; Get back original cursor
		Ret				; And return from routine

;	Shift Line One Space Left (For Delete)
;	--------------------------------------

ShiftLeft:	Mov	DI,0020h		; Blank at end
		Mov	BL,DL			; Save cursor column
		Mov	DL,[MaxCharCol]		; Set cursor to end of line
		
ShiftLeftLoop:	Call	ReadAndWrite		; Read character and write

		Dec	DL			; Kick down cursor column
		Cmp	DL,BL			; See if at original yet
		Jge	ShiftLeftLoop		; If still higher, keep going 

		Inc	DL			; Put cursor back to original
		Ret				; And return from routine

;	Read and Write Character for Line Shifts
;	----------------------------------------

ReadAndWrite:	Mov	AH,2			; Set Cursor from DX
		Int	10h			;   through BIOS

		Mov	AH,08h			; Read Character and Attribute
		Int	10h			;   through BIOS

		Xchg	AX,DI			; Switch with previous char

		Mov	CX,1			; One character to write
		Mov	AH,0Ah			; Write character only
		Int	10h			;   through BIOS

		Ret				; Return from Routine


KeyboardBuffer  db  128 dup(0) 

OldInterrupt21	dd	?		; Original Interrupt 21 vector
OldInterrupt16	dd	?		; Original Interrupt 16 vector
DoingBuffKey	db	0		; Flag for doing Function Call 0Ah
BufferPointer	dw	KeyboardBuffer	; Pointer to Keyboard Buffer
BufferCounter	db	0		; Number of characters in buffer
MaxCharCol	db	?		; Maximum Character Column on screen
OriginalCursor	dw	?		; Place to save cursor on full-screen
InsertOn	db	0		; Insert mode flag

KeyRoutine	dw	Home,Up,PgUp,Dummy,Left,Dummy,Right
                dw      Dummy,EndLine,Down,PgDn,Insert,Delete

dosedit         endp

;	New Interrupt 21 (DOS Function Calls)
;	-------------------------------------

NewInterrupt21	Proc	Far

		Mov	CS:[DoingBuffKey],0	; Turn flag off initially

		Cmp	AH,0Ah			; Check if doing buffered input
		Jz	BufferedInput

		Jmp	CS:[OldInterrupt21]	; If not, do regular interrupt

BufferedInput:	Mov	CS:[DoingBuffKey],-1	; If so, turn on flag

		PushF				; Simulate regular interrupt
		Call	CS:[OldInterrupt21]

		Mov	CS:[DoingBuffKey],0	; Turn off flag
		Mov	CS:[BufferCounter],0	; Re-set character counter

		IRet				; Return to user program

NewInterrupt21	EndP


;	New Interrupt 16 (BIOS Keyboard Routine)
;	----------------------------------------

NewInterrupt16	Proc	Far

		Sti				; Re-enable interrupts
		Cmp	CS:[DoingBuffKey],0	; Check if doing call 0Ah
		Jz	DoNotIntercept		; If not, do old interrupt

		Cmp	CS:[BufferCounter],0	; Check if chars in buffer
		Jnz	Substitute		; If so, get them out

		Cmp	AH,0			; See if doing a get key
		Jz	CheckTheKey		; If so, get the key

DoNotIntercept:	Jmp	CS:[OldInterrupt16]	; Otherwise, do old interrupt

CheckTheKey:	PushF				; Save flags
		Call	CS:[OldInterrupt16]	; Do regular interrupt

		Cmp	AX,4800h		; Check if up cursor
		Jnz	NotTriggerKey		; If not, don't bother 

		Call	FullScreen		; Move around the screen
 
		Cmp	CS:[BufferCounter],0	; Any chars to deliver?
		Jz	CheckTheKey		; If not, get another key

ReturnBuffer:	Call	GetBufferChar		; Otherwise, pull one out

		Inc	CS:[BufferPointer]	; Kick up the pointer
		Dec	CS:[BufferCounter]	; And knock down the counter

NotTriggerKey:	IRet				; And go back to calling prog

;	Substitute Key from Buffer
;	--------------------------

Substitute:	Cmp	AH,2			; See if shift status check
		Jae	DoNotIntercept		; If so, can't be bothered

		Cmp	AH,0			; See if get a key
		Jz	ReturnBuffer		; If so, get the key above

		Call	GetBufferChar		; Otherwise get a key
		Cmp	CS:[BufferCounter],0	; And clear zero flag

		Ret	2			; Return with existing flags

NewInterrupt16	EndP


code            ends

ProgramEnd      EQU $-01h

                end     Entry

