0

The problem in my program is when I try to take a character from a buffer which contains a string of characters, assign one character to AL register and call a procedure, which converts the character in AL to HEX, I get an infinite loop. Here is my code:

.model small
.stack 100H

.data

about           db 'example.exe [/?] [sourceFile2]]',13,10,13,10,9,'/? - help',13,10,'$'
err_s           db 'Unable to open source file',13,10,'$'
str_term        db '$'
sourceF         db 12 dup (0)
sourceFHandle   dw ?
buffer          db 500 dup (?)

.code

START:
    mov ax, @data
    mov es, ax                  ; es so we can use stosb function: Store AL at address ES:(E)DI

    mov si, 81h

    call    skip_spaces

    mov al, byte ptr ds:[si]    ; read first symbol of program parameter
    cmp al, 13                  ; if there's no parameters
    jne _1
    jmp help                    ; then jump to help
_1:

    ;; do we need to print out help
    mov ax, word ptr ds:[si]
    cmp ax, 3F2Fh               ; if input is "/?" - 3F = '?'; 2F = '/'
    jne _2
    jmp help                    ; if "/?" is found, print out help

_2:

    ;; source file name
    lea di, sourceF
    call    read_filename       ; move from parameter to line

    push    ds
    push    si

    mov ax, @data
    mov ds, ax

    jmp startConverting

readSourceFile:
    pop si
    pop ds

    ;; source file name
    lea di, sourceF
    call    read_filename           ; move from parameter to line

    push    ds
    push    si

    mov ax, @data
    mov ds, ax

    cmp byte ptr ds:[sourceF], '$'  ; if there was nothing to read
    jne startConverting
    jmp closeF

startConverting:
    ;; open
    cmp byte ptr ds:[sourceF], '$'  ; if there was nothing to read
    jne source_from_file

    mov sourceFHandle, 0
    jmp read

source_from_file:
    mov dx, offset sourceF          ; file name
    mov ah, 3dh                     ; open file command
    mov al, 0                       ; 0 - reading, 1-writing
    int 21h                         ; INT 21h / AH= 3Dh - open existing file
    jc  err_source                  ; CF set on error AX = error code.
    mov sourceFHandle, ax           ; save filehandle

read:
    mov bx, sourceFHandle
    mov dx, offset buffer           ; address of buffer in dx
    mov cx, 500                     ; how many bytes to read
    mov ah, 3fh                     ; function 3Fh - read from file
    int 21h

    mov cx, ax                      ; bytes actually read
    cmp ax, 0                       ; if there was nothing to read
    jne _6                          ; not the end of file

    mov bx, sourceFHandle           ; end of the file being read
    mov ah, 3eh                     ; close the file
    int 21h
    jmp readSourceFile              ; open another file to read if it was specified in the parameters
_6:
    mov si, offset buffer           ; read from buffer

    cmp sourceFHandle, 0
    jne _7
    cmp byte ptr ds:[si], 13
    je  closeF
_7:
    push    cx                      ; save big loop CX

sort_out:
    lodsb                           ; Load byte at address DS:(E)SI into AL
    push    cx                      ; place cx
    mov ah, 40h                     ; INT 21h / AH= 40h - write to file
    int 21h
    pop cx
    loop    sort_out

    pop cx

    loop    read

help:
    mov ax, @data
    mov ds, ax

    mov dx, offset about         
    mov ah, 09h
    int 21h

    jmp _end

closeF:
    ;; close the destination file
    mov ah, 3eh                     ; close
    int 21h

result:
    MOV si, offset buffer           ; source index = buffer coordinates
    INC si                          ; add 1 to si
    MOV bh, [si]                    ; let bh know how many symbols in total
    INC si                          ; go to the symbol itself

    mov bl, 0                       ; initialize bl counter to 0

    jmp char

    ; print out the text in buffer
    mov dx, offset buffer
    mov ah, 09h
    int 21h

_end:
    ; add a string terminator to avoid static output
    db '$'
    mov ax, @data

    mov ax, 4c00h
    int 21h  

char:
    LODSB                               ; take a character from es:si and add it to al

    ; increment bl
    INC bl

    MOV dl, al                          ; add a symbol from al to dl
    mov ah,2
    int 21h

    ; try to convert the current symbol in al to HEX and print it out

    ; =======INFINITE LOOP PROBLEM HERE========
    call char_to_hex

    DEC bh                              ; subtract 1 from total amount of symbols
    JZ _end                             ; if bh = 0, end program
    JMP char                            ; if not, jump to other symbol

err_source:
    mov ax, @data
    mov ds, ax

    mov dx, offset err_s        
    mov ah, 09h
    int 21h

    mov dx, offset sourceF
    int 21h

    mov ax, 4c01h
    int 21h 

;; procedures

skip_spaces PROC near

skip_spaces_loop:
    cmp byte ptr ds:[si], ' '
    jne skip_spaces_end
    inc si
    jmp skip_spaces_loop
skip_spaces_end:
    ret

skip_spaces ENDP

read_filename PROC near

    push    ax
    call    skip_spaces
read_filename_start:
    cmp byte ptr ds:[si], 13        ; if there is no parameters
    je  read_filename_end           ; if yes, its the end of the filename
    cmp byte ptr ds:[si], ' '       ; if space
    jne read_filename_next          ; then skip it and jump to the next parameter
read_filename_end:
    mov al, '$'                     ; add '$' to the end
    stosb                           ; Store AL at address ES:(E)DI, di = di + 1
    pop ax
    ret

read_filename_next:
    lodsb                           ; loads other symbol
    stosb                           ; Store AL at address ES:(E)DI, di = di + 1
    jmp read_filename_start

read_filename ENDP

; Char to Hex converting
char_to_hex PROC                   ; Accept a character, print it's ascii value in hex.

        MOV DX, OFFSET AskChar      ; Display prompt
        MOV AH, 09H
        INT 21H

        MOV AH, 07H                 ; Get keyboard input w/ no echo (AL)
        INT 21H

        MOV CL, AL                  ; Copy user input (AL) to CL
        MOV AX, 0                   ; Clear AX (get rid of HO bits)
        MOV AL, CL                  ; Copy user input back into AL

        MOV BX, 16                  ; Set up the divisor (base 16)
        MOV CX, 0                   ; Initialize the counter
        MOV DX, 0                   ; Clear DX

        Div2:                         
                                    ; Dividend (what's being divided) in DX/AX pair, Quotient in AX, Remainder in DX.
            DIV BX                  ; Divide (will be word sized).
            PUSH DX                 ; Save DX (the remainder) to stack.

            ADD CX, 1               ; Add one to counter
            MOV DX, 0               ; Clear Remainder (DX)
            CMP AX, 0               ; Compare Quotient (AX) to zero
            JNE Div2              ; If AX not 0, go to "Div2:"

        getHex2:
            MOV DX, 0               ; Clear DX.
            POP DX                  ; Put top of stack into DX.
            ADD DL, 30h             ; Conv to character.

            CMP DL, 39h
            JG MoreHex2

        HexRet2:        

            MOV AH, 02h             ; 02h to display AH (DL)
            INT 21H                 ; Send to DOS

            LOOP getHex2            ; If more to do, getHex2 again
                                    ; LOOP subtracts 1 from CX. If non-zero, loop.
            JMP Skip2
        MoreHex2:
            ADD DL, 7h
            JMP HexRet2             ; Return to where it left off before adding 7h.
        Skip2:
            RET
    char_to_hex ENDP

end START

My assigment is to get an output like this:

00000000 4d 61 6e 6f 20 62 61 74 61 69 20 62 75 76 6f 20 ¦Mano batai buvo ¦
00000010 64 75 2c 0a 56 69 65 6e 61 73 20 64 69 6e 67 6f ¦du,.Vienas dingo ¦
00000020 20 2d 20 6e 65 72 61 6e 64 75 2e 0a 41 f0 20 73 ¦ - nerandu..Aš s ¦
00000030 75 20 76 69 65 6e 75 20 62 61 74 75 6b 75 0a 4e ¦u vienu batuku.N¦
00000040 69 65 6b 75 72 20 65 69 74 69 20 6e 65 67 61 6c ¦iekur eiti negal ¦
00000050 69 75 2e 0a ¦iu..¦
00000054

Even though my program needs more work to get such a result, I at least would like to get the converting chars to hex part right.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
user2592200
  • 9
  • 1
  • 2
  • Where exactly do you get the infinite loop? – Michael Dec 16 '13 at 10:12
  • 2
    What are people doing still writing 16-bit code, particularly with TASM? :P It hasn't been relevant for a decade or more. – cHao Dec 16 '13 at 10:16
  • @cHao: It appears to be used for educational purposes at some schools (don't ask me why). Heck, I once took a course where we had some M68000 assembly lab assignments, and this wasn't that many years ago. – Michael Dec 16 '13 at 10:27
  • 1
    @Michael, M68K is at least cool. :) – Devolus Dec 16 '13 at 10:47
  • After looking at your code, I would recommend to rewrite the way how you are converting a value in AL to a HEX string. Creating a hex output doesn't need to use `div` which makes it much more complicated IMO. Using shift operator would be more appropriate in this case and makes the code much more readable. – Devolus Dec 16 '13 at 12:32

2 Answers2

0

Did you take char_to_hex from another exercise and paste it into this program? That would explain this part:

; Char to Hex converting
char_to_hex PROC                   ; Accept a character, print it's ascii value in hex.

    MOV DX, OFFSET AskChar      ; Display prompt
    MOV AH, 09H
    INT 21H

    MOV AH, 07H                 ; Get keyboard input w/ no echo (AL)
    INT 21H

I can't find the AskChar symbol anywhere, so who knows what is being printed - but the last two lines wait (patiently) on the keyboard to give it a character. Could that be the "infinite loop"?

John Burger
  • 3,662
  • 1
  • 13
  • 23
  • It's pretty safe to assume the the OP of this question has long since vanished. Their [user page](http://stackoverflow.com/users/2592200/user2592200) says "Last seen Feb 4 '14 at 20:11". It's probably best to leave old bad questions like this alone, unless there's something to add that might really be helpful for future readers. If you're going through the back archives of unanswered questions for a tag you like, it's tempting to answer everything, but when the OP has disappeared, it will never be "accepted" to get the question out of the unanswered list. – Peter Cordes Jun 14 '16 at 11:08
  • That's certainly part of why I do it (to get it out of the unanswered list), but it's also to at least have AN answer for future readers... What I really don't understand though is the sheer quantity of answers-in-comments. They show up (of course) as "0 answers" - I hate that. – John Burger Jun 14 '16 at 11:13
  • Yup, unanswered questions bug me, too. Some people have a bad habit of posting comments instead of minimal but sufficient answers. I often start to write a comment, then realize I can just post it as an answer. Then I usually spend twice as long expanding on what I was going to say... – Peter Cordes Jun 14 '16 at 11:14
  • ...and getting a better end result. Yup! – John Burger Jun 14 '16 at 11:15
  • Yeah, but I understand why people with limited time to answer questions might limit themselves to comments. Anyway, when I was first starting to answer a lot of asm questions on SO about a year ago, I looked through the back archives of unanswered questions and answered a few of them, but I soon realized that there was no way to even make much of a dent in that pile. I did find a couple old question that were worth answering, though, like [this one](http://stackoverflow.com/questions/26046634/micro-fusion-and-addressing-modes) where there was actually a way to test it by experiment. – Peter Cordes Jun 14 '16 at 11:19
0

char_to_hex clobbers bx, and you call it inside a loop that uses bh as the loop counter.

You could have found this yourself this if you'd run your code in a debugger so you could look at register values while it was running.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847