Read and output a string TASM Assembly - string

What I want to do is to read a string from the keyboard and output that same string. However, using the code below in TASM, I get only gibberish:
UPDATED
DATA SEGMENT PARA PUBLIC 'DATA'
MSG DB 10,0,80 dup(?) ; variable to hold string
DATA ENDS
CODE SEGMENT PARA PUBLIC 'CODE'
START PROC FAR
ASSUME CS:CODE, DS:DATA
PUSH DS
XOR AX, AX
PUSH AX
MOV AX,DATA
MOV DS, AX
MOV AH, 0AH
MOV DX, OFFSET MSG
INT 21H ; read string
MOV AH, 09H
INT 21H ;output string
RET
START ENDP
CODE ENDS
END START
Now I get the chance to enter input but the result is gibberish. Where am I wrong?

Thanks to all comments, I managed to write the program which reads and displays a string:
DATA SEGMENT PARA PUBLIC 'DATA'
MAXLEN DB 20
LEN DB 0
MSG DB 20 DUP(?)
DATA ENDS
CODE SEGMENT PARA PUBLIC 'CODE'
START PROC FAR
ASSUME CS:CODE, DS:DATA
PUSH DS
XOR AX, AX
PUSH AX
MOV AX,DATA
MOV DS, AX
MOV AH, 0AH
MOV DX, OFFSET MAXLEN
INT 21H
MOV DL, 10
MOV AH, 02H
INT 21H ;NEW LINE FEED
MOV AL, LEN
CBW ; EXTEND AL TO AX
MOV SI, AX
MOV MSG+SI, '$'
MOV AH, 09H
MOV DX, OFFSET MSG
INT 21H
RET
START ENDP
CODE ENDS
END START

Related

TASM, Assembly, can't change string, offset

I try to change the string to the other one, but the output I get is broken.
How do I change string to the other one so it doesn't do this:
Intended output:
in rect
under line
out circ
Also, I do not know the purpose of "offset" in the code so it also can be the problem.
Also, I get some warnings when trying to assemble it and I don't know they mean:
The code:
.model small
.data
X db 0
Y db 0
var0 db 0
rect db "out rect",13,10,"$"
rect_plus db "in rect",13,10,"$"
line db "under line",13,10,"$"
line_plus db "above line",13,10,"$"
circ db "out circ",13,10,"$"
circ_plus db "in circ",13,10,"$"
.code
main:
mov ax, #data
mov ds, ax
jmp input
input:
...
jmp rect_check1
rect_check1:
...
jb rect_check2
jmp rect_print
rect_check2:
...
jb rect_change
jmp rect_print
rect_change:
lea bx, rect; <============== SOMETHING WRONG HERE
mov [bx], offset rect_plus; <=========================== OR HERE
jmp rect_print
rect_print:
mov dx, offset rect; <=========================== OR HERE
mov ah, 09h
int 21h
jmp line_check
line_check:
...
jb line_change
jmp line_print
line_change:
lea bx, line; <=========================== OR HERE
mov [bx], offset line_plus; <=========================== OR HERE
jmp line_print
line_print:
mov dx, offset line; <=========================== OR HERE
mov ah, 09h
int 21h
jmp circ_check
circ_check:
...
jb circ_change
jmp circ_print
circ_change:
lea bx, circ; <=========================== OR HERE
mov [bx], offset circ_plus; <=========================== OR HERE
jmp circ_print
circ_print:
mov dx, offset circ; <=========================== OR HERE
mov ah, 09h
int 21h
jmp quit
quit:
mov ax, 4c00h
int 21h
end main
rect_change:
lea bx, rect; <============== SOMETHING WRONG HERE
mov [bx], offset rect_plus; <=========================== OR HERE
jmp rect_print
Your logic is wrong here.
lea bx, rect loads the offset of string "out rect",13,10,"$" to register bx. The offset in bx is then 0003h. The next instruction tries to overwrite one or two bytes of memory at ds:bx (the letters "o" or "ou") with offset of another string "in rect",13,10,"$" (with binary number 000Eh) which makes no sense. As you didn't specify how many bytes you're going to overwrite, TASM gives you the Warning.
Restructuralize your spaghetti code and make your subprocedures callable (ending with ret), for instance
line_print PROC ; Display the $-terminated string addressed with DS:DX.
mov ah, 09h
int 21h
ret
line_print ENDP
Then, whenever you want to display a string, load its offset to dx and call the subprocedure:
mov dx,offset rect
call line_print
; check the rectangle
mov dx,offset rect_plus
call line_print

Need help combining two strings TASM

I need help in combining two programs I have and I can't seem to get it working for me. Don't get the desired output.
So here's my problem statement:
Combine Two separate strings in a third string and display it, Where the first String is as it is and the second string is reversed.
Example:
Input:
String 1: 'Hello'
String 2: '.dlroW '
Output:
'Hello World.'
end of Example.
Now there are two ways we can go about this.
First: Use string functions.(Preferred)
Now I am fairly new to learning Assembly Language so I would like to do it using string functions so I can learn something New.
Second: Without using string functions.
Another Approach is if someone can help combining two programs, One for the concatenation of the string and the other for reversal, Note that I have written the two individual programs and they run well without any hiccups, I just can't seem to do it together. How I am going about with this is before concatenating the string I am trying to reverse it, then proceeding with the addition of the second string. But I can't seem to get it working. I've tried to the best of my knowledge.
//Concatenation Code
.model tiny
.data
msg1 db 10,13,"Enter the string 1: $"
cat db 30 DUP('$')
msg2 db 10,13,"Enter the string 2: $"
msg3 db 10,13,"Concatenated string is: $"
.code
mov ax,#data
mov ds,ax
lea dx,msg1
mov ah,09h
int 21h
lea si,cat
up: mov ah,01h
int 21h
mov [si],al
inc si
cmp al,0dh
jnz up
lea dx,msg2
mov ah,09h
int 21h
dec si
up1: mov ah,01h
int 21h
mov [si],al
inc si
cmp al,0dh
jnz up1
lea dx,msg3
mov ah,09h
int 21h
lea dx,cat
mov ah,09h
int 21h
mov ah,4ch
int 21h
end`
Here's Part 2
//Reversal Code
.model tiny
.data
msg1 db 10,13,"enter the string: $"
string db 40 DUP('$')
rev db 40 DUP('$')
msg2 db 10,13,"reverse string is: $"
.code
mov ax,#data
mov ds,ax
lea dx,msg1
mov ah,09h
int 21h
mov ah,0ah
lea dx,string
int 21h
lea si,string
lea di,rev
mov cl,[si+1]
mov ch,00h
add di,cx
inc si
inc si
up: mov al,[si]
mov [di],al
inc si
dec di
loop up
inc di
mov ah,09h
lea dx,msg2
int 21h
mov ah,09h
lea dx,[di]
int 21h
mov ah,4ch
int 21h
end
And Here is the code I came Up with by combining those two.
//That's the code I tried Combining
.model tiny
.data
.model tiny
.data
msg1 db 10,13,"Enter string1: $"
cat db 30 DUP('$')
msg2 db 10,13,"Enter string2: $"
msg3 db 10,13,"Concatenated string is: $"
.code
mov ax, #data
mov ds,ax
lea dx,msg1
mov ah,09h
int 21h
lea si,cat
up: mov ah,01h
int 21h
mov [si],al
inc si
cmp al,0dh
jnz up
lea dx, msg2
mov ah,09h
int 21h
dec si
up2:mov al,[si]
mov [di],al
inc si
dec di
loop up2
inc di
up1:mov ah,01h
int 21h
mov [si],al
inc si
cmp al,0dh
jnz up1
lea dx,msg3
mov ah,09h
int 21h
lea dx,cat
mov ah,09h
int 21h
mov ah,4ch
int 21h
end
My Output
As you can see clearly I have failed at doing either task correctly. So can someone tell me where I am going wrong? Or teach me how to do this using the string Functions?
The up2 loop that tries to do string reversal comes too soon!. You've placed it where the 2nd string (the one that needs reversal) isn't even inputted yet.
If you would have written comments in your program, then you would probably have noticed this yourself.
This up2 loop uses the LOOP instruction that depends on the CX register but your program does not assign any suitable value to CX.
And also your working reversal program is using 2 buffers. Why then do you expect the combo to work from a single buffer?
Define the cat buffer so it can hold both strings.
Define the str buffer so it can hold the second string.
lea dx, msg1
mov ah, 09h ; DOS.PrintString
int 21h
lea di, cat
up: ; Input f i r s t string
mov ah, 01h ; DOS.GetCharacter
int 21h ; -> AL
mov [di], al
inc di
cmp al, 13
jne up
dec di ; Throw out the 13
; This marks the start of the reversed string, VERY IMPORTANT
; So don't change DI while inputting the 2nd string
lea dx, msg2
mov ah, 09h ; DOS.PrintString
int 21h
lea si, str
mov dx, si
up1: ; Input s e c o n d string
mov ah, 01h ; DOS.GetCharacter
int 21h ; -> AL
mov [si], al
inc si
cmp al, 13
jne up1
dec si ; Throw out the 13
cmp si, dx
je done ; Second string was empty. CAN HAPPEN!
up2: ; Reversed copying of s e c o n d string
dec si
mov al, [si]
mov [di], al
inc di
cmp si, dx
ja up2
done:
mov ax, 0A0Dh ; Add a proper carriage return and linefeed to the result
mov [di], ax
mov al, '$' ; Terminate the result with a dollar sign
mov [di+2], al
lea dx, msg3
mov ah, 09h ; DOS.PrintString
int 21h
lea dx, cat
mov ah, 09h ; DOS.PrintString
int 21h
First: Use string functions.(Preferred)
Both in the up loop and in the up2 loop, do you find next pair of instructions:
mov [di], al
inc di
Provided
the direction flag DF is clear so that DI can increment
the ES segment register points to #data
you can replace these 2 instructions by a single STOSB instruction.
This is what needs to go on top of your program:
.code
mov ax, #data
mov ds, ax
mov es, ax
cld
If we allowed ourselves to write a silly sequence of multiple std (set direction flag) and cld (clear direction flag) instructions, we could also replace mov al, [si] with lodsb. Care must be taken to keep a valid SI pointer (*).
dec si ; (*)
up2: ; Reversed copying of s e c o n d string
std
lodsb ; Due to STD, SI will decrement
cld
stosb ; Due to CLD, DI will increment
cmp si, dx
jae up2 ; (*)
done:
mov ax, 0A0Dh ; Add a proper carriage return and linefeed to the result
stosw
mov al, '$' ; Terminate the result with a dollar sign
stosb
In code that sets the direction flag (using std) it is best to end with a cld instruction so the direction flag is in the state we most expect!

Getting string input and displaying input with DOS interrupts MASM

In MASM, I created a buffer variable to hold the user string input from keyboard. I am stuck on how to hold the string input into that buffer variable. I don't have any libraries linked like the irvine ones and want to do this with DOS interrupts. So far I have something along the lines of
.model small
.stack 100h
.data
buff db 25 dup(0), 10, 13
lbuff EQU ($ - buff) ; bytes in a string
.code
main:
mov ax, #data
mov ds, ax
mov ah, 0Ah ; doesn't work
mov buff, ah ; doesn't seem right
int 21h
mov ax, 4000h ; display to screen
mov bx, 1
mov cx, lbuff
mov dx, OFFSET buff
int 21h
mov ah, 4ch
int 21h
end main
I assume using 0Ah is correct as it is for reading array of input of buffered characters.
I made some changes to your code. First, the "buff" variable needs the three level format (max number of characters allowed, another byte for the number of characteres entered, and the buffer itself) because that's what service 0AH requires. To use service 0AH I added "offset buff" (as Wolfgang said). Here it is:
.model small
.stack 100h
.data
buff db 26 ;MAX NUMBER OF CHARACTERS ALLOWED (25).
db ? ;NUMBER OF CHARACTERS ENTERED BY USER.
db 26 dup(0) ;CHARACTERS ENTERED BY USER.
.code
main:
mov ax, #data
mov ds, ax
;CAPTURE STRING FROM KEYBOARD.
mov ah, 0Ah ;SERVICE TO CAPTURE STRING FROM KEYBOARD.
mov dx, offset buff
int 21h
;CHANGE CHR(13) BY '$'.
mov si, offset buff + 1 ;NUMBER OF CHARACTERS ENTERED.
mov cl, [ si ] ;MOVE LENGTH TO CL.
mov ch, 0 ;CLEAR CH TO USE CX.
inc cx ;TO REACH CHR(13).
add si, cx ;NOW SI POINTS TO CHR(13).
mov al, '$'
mov [ si ], al ;REPLACE CHR(13) BY '$'.
;DISPLAY STRING.
mov ah, 9 ;SERVICE TO DISPLAY STRING.
mov dx, offset buff + 2 ;MUST END WITH '$'.
int 21h
mov ah, 4ch
int 21h
end main
When 0AH captures the string from keyboard, it ends with ENTER (character 13), that's why, if you want to capture 25 characters, you must specify 26.
To know how many characters the user entered (length), access the second byte (offset buff + 1). The ENTER is not included, so, if user types 8 characters and ENTER, this second byte will contain the number 8, not 9.
The entered characters start at offset buff + 2, and they end when character 13 appears. We use this to add the length to buff+2 + 1 to replace chr(13) by '$'. Now we can display the string.
This is my code,maybe can help you.
;Input String Copy output
dataarea segment
BUFFER db 81
db ?
STRING DB 81 DUP(?)
STR1 DB 10,13,'$'
dataarea ends
extra segment
MESS1 DB 'After Copy',10,13,'$'
MESS2 DB 81 DUP(?)
extra ends
code segment
main proc far
assume cs:code,ds:dataarea,es:extra
start:
push ds
sub ax,ax
push ax
mov ax,dataarea
mov ds,ax
mov ax,extra
mov es,ax
lea dx,BUFFER
mov ah,0ah
int 21h
lea si,STRING
lea di,MESS2
mov ch,0
mov cl,BUFFER+1
cld
rep movsb
mov al,'$'
mov es:[di],al
lea dx,STR1 ;to next line
mov ah,09h
int 21h
push es
pop ds
lea dx,MESS1 ;output:after copy
mov ah,09h
int 21h
lea dx,MESS2
mov ah,09h
int 21h
ret
main endp
code ends
end start
And the result is:
c:\demo.exe
Hello World!
After Copy
Hello World!
You may follow this code :
; Problem : input array from user
.MODEL SMALL
.STACK
.DATA
ARR DB 10 DUB (?)
.CODE
MAIN PROC
MOV AX, #DATA
MOV DS, AX
XOR BX, BX
MOV CX, 5
FOR:
MOV AH, 1
INT 21H
MOV ARR[BX], AL
INC BX
LOOP FOR
XOR BX, BX
MOV CX, 5
PRINT:
MOV AX, ARR[BX] ;point to the current index
MOV AH, 2 ;output
MOV DL, AX
INT 21H
INC BX ;move pointer to the next element
LOOP PRINT ;loop until done
MAIN ENDP
;try this one, it takes a 10 character string input from user and displays it after in this manner, "Hello *10character string input"
.MODEL TINY
.CODE
.286
ORG 100h
START:
MOV DX, OFFSET BUFFER
MOV AH, 0ah
INT 21h
JMP PRINT
BUFFER DB 10,?, 10 dup(' ')
PRINT:
MOV AH, 02
MOV DL, 0ah
INT 21h
MOV AH, 9
MOV DX, OFFSET M1
INT 21h
XOR BX, BX
MOV BL, BUFFER[1]
MOV BUFFER [BX+2], '$'
MOV DX, OFFSET BUFFER +2
MOV AH, 9
INT 21h
M1: db 'Hello $'
END START
END

Sorting strings in 8086 Assembly

I want to write a 8086 assembly program that takes 5 strings from the user as an input and then sorts these strings and prints the sorted result as an output. I actually do everything but I have a big problem with the sorting part. I know how to use a for example bubble sort to sort the items in an array that start from a specific address but here I have 5 different strings that are not in the same array. each string has its own address and its own characters. I try to compare last character of each string with each other and then if one is bigger that another one i swap the whole string and then I go on and do that for the whole characters of all string to the first.
For example if our input strings are:
eab
abe
cbd
cda
adb
I will first sort the last character of every string and I come up with this:
cda
eab
adb
cbd
abe
Then I will compare them by the middle character:
eab
cbd
abe
cda
adb
and at last with the first character and everything is sorted:
abe
adb
cbd
cda
eab
but it is actually what in my mind and I don't have any idea who to implement that for my job.
; multi-segment executable file template.
data segment
data1 db 64,?,64 dup(?)
data2 db 64,?,64 dup(?)
data3 db 64,?,64 dup(?)
data4 db 64,?,64 dup(?)
data5 db 64,?,64 dup(?)
change db 66 dup(?)
msg db 0ah,0dh,"You enter a wrong option",0ah,0dh,"try again",0ah,0dh,"$"
prompt db 0ah,0dh,"Choose an option:",0ah,0dh,"$"
prompt1 db ".a: Sort in ascending order",0ah,0dh,"$"
prompt2 db ".d: Sort in descending order",0ah,0dh,"$"
prompt3 db ".q: Quit",0ah,0ah,0dh,"$"
enter db 0ah,0ah,0dh,"Enter 5 strings:",0ah,0dh,"$"
pkey db 0ah,0dh,"press any key...$"
ends
stack segment
dw 128 dup(0)
ends
code segment
main proc far
; set segment registers:
mov ax, data
mov ds, ax
mov es, ax
again:
; printing the prompts for the user
lea dx, prompt
mov ah, 09h
int 21h
lea dx, prompt1
mov ah, 09h
int 21h
lea dx, prompt2
mov ah, 09h
int 21h
lea dx, prompt3
mov ah, 09h
int 21h
; getting a character from the user as an input
mov ah, 01h
int 21h
; determining which option the user selects
cmp al, 'a'
je ascending
cmp al, 'd'
je descending
cmp al, 'q'
je quit
; this is for the time that the user enters a wrong char
lea dx, msg
mov ah, 09h
int 21h
jmp again ; again calling the application to start
ascending:
call input
call AscendSort
jmp again ; again calling the application to start
descending:
call input
call DescendSort
jmp again ; again calling the application to start
quit:
lea dx, pkey
mov ah, 9
int 21h ; output string at ds:dx
; wait for any key....
mov ah, 1
int 21h
mov ax, 4c00h ; exit to operating system.
int 21h
main endp
;.................................................
; this subroutine gets input from user
input proc
lea dx, enter
mov ah, 09h
int 21h
call newline
mov ah, 0ah
lea dx, data1
int 21h
call newline
mov ah, 0ah
lea dx, data2
int 21h
call newline
mov ah, 0ah
lea dx, data3
int 21h
call newline
mov ah, 0ah
lea dx, data4
int 21h
call newline
mov ah, 0ah
lea dx, data2
int 21h
call newline
ret
input endp
;................................................
; sorting the strings in the ascending order
AscendSort proc
mov si, 65
lea dx, change
mov al, data1[si]
cmp al, data2[si]
ja l1
?????
ret
AscendSort endp
;................................................
; sorting the strings in the descending order
DescendSort proc
ret
DescendSort endp
;................................................
; newline
newline proc
mov ah, 02h
mov dl, 0ah
int 21h
mov dl, 0dh
int 21h
ret
newline endp
ends
end main ; set entry point and stop the assembler.
Any other algorithm for sorting these whole strings also will be appreciated.
I actually figure out the answer myself, I use string commands to compare the strings 2 by 2 with each other to see if they're bigger, smaller or equal. Something like the code below in the specific macro that takes two strings to check them and do the required operation like swapping the strings to make them sorted:
check macro a, b
local next, finish
cld
mov cx, 64 ; the size of our buffer that saves the string
mov si, a
mov di, b
repe cmpsb ; comparing two strings with each other
ja next
jmp finish
next:
; swaping our strings if needed
mov cx, 64
mov si, a
lea di, change
rep movsb
mov cx, 64
mov si, b
mov di, a
rep movsb
mov cx, 64
lea si, change
mov di, b
rep movsb
finish:
endm

search for string in file in ASSEMBLY

I need to write a program in ASSEMBLY to search for a string (input for keyboard) in all file of current folder.
What's interrupt can I use and what's algorithm of this program?
Hmm...here's some code I wrote (at least I think I wrote it -- it looks like code I'd have written, though it doesn't have any comments to confirm it) to list the files in a directory:
.model small, c
.stack
.data
file_spec db "*.*", 0
DTA db 128h dup(0)
buffer db 30 dup(0)
.code
main proc
mov ax, #Data
mov ds, ax
mov dx,offset DTA
mov ah,1Ah
int 21h ; set DTA location
mov dx,offset file_spec
xor cx, cx
mov ah,4Eh
int 21h
jc quit
print_name:
lea si, DTA + 30
next_char:
lodsb
int 29h
test al, al
jnz next_char
mov al, 13
int 29h
mov al, 10
int 29h
mov dx, offset file_spec
xor cx, cx
mov ah, 4fh
int 21h
jnc print_name
quit:
mov ax, 4c00h
int 21h
main endp
end main
Here's another that opens and displays a file:
data segment para public 'DATA'
line db 80 dup(?)
file db "test.txt"
handle dw ?
data ends
code segment para public 'CODE'
assume ds:data
assume cs:code
main proc
mov ax,data
mov ds,ax
; okay. First, open the file
mov dx,offset file
mov ax,3d00h
int 21h
mov handle,ax
read_loop:
mov dx,offset line
mov bx,handle
mov cx, 80 ; the size of our buffer.
mov ah,3fh
int 21h
jc done
test ax,ax
jz done
mov bx,1
mov cx,ax
mov dx,offset line
mov ah,40h
int 21h
jmp read_loop
done:
mov ax,4c00h
int 21h
main endp
code ends
end main
Searching for the data in the file would be basically a matter of writing a strstr in assembly language. You'd probably want to start with a quick scan using rep cmpsb and then do a byte-by-byte comparison when you find a candidate match. If that fails, you increment the position and try again.

Resources