	.TITLE	ETHERMON_PARSE Parser and Accessories for Ethernet Monitor
	.IDENT	/V1.0/

;
;  define funny system symbols used by this program
;
	.LIBRARY	/SYS$LIBRARY:LIB/
	$NMADEF	GLOBAL
	.IF	NE NMA$C_STATE_ON
	.WARN	0	; inconsistency in FORTRAN code, fix it!!!!!
	.ENDC
	$TPADEF

	.SBTTL	FORTRAN COMMON's

	.PSECT	LCV_EXIT,NOEXE,RD,WRT,GBL,SHR,OVR,PIC,LONG
LCV_EXIT:
	.BLKB	1	; flag to indicate EXIT command entered

	.PSECT	PARSE_ARG2,NOEXE,RD,WRT,GBL,SHR,OVR,PIC,LONG
slomode:	.blkl	1	; if zero run in slow mode, if >0 fast mode.
	.PSECT	PARSE_ARGS,NOEXE,RD,WRT,GBL,SHR,OVR,PIC,LONG
ICVPRS_NUMBER:
	.BLKL	1	; generic parsed number
BCVPRS_ADDRNUM:
	.BLKB	6	; parsed address number
BCVPRS_PROTNUM:
	.BLKB	2	; parsed protocol number
BCVPRS_DSTADR:
	.BLKB	6	; parsed address for destination
BCVPRS_SRCADR:
	.BLKB	6	; parsed address for source
		;*** next three bytes must remain in this order ***
BCVPRS_DSTMOD:
	.BLKB	1	; filter mode for destination addr (1=EXCLUDE, 2=ONLY)
BCVPRS_SRCMOD:
	.BLKB	1	; filter mode for source addr (1=EXCLUDE, 2=ONLY)
BCVPRS_PRTMOD:
	.BLKB	1	; filter mode for protocol (1=EXCLUDE, 2=ONLY)
		;*** previous three bytes must remain in this order ***
BCVPRS_FLTMOD:
	.BLKB	1	; overall filter mode (1=ENABLE, 2=DISABLE)
NCVPRS_FILESPECLEN:
	.BLKW	1	; length of used filespec buffer
CCVPRS_FILESPEC:
	.BLKB	128	; file specification buffer

	.PSECT	$LOCAL,NOEXE,RD,WRT,NOSHR,LCL,PIC,LONG
BLV_SAVE_FLT_ENA:
	.BLKB	1	; place to save filter EXCLUDE/ONLY flag

	.SBTTL	Command Line Parse State Table

COMMA	=	^X2C

	$INIT_STATE	CMDLIN_STATE,CMDLIN_KEY

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT
	$TRAN	'ADD',STATE_ADD
	$TRAN	'CLEAR',STATE_CLEAR
	$TRAN	'DISPLAY',STATE_DISPLAY
	$TRAN	'EXIT',TPA$_EXIT,EXIT_COMMAND
	$TRAN	'HELP',STATE_HELP
	$TRAN	'SET',STATE_SET
	$TRAN	'SHOW',STATE_SHOW
	$TRAN	'TRACE',STATE_TRACE
	$TRAN	'SPEED',STATE_SLOFST

	$STATE	ENDLIN
	$TRAN	TPA$_EOS,TPA$_EXIT
	$TRAN	'!',TPA$_EXIT

	$STATE  STATE_SLOFST
	$TRAN	'SLOW',STATE_SLOW
	$TRAN	'FAST',STATE_FAST

	$STATE  STATE_SLOW
	$TRAN	!$ENDLIN,TPA$_EXIT,SETSLO

	$STATE  STATE_FAST
	$TRAN	!$ENDLIN,TPA$_EXIT,SETFAST

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT

	$STATE	STATE_ADD
	$TRAN	'FILTER',STATE_ADD_FILTER

	$STATE	STATE_ADD_FILTER
	$TRAN	!FILTER_quals,STATE_ADD_FILTER
	$TRAN	!ENDLIN,TPA$_EXIT,ADD_FILTER

	$STATE	STATE_CLEAR
	$TRAN	'FILTER',STATE_CLEAR_FILTER
	$TRAN	'PROTOCOL_NAME',STATE_CLEAR_PROTNAM

	$STATE	STATE_CLEAR_FILTER
	$TRAN	!ALL_qual,STATE_CLEAR_FILTER_2,,,,-1
	$TRAN	TPA$_DECIMAL,STATE_CLEAR_FILTER_2,,,,1

	$STATE	STATE_CLEAR_FILTER_2
	$TRAN	!ENDLIN,TPA$_EXIT,CLEAR_FILTER

	$STATE	STATE_CLEAR_PROTNAM
	$TRAN	!ALL_qual,STATE_CLEAR_PROTNAM_2
	$TRAN	!protocol_num,STATE_CLEAR_PROTNAM_2

	$STATE	STATE_CLEAR_PROTNAM_2
	$TRAN	!ENDLIN,TPA$_EXIT

	$STATE	STATE_DISPLAY
	$TRAN	'DESTINATION',,,,,1
	$TRAN	'PROTOCOL',,,,,2
	$TRAN	'SIZE',,,,,3
	$TRAN	'SOURCE',,,,,4
	$TRAN	'STATISTICS',,,,,5

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT,DISPLAY
	$TRAN	'/'

	$STATE
	$TRAN	'ALL_STATISTICS',,,1,ICVPRS_NUMBER

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT,DISPLAY

	$STATE	STATE_HELP
	$TRAN	!skip_to_end,TPA$_EXIT,HELP

	$STATE	STATE_SET
	$TRAN	'ADDRESS_NAME',STATE_SET_ADDRNAM
	$TRAN	'FILTER',STATE_SET_FILTER
	$TRAN	'INTERVAL',STATE_SET_INTERVAL
	$TRAN	'LENGTH',STATE_SET_LENGTH
	$TRAN	'PROTOCOL_NAME',STATE_SET_PROTNAM

	$STATE	STATE_SET_ADDRNAM
	$TRAN	!AUTO_qual,STATE_SET_ADDRNAM_AUTO
	$TRAN	!address_num

	$STATE
	$TRAN	TPA$_SYMBOL,,save_filespec
	$TRAN	!quoted_string,,save_filespec

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT,SET_ADDRNAM

	$STATE	STATE_SET_ADDRNAM_AUTO
	$TRAN	!ENDLIN,TPA$_EXIT,SET_ADDRNAM_AUTO

	$STATE	STATE_SET_FILTER
	$TRAN	TPA$_DECIMAL,,save_number

	$STATE	STATE_SET_FILTER_2
	$TRAN	!FILTER_quals,STATE_SET_FILTER_2
	$TRAN	!ENDLIN,TPA$_EXIT,SET_FILTER

	$STATE	STATE_SET_INTERVAL
	$TRAN	TPA$_DECIMAL

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT,SET_INTERVAL

	$STATE	STATE_SET_LENGTH
	$TRAN	TPA$_DECIMAL,,VALIDATE_MSGLEN

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT,SET_LENGTH

	$STATE	STATE_SET_PROTNAM
	$TRAN	!protocol_num

	$STATE
	$TRAN	TPA$_SYMBOL,,save_filespec
	$TRAN	!quoted_string,,save_filespec

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT,SET_PROTNAM

	$STATE	STATE_SHOW
	$TRAN	'ADDRESS_NAMES',STATE_SHOW_ADDRESS
	$TRAN	'FILTER',STATE_SHOW_FILTER
	$TRAN	'PORT_STATUS',STATE_SHOW_PORT
	$TRAN	'PROTOCOL_NAMES',STATE_SHOW_PROTOCOL

	$STATE	STATE_SHOW_ADDRESS
	$TRAN	!ENDLIN,TPA$_EXIT,SHOW_ADDRESS_NAMES

	$STATE	STATE_SHOW_FILTER
	$TRAN	!ENDLIN,TPA$_EXIT,SHOW_FILTER

	$STATE	STATE_SHOW_PORT
	$TRAN	!ZERO_qual,,,-1,ICVPRS_NUMBER
	$TRAN	TPA$_LAMBDA

	$STATE
	$TRAN	!ENDLIN,TPA$_EXIT,SHOW_PORT_STATUS

	$STATE	STATE_SHOW_PROTOCOL
	$TRAN	!ENDLIN,TPA$_EXIT,SHOW_PROTOCOL_NAMES

	$STATE	STATE_TRACE
	$TRAN	!ENDLIN,TPA$_EXIT,TRACE
	$TRAN	'/'

	$STATE
	$TRAN	'ASCII',STATE_TRACE,,1,BCVPRS_PROTNUM
	$TRAN	'BINARY',STATE_TRACE,,2,BCVPRS_PROTNUM
	$TRAN	'INTERVAL',STATE_TRACE_INTERVAL,,8,BCVPRS_PROTNUM
	$TRAN	'OUTPUT',STATE_TRACE_OUTPUT,,4,BCVPRS_PROTNUM

	$STATE	STATE_TRACE_INTERVAL
	$TRAN	'='

	$STATE
	$TRAN	!delta_time,STATE_TRACE,get_delta_time

	$STATE	STATE_TRACE_OUTPUT
	$TRAN	'='

	$STATE
	$TRAN	TPA$_FILESPEC,STATE_TRACE,save_filespec

	$STATE	ALL_qual
	$TRAN	'/'

	$STATE
	$TRAN	'ALL',TPA$_EXIT

	$STATE	address_num
	$TRAN	TPA$_HEX,,VALIDATE_ADDRNUM,,,0

	$STATE
	$TRAN	'-'

	$STATE
	$TRAN	TPA$_HEX,,VALIDATE_ADDRNUM,,,1

	$STATE
	$TRAN	'-'

	$STATE
	$TRAN	TPA$_HEX,,VALIDATE_ADDRNUM,,,2

	$STATE
	$TRAN	'-'

	$STATE
	$TRAN	TPA$_HEX,,VALIDATE_ADDRNUM,,,3

	$STATE
	$TRAN	'-'

	$STATE
	$TRAN	TPA$_HEX,,VALIDATE_ADDRNUM,,,4

	$STATE
	$TRAN	'-'

	$STATE
	$TRAN	TPA$_HEX,TPA$_EXIT,VALIDATE_ADDRNUM,,,5

	$STATE	AUTO_qual
	$TRAN	'/'

	$STATE
	$TRAN	'AUTOMATIC',TPA$_EXIT,,-1,ICVPRS_NUMBER
	$TRAN	'NOAUTOMATIC',TPA$_EXIT

	$STATE	delta_time
	$TRAN	TPA$_DECIMAL,,validate_time,,,23
	$TRAN	TPA$_LAMBDA

	$STATE
	$TRAN	':'
	$TRAN	TPA$_LAMBDA,TPA$_EXIT

	$STATE
	$TRAN	TPA$_DECIMAL,,validate_time,,,59
	$TRAN	TPA$_LAMBDA

	$STATE
	$TRAN	':'
	$TRAN	TPA$_LAMBDA,TPA$_EXIT

	$STATE
	$TRAN	TPA$_DECIMAL,,validate_time,,,59
	$TRAN	TPA$_LAMBDA

	$STATE
	$TRAN	'.'
	$TRAN	TPA$_LAMBDA,TPA$_EXIT

	$STATE
	$TRAN	TPA$_DECIMAL,TPA$_EXIT,validate_time,,,99

	$STATE	FILTER_quals
	$TRAN	'/'

	$STATE
	$TRAN	'DISABLE',TPA$_EXIT,save_filter_mode,,,2
	$TRAN	'ENABLE',TPA$_EXIT,save_filter_mode,,,1
	$TRAN	'EXCLUDE',,save_filter_switch,,,1
	$TRAN	'NODESTINATION',TPA$_EXIT,mark_filter_switch,,,0
	$TRAN	'NOPROTOCOL',TPA$_EXIT,mark_filter_switch,,,2
	$TRAN	'NOSOURCE',TPA$_EXIT,mark_filter_switch,,,1
	$TRAN	'ONLY',,save_filter_switch,,,2

	$STATE
	$TRAN	'='

	$STATE
	$TRAN	'('
	$TRAN	!FILTER_qual_subqual,TPA$_EXIT

	$STATE	FILTER_qual_2
	$TRAN	!FILTER_qual_subqual

	$STATE
	$TRAN	COMMA,FILTER_qual_2
	$TRAN	')',TPA$_EXIT

	$STATE	FILTER_qual_subqual
	$TRAN	'DESTINATION',FILTER_qual_subqual_DST
	$TRAN	'PROTOCOL',FILTER_qual_subqual_PRO
	$TRAN	'SOURCE',FILTER_qual_subqual_SRC

	$STATE	FILTER_qual_subqual_DST
	$TRAN	'='

	$STATE
	$TRAN	!address_num,TPA$_EXIT,save_addr_as_dst

	$STATE	FILTER_qual_subqual_PRO
	$TRAN	'='

	$STATE
	$TRAN	!protocol_num,TPA$_EXIT,save_protocol_mode

	$STATE	FILTER_qual_subqual_SRC
	$TRAN	'='

	$STATE
	$TRAN	!address_num,TPA$_EXIT,save_addr_as_src

	$STATE	protocol_num
	$TRAN	TPA$_HEX,,VALIDATE_PROTNUM,,,0

	$STATE
	$TRAN	'-'

	$STATE
	$TRAN	TPA$_HEX,TPA$_EXIT,VALIDATE_PROTNUM,,,1

	$STATE	quoted_string
	$TRAN	'"'

	$STATE	quoted_string_2
	$TRAN	'"',TPA$_EXIT
	$TRAN	TPA$_ANY,quoted_string_2

	$STATE	skip_to_end
	$TRAN	!ENDLIN,TPA$_EXIT
	$TRAN	TPA$_ANY,skip_to_end

	$STATE	ZERO_qual
	$TRAN	'/'

	$STATE
	$TRAN	'ZERO',TPA$_EXIT

	$END_STATE

	.SBTTL	Command Parsing Subroutine

	.PSECT	$CODE,EXE,RD,NOWRT,LCL,SHR,PIC,LONG

	.ENTRY	EVALUATE_COMMAND,^M<R2,R3,R4,R5>
	CLRL	ICVPRS_NUMBER		; clear any variables related to filters,
	CLRW	BCVPRS_PROTNUM
	CLRL	BCVPRS_SRCADR
	CLRW	BCVPRS_SRCADR+4
	CLRL	BCVPRS_DSTADR
	CLRW	BCVPRS_DSTADR+4
	CLRB	BCVPRS_DSTMOD
	CLRB	BCVPRS_SRCMOD
	CLRB	BCVPRS_PRTMOD
	CLRB	BCVPRS_FLTMOD
	CLRW	NCVPRS_FILESPECLEN
	CLRB	BLV_SAVE_FLT_ENA
	SUBL2	#TPA$K_LENGTH0,SP	; build TPARSE argblk on stack,
	MOVC5	#0,(SP),#0,#TPA$K_LENGTH0,(SP) ; clear block,
	MOVL	#TPA$K_COUNT0,TPA$L_COUNT(SP) ; fill in the block,
	MOVL	#TPA$M_ABBREV,TPA$L_OPTIONS(SP)
	MOVAQ	@4(AP),R0
	MOVZWL	(R0),TPA$L_STRINGCNT(SP)
	MOVAB	@4(R0),TPA$L_STRINGPTR(SP)
	PUSHAB	CMDLIN_KEY		; call the parser,
	PUSHAB	CMDLIN_STATE
	PUSHAL	8(SP)
	CALLS	#3,G^LIB$TPARSE
	BLBS	R0,99$			; exit if successful,
	CMPL	R0,#LIB$_SYNTAXERR	; else test what type of error it was,
	BNEQ	90$			; not a syntax error, continue.
	BBC	#TPA$V_AMBIG,TPA$L_OPTIONS(SP),90$ ; skip if not ambiguous error,
	MOVL	#CLI$_ABVERB,R0		; else change error status,
90$:	PUSHL	R0			; build message vector on stack,
	PUSHL	#1
	$PUTMSG_S	MSGVEC=12(SP)	; report error,
99$:	RET				; return.

	.SBTTL	Command Execution Support Subroutines

	.ENTRY	EXIT_COMMAND,^M<>
	MNEGB	#1,LCV_EXIT		; flag EXIT command as entered,
	RET				; return.

	.ENTRY	VALIDATE_MSGLEN,^M<>
	MOVL	TPA$L_NUMBER(AP),ICVPRS_NUMBER ; save number value,
	CMPL	TPA$L_NUMBER(AP),#1500	; test if number is too large,
	BLEQU	99$			; skip if OK,
	MOVL	#ETH__MSGTOOLNG,R0	; else report error.
99$:	RET

	.ENTRY	validate_time,^M<>
	CMPL	TPA$L_NUMBER(AP),-	; check if number in range,
		TPA$L_PARAM(AP)
	BLEQU	99$			; skip out if OK,
	MOVZWL	#SS$_IVTIME,R0		; else report error.
99$:	RET

day_prolog:
	.ASCID	"0 "

	.ENTRY	get_delta_time,^M<>
	CLRQ	-(SP)			; make an empty dynamic string descriptor,
	MOVW	#^X020E,2(SP)
	PUSHAQ	day_prolog		; build properly formatted time string,
	PUSHAQ	4(SP)
	CALLS	#2,G^STR$APPEND
	PUSHAQ	TPA$L_TOKENCNT(AP)
	PUSHAQ	4(SP)
	CALLS	#2,G^STR$APPEND
	$BINTIM_S	TIMBUF=4(SP),-	; attempt to translate time,
			TIMADR=BCVPRS_DSTADR
	PUSHR	#^M<R0>			; preserve $BINTIM status,
	PUSHAQ	4(SP)			; release the dynamic string,
	CALLS	#1,G^STR$FREE1_DX
	POPR	#^M<R0>			; restore $BINTIM status,
	RET				; return w/results (whatever they are).

	.ENTRY	save_number,^M<>
	MOVL	TPA$L_NUMBER(AP),ICVPRS_NUMBER ; copy number from argblk to COMMON,
	RET				; exit.

	.ENTRY	save_filter_mode,^M<>
	MOVB	TPA$L_PARAM(AP),BCVPRS_FLTMOD ; save filter mode,
	RET				; exit.

	.ENTRY	mark_filter_switch,^M<>
	MOVL	TPA$L_PARAM(AP),R1	; get number of desired target,
	MNEGB	#1,BCVPRS_DSTMOD[R1]	; mark filter mode as "clear it",
	RET				; exit.

	.ENTRY	SETFAST,^M<>
	MOVL	#1,SLOMODE
	RET

	.ENTRY	SETSLO,^M<>
	CLRL	SLOMODE
	RET

	.ENTRY	save_filter_switch,^M<>
	MOVB	TPA$L_PARAM(AP),BLV_SAVE_FLT_ENA ; save filter EXCLUDE/ONLY switch,
	RET				; exit.

	.ENTRY	VALIDATE_ADDRNUM,^M<>
	MOVL	TPA$L_PARAM(AP),R1	; get index into buffer array,
	MOVB	TPA$L_NUMBER(AP),BCVPRS_ADDRNUM[R1] ; copy value into buffer,
	CMPL	TPA$L_TOKENCNT(AP),#2	; test if number too long,
	BGTRU	98$			; bomb if too long,
	CMPL	TPA$L_NUMBER(AP),#^XFF	; is number in range?
	BLSSU	99$			; skip out if so,
98$:	MOVL	#ETH__BADADDRNUM,R0 ; else report syntax error.
99$:	RET

	.ENTRY	VALIDATE_PROTNUM,^M<>
	MOVL	TPA$L_PARAM(AP),R1	; get index into buffer array,
	MOVB	TPA$L_NUMBER(AP),BCVPRS_PROTNUM[R1] ; copy value into buffer,
	CMPL	TPA$L_TOKENCNT(AP),#2	; test if number too long,
	BGTRU	98$			; bomb if too long,
	CMPL	TPA$L_NUMBER(AP),#^XFF	; is number in range?
	BLSSU	99$			; skip out if so,
98$:	MOVL	#ETH__BADPROTNUM,R0 ; else report syntax error.
99$:	RET

	.ENTRY	save_addr_as_dst,^M<>
	MOVL	BCVPRS_ADDRNUM,BCVPRS_DSTADR ; copy 1st part of address,
	MOVW	BCVPRS_ADDRNUM+4,BCVPRS_DSTADR+4 ; copy rest of address,
	MOVB	BLV_SAVE_FLT_ENA,BCVPRS_DSTMOD ; save mode of address,
	RET				; exit.

	.ENTRY	save_addr_as_src,^M<>
	MOVL	BCVPRS_ADDRNUM,BCVPRS_SRCADR ; copy 1st part of address,
	MOVW	BCVPRS_ADDRNUM+4,BCVPRS_SRCADR+4 ; copy rest of address,
	MOVB	BLV_SAVE_FLT_ENA,BCVPRS_SRCMOD ; save mode of address,
	RET				; exit.

	.ENTRY	save_protocol_mode,^M<>
	MOVB	BLV_SAVE_FLT_ENA,BCVPRS_PRTMOD ; save mode of protocol,
	RET				; exit.

	.ENTRY	save_filespec,^M<R2,R3,R4,R5>
	PUSHR	#^M<R0>			; preserve success status,
	MOVC5	TPA$L_TOKENCNT(AP),-	; copy string to COMMON buffer,
		@TPA$L_TOKENPTR(AP),#^A/ /,#128,CCVPRS_FILESPEC
	MOVW	TPA$L_TOKENCNT(AP),NCVPRS_FILESPECLEN ; save string length,
	CMPW	TPA$L_TOKENCNT(AP),#128
	BLEQU	90$
	MOVW	#128,NCVPRS_FILESPECLEN ; adjust if string truncated,
90$:	POPR	#^M<R0>			; restore success status,
	RET				; exit.

	.END
