; Reverse.asm, a sample program for ZD86
;
; This program takes the command line, reverses the characters, and then
; displays the reversed line on the standard output.
;
; To assemble and create a .Z86 file for reverse:
;
; With A86
; -----------------------
; A86 -S reverse.asm
; Sym-Z86 reverse
; -----------------------
; With TASM
; -----------------------
; TASM /l reverse
; TLINK /t reverse
; Lst-Z86 reverse
; -----------------------
; With MASM
; -----------------------
; MASM reverse,,reverse.lst;
; LINK reverse;
; EXE2BIN reverse.exe reverse.com
; Lst-Z86 reverse

Code_seg  SEGMENT

StdOut              EQU       1

Backspace           EQU       8
LF                  EQU       10
CR                  EQU       13
EOF                 EQU       26

          ORG       80h

          Command_line        DB        ?         ; Length byte of command line
          Line                DB        ?         ; Start of command line

          ORG       100h

          ASSUME    CS:Code_seg,DS:Code_seg,ES:Code_seg,SS:Code_seg
Main:
          JMP       Past_data

          ; If someone types "type reverse.com" from DOS
          ; the following will display a useful message rather than garbage.

                              DB        3 DUP (Backspace)
          Help_msg            DB        "Usage: Reverse (text to reverse)"
          End_help_msg        DB        EOF


Past_data:

;         Here is the code.  First, there is a check if any characters
;         were typed on the command line.  If not, then a help message is
;         printed.  Otherwise, the command line is printed reversed.
;
;         Note: Purposefully, this is not streamlined code.  It is kept
;         fairly simple, to make it easy to understand as quickly as possible.

          MOV       CL,byte ptr [Command_line]
          XOR       CH,CH
          JCXZ      No_command_line

          MOV       SI,OFFSET Line
          MOV       DI,OFFSET Reverse_line
          REP       MOVSB                         ; copy text to own location

          MOV       DX,DI                         ; points to right after line
          CALL      Print_line_reversed           ; just line this proc wants

CRLF_and_quit:
          MOV       AH,6                          ; direct console output
          MOV       DL,CR                         ; print Carriage Return
          INT       21h
          MOV       DL,LF                         ; plus Line Feed
          INT       21h

Exit:
          INT       20h

No_command_line:
          MOV       End_help_msg,"$"              ; DOS print string ends w/"$"
          MOV       DX,OFFSET Help_msg
          MOV       AH,9
          INT       21h                           ; print string at DS:DX
          JMP       CRLF_and_quit
;------------------------------------------------------------------------------
Print_line_reversed:
;Pre : DX -> first char AFTER line, Reverse_line -> first char in line
;Post: AX, BX, CX, DX unchanged

          PUSH      AX
          PUSH      BX
          PUSH      CX
          PUSH      DX

          MOV       DI,DX
          DEC       DI                            ; start at last char
          MOV       SI,OFFSET Reverse_line        ; and first char
          SUB       DX,SI                         ; DX now has length
          MOV       CX,DX                         ; since reversing requires
          SHR       CX,1                          ; going 1/2 way from end and

Do_reverse_line:
          LODSB                                   ; AL <- DS:[SI] INC SI
          MOV       AH,byte ptr [DI]
          MOV       byte ptr [SI-1],AH
          MOV       byte ptr [DI],AL
          DEC       DI
          LOOP      Do_reverse_line

Print_line:
          MOV       AH,40h                        ; Write to file/device
          MOV       BX,StdOut                     ; DX still has length of line
          MOV       CX,DX                         ; which CX needs
          MOV       DX,OFFSET Reverse_line
          INT       21h

Quit_reversed:

          POP       DX
          POP       CX
          POP       BX
          POP       AX

          RET
;------------------------------------------------------------------------------

Reverse_line:                           ; use the area after the .COM file

Code_seg  ENDS

          END       Main
