Length of input string in assembly language - string

I want to do two things:
1) Take a string from user
2) Find the length of that string
I tried the following code:
.model small
.stack 100h
.data
MAXLEN DB 100
ACT_LEN DB 0 ;Actual length of the string
ACT_DATA DB 100 DUP('$') ;String will be stored in ACT_DATA
MSG1 DB 10,13,'ENTER STRING : $'
.CODE
START:
MOV AX,#data
MOV DS,AX
;Normal printing
LEA DX,MSG1
MOV AH,09H
INT 21H
;Cant understand code from here!
LEA DX,ACT_DATA
MOV AH,0AH
MOV DX,OFFSET MAXLEN
INT 21H
LEA SI,ACT_DATA
MOV CL,ACT_LEN
;AND THEH SOME OPERATIONS
END START
But I am confused how the length is stored in CL register, i.e. how the ACT_LEN value is incremented? And what actually does mov AH,0A has relation with length?

Int 21/AH=0Ah
Format of DOS input buffer:
Offset Size Description (Table 01344)
00h BYTE maximum characters buffer can hold (MAXLEN)
01h BYTE (call) number of chars from last input which may be recalled (ACT_LEN)
(ret) number of characters actually read, excluding CR
02h N BYTEs actual characters read, including the final carriage return (ACT_DATA)
The buffered input interrupt will fill in these values.
LEA DX,ACT_DATA
MOV AH,0AH
MOV DX,OFFSET MAXLEN
INT 21H
You do not need LEA DX,ACT_DATA
mov AH,0A is the number of the interrupt to call. Ralph Brown has a big list of interrupts with descriptions and what goes in/comes out.

Related

Intel 8086 assembly reversing order of string

So I'm programming code in Intel 8086 assembly where I want to input two strings(one string in one line) and a want to save them to the variables. Each string can contain up to 100 utf8 characters. In the output, I try to change the order of then (the first line is going to be the second string from the input) but I get an error that the service 21h is trying to read from an undefined byte. Can you explain to me what I Should change in my code?
cpu 8086
segment code
..start mov ax, data
mov ds, ax
mov bx,stack
mov ss,bx
mov sp,dno
input1 mov ah,0x0a
mov dx, load
int 21h
mov bl,[load+1]
mov [chars1+bx],byte '$'
input2 mov ah,0x0a
mov dx, load
int 21h
mov bl,[load+1]
mov [chars2+bx],byte '$'
output mov dx,chars2
mov ah,9
int 21h
mov dx,chars1
mov ah,9
int 21h
end hlt
segment data
load db 200, ?
chars1 db ?
resb 100
chars2 db ?
resb 100
segment stack
resb 100
dno: db ?
but I get an error that the service 21h is trying to read from an undefined byte. Can you explain to me what I Should change in my code?
You are not loading the address of the input structure that is required by the DOS.BufferedInput function 0Ah. Read all about it in How buffered input works.
Emu8086 follows MASM programming style where mov dx, load will set the DX register equal to the word stored at the address load. To actually receive the address itself, you'll need to write mov dx, offset load.
A further problem is that both input1 and input2 try to use the same load input structure but with different buffer memories. The buffer has to be part of the input structure for this DOS function; it always has to reside at offset 2 from the provided address (load in your case).
This is how you can solve it:
...
input1: mov ah, 0Ah
mov dx, OFFSET loadA
int 21h
mov bl, [loadA+1]
mov bh, 0
mov [charsA+bx], byte '$'
input2: mov ah, 0Ah
mov dx, OFFSET loadB
int 21h
mov bl, [loadB+1]
mov bh, 0
mov [charsB+bx], byte '$'
output: mov dx, OFFSET charsB
mov ah, 09h
int 21h
mov dx, OFFSET crlf
mov ah, 09h
int 21h
mov dx, OFFSET charsA
mov ah, 09h
int 21h
...
loadA db 101, 0
charsA db 101 dup (0)
loadB db 101, 0
charsB db 101 dup (0)
crlf db 13, 10, "$"
...
101 provides room for 100 characters and 1 terminating carriage return.
Don't trust too much registers that you didn't set yourself! Write an explicite mov bh, 0 before using the whole of BX.
Since you want these strings outputted on different lines, I've added code to move to the start of the following line. See the crlf.

8086 Write a program that takes one string from the input and inserts white space between every two letters

8086 Write a program that takes one string from the input and inserts white space between every two letters
using nasm and MSDOS
i have do following code but it is not working
start:
mov ax,data
mov ds, ax
mov es, ax
mov cx, size;cx will contain size,we need it to
; check if we have got 10 inputs from key board
lea dx, Enter_string;it will display a text on screen to enter text
mov ah, 9
int 21h
call get_string;input string from keyboard
mov ax, 4ch;terminating
int 21h
get_string:
mov si, 0; si will be used as index
mov bx, offset string
get_char:
mov ah, 1; get a char from keyboard
int 21h
mov [bx][si], al; saving input in string
inc si
cmp si,cx;if si=7 than, no need to take more input
jne get_char
ret
. You should prefer the simplicity of .COM programs while learning. They already start with all the segment registers pointing to the program.
. The DOS exit function expects the function number in AH.
. On NASM you don't use mov bx, offset string. Just write mov bx, string.
. It's easy to combine the tasks of inputting a string and interjecting space characters. See below code:
org 256 ;.COM programs have CS=DS=ES=SS
start:
mov cx, size ;cx will contain size,we need it to
; check if we have got 10 inputs from key board
mov dx, Enter_string ;it will display a text on screen to enter text
mov ah, 9
int 21h
call get_string ;input string from keyboard
mov ax, 4C00h ;terminating
int 21h
get_string:
push cx
mov si, 0 ; si will be used as index
get_char:
mov ah, 1 ; get a char from keyboard
int 21h
mov ah, " "
mov [string+si], ax ; saving input in string PLUS THE SPACE CHARACTER
add si, 2
dec cx ;if si=7 than, no need to take more input
jnz get_char
pop cx
ret
Remember that you don't actually need the last space character. Just overwrite it with the string terminator that you normally would add to this string!

Assembly Language: Completing the program to get the midstring

.model small
.stack
.data
msg1 db "Enter string max of 9 characters: $"
msg2 db 13,10, "Enter a number: $"
msg3 db 13,10, "Midstring: $"
strNine db "$"
num db 0,"$"
mid db "$"
varName label byte
maxL db 10
actL db 0
actCont db 10 dup("?")
.code
mov ax,#data
mov ds,ax
;-------------------- Input String ---------------------
mov ah,9
lea dx,msg1
int 21h
mov ah,0ah
int 21h
mov strNine,al
mov bh,strNine
;-------------------- Number ---------------------
mov ah,9
lea dx,msg2
int 21h
mov ah,1
int 21h
mov num,al
mov bl,num
;-------------------- Midstring ---------------------
mov ah,9
lea dx,msg3
int 21h
mov ah,4ch
int 21h
END
I need to find the midstring and I'm stuck since I'm new to Assembly Language.
Expected behaviour:
Enter max of 9 String: helloword
Enter a number: 3
Midstring: lloword
The leading space, the h and e shall be deleted because of the number input by the user.
The only part the I've gotten is to get the input from the user which is the string and number which i have saved in the BX memory which is used for indexing
I just need some tips/guides from you guys to finish the program.
mov ah,9
lea dx,msg1
int 21h
mov ah,0ah
int 21h
How can this input work at all? At the moment that you call the DOS input function your DX register is still set for the msg1 when it should be set to point to the varName input structure.
mov ah,0ah
int 21h
mov strNine,al
mov bh,strNine
What do you expect the AL register to hold at this point? This DOS function doesn't store a useful value there!

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

How to compare two strings in assembly?

I'm new in assembly. I want to compare two string using "cmps". I read some examples and I write this :
GETSTR MACRO STR
MOV AH,0AH
LEA DX,STR
INT 21H
ENDM
PRINTSTR MACRO STR
MOV AH,09H
LEA DX,STR
INT 21H
ENDM
EXTRA SEGMENT
DEST DB ?
EXTRA ENDS
DATA SEGMENT
SOURCE DB ?
STR1 DB 0AH,0DH,'ENTER STR : ' ,'$'
ENTER DB 10,13,'$'
SAME DB 0AH,0DH,'TWO STR ARE THE SAME ' ,'$'
NSAME DB 0AH,0DH,'TWO STR ARE NOT THE SAME ' ,'$'
USER DB 6,10 DUP('$')
USER1 DB 6,10 DUP('$')
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA,CS:CODE,ES:EXTRA
START:
MOV AX,DATA
MOV DS,AX
MOV AX,EXTRA
MOV ES,AX
PRINTSTR STR1
GETSTR USER1
PRINTSTR STR1
GETSTR USER
LEA BX,USER
MOV SI,BX
LEA BX,USER1
MOV DI,BX
CLD
MOV CX,5
REPE CMPSB
JCXZ MTCH
PRINTSTR NSAME
JMP ENDPR
MTCH:
PRINTSTR SAME
ENDPR:
MOV AH,4CH
INT 21H
CODE ENDS
END START
I have some question:
what is exactly the numbers 6,10 in the code below :
USER DB 6,10 DUP('$')
Is there any mistake with the Macros?
Is it necessary to declare EXTRA SEGMENT ?
For any similar strings input the output is : "they are not the same?" what is the reason?
The number 6 defines the number of characters plus 1 that you want DOS to input. The number 10 defines the length of the buffer that follows. Actually the number 7 would have been enough!
The macros seem fine.
You don't need the EXTRA segment. Moreover putting it into ES is wrong because both strings that you will be comparing are in the DATA segment.
Also both LEA instructions must fetch an address that is 2 higher. The first byte will still be the maximum number of bytes to read (6) and the second byte will be the number of bytes actually read [0,5]
The comparison you're making indifferably uses 5 characters. If you don't take into account the real number of characters as reported by DOS in the second byte it's no wonder results might not be satisfying.

Resources