PAGE 90,132 ;AN000;A2 TITLE DCOPYPAR.SAL - LOOK AT COMMAND LINE PARMS ;****************** START OF SPECIFICATIONS ***************************** ; MODULE NAME: DCOPYPAR.SAL ; ; DESCRIPTIVE NAME: Handle the definition of the DOS command line parameters ; and the interface to the DOS system PARSER. ; ;FUNCTION: The static data areas are prescribed by the DOS system PARSER ; to define the several parameters presented to DISKCOPY. These ; data areas are passed to the PARSER, and its responses checked ; to determine the nature of the user's specifications. Any errors ; found in the user's parameters are defined in messages back ; to the user. ; ; ENTRY POINT: PARSER, near ; ; INPUT: (DOS COMMAND LINE PARAMETERS) ; ; [d:][path] DISKCOPY [d: [d:]][/1] ; ; WHERE ; [d:][path] - Path where the DISKCOPY command resides. ; ; [d:] - To specify the Source drive ; ; [d:] - To specify the Destination drive ; ; [/1] - To copy only the first side of the diskette, ; regardless of the diskette or drive type. ; ; Upon entry to PARSER in this module, ; "CURRENT_PARM" = offset to start of parm text in command string ; "ORDINAL" = initialized to zero ; PSP+81H = text of DOS command line parms string ; EXIT-NORMAL: ; "SOURCE_DRIVE" = CHAR OF FIRST DRIVE ID SPECIFIED, BLANK IF NONE ; "TARGET_DRIVE" = CHAR OF SECOND DRIVE ID IF BOTH SPECIFIED, BLANK ; IF NONE OR ONLY ONE SPECIFIED ; "USER_OPTION" = 01 ON IF /1, -1 IF /1 NOT SPECIFIED. ; EXIT-ERROR: ; IF ERROR, ERROR MESSAGE IS DISPLAYED, AND "EXITFL" HAS "EXPAR". ; INTERNAL REFERENCES: ; ROUTINES: ; PARSER:NEAR Call the system Parser to decode command line ; PARSE_ERROR:NEAR Display the appropriate Parse error message. ; DATA AREAS: ; The several parameter control blocks, defined by the System ; PARSER interface, defining the DISKCOPY parameters. ; EXTERNAL REFERENCES: ; ROUTINES: ; SENDMSG:NEAR Uses Msg Descriptor to drive message handler. ; SYSPARSE:NEAR System Command Line Common Parser. ; ; DATA AREAS: ; EXITFL:BYTE Errorlevel return code. ; MSGNUM_PARSE:WORD Message descriptor for all parse errors. ; USER_OPTION:BYTE /1 parm indicator ; SOURCE_DRIVE:BYTE character of first specified drive ; TARGET_DRIVE:BYTE character of second specified drive ; ; NOTES: ; This module should be processed with the SALUT preprocessor ; with the re-alignment not requested, as: ; ; SALUT DCOPYPAR,NUL ; ; To assemble these modules, the alphabetical or sequential ; ordering of segments may be used. ; ; For LINK instructions, refer to the PROLOG of the main module, ; DISKCOPY.SAL. ; ;PROGRAM AUTHOR: DOS 4.00 EMK ;****************** END OF SPECIFICATIONS ***************************** IF1 ;AN000; %OUT COMPONENT=DISKCOPY, MODULE=DCOPYPAR.SAL... ;AN000; ENDIF ;AN000; ; = = = = = = = = = = = = INCLUDE PATHMAC.INC ;AN015;PATHGEN MACRO ; = = = = = = = = = = = = HEADER MACRO TEXT ;;AN000; .XLIST ;;AN000; SUBTTL TEXT ;;AN000; .LIST ;;AN000; PAGE ;;AN000; ENDM ;;AN000; ; = = = = = = = = = = = = ; $SALUT (4,23,28,36) ;AN000; ; LOCAL EQUATES FALSE EQU 0 ;AN000;RETURN VALUES FOR TRUE EQU NOT FALSE ;AN000; /1 SWITCH CHAR_A EQU "A" ;AN000;ASCII VALUE OF CHARACTER "A" BLANK EQU " " ;AN001; NUL EQU 0 ;AN003; ; = = = = = = = = = = = = ; EXIT CODES FROM SYSPARSE (WHEN CY=0) SYSPRM_EX_OK EQU 0 ;AN000; no error SYSPRM_EX_MANY EQU 1 ;AN000; too many operands SYSPRM_EX_MISSING EQU 2 ;AN000; required operand missing SYSPRM_EX_NOT_SWLIST EQU 3 ;AN000; not in switch list provided SYSPRM_EX_NOT_KEYLIST EQU 4 ;AN000; not in keyword list provided SYSPRM_EX_RANGE EQU 6 ;AN000; out of range specified SYSPRM_EX_VALUE EQU 7 ;AN000; not in value list provided SYSPRM_EX_STRING EQU 8 ;AN000; not in string list provided SYSPRM_EX_SYNTAX EQU 9 ;AN000; syntax error SYSPRM_EX_EOL EQU -1 ;AN000; end of command line ; = = = = = = = = = = = = HEADER ;AN000; PSP STRUC ;AN000; DB 80H DUP (?) ;AN000;SKIP OVER FIRST HALF OF PSP PSP_PARMLEN DB ? ;AN000;NUMBER OF BYTES IN DOS COMMAND LINE PSP_COMMAND DB 127 DUP(?) ;AN000;TEXT OF DOS COMMAND LINE PSP ENDS ;AN000; MSG_DESC STRUC ;AN003; MSG_NUM DW ? ;AN003;MESSAGE NUMBER (TO AX) MSG_HANDLE DW ? ;AN003;HANDLE OF OUTPUT DEVICE (TO BX) MSG_SUBLIST DW ? ;AN003;POINTER TO SUBLIST (TO SI) MSG_COUNT DW ? ;AN003;SUBSTITUTION COUNT (TO CX) MSG_CLASS DW ? ;AN003;MESSAGE CLASS (IN HIGH BYTE, TO DH) ; LOW BYTE HAS 0 (FUNCTION "NO INPUT", TO DL) MSG_DESC ENDS ;AN003; ONE_SUBS EQU 1 ;AN003;NUMBER OF VARIABLES SUBLIST STRUC ;AN000; SUB_SIZE DB ? ;AN003;SUBLIST SIZE (POINTER TO NEXT SUBLIST) SUB_RES DB ? ;AN003;RESERVED ;NEXT FIELD IS TO BE USED AS A DOUBLE WORD SUB_VALUE DW ? ;AN003;TIME, DATE, OR PTR TO DATA ITEM SUB_VALUE_SEG DW ? ;AN003;SEG ID OF PTR ;(ABOVE FIELD MUST BE FILLED AT EXECUTION TIME ; IF THIS IS A .COM FILE) SUB_ID DB ? ;AN003;N OF %N SUB_FLAGS DB ? ;AN003;DATA TYPE FLAGS SUB_MAX_WIDTH DB ? ;AN003;MAXIMUM FIELD WIDTH (0=UNLIMITED) SUB_MIN_WIDTH DB ? ;AN003;MINIMUM FIELD WIDTH SUB_PAD_CHAR DB ? ;AN003;CHARACTER FOR PAD FIELD ; CAN BE " ", "0" OR ",". ; "," CAUSES INSERTION OF THE ACTIVE ; THOUSANDS SEPARATOR BETWEEN EVERY 3 DIGITS. SUBLIST ENDS ;AN003; ; = = = = = = = = = = = = HEADER ;AN000; ; $SALUT (4,14,19,36) ;AN000; EXTRN EXPAR:ABS ;AN000;ERRORLEVEL VALUE FOR BAD PARMS EXTRN FINE:ABS ;AN000;RETURN STATUS INDICATOR CSEG SEGMENT PARA PUBLIC 'CODE' ;AN000; ASSUME CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG ;AN000; EXTRN SENDMSG:NEAR ;AN000;USES MSG DESCRIPTOR TO DRIVE MESSAGE HANDLR EXTRN SYSPARSE:NEAR ;AN000;SYSTEM COMMAND LINE PARSER EXTRN EXITFL:BYTE ;AN000;ERRORLEVEL RETURN CODE EXTRN SOURCE_DRIVE:BYTE ;AN000;FIRST DRIVE LETTER SPECIFIED IN PARMS EXTRN TARGET_DRIVE:BYTE ;AN000;SECOND DRIVE LETTER SPECIFIED EXTRN USER_OPTION:BYTE ;AN000;NO OPTION (-1) /1 (1), INVALID (9) NO_OPTION EQU -1 ;AN000;NO OPTION "/1" SPECIFIED OPTION_1 EQU 1 ;AN000;OPTION "/1" SPECIFIED EXTRN MSGNUM_PARSE:WORD ;AN000;MESSAGE DESCRIPTOR FOR ALL PARSE ERRORS EXTRN MSGNUM_INVALID_PARM2:WORD ;AN005;HELP INFO EXTRN SUBLIST_PARSE:WORD ;AN003;POINTS TO INVALID PARM ; = = = = = = = = = = = = CURRENT_PARM DW 81H ;AN000;POINTER INTO COMMAND OF NEXT OPERAND PUBLIC CURRENT_PARM ;AN000; ORDINAL DW 0 ;AN000;ORDINAL NUMBER OF WHICH PARM TO PARSE PUBLIC ORDINAL ;AN000; ; = = = = = = = = = = = = HEADER ;AN000; ;INPUT PARAMETERS CONTROL BLOCK, POINTED TO BY ES:DI WHEN CALLING PARSER PUBLIC PARMS ;AN000;LET LINK MAKE PARMS BLOCK ADDRESSABLE PARMS LABEL BYTE ;AN000;PARMS CONTROL BLOCK DW PARMSX ;AN000;POINTER TO PARMS EXTENSION DB 0 ;AN000; NUMBER OF STRINGS (0, 1, 2) ; NEXT LIST WOULD BE EXTRA DELIM LIST ; (,& WHITESPACE ALWAYS) ; NEXT LIST WOULD BE EXTRA END OF LINE LIST ; (CR,LF,0 ALWAYS) ;SYSTEM PARSER PARAMETER EXTENSION CONTROL BLOCK PARMSX LABEL BYTE ;AN000;PARMS EXTENSION CONTROL BLOCK DB 0,2 ;AN000; MIN, MAX POSITIONAL OPERANDS ALLOWED DW CONTROL_POS ;AN000; DESCRIPTION OF POSITIONAL 1 DW CONTROL_POS ;AN000; DESCRIPTION OF POSITIONAL 2 DB 1 ;AN000; MAX SWITCH OPERANDS ALLOWED DW CONTROL_SW ;AN000; DESCRIPTION OF SWITCH 1 DB 0 ;AN000; MAX KEYWORD OPERANDS ALLOWED ; THERE IS NO CONTROL BLOCK ; DEFINING KEYWORDS ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = HEADER ;AN000; ;PARSER CONTROL BLOCK DEFINING THE ONLY POSITIONAL PARAMETER, OPTIONAL ;FIRST POSITIONAL PARAMETER IS: ; [D:] - SPECIFY THE SOURCE DRIVE. PUBLIC CONTROL_POS ;AN000;LET LINK MAKE THIS ADDRESSABLE CONTROL_POS LABEL BYTE ;AN000;FIRST POSITIONAL DESCRIPTOR FOR FILESPEC, ; OPTIONAL DW 0101H ;AN000; CONTROLS TYPE MATCHED ; SELECTED BITS: "DRIVE ONLY" AND "OPTIONAL" ; 8000H=NUMERIC VALUE, (VALUE LIST WILL BE CHECKED) ; 4000H=SIGNED NUMERIC VALUE (VALUE LIST WILL BE ; CHECKED) ; 2000H=SIMPLE STRING(VALUE LIST WILL BE CHECKED) ; 1000H=DATE STRING (VALUE LIST WON'T BE CHECKED) ; 0800H=TIME STRING (VALUE LIST WON'T BE CHECKED) ; 0400H=COMPLEX LIST (VALUE LIST WON'T BE CHECKED) ; 0200H=FILE SPEC (VALUE LIST WON'T BE CHECKED) ; 0100H=DRIVE ONLY (VALUE LIST WON'T BE CHECKED) ; 0080H=QUOTED STRING (VALUE LIST WON'T BE CHECKED) ; 0010H=IGNORE ":" AT END IN MATCH ; 0002H=REPEATS ALLOWED ; 0001H=OPTIONAL DW 0002H ;AN000;FUNCTION_FLAGS ; 0001H=CAP RESULT BY FILE TABLE ; 0002H=CAP RESULT BY CHAR TABLE ; 0010H=REMOVE ":" AT END DW RESULT1 ;AN000; RESULT BUFFER DW NOVALS ;AN000; NO VALUE LISTS DB 0 ;AN000; NUMBER OF KEYWORD/SWITCH SYNONYMS ; IN FOLLOWING LIST ;VALUE CONTROL BLOCK FOR THE POSITIONAL PARAMETERS NOVALS DB 0 ;AN000;NO VALUE DEFINITIONS ;RESULTS CONTROL BLOCK FOR THE POSITIONAL PARAMETER RESULT1 LABEL BYTE ;AN000; BELOW FILLED IN FOR DEFAULTS DB 6 ;AN000; TYPE RETURNED: 0=RESERVED, ; 1=NUMBER, 2=LIST INDEX, ; 3=STRING, 4=COMPLEX, ; 5=FILESPEC, 6=DRIVE ; 7=DATE, 8=TIME ; 9=QUOTED STRING RESULT_TAG DB 0FFH ;AN000; MATCHED ITEM TAG DW 0 ;AN000;POINTER TO SYNONYM RESULT_PTR1 DB ? ;AN000;DRIVE NUMBER (A=1, B=2, ETC) ; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = HEADER ;AN000; ;PARSER CONTROL BLOCK DEFINING THE ONLY SWITCH, OPTIONAL ;THE SWITCH IS "/1", MEANING ONLY COPY FIRST SIDE. PUBLIC CONTROL_SW ;AN000;LET LINK MAKE THIS ADDRESSABLE CONTROL_SW LABEL BYTE ;AN000;SWITCH DESCRIPTOR FOR /1 DW 0001H ;AN000; CONTROLS TYPE MATCHED ;SELECTED BITS: "OPTIONAL" ; 8000H=NUMERIC VALUE, (VALUE LIST WILL BE CHECKED) ; 4000H=SIGNED NUMERIC VALUE (VALUE LIST WILL BE ; CHECKED) ; 2000H=SIMPLE STRING(VALUE LIST WILL BE CHECKED) ; 1000H=DATE STRING (VALUE LIST WON'T BE CHECKED) ; 0800H=TIME STRING (VALUE LIST WON'T BE CHECKED) ; 0400H=COMPLEX LIST (VALUE LIST WON'T BE CHECKED) ; 0200H=FILE SPEC (VALUE LIST WON'T BE CHECKED) ; 0100H=DRIVE ONLY (VALUE LIST WON'T BE CHECKED) ; 0080H=QUOTED STRING (VALUE LIST WON'T BE CHECKED) ; 0010H=IGNORE ":" AT END IN MATCH ; 0002H=REPEATS ALLOWED ; 0001H=OPTIONAL DW 0002H ;AN000;FUNCTION_FLAGS ; 0001H=CAP RESULT BY FILE TABLE ; 0002H=CAP RESULT BY CHAR TABLE ; 0010H=REMOVE ":" AT END DW RESULTSW1 ;AN000; RESULT BUFFER DW NOVALS ;AN000; VALUE LISTS DB 1 ;AN000; NUMBER OF KEYWORD/SWITCH SYNONYMS ; IN FOLLOWING LIST SW_1 DB "/1",0 ;AN000; IF n >0, SWITCH 1 ;RESULTS CONTROL BLOCK FOR THE SWITCHES RESULTSW1 LABEL BYTE ;AN000; BELOW FILLED IN FOR DEFAULTS DB 3 ;AN000; TYPE RETURNED: 0=RESERVED, ; 1=NUMBER, 2=LIST INDEX, ; 3=STRING, 4=COMPLEX, ; 5=FILESPEC, 6=DRIVE ; 7=DATE, 8=TIME ; 9=QUOTED STRING DB 0FFh ;AN000; MATCHED ITEM TAG DW 0 ;AN000; SYNONYM POINTER (BASED ON ES:) RESULT_PTR2 DD ? ;AN000; OFFSET OF STRING VALUE ; = = = = = = = = = = = = PATHLABL DCOPYPAR ;AN015; HEADER ;AN000; ; $SALUT (4,4,9,36) ;AN000; PARSER PROC NEAR ;AN000; PUBLIC PARSER ;AN000; ;INPUT: "CURRENT_PARM" = OFFSET TO NEXT PARM IN COMMAND STRING ; "ORDINAL" = COUNT OF NEXT PARM TO PARSE ; PSP+81H = TEXT OF DOS COMMAND LINE PARMS STRING ;OUTPUT: "SOURCE_DRIVE" = VALUE OF FIRST DRIVE ID SPECIFIED, 0 IF NONE ; "TARGET_DRIVE" = VALUE OF SECOND DRIVE ID IF BOTH SPECIFIED, 0 ; IF NONE OR ONLY ONE SPECIFIED ; "USER_OPTION" = "OPTION_1" IF /1 SPECIFIED, -1 IF NOT SPECIFIED ; IF ERROR, ERROR MESSAGE IS DISPLAYED, AND "EXITFL" HAS "EXPAR". ; DX="FINE" IF NO ERROR, OR HAS OFFSET OF PARSE ERROR DESCRIPTOR IF PROBLEM ; = = = = = = = = = = = = MOV USER_OPTION, NO_OPTION ;AN000;ASSUME NO /1 IS ENTERED. ; $SEARCH COMPLEX ;AN000;LOOP THRU COMMAND LINE JMP SHORT $$SS1 $$DO1: ;LOOKING AT RETURN CODE FROM SYSPARSE... CMP AX,SYSPRM_EX_OK ;AN000;WERE THERE ANY ERRORS? ; $EXITIF NE ;AN000;HAD A PROBLEM JE $$IF1 CALL PARSE_ERROR ;AN000;DISPLAY REASON FOR ERROR ; $ORELSE ;AN000;SINCE NO PROBLEM, SO FAR JMP SHORT $$SR1 $$IF1: MOV ORDINAL,CX ;AN000;SAVE UPDATED COUNT MOV CURRENT_PARM,SI ;AN000;REMEMBER HOW FAR I GOT MOV BX,DX ;AN000;SET DATA BASE REG TO POINT TO THIS OPERAND CMP BX,OFFSET RESULT1 ;AN000;WAS POSITIONAL PARM SPECIFIED? ; $IF E ;AN000;IF POSITIONAL PARM SPECIFIED, JNE $$IF4 MOV SI,CX ;AN000;USE COUNT OF POSITIONALS AS INDEX MOV AL,RESULT_PTR1 ;AN000;GET VALUE OF DRIVE (A=1, B=2, ETC) MOV SOURCE_DRIVE-1[SI],AL ;AN000;SAVE RESPONSE VALUE ;IN EITHER SOURCE_DRIVE OR TARGET_DRIVE ;ACCORDING TO ORDINAL IN SI (FROM CX) ; $ELSE ;AN000;SINCE NOT POSITIONAL PARM SPECIFIED JMP SHORT $$EN4 $$IF4: MOV SW_1,BLANK ;AN001;AVOID GETTING DUPLICATE SWITCH MOV USER_OPTION,OPTION_1 ;AN000;MUST HAVE BEEN THE SWITCH, /1 ; $ENDIF ;AN000; $$EN4: ; $STRTSRCH ;AN000; $$SS1: LEA DI,PARMS ;AN000; ES:DI = PARSE CONTROL DEFINITON MOV SI,CURRENT_PARM ;AN000; DS:SI = COMMAND STRING, NEXT PARM XOR DX,DX ;AN000; RESERVED, INIT TO ZERO MOV CX,ORDINAL ;AN000; OPERAND ORDINAL, INITIALLY ZERO CALL SYSPARSE ;AN000;LOOK AT DOS PARMS ; AX=EXIT CODE ; BL=TERMINATED DELIMETER CODE ; CX=NEW OPERAND ORDINAL ; SI=SET TO PAST SCANNED OPERAND ; DX=SELECTED RESULT BUFFER CMP AX,SYSPRM_EX_EOL ;AN000; IS THAT THE END OF THE PARMS? ;IF NOT, LOOP BACK AND FIND OUT ; WHAT THAT PARM IS ; $ENDLOOP E ;AN000;END OF LIST JNE $$DO1 MOV DX,FINE ;AN000;REPORT THAT PARSER WENT OK ; $ENDSRCH ;AN000;FINISHED WITH DOS COMMAND LINE $$SR1: RET ;AN000;RETURN TO CALLER PARSER ENDP ;AN000; ; = = = = = = = = = = = = HEADER ;AN000; PARSE_ERROR PROC NEAR ;AN000; ;INPUT: AX - ERROR NUMBER RETURNED FROM PARSE. ; "CURRENT_PARM" - OFFSET TO WHERE THE BAD PARM STARTED ;OUTPUT: APPROPRIATE ERROR MESSAGE IS PREPARED FOR DISPLAY. ; DX IS SET TO OFFSET OF PARSE ERROR DESCRIPTOR. ; = = = = = = = = = = = = MOV MSGNUM_PARSE,AX ;AN000;PASS MESSAGE NUMBER TO DESCRIPTOR MOV EXITFL,EXPAR ;AN000;ERRORLEVEL CODE TO "PARM ERROR" MOV AX,CURRENT_PARM ;AN003;GET POINTER TO START OF BAD PARM CMP SI,AX ;AN003;HAS THE INDEX TO COMMAND LINE MOVED? ; $IF NE ;AN003;YES, THERE IS A FAULTY PARM JE $$IF10 MOV BYTE PTR [SI],NUL ;AN003;DELIMIT THE BAD PARM MOV SUBLIST_PARSE.SUB_VALUE,AX ;AN000;POINT SUBLIST TO BAD PARM MOV MSGNUM_PARSE.MSG_SUBLIST,OFFSET SUBLIST_PARSE ;AN003;POINT TO SUBLIST MOV MSGNUM_PARSE.MSG_COUNT,ONE_SUBS ;AN003;SET COUNT OF SUBLISTS TO ONE ; $ENDIF ;AN003;INDEX MOVED? $$IF10: MOV DI,OFFSET MSGNUM_PARSE ;AC005;PASS BACK OFFSET TO PARSE ERR DESCRIPTOR CALL SENDMSG ;AN005;DISPLAY THE ERROR MESSAGE ; "Do not specify filename(s)",CR,LF ; "Command Format: DISKCOPY d: d: [/1]",CR,LF MOV DX,OFFSET MSGNUM_INVALID_PARM2 ;AN005;DISPLAY HELP INFO RET ;AN000;RETURN TO CALLER PARSE_ERROR ENDP ;AN000; ; = = = = = = = = = = = = PATHLABL DCOPYPAR ;AN015; CSEG ENDS ;AN000; END ;AN000;