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 . . ."