Google
 

Trailing-Edge - PDP-10 Archives - decuslib10-08 - 43,50512/misc.b36
There are no other files named misc.b36 in the archive.
MODULE MISC=
!
!Miscellaneous TOPS-10 dependant routines
!

!
! Facility:	NETSPL	on TOPS-10 only
!
BEGIN
!
! Conditional compilation
!
COMPILETIME FTNETSPL=(%VARIANT AND 2) NEQ 0;
COMPILETIME FTRMCOPY=NOT FTNETSPL;

!
! Table of contents
!
%IF NOT FTRMCOPY %THEN
FORWARD ROUTINE
SCALLI, !Execute a CALLI return 1 if skip 0 otherwise (ignore value returned)
RCALLI,	!Do a CALLI & return value in register
HIBERN,	!Sleep until something interesting happens
 !The following routines convert fields between DAP & system format
 !The suffix _DS means convert from DAP to system format, _SD the reverse
NETQDEV,!Return device FTS requests are queued to
GETLNN, !Get local node number
WHERE,  !Get node number where device is located
DTM_DS,	!Date & Time
DTM_SD,
PRO_QS,	!Convert from RMCOPY format (almost the same as DAP) to sys format
PRO_QD,	!Convert from the 9-bit-byte format in the queue to DAP EX format
PRO_DS;
%FI

FORWARD ROUTINE
PRO_SD;	!Protection

%IF NOT FTRMCOPY %THEN
FORWARD ROUTINE
DAT_DS,	!DATATYPE
DAT_SD,
DTE_SD,	!Date only
TIM_SD,	!Time only
WRDTM,	!Convert date & time to ASCII
TSTAMP,	!Write a time stamp
WRNM2A,	!Write a 2 digit non-zero-supressed decimal number to string
WRNUMF,	!Write a number to a fixed field
FIXIMG;	!Don't extend file by 1 word in Image mode
%FI

!
! Libraries
!

%IF NOT FTRMCOPY %THEN
REQUIRE 'INTR.REQ';
LIBRARY 'DAPLIB';
%ELSE
LIBRARY 'TBL';
%FI
!
! Version information
!
THIS_IS [MISC]	VERSION [1]	EDIT [6]	DATE [10,DEC,79]
!
!	R E V I S I O N   H I S T O R Y
!
%(
[6]	Fix FIXIMG routine to really work
[5]	Put in FIXIMG routine to not extend image-mode files by 1 word
[4]	Put in WRNUMF routine to write fixed-length fields
[3]	Break out part of TSTAMP into WRDTM
[2]	Make NETSPL wake up every now and then on general principle
[1]	The beginning

END	R E V I S I O N   H I S T O R Y		)%

UNDECLARE %QUOTE DATE;
!
! External routines
!
%IF FTNETSPL %THEN
EXTERNAL ROUTINE
DATE,
MSTIME,
WRNUM,
MOVEAZ,
RDNUM;			!Read number from ASCII string
!
! Literals
!

LITERAL SLEEPTIME=1;
LITERAL WHEREUUO=%O'63';	!WHERE UUO on TOPS-10=CALLI 63

GLOBAL BIND MONTAB=
	UPLIT('JAN','FEB','MAR','APR','MAY','JUN',
		'JUL','AUG','SEP','OCT','NOV','DEC'):VECTOR;
!GLOBAL BIND MONTHLEN=
!	UPLIT(31,28,31,30,31,30,31,31,30,31,30,31);

!
! Builtin
!
BUILTIN MACHSKIP,MACHOP;

!
! Routines
!
GLOBAL ROUTINE SCALLI(FUN,ARG)=
	BEGIN
	REGISTER FF,A;
	A=.ARG;
	FF=.FUN;
	IF MACHSKIP(%O'047',A,0,FF) THEN 1 ELSE 0
	END; !SCALLI

GLOBAL ROUTINE RCALLI(FUN,ARG)=
	BEGIN
	REGISTER FF,A;
	A=.ARG;
	FF=.FUN;
	IF MACHSKIP(%O'047',A,0,FF) THEN .A ELSE 0
	END; !RCALLI

GLOBAL ROUTINE GETTAB(ARG)=RCALLI(%O'41',.ARG);

GLOBAL ROUTINE HIBERN=
!Routine to go to sleep until something happens
BEGIN
REGISTER R;
GLOBAL HIBTIME: INITIAL(XWD(%O'320',SLEEPTIME*1000));
R=.HIBTIME;
CALLI(R,%O'72');
WIN
END;
GLOBAL ROUTINE NETQDEV=
!Return sixbit name of device FTS requests are queued to
!Returns: SIXBIT network queue device
BEGIN
REGISTER	R,
		S;

S=GETLNN();	!Get our node number
R=%SIXBIT'NETS00';	!Template
R<6,3>=.S<3,3>;	!Move first digit
R<0,3>=.S<0,3>;	!Move second digit
.R		!Return sixbit device name
END;		!NETQDEV
GLOBAL ROUTINE GETLNN=
!Return host node number
!Returns: host node number

WHERE(%SIXBIT'CTY');	!The CTY is always connected to the host

GLOBAL ROUTINE WHERE(DEV)=
!Find the node a device is connected to
!DEV: SIXBIT device name
!Returns: node number
BEGIN
REGISTER R;

R=.DEV;
CALLI(R,WHEREUUO);	!Do the UUO
.R			!Node number is in the register
END;	!WHERE
GLOBAL ROUTINE DTM_DS(STR,SDATE,STIME)=
!Convert ASCII date & time to internal format 
!Arguments:
!STR:	String containing date&time 'dd-mmm-yy hh:mm:ss'
!--Next 2 args are address to return:
!SDATE:	Date in internal format
!STIME:	Time in internal format
BEGIN
LOCAL PTR;
LOCAL MMM,DD,YY,HH,MM,SS;

PTR=CH$PTR(.STR);
DD=RDNUM(PTR,10);		!Get day of month
CH$RCHAR_A(PTR);		!Skip over '-'
MMM=0;				!Clear it first
CH$MOVE(3,.PTR,CH$PTR(MMM));	!Get month in ASCII
PTR=CH$PLUS(.PTR,4);		!Skip over 3 chars of month and '-'
YY=RDNUM(PTR,10);		!Get year
CH$RCHAR_A(PTR);		!Skip over space
HH=RDNUM(PTR,10);		!Get hour of day
CH$RCHAR_A(PTR);		!Skip over ":"
MM=RDNUM(PTR,10);		!Get minute
CH$RCHAR_A(PTR);		!Skip over ":"
SS=RDNUM(PTR,10);		!Get second

!Now convert month to number

MMM=(INCR M FROM 0 TO 11 DO IF .MONTAB[.M] EQL .MMM THEN EXITLOOP .M);
.SDATE=((((.YY-64)*12)+.MMM)*31)+.DD-1;	!Date in TOPS-10 format
.STIME=((.HH*60)+.MM);		!Minutes since midnight
END;
GLOBAL ROUTINE DTM_SD(STR,SDATE,STIME)=
!Convert internal date & time to DAP format
!Arguments:
!STR:	Address to write string (area must be big enough for 18 characters)
!SDATE: TOPS-10 File System format date (MINUTES past midnight)
!STIME:	System format time
BEGIN
LOCAL PTR;

PTR=CH$PTR(.STR);
DTE_SD(PTR,.SDATE);	!Do the date
CH$WCHAR_A(%C' ',PTR);	!space
TIM_SD(PTR,(.STIME*60*1000));	!and the time (converting to milliseconds)

END;
GLOBAL ROUTINE PRO_QS(PRO)=
!Convert protection field from RMCOPY (via QUASAR) into system-dependant format
!Argument:
!PRO: protection bit field from EQ.
!Returns: protection digit
BEGIN
MAP PRO: EX;	!Treat this like an EX field, sort of
PRO<27,8>=.PRO;	!Copy the bits into the right place
PRO[XB$CNG]=.PRO<8,1>;	!Get the "change protection" bit
!PRO[XB$EXT]=.PRO<8,1>;	!this goes here if XB$CNG moves to bit 7
PRO<0,18>=0;	!Clear the rest of it
PRO_DS(.PRO)	!Thus reformatted, call the following routine...
END; !PRO_QS

GLOBAL ROUTINE PRO_QD(QP)=
BEGIN
!Convert a 9-bit protetion byte from queue entry to DAP EX format

!
! Formal Parameters
!

!QP: 9-bit protection byte, right justified

!
! Returned value
!

!  A one-word (2-byte) EX field


!
! Locals
!

LOCAL	EXF: EX[3],			!Build it here
	EXFPTR;				!Byte pointer

EXF=0;
EXFPTR=CH$PTR(EXF,0,9);
CH$WCHAR_A( (.QP AND %O'177'),EXFPTR);	!Write the low 7 bits
IF (QP=.QP ^ -8) NEQ 0			!And the rest, if anything
THEN	BEGIN
	EXF[7]=1;			!Set the extension bit
	CH$WCHAR_A(.QP,EXFPTR);		!And write the other byte
	END;
.EXF					!Return this as our value
END;	!PRO_QD

GLOBAL ROUTINE PRO_DS(PRO)=
!Convert DAP format protection field to internal format
!Argument:
!PRO:	Protection field (EX-3) from DAP
!Returns: protection digit to store
BEGIN
MAP PRO: EX;

!Grant the access requested plus as little additional as the o.s will let us
IF .PRO[XB$CNG]
 THEN	BEGIN	!Can't change protection, code must be at least 1
	IF .PRO[XB$DLE]
	 THEN	BEGIN	!Can't delete (so can't rename) code>1
		IF .PRO[XB$WRV]
		 THEN	BEGIN	!Can't write (supercede) code>2
			IF .PRO[XB$UPD]
			 THEN	BEGIN !Can't update, code >3
				IF .PRO[XB$APP] OR .PRO[XB$EXT]
				 THEN	BEGIN	!Cant append, code>4
					IF .PRO[XB$RDV]
					 THEN	BEGIN	!Can't read, code 6 or 7
						IF .PRO[XB$EXE]
						 THEN 7	!No access at all
						 ELSE 6	!Execute only
						END
					 ELSE 5	!Read, execute
					END
				 ELSE 4	!Append, read, execute
				END
			 ELSE 3	!Update, append, read, execute
			END
		 ELSE 2	!Supercede, update, append, read, execute
		END
	 ELSE 1	!Rename, supercede, update, append, read, execute
	END
 ELSE 0	!Everything
END;
%FI	!End FTNETSPL
GLOBAL ROUTINE PRO_SD(PRO)=
!Convert internal format protection field to DAP format
!PRO: protection digit in binary
!Returns: the extensible field stored in EX structure format

BEGIN
%IF FTRMCOPY %THEN
LITERAL		!BIT DEFINITIONS IN DAP PROTECTION FIELDS

	XB$RDV=0,		! DENY READ ACCESS
	XB$WRV=1,		! DENY WRITE ACCESS
	XB$EXE=2,		! DENY EXECUTE ACCESS
	XB$DLE=3,		! DENY DELETE ACCESS
	XB$APP=4,		! DENY APPEND ACCESS
	XB$LST=5,		! DENY LIST (directory) ACCESS
	XB$UPD=6,		! DENY UPDATE ACCESS
	XB$CNG=8;		! DENY CHANGE PROTECTION ACCESS
!LITERAL XB$EXT=9;		! DENY EXTEND ACCESS
MACRO EX(FOO)=BITVECTOR[FOO*8]%;
%FI	!End FTRMCOPY

LOCAL R: EX[3];

R=0;		!Allow everything to start with
SELECT .PRO OF
	SET
	[1 TO 7]:	R[XB$CNG]=1;	!Can't change attributes
	[2 TO 7]:	R[XB$DLE]=1;	!Can't delete it
	[3 TO 7]:	R[XB$WRV]=1;	!Can't supercede it
	[4 TO 7]:	R[XB$UPD]=1;	!Can't update it
	[5 TO 7]:	%IF %DECLARED(XB$EXT) %THEN
			R[XB$EXT]=
			%FI
			(R[XB$APP]=1); !Can't append to it
	[6 TO 7]:	R[XB$RDV]=1;	!Can't read it
	[7]:		R[XB$EXE]=1;	!Can't execute it
	TES;
R[XB$LST]=(NOT .PRO) AND 1;	!Set this in case this is a directory

.R
END;
%IF NOT FTRMCOPY %THEN
GLOBAL ROUTINE DAT_DS(NB,DATATYPE)=
!Convert DATATYPE field from DAP and store it in file block
!Arguments:
!FB:	file block
!DATATYPE: DATATYPE field from DAP
BEGIN
MAP DATATYPE: REF EX;	!Extensible field
MAP NB: REF NDB;
BIND FB=N[FB]: REF FILE_BLOCK;
IF .DATATYPE[DAT$ASC] THEN FB[FILE$MODE]=_IOASC	!Mode 0= Ascii
		ELSE FB[FILE$MODE]=_IOIMG;	!Mode 10= Image
END;
GLOBAL ROUTINE DAT_SD(NB,DATATYPE)=
!Generate appropriate DATATYPE field from file block & return as value
!Argument:
!NB:	node block
!DATATYPE: addr to store it in
!Returns: DATATYPE field
BEGIN
MAP DATATYPE: REF EX[2];
MAP NB: REF NDB;
BIND FB=N[FB]: REF FILE_BLOCK;
	IF (.N[OSTYPE] NEQ DAP$TOPS10) AND (.N[OSTYPE] NEQ DAP$TOPS20) AND
	(.N[RMC$O_B16P]+.N[RMC$O_B36]+.N[RMC$O_B16I] EQL 0)
	THEN	DATATYPE[DAT$ASC]=1
	ELSE	DATATYPE[DAT$IMA]=1;
				!Default to ASCII block mode
				!Unless this is TOPS-10 or TOPS-20
..DATATYPE
END;
GLOBAL ROUTINE DTE_SD(PTR,SDATE)=
!Convert system date to DAP format
!PTR: addr of byte pointer to write DAP format DATE 		dd-mmm-yy
!SDATE: TOPS-10 format date
BEGIN
LOCAL
	DD,MMM,YY;

YY=64+(.SDATE/(12*31));	!Get year (last 2 digits anyway)
MMM=(.SDATE/31) MOD 12;		!Get month number
DD=(.SDATE MOD 31)+1;		!and day of month

WRNM2A(.DD,10,.PTR);		!Write day of month
CH$WCHAR_A(%C'-',.PTR);		!-
.PTR=CH$MOVE(3,CH$PTR(MONTAB[.MMM]),..PTR);	!month (3 letter abbreviation)
CH$WCHAR_A(%C'-',.PTR);		!-
WRNM2A(.YY,10,.PTR);		!and 2 digits of year
END;	!DAT_SD
GLOBAL ROUTINE TIM_SD(PTR,STIME)=
!Convert milliseconds-past-midnight to DAP format	hh:mm:ss
!PTR: addr of b.p. to write dap format TIME
!STIME: # of milliseconds since midnight
BEGIN
LOCAL
	HH,MM,SS;

SS=(STIME=(.STIME/1000)) MOD 60;!Seconds
HH=.STIME/(60*60);		!Hours
MM=(.STIME/60) MOD 60;		!Minutes

WRNM2A(.HH,10,.PTR);		!Hours
CH$WCHAR_A(%C':',.PTR);		!:
WRNM2A(.MM,10,.PTR);		!Minutes
CH$WCHAR_A(%C':',.PTR);		!:
WRNM2A(.SS,10,.PTR);		!Seconds

END;	!TIM_SD
GLOBAL ROUTINE WRDTM(PTR)=
!Write date&time stamp thru pointer
!PTR:  byte pointer
!Returns: updated byte pointer
BEGIN
EXTERNAL ROUTINE
	MSTIME,
	DATE;


DTE_SD(PTR,DATE());	!Date first
CH$WCHAR_A(%C' ',PTR);	!space
TIM_SD(PTR,MSTIME());	!and time
CH$WCHAR_A(%C' ',PTR);
CH$WCHAR(0,.PTR);	!Make ASCIZ

.PTR		!Return new value of pointer
END;	!WRDTM

GLOBAL ROUTINE TSTAMP=
!write date&time stamp to LOG file
BEGIN
EXTERNAL ROUTINE
	LOGS;

OWN
	BUFF:VECTOR[CH$ALLOCATION(24)];
LOCAL
	PTR;

PTR=CH$PTR(BUFF);
WRDTM(.PTR);		!Convert date & time to ASCII
LOGS(BUFF);		!send to log file

END;	!TSTAMP
GLOBAL ROUTINE WRNM2A(NUM,RAD,PTR)=
!Write a 2 digit non-zero-supressed number
!NUM: value to write
!RAD: radix
!PTR: address of byte pointer
BEGIN
CH$WCHAR_A(((.NUM/.RAD) MOD .RAD)+%C'0',.PTR);
CH$WCHAR_A((.NUM MOD .RAD)+%C'0',.PTR);
END;
GLOBAL ROUTINE WRNUMF(NUM,RAD,PTR,FILL,LEN)=
!Convert an integer to ASCII and fill out to a fixed length
!Number will be right-justified in field, if it fits in the field
!Creates ASCIZ string, returning pointer to the null byte at the end
! so that subsequent writing to that string does not leave imbedded null bytes
!IF THE NUMBER IS TOO BIG TO FIT IT WILL ALL BE WRITTEN ANYWAY

!
! Formal Parameters
!
!NUM:	Integer to convert to ASCII
!RAD:	Radix for conversion
!	If negative do signed conversion, else do unsigned
!	Use absolute value for radix in either case
!PTR:	Destination byte pointer
!FILL:	ASCII character to fill field out to specified length
!LEN:	Length of field

!
! Returned value
!
!Pointer to null byte at end of string

BEGIN
LOCAL	BUFF: VECTOR[CH$ALLOCATION(14)],	!Buffer to save ASCII number
	L;					!Length of ASCII number

L=WRNUM(.NUM,.RAD,CH$PTR(BUFF));	!Convert number and store in BUFF
					!L now contains # of characters needed
IF (.LEN-.L) GTR 0
 THEN	PTR=CH$FILL(.FILL,(.LEN-.L),.PTR); !Put in fillers if needed

MOVEAZ(%REF(CH$PTR(BUFF)),PTR);		!Copy ASCII number to right place
.PTR					!Return updated pointer
END; !WRNUMF
GLOBAL ROUTINE FIXIMG(NB,FB)=
!Avoid extending image-mode file by 1 word if length is odd
BEGIN
MAP	NB: REF NDB,		!Not referenced currently
	FB: REF FILE_BLOCK;

IF (.(FB[FILE$O_PTR])<30,6> EQL 32) AND (.FB[FILE$MODE] EQL _IOIMG)
THEN
	BEGIN
	FB[FILE$O_PTR]=.FB[FILE$O_PTR]-%O'320000000001';
	FB[FILE$O_COUNT]=.FB[FILE$O_COUNT]+1;
	END;
END;
%FI !End NOT FTRMCOPY
END ELUDOM