[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference noted::hackers_v1

Title:-={ H A C K E R S }=-
Notice:Write locked - see NOTED::HACKERS
Moderator:DIEHRD::MORRIS
Created:Thu Feb 20 1986
Last Modified:Mon Aug 03 1992
Last Successful Update:Fri Jun 06 1997
Number of topics:680
Total number of notes:5456

185.0. "Read sequantial file BACKwards!" by RICARD::HEIN () Mon Dec 30 1985 05:02

	The following chunk of BASIC code will read most sequential
	files with variable length records BACKWARDS (LIFO?).
	It can also serve as a sample how to read ANY file format
	in BASIC directly calling RMS block IO.

	What good does that do? I dunno. Maybe someday, someone mumble mumble...

Happy New Year to everybody,

	Hein.

 1	OPTION TYPE = EXPLICIT	!Hein van den Heuvel, Xmas 1985, Valbonne
	ON ERROR GO TO HELL
	EXTERNAL LONG FUNCTION	SYS$OPEN(FAB$TYPE), SYS$CONNECT(RAB$TYPE), &
				SYS$READ(RAB$TYPE), SYS$CLOSE(FAB$TYPE)
	EXTERNAL LONG CONSTANT	RMS$_NORMAL, RMS$_EOF
	DECLARE LONG CONSTANT	FAB_CODE = 20483, RAB_CODE = 17409
	DECLARE LONG CONSTANT	M_GET = 2, M_BIO = 32

	RECORD FAB$TYPE
    	   long START,	long FOP,	long STS,	long STV	&
	  ,long ALQ,	word DEQ,	byte FAC,	byte SHR	&
	  ,long CTX,	byte RTV,	byte ORG,	byte RAT	&
	  ,byte RFM,	long JNL,	long XAB,	long NAM	&
	  ,long FNA,	long DNA,	byte FNS,	byte DNS	&
	  ,word MRS,	long MRN,	word BLS,	byte BKS	&
	  ,byte FSZ,	long DEV,	long SDC,	word GBC	&
	  ,byte ACM,	byte RCF,	long FILL
    	END RECORD

	RECORD RAB$TYPE
	   long START,	long ROP,	long STS,	long STV	&
	  ,long RFA_VBN,word RFA_ID,	word FILL,	long CTX	&
	  ,word FILL,	byte RAC,	byte TMO,	word USZ	&
	  ,word RSZ,	long UBF,	long RBF,	long RHB	&
	  ,long KBF,	byte KSZ,	byte KRF,	byte MBF	&
	  ,byte MBC,	long BKT,	long FAB,	long XAB
	END RECORD

	DECLARE STRING	FILE_NAME, 					&
		LONG	RMS_STATUS, I, THIS_REC, LAST_REC,		&
		WORD	LAST_LEN, LEFT_OVER_LENGHT
	MAP (RMS) RAB$TYPE RAB, FAB$TYPE FAB, STRING NAME_BUFFER = 80
	MAP (BUF) WORD BUF(255), STRING LEFT_OVER = 255
	MAP DYNAMIC (BUF) STRING REC
	INPUT 'File name'; FILE_NAME
	NAME_BUFFER = FILE_NAME
	FAB::START = FAB_CODE		!Set FAB$B_BID and FAB$B_BLN
	RAB::START = RAB_CODE		!Set RAB$B_BID and RAB$B_BLN
	RAB::FAB = LOC(FAB::START)	!Put Address of Fab in Rab
	FAB::FNA = LOC(NAME_BUFFER)	!Put Address of name_buf in Fab
	FAB::FNS = LEN(FILE_NAME)	!Put Lenght of file_name in Fab
	FAB::FAC = M_GET + M_BIO	!READ access in BLOCK I/O mode
	RMS_STATUS = SYS$OPEN(FAB)	!Open the file
    		CALL LIB$STOP(RMS_STATUS BY VALUE) IF RMS_STATUS <> RMS$_NORMAL
    	RMS_STATUS = SYS$CONNECT(RAB)	!Connect a buffer
    		CALL LIB$STOP(RMS_STATUS BY VALUE) IF RMS_STATUS <> RMS$_NORMAL
	RAB::UBF = LOC(BUF(0))		!Put Address of user_buf in Rab
	RAB::USZ = 512%			!Set User buffer Size
 !

 !	Let's go hunt for a place to start by reading the last block and
 !	scanning backwards. I guess using a XABFHC could make this cleaner.
 !
	RAB::BKT = FAB::ALQ			!Stuff the VBN into the RAB
    	RMS_STATUS = SYS$READ(RAB)		!Read bucket in buffer
    	WHILE RMS_STATUS = RMS$_EOF		!Beyond EOF?
	  RAB::BKT = RAB::BKT - 1%		!Go back
    	  RMS_STATUS = SYS$READ(RAB)		!Read bucket in buffer
	NEXT
    	CALL LIB$STOP(RMS_STATUS BY VALUE) IF RMS_STATUS <> RMS$_NORMAL
	LAST_LEN = (RAB::RSZ / 2%) - 1%		!Save starting point
	LAST_REC = RAB::BKT * 512 + RAB::RSZ	!Save starting point
	THIS_REC = LAST_REC			!Init
 !
 !	Got our starting point, now let's go for it!
 !
	WHILE RAB::BKT > 0%			!Loop through the file
    	  RMS_STATUS = SYS$READ(RAB) UNLESS 	!Read (previous) bucket unless&
	    RAB::RFA_VBN = RAB::BKT 		!..already there (eof)
    	  CALL LIB$STOP(RMS_STATUS BY VALUE) UNLESS (RMS_STATUS=RMS$_NORMAL)
	  FOR I = LAST_LEN TO 0 STEP -1		!Loop through block
	    IF LAST_REC = THIS_REC + ((BUF(I) + 1%) AND -2%) THEN !Pointing ok?
	      !		
	      ! Here we point to a word with a value that treated as a record 
	      ! length and added to our current position points to the last
	      ! valid record seen. Chances are pretty slim that this is anything
	      ! other then a *** VALID RECORD ***. Grab it while we can.
	      !
	      REMAP (BUF) STRING FILL=(I+1%)*2%	!Skip the first bit and length&
	        ,REC = BUF(I)			!..and put REC were it should be
	      PRINT REC				!Print the record
	      LAST_REC = THIS_REC - 2%		!New address for last record
	      LAST_LEN = I			!New pointer to last length
	    END IF				!
	    THIS_REC = THIS_REC - 2%		!Address of this (trial) record
	  NEXT I				!Walk the Block
	  LEFT_OVER_LENGHT = LAST_LEN * 2%	!Convert word steps to bytes.
	  REMAP (BUF) REC = LEFT_OVER_LENGHT	!Re-map buffer layout
	  LEFT_OVER = REC			!Save last bit from this block
	  RAB::BKT = RAB::BKT - 1%		!Update the VBN into the RAB
	  LAST_LEN = 255%			!Init pointer for full block
	NEXT					!Loop
	GO TO 2					!All done

 HELL:	PRINT ERT$(ERR) UNLESS ERR = 11
	RESUME 2
 2	END
T.RTitleUserPersonal
Name
DateLines
185.1But... it's very easy!BARNA::SOLEPONTJaume, �Barcelona 1992� more than everMon Oct 06 1986 16:466
	The best hack to read ANY TYPE OF FILE backwards is...

		$ MOUNT /SYSTEM /SPIN=REVERSE  ddcu:
		$ etc...

							*Jaume ;->
185.2?MANANA::COLGATEWim ColgateTue Oct 07 1986 13:481
    Spin?