[comp.binaries.ibm.pc.d] 8086 assembler query

djm@etive.ed.ac.uk (D Murphy) (05/30/89)

I'm writing an assembly language program for a PC and need to access
command line arguments as strings. On execution, DOS sets DS and ES to
the segment address of the Program Segment Prefix, and the area of memory
offset 81h to 100h from the PSP contains all the characters (except
pipes and redirection) entered after the command name. The code fragment
below was what I thought would do the job. Unfortunately it doesn't and
I can't see why it doesn't. I'd appreciate any suggestions as to why it
won't work and/or advice on what to do to make it work.
When run, all that happens is that a pile of characters are written to the
screen, including the command line parameters, then the end of the program
is reached and execution stops.

Thanks in anticipation,

Murff....

JANET: djm@uk.ac.ed.etive      Internet: djm%ed.etive@nsfnet-relay.ac.uk   
       Murff@uk.ac.ed.emas-a             Murff%ed.emas-a@nsfnet-relay.ac.uk
       trinity@uk.ac.ed.cs.tardis        trinity%ed.cs.tardis@nsfnet-relay.ac.uk
D.J. Murphy     *Artificial* intelligence ?  Evidently.....



CODE FRAGMENT FOLLOWS:

;
data SEGMENT
;
     ;
     ; Strings
     infile     DB   40 DUP (0)                 ; Old filename
     outfile    DB   40 DUP (0)                 ; New filename

     ;
;
data ENDS
;
; ********* Code ************
;
code SEGMENT
;
     ASSUME cs:code,ds:data,ss:stack
;
start:                               ; <----- ENTRY POINT HERE ------
     mov bx,0081                     ; pointer to start of command line
     mov dh,00                       ; clear start-of-args flag
     mov al,00                       ; zero argument count
;
;***********************************************
;
; Register utilization for command line scanning
; ah = current character
; al = argument count
; bx = PSP offset for reading command line
; cx = pointer to offset of current argument
; dh = reading-argument flag
; dl = not used
; ds = not altered
; es = PSP segment address
; ss = not altered
; cs = not altered
;
;***********************************************
;
jp1: inc bx                          ; start searching command line
     mov ah,[bx]                     ; load character
     cmp ah,13d                      ; end of command line ?
     je jp5                          ; change dir entry if yes
     cmp dh,01                       ; have we started reading an argument ?
     je jp3                          ; if we have, process character
     cmp ah,20                       ; if not, is this the start of an arg ?
     je jp1                          ; if not, get next character
                                     ;
     mov dh,01                       ; if it is, set read-arg flag
     inc al                          ; increment argument count
     cmp al,01                       ; is this the first argument ?
     jnz jp2                         ;
     mov cx,OFFSET infile            ; if it is, load cx with pointer to infile
     jmp jp3                         ; and process character
                                     ;
jp2: mov cx,OFFSET outfile           ; otherwise load cx = pointer to outfile
                                     ;
jp3: cmp ah,20                       ; is current character a space ?
     je jp4                          ; if it is, set string termination
     push bx                         ;
     mov bx,cx                       ;
     mov ah,[bx]                     ; otherwise write character to string
     pop bx                          ;
     inc cx                          ; and increment string pointer
     jmp jp1                         ; then get the next character
                                     ;
jp4: mov dh,00                       ; otherwise clear read-arg flag
     cmp al,02                       ; was that the second argument ?
     je jp5                          ; stop reading if it was
     jmp jp1                         ; otherwise loop to get next argument
                                     ;
jp5:
    

kaldis@topaz.rutgers.edu (Theodore A. Kaldis) (06/06/89)

In article <2178@etive.ed.ac.uk> djm@etive.ed.ac.uk (D Murphy) writes:

> I'm writing an assembly language program for a PC and need to access
> command line arguments as strings. On execution, DOS sets DS and ES
> to the segment address of the Program Segment Prefix, and the area of
> memory offset 81h to 100h from the PSP contains all the characters
> (except pipes and redirection) entered after the command name.

Yes, and the byte at 80h has the count of characters entered in the
command line.  It is a good idea to check to see if this value is
zero, in which case there is no command line argument.

> The code fragment below was what I thought would do the job.
> Unfortunately it doesn't and I can't see why it doesn't. I'd
> appreciate any suggestions as to why it won't work and/or advice on
> what to do to make it work.  When run, all that happens is that a
> pile of characters are written to the screen, including the command
> line parameters, then the end of the program is reached and execution
> stops.

The problems with the code below are minor, but even so, this code
strikes me as being rather messy.  To correct it and make it work
properly only requires minor changes, as shown below.


;-------------------------------------------
;CODE FRAGMENT FOLLOWS:

	.RADIX	16

data	SEGMENT

; Strings
infile		DB	40 DUP (0)	; Old filename
outfile		DB	40 DUP (0)	; New filename

data ENDS

; ********* Code ************

code	SEGMENT

	ASSUME	cs:code,ds:data,ss:stack
start:					; <----- ENTRY POINT HERE ------
	mov	bx,81			; pointer to start of command line
	mov	dh,0			; clear start-of-args flag
	mov	al,0			; zero argument count

	MOV	AX,DATA
	MOV	ES,AX			; SET ES TO POINT TO DATA SEGMENT
					; IF YOU DON'T DO THIS, ES WILL
					; CONTINUE TO POINT TO PSP SEGMENT

;	(The ASSUME directive is only recognized by the assembler, and does
;	 not affect any registers.  The DS and ES registers must be set
;	 by the programmer.)

jp1:	inc	bx			; start searching command line
	mov	ah,[bx]			; load character
	cmp	ah,13d			; end of command line ?
	je	jp5			; change dir entry if yes

	cmp	dh,1			; have we started reading an argument ?
	je	jp3			; if we have, process character

	cmp	ah,20			; if not, is this the start of an arg ?
	je	jp1			; if not, get next character

	mov	dh,1			; if it is, set read-arg flag
	inc	al			; increment argument count
	cmp	al,1			; is this the first argument ?
	jnz	jp2

	mov	cx,OFFSET infile	; if so, load cx with pointer to infile
	jmp	jp3			; and process character

jp2:	mov	cx,OFFSET outfile	; else load cx = pointer to outfile
jp3:	cmp	ah,20			; is current character a space ?
	je	jp4			; if it is, set string termination

	push	bx
	mov	bx,cx
;	mov	ah,[bx]			; otherwise write character to string

; THE ABOVE LINE IS YOUR PROBLEM.  YOU ARE SIMPLY RELOADING THE AH REGISTER
; WITH WHATEVER VALUE IS POINTED AT BY THE BX REGISTER.  THE FOLLOWING WILL
; CORRECT IT:

	MOV	ES:[BX],AH

; PLEASE NOTE THAT YOU MUST USE A SEGMENT OVERRIDE HERE.  REMEMBER, WE LOADED
; THE SEGMENT VALUE OF THE DATA SEGMENT INTO ES ABOVE

	pop	bx
	inc	cx			; and increment string pointer
	jmp	jp1			; then get the next character

jp4:	mov	dh,0			; otherwise clear read-arg flag
	cmp	al,2			; was that the second argument ?
	je	jp5			; stop reading if it was
	jmp	jp1			; otherwise loop to get next argument

jp5:	...
;-------------------------------------------

Now, as I said, this bit of code strikes me as a bit sloppy and far
too verbose for what you are trying to do.  Study the following,
figure out what it does, and see if you can adapt it to your needs.

;-------------------------------------------

CR		EQU	0Dh
LF		EQU	0Ah
CMD_TAIL	EQU	80h


CSEG		SEGMENT	PARA PUBLIC 'CODE'
		ASSUME	CS:CSEG,SS:SSEG,DS:DSEG,ES:NOTHING

START:		MOV	AX,DSEG			; load extra segment
		MOV	ES,AX

		MOV	SI,CMD_TAIL		; how long is cmd tail?
		CMP	BYTE PTR [SI],0
		JNA	NO_ARGS			; no cmd line args

		MOV	AH,[SI]			; save cmd tail length
		XOR	CL,CL			; zero out CL
		MOV	DI,OFFSET INFILE

STRP_SPC_1:	INC	SI			; strip leading spaces
		INC	CL
		CMP	CL,AH
		JAE	NO_ARGS			; spaces only entered

		CMP	BYTE PTR [SI],20h
		JNA	STRP_SPC_1

		CLD				; clear direction flag

GET_IN_CHAR:	MOVSB
		INC	CL
		CMP	BYTE PTR [SI],20h
		JNA	STRP_SPC_2		; got infile
		JMP	SHORT GET_IN_CHAR

STRP_SPC_2:	INC	SI			; strip intermediate spaces
		INC	CL
		CMP	CL,AH
		JAE	NO_ARG2			; no arg2 entered

		CMP	BYTE PTR [SI],20h
		JNA	STRP_SPC_2

		MOV	DI,OFFSET OUTFILE

GET_OUT_CHAR:	MOVSB
		CMP	BYTE PTR [SI],20h
		JNA	GOT_FNAMES		; got both filenames
		JMP	SHORT GET_OUT_CHAR

NO_ARGS:	MOV	AX,DSEG
		MOV	DS,AX			; load data seg

		MOV	DX,OFFSET IN_MSG	; display prompt
		MOV	CX,IN_MSG_LN
		MOV	BX,2			; use stderr handle
		MOV	AH,40h
		INT	21h

		MOV	DX,OFFSET INFILE	; get input filename
		MOV	CX,40h
		XOR	BX,BX			; use stdin handle (kbd)
		MOV	AH,3Fh
		INT	21h

		MOV	BX,DX
		ADD	BX,AX
		SUB	BX,2
		MOV	BYTE PTR [BX],0		; make filename ASCIIZ
		JMP	SHORT GET_OUTFILE

NO_ARG2:	MOV	AX,DSEG			; load data seg
		MOV	DS,AX

GET_OUTFILE:	MOV	DX,OFFSET OUT_MSG	; display prompt
		MOV	CX,OUT_MSG_LN
		MOV	BX,2			; use stderr handle
		MOV	AH,40h
		INT	21h

		MOV	DX,OFFSET OUTFILE	; get output filename
		MOV	CX,40h
		XOR	BX,BX			; use stdin handle (kbd)
		MOV	AH,3Fh
		INT	21h

		MOV	BX,DX
		ADD	BX,AX
		SUB	BX,2
		MOV	BYTE PTR [BX],0		; make filename ASCIIZ
		JMP	SHORT GOT_FNAMES_2

GOT_FNAMES:	PUSH	ES
		POP	DS			; load data seg
GOT_FNAMES_2:	...				; rest of program goes here

CSEG		ENDS

DSEG		SEGMENT	PARA PUBLIC 'DATA'
IN_MSG		DB	CR,LF,'Please enter input filename: '
IN_MSG_LN	EQU	$-IN_MSG
OUT_MSG		DB	CR,LF,'Please enter output filename: '
OUT_MSG_LN	EQU	$-OUT_MSG
INFILE		DB	40h DUP (0)
OUTFILE		DB	40h DUP (0)
DSEG		ENDS

SSEG		SEGMENT	PARA STACK 'STACK'
		DB	100h DUP (?)
SSEG		ENDS

		END	START
-- 
              Theodore A. Kaldis                      |  "Perhaps we may
              +-+-+-+-+-+-+-+-+-                      |   frighten away
      email:  kaldis@topaz.rutgers.edu                |   the ghost of so
       UUCP:  {...}!rutgers!topaz.rutgers.edu!kaldis  |   many years ago
 U.S. Snail:  P.O. Box #1212, Woodbridge, NJ  07095   |   with a little
 ex-Ma Bell:  (201) 283-4855  (voice)                 |   illumination . . ."