Google
 

Trailing-Edge - PDP-10 Archives - decus_20tap4_198111 - decus/20-0110/io.sai
There are 3 other files named io.sai in the archive. Click here to see a list.
ENTRY;
COMMENT
.SEC(IO.SAI - PROC10 I/O package)
.index(IO.SAI - PROC10 I/O package)
.;
COMMENT
.SEC(IO.SAI package)
.INDEX(IO.SAI package)
.;
Begin "IO.SAI"


Require "DEFINE.REQ" source!file;
Require "PRCMAX.REQ" source!file;
Require "PRCINV.REQ" source!file;

#


	IO.SAI - An I/O package for DDTG data files on the PDP10.
	---------------------------------------------------------



		BRUCE SHAPIRO and PETER LEMKIN
		IMAGE PROCESSING UNIT
		NCI, DCBD
		NATIONAL INSTITUTES OF HEALTH
		BETHESDA, MARYLand  20014


Revised Nov 14, 1976 - Lemkin, removed [50,752] ref and fixed NUMBER mode
Revised July 27, 1976 - Lemkin fixed GETPIX BM data mode
Revised July 7, 1976 - Lemkin fixed GETDDTG
Revised May 25, 1976 - Lemkin fixing mask PUTBMASK
Revised May 24, 1976 - Lemkin fixing mask and boundry title i/o
Revised May 19, 1976 - Lemkin, made arrays SAFE
Revised May 17, 1976 - Lemkin, made procedures SIMPLE
Revised April 14, 1976 - Lemkin, fixed put mask size
Revised April 10, 1976 - Lemkin, added GET/PUTARRAY procedures
		AUGUST 25, 1975
Revised SEPTEMBER 9, 1975
Revised SEPTEMBER 23, 1975
Revised OCTOBER 8, 1975
Revised December 17, 1975 - Lemkin, added byte modes
Revised December 18, 1975 - Lemkin, added HEADER
Revised December 24, 1975 - Lemkin, speeded up DECODE
Revised December 30, 1975 - MADE IT WORK!
Revised Jan 12, 1976 Lemkin - added GETPIX, PUTPIX
Revised Jan 14, 1976 Lemkin - corrected GETPIX, PUTPIX
Revised Jan 15, 1976 - Lemkin, fixed oheader ref. in MAKEHEADER
Revised Jan 16, 1976 - Lemkin, fixed iheader ref. in GETDDTG
Revised Jan 30, 1976 - Lemkin, fixed CVI7, and deleted extraneous code.
Revised Feb 3, 1976 - Lemkin, added devices to io!file!names
Revised Feb 4, 1976 - Lemkin, added GETBOUNDARY, PUTBOUNDARY,
				GETMASK, PUTMASK
Revised Feb 11, 1976 - Lemkin, added modes 14 and 15 to MAKHEADER
Revised Feb 12, 1976 - Lemkin, added length to GETBOUNDARY
Revised Feb 12, 1976- Shapiro, fixed length in GETBOUNDARY
Revised Feb 13, 1976 - Lemkin, added length spec to input of 
			PUTBOUNDARY
Revised Feb 18, 1976 - Lemkin, fixed case limit test in MAKHEADER
Revised Feb 19, 1976 - Lemkin, speeded up For loops on GET/PUTs
Revised March 5, 1976 - Lemkin, fixed header[80] for types 9-12



	INTRODUCTION
	------------

	The set of routines in IO.SAI enable a user to read  or
        write  grey  scale  picture  files (256 by 256 with 256
        levels of grey) or variable size boundary files on  the
        PDP10. The data is packed so that it may be manipulated
        by the RTPP-PDP8/e  configuration.  In  particular  the
        programs  called  DDTG and PROCES running on the PDP8/e
        will read and produce data of this form. With the   aid
        of  these programs, it is therefore possible to process
        images scanned by the RTPP on the PDP10.

	Similarly, any images produced on the  PDP10 with  this
        package may be processed by the RTPP. 

	In addition  to  insuring  the  compatability  of  data
        formats  between  the  PDP8/e  and  the PDP10, the data
        packing used assures maximum packing density.

	Procedures GETDDTG and PUTDDTG are used to  lookup  and
        enter  DDTG  files  and  read  and  write  the  header.
        MAKEHEADER is used to create an header Array for use in
        PUTDDTG  while CVTHEADER is used to convert the Integer
        Array iheader to  selected  variables.      GETLINE  and
        PUTLINE  are used on successive calls to read and write
        line data.  GET12BIT  and  PUT12BIT  (and  their  8-bit
        versions  GET8BIT  and  PUT8BIT)  are  used to read and
        write 12 and 8 bit byte data.          CLOSEINDATA  and
        CLOSEOUTDATA  are  used  to  close the input and output
        channels respectively so that another file may be used.
        Only one input and out channel may be active at a time.
;
COMMENT
.NEXT PAGE
.SS(Logical data file format)
.index(Logical data file format)

	Logical Data file format
	------------------------

	A DDTG data file consists of a file header followed  by
DDTG data where the data format is described in the header.

	------------------------------------------
	| Header | Variable length data segment  |
	------------------------------------------
	 1 block		n blocks

The header contains the following information:

12-bit
word
number	field and function
------	-------------------
1	(a) data file space mode (7 to 15 decimal) - 1 word
		BM=7, MASK=10, QMT=11, GRAFPEN=12, GALSCAN=13,
		STATE=15.
2	(b) file length in blocks (0 means variable)  - 1 word
3:4	(c) number of data (0 means variable) - 2 words
5	(d) number of words/datum (a fraction
		expressed by the numerator in the left 6-bit byte,
		and the denominator in the right 6-bit byte  - 1 word.
6	(e) data file submode number (see DDTG.DOC table 2) - 1 word
7	(f) data length - 1 word (0=8-bit, 1=10-bit,
				2=12 bit data, 3=16-bit, 4=1-bit)
8	(g) information type - 1 word (0=z data, 1=xy data,
				2=xyz data (not used), 3=(x(e),x(x))
				MASK reg. data, 4=QMT function comp.
				data, 5=bin. mask, 6=36bit PDP10 words)
9	(h) data packing mode  - 1 word (0 means packed 8-bit,
				1 means unpacked in 12-bit words).
10	(i) OS/8 date word when file created - 1 word
		month - bits 0:3
		day -   bits 4:8
		year (0 to 7) - bits 9:11.
11	(j) horizontal window coordinate before scan - 1 word
12	(k) vertical window coordinate before scan - 1 word
13:16	(l) file name and extension (6-bit Ascii) - 4 words
17:52	(m) 72 character Comment (6-bit Ascii) with zero last 
				character - 36 words
53:76	(n) 12-tuple double precision  CURRENT  position  state
	    vector, see MDPDATA[7:8,1:12] in COMMON - 24 words
77	(o) gray value  used  for  filling  masks  (8-bits  lsb
	    default is 255) - 1 word
78	(p) Class key (0 if not used), 1 to 12 if used.
79:80	(q) Time of day in two words packed 4A6
81	(r) Size of image for tsubmode 15 as (2**n)-1
.next page
;
COMMENT
.next page
.ss(Table 2. Data space file header information)
.index(Table 2. Data space file header information)

Table 2. Data space file header information (from DDTG.DOC)
--------------------------------------------
The table below specifies (a)-(h) where appropriate for the  12
data file modes.

Data file mode	|  (a)	|  (b)	|  (c)	|  (d)	|  (e)
------------------------------------------------------
1 BMi		|  7	|  171	|  65K	|  2/3	| 1  (8-BIT PACKED)
2 BMi		|  7	|  342	|  65K	|  4/3	| 2  (16-BIT PACKED)
------------------------------------------------------
3 MASK		|  10	|  8	| 1024	|  2	| 3 
------------------------------------------------------
4 QMT		|  11	| 8 MAX | 1018MAX|  6	| 4 (VAR)
------------------------------------------------------
5 GRAF-PEN	|  12	|  VAR. |  VAR. |  2	| 5 (10-BIT VECTOR)
6 GRAF-PEN	|  12	|  VAR. |  VAR. |  2	| 6 (10-BIT NOVECTOR)
7 GRAF-PEN	|  12	|  VAR. |  VAR. |  4/3  | 7 (8-BIT VECTOR)
8 GRAF-PEN	|  12	|  VAR. |  VAR. |  4/3  | 8 (8-BIT NOVECTOR)
------------------------------------------------------
9 GALV-SCAN	|  13   |  171  |  65K. |  2/3	| 9 (256 RASTER)
10 GALV-SCAN	|  13   | 1736  | 1048K |  2/3	| 10 (1024 RASTER)
11 GALV-SCAN	|  13   |  171  |  65K. |  2/3	| 11 (256 RAST-MASK)
12 GALV-SCAN	|  13   | 1736  | 1048K |  2/3	| 12 (1024 RAST-MASK)
------------------------------------------------------
13 STATE	|  15   |    1  |    12 |    2	| 13 (see header)
------------------------------------------------------
14 BMASK	|  16   |   VAR |   VAR |   12	| 14 (in PROC10)
------------------------------------------------------
15 IMAGE	|  17   |   VAR |   VAR |  2/3	| 15 (in PROC10)
------------------------------------------------------
16 PDP10 DATA	|  18   |   VAR | n wds |  3/1	| 16  PDP10 36bit words


Data file mode	|  (f)	|  (g)	|  (h)	
--------------------------------------
1 BMi		|  0	|  0	|  0  (MEMORY i=[0:7])
2 BMi		|  3	|  0	|  0  (MEMORY i=[0:7])
--------------------------------------
3 MASK		|  1	|  3	|  1
--------------------------------------
4 QMT		|  1	|  4   |   1
--------------------------------------
5 GRAF-PEN	|  1	|  1   |   1 (DOUBLE 0 IS EOF)
6 GRAF-PEN	|  1	|  1   |   1 (DOUBLE 0 IS EOF)
7 GRAF-PEN	|  0	|  1   |   0 (DOUBLE 0 IS EOF)
8 GRAF-PEN	|  0	|  1   |   0 (DOUBLE 0 IS EOF)
--------------------------------------
9 GALV-SCAN	|   0   |  0  |    0
10 GALV-SCAN	|   0   |  0  |    0
11 GALV-SCAN	|   0   |  0  |    0
12 GALV-SCAN	|   0   |  0  |    0
--------------------------------------
13 STATE	|   1   |  4  |    1
--------------------------------------
14 BMASK	|   4   |  5  |    0
--------------------------------------
15 IMAGE	|   0   |  0  |    0
--------------------------------------
16 PDP10 DATA	|   2   |  6  |    1
;
COMMENT
.next page
.ss(Physical data file format)
.index(Physical data file format)

	PHYSICAL DATA FORMAT
	--------------------

	All  physical  data is comprised of 8-bit bytes. On the
        PDP8/e 3 bytes  are  packed  into  2  PDP8/e  words  as
        follows:

	***********************
	* HIGH3 *    BYTE1    *
	***********************
	* LOW3  *    BYTE2    *
	***********************

	note that the high and low segments (each 4 bits)  must
        be concatenated to form the third byte.

	A similar packing arrangement exists for  data  on  the
        PDP10,  except  that  now,  36  bit  words are used and
        therefore, exactly 9 bytes will fit  into  two  36  bit
        PDP10 words as follows:

	*******************************************************
	* HIGH3 *  BYTE1  *  LOW3 *  BYTE2  * HIGH6 *  BYTE4  *
	*******************************************************
	*  LOW6 *  BYTE5  * HIGH9 *  BYTE7  *  LOW9 *  BYTE8  *
	*******************************************************

	Again note that HIGHn and LOwn must be concatenated  to
        form an 8 bit byte.
;
COMMENT
.next page
.ss(PDP8e/PDP10 file transmission methods)
.index(PDP8e/PDP10 file transmission methods)
.;
"

		PDP8e/PDP10 file transmission methods
		-------------------------------------
	The I/O routines implemented in this package will  read
        files of  the  latter  form  which were  either created
        directly  on  the  PDP10  with  this  package  or  were
        transferred  from  the  PDP8/e with either the MAG-TAPE
        routines or PIP10 with a /I switch for  DEC-TAPE  (also
        using PIP on the PDP10, with a /I switch).


.ss(External IO.SAI procedure calls)
.index(External IO.SAI procedure calls)
	External IO.SAI Procedure calls
	-------------------------------

[1]	Boolean Simple GETDDTG(String io!file!name;
		 Reference Integer Array iheader);
		-lookup the file and get the header.
		 returns True if file not found Else false.

		io!file!name-a String variable containing the
			name of the file containing the data.

		iheader-an Integer Array iheader[0:255] 
			which when called with iheader[0] set
			to '1' will be filled with the contents
			of the 256 12-bit byte file header. Otherwise
			it is assumed that the file
			does not contain a header and the first
			byte in the file is taken as data.
			If iheader[0]='N' then data is read
			in as a raster of ascii numbers.

[2]	Simple GETLINE(Reference Integer Array ILINE);
		will retrieve the next 256 sequential 8-bit
		bytes of data from ithe input specified file.

		ILINE-a 256 word one-dimensional Integer Array.
			This Array will be filled with unpacked 8-bit
			data. It should be dimensioned in the calling
			program as ILINE[0:255].


[3]	Integer Simple GET12BIT - will retrieve the next 12-bit input byte.
			note that GETDDTG must have been called
			previously with a header request to
			initialize the file.

[4]	Integer Simple GET8BIT - will retrieve the next 8-bit input byte.
			note that GETDDTG must have been called
			previously with a header request to
			initialize the file.

[5]	Simple CLOSEINDATA-will permit the the Opening
			of a new input file. Any previous
			input file Opened will not be accessible.

[6]	Boolean Simple PUTDDTG(String Oio!file!name;
		 Integer Array oheader);
		-enter the file and write out the header.
		 returns True Enter error Else false.

		Oio!file!name-a String variable which will
			contain the name of the output file.

		oheader-a 256 word Integer Array which when oheader[0]
			is zero will cause the Procedure to
			assume that no header is to exist in
			the output file. If the it is '1'
			Then the header will be written
			at the Beginning of the file.



[7]	Simple PUTLINE(Integer Array OLINE)
		will store the next 256 bytes sequentially
		in packed format

		OLINE-a 256 word one-dimensional Integer Array
			which contains the next 256 bytes to
			be wrItten. It should be dimensioned
			in the calling program as OLINE[0:255].


[8]	Simple PUT12BIT(Integer N12BIT) - will write out the value of
			its argument N12BIT. note that
			PUTDDTG must have been called
			previously with a header request to
			initialize the file.

[9]	Simple PUT8BIT(Integer N8BIT) - will write out the value of
			its argument N8BIT. note that
			PUTDDTG must have been called
			previously with a header request to
			initialize the file.

[10]	Simple CLOSEOUTDATA-will close the output file written
			with the PUTDDTG Procedures. It will also
			permit the Opening of a new output file 
			when PUTDDTG is called. Only one output file
			may be Opened at a time.

[11]	Simple MAKEHEADER( Integer submode;
		  String Oio!file!name, com;
			 Integer Array oheader);
		- setup an initial header Array based on the
		submode information (see table 2), the
		io!file!name, Comment (com) and store it in oheader.


[12]	Simple CVTHEADER(Reference Integer submode;
		 	Reference String io!file!name, com;
		 	Reference Integer Array iheader);
		- convert a header Array into the
		submode information (see table 2), the
		io!file!name, Comment (com) from oheader.

[13]	Boolean Simple GETPIX( Reference Integer Array image3;
		Reference String io!file!name, com;
		Reference Integer Array header);
		- Input a picture from  the  specified  file  and
		return with the title in the input string.  The
		procedure returns true if it  failed  otherwise
		it returns false.

[14]	Boolean Simple PUTPIX( Reference Integer Array image1;
		String io!file!name, com;
		Reference Integer Array header);
		- Output a  picture  into  the  specified  file
		given  the Comment string com.  If it fails the
		Enter  it  returns  true  otherwise  it returns
		false.

[15]	Boolean Simple GETBMASK( Reference Integer Array mask3;
		Reference String io!file!name, com;
		Reference Integer Array header);
		- Input a binary mask from  the  specified  file  and
		return with the title in the input string.  The
		procedure returns true if it  failed  otherwise
		it returns false.

[16]	Boolean Simple PUTBMASK( Reference Integer Array mask1;
		String io!file!name, com;
		Reference Integer Array header);
		- Output a  binary mask  into  the  specified  file
		given  the Comment string com.  If it fails the
		Enter  it  returns  true  otherwise  it returns
		false.

[17]	Boolean Simple GETBOUNDARY( Reference Integer Array 
		boundary3;
		Reference String io!file!name, com;
		Reference Integer Array header;
		Reference Integer bnd!length);
		- Input a boundary from  the  specified  file  and
		return with the title in the input string.  The
		procedure returns true if it  failed  otherwise
		it returns false. Bnd!length is the boundary
		length including the logical eof which is (x,y)=(0,0).

[18]	Boolean Simple PUTBOUNDARY( Reference Integer Array 
		boundary1;
		String io!file!name, com;
		Reference Integer Array header;
		Integer bnd!length);
		- Output a  boundary  into  the  specified  file
		given  the Comment string com.  If it fails the
		Enter  it  returns  true  otherwise  it returns
		false. note that header[0] should be 0 to generate
		the header.

[19]	Boolean Simple GETARRAY( Reference Integer Array 
		data!array;
		Reference String io!file!name, com;
		Reference Integer Array header;
		Reference Integer total!array!size);
		- Input an Integer ARRAY from the specified file and
		return with the title in the input string.  The
		procedure returns true if it  failed  otherwise
		it returns false. total!array!size is the ARRAY
		length.

[20]	Boolean Simple PUTARRAY( Reference Integer Array 
		data!array;
		String io!file!name, com;
		Reference Integer Array header;
		Integer total!array!size, array!type, number!tuples);
		- Output an Integer ARRAY into the specified file
		given  the Comment string com.  If it fails the
		Enter  it  returns  true  otherwise  it returns
		false. note that header[0] should be 0 to generate
		the header. In either case, header[80]_array!type,
		and header[81]_number!tuples.


	LINKING TO THE Procedures
	-------------------------

		These Procedures may be incorporated in any
	user SAIL program by placing the file IO.REQ in your
	program.
---------------------------------------------------------"
COMMENT
.next page
.SS(GET IO.SAI procedures)
.index(GET IO.SAI procedures)
.;
Begin "GET"
#-----------------------------------------------------------
#	Own variables For use in GETting data
#-----------------------------------------------------------;
  Own Integer
	r,
	c,
	pz,
	data,
	twocounter,
	by1,
	by2,
	by3,
	device!name,
	bytecounter,
	flag,
	I,
	brchar,
	eoflag,
	mask4,
	mask8,
	word,
	sstuffbytecnt,
	channum,
	num,
	tempword1,
	tempword2,
	tempword3,
	tempword4,
	tempword5,
	tempword6,
	high1,
	high2,
	high3,
	low1,
	low2,
	low3;

Safe Own Integer Array
	sstuff[1:60];
COMMENT
.next page
.sss(Procedure CLOSEINDATA)
.index(Procedure CLOSEINDATA)
.;
  Internal Simple Procedure CLOSEINDATA;
  Begin "CLOSEINDATA"

#-----------------------------------------------------------
#	THIS Procedure WILL RESET flag SO THAT If INPUT
#	FROM A NEW FILE IS DESIRED THE INITIALIZATION CODE
#	WILL BE ENTERED WITH A NEW FILE NAME SUPPLIED AS
#	AN ARGUMENT TO GETDDTG.
#-----------------------------------------------------------;
	flag_false;
	RETURN;
  End "CLOSEINDATA";
COMMENT
.NEXT PAGE
.SSS(Procedure DECODE)
.index(Procedure DECODE)
.;
  Simple Procedure DECODE(Integer index);
  Begin "DECODE"


#-------------------------------------------------------------
#	THIS Procedure WILL EXTRACT THE 8 BIT byteS FROM TWO
#	PDP10 wordS LOCATED IN THE BUFFER 'sstuff'. TWO PDP10
#	wordS CONTAIN EXACTLY 9 PDP8/E 8 BIT byteS. WHEN THE
#	Procedure IS CALLED A DETERMINATION IS MADE AS TO
#	WHICH PAIR OF PDP10 wordS IN 'sstuff' SHOULD BE
#	DECODED. THE UNPACKING ALWAYS USES TWO PDP10 wordS
#	For EACH CALL.
#-------------------------------------------------------------;

	Integer K;
	k_sstuff[index];
	 high1_(K Land mask4) Lsh -28;
	 tempword1_(K Land (mask8 Lsh -4)) Lsh -24;
	 low1_(K Land (mask4 Lsh -12)) Lsh -20;
	 tempword2_(K Land (mask8 Lsh -16)) Lsh -12;
	 high2_(K Land (mask4 Lsh -24)) Lsh -4;
	 tempword3_K Land (mask8 Lsh -28);

	k_sstuff[index+1];
	 low2_(K Land mask4) Lsh -32;
	 tempword4_(K Land (mask8 Lsh -4)) Lsh -24;
	 high3_(K Land (mask4 Lsh -12)) Lsh -16;
	 tempword5_(K Land (mask8 Lsh -16)) Lsh -12;
	 low3_(K Land (mask4 Lsh -24)) Lsh -8;
	 tempword6_K Land (mask8 Lsh -28);
  End "DECODE";
COMMENT
.NEXT PAGE
.SSS(Procedure GET8BIT)
.index(Procedure GET8BIT)
.;

Internal Integer Simple Procedure GET8BIT;

  Begin "GET8BIT"

#---------------------------------------------------------
#	THIS Procedure WHEN GIVEN A byte numBER WILL EXTRACT
#	THE NEXT SEQUENTIAL byte FROM THE BUFFER 'sstuff'.
#---------------------------------------------------------;

	Integer
	L,
	K,
	byte;


	 k_sstuffbytecnt MOD 270;

#----------------------------------------------------------
#	If K=0 THE 'sstuff' BUFFER MUST BE FILLED FROM THE DISK
#	DISK FILE THAT WAS SPECIFIED. THIRTY PDP10 wordS ARE
#	READ FROM DISK. THIS numBER REPRESENTS 270 byteS WHICH
#	APPROXIMATES A 256 byte Iline AND IS ALSO DIVISIBLE BY 9
#	(THE numBER OF PDP8/E wordS IN TWO PDP10 wordS).
#-------------------------------------------------------------;

	 If K=0 Then
	 Begin "REFILL-BUFFER"
	   ARRYIN(channum,sstuff[1],60);
	   sstuffbytecnt_0;
	   word_-1;
	 End "REFILL-BUFFER";

#---------------------------------------------------------
#	KEEP TRACK OF THE numBER OF byteS REMOVED FROM 'sstuff'.
#--------------------------------------------------------;

	 sstuffbytecnt_sstuffbytecnt+1;

#---------------------------------------------------------
#	DETERMINE WHICH ONE OF THE 9 possible byteS TO
#	RETRIEVE FROM THE PDP10 word PAIR.
#---------------------------------------------------------;

	bytecounter_bytecounter+1;
	 L_((bytecounter-1) MOD 9);

#----------------------------------------------------------
#	If L=0 IT IS NECESSARY TO DECODE THE PDP10 word PAIR
#	INTO IT comPONENT PARTS WHICH WILL Then BE PIECED
#	TOGETHER TO For AN 8 BIT byte.
#----------------------------------------------------------;

	 If L=0 Then DECODE(word_word+2);

#-------------------------------------------------------------
#	NOW GET THE CORRECT byte.
#------------------------------------------------------------;

	 Case l Of
	 Begin "PIECEIT"

	   byte_tempword1;
	   byte_tempword2;
	   byte_high1 Lor low1;
	   byte_tempword3;
	   byte_tempword4;
	   byte_high2 Lor low2;
	   byte_tempword5;
	   byte_tempword6;
	   byte_high3 Lor low3;
	 End "PIECEIT";

#----------------------------------------------------------
#	NOW THAT THE byte HAS FINALLY BEEN RETRIEVED, RETURN IT
#	TO THE CALLER.
#---------------------------------------------------------;

	 Return(byte);

  End "GET8BIT";
COMMENT
.NEXT PAGE
.SSS(Procedure GET12BIT)
.index(Procedure GET12BIT)
.;
Internal Integer Simple Procedure GET12BIT;

Begin "GET12BIT"
#
#	Return a 12-bit byte from the input buffer
#	already Opened with GETDDTG;

	If twocounter=2 Then
		Begin "read-3-bytes"
		by1_GET8BIT;
		by2_GET8BIT;
		by3_GET8BIT;
		twocounter_0;
		End "read-3-bytes";

	twocounter_twocounter+1;

	If twocounter=1 
		Then Return (by1 Lor ((by3 Lsh 4) Land '7400))
		Else Return (by2 Lor ((by3 Lsh 8) Land '7400));

End "GET12BIT";
COMMENT
.NEXT PAGE
.SSS(Procedure GETLINE)
.index(Procedure GETLINE)
.;
Internal Simple Procedure GETLINE(Reference Integer Array Iline);

Begin "GETLINE"

#---------------------------------------------------------
#	GET THE NEXT 256 byteS If the not the first header call.
#--------------------------------------------------------;


  For num_0 Step 1 Until 255 Do Iline[num]_GET8BIT;

  RETURN;

End "GETLINE";
COMMENT
.NEXT PAGE
.sss(Procedure GETDDTG)
.INDEX(Procedure GETDDTG)
.;
Internal Boolean Simple Procedure GETDDTG( String io!file!name;
			 Reference Integer Array iheader);

Begin "GETDDTG"

Integer iomode;

#--------------------------------------------------------
#	This Procedure is used to LOOKUP the file and
#	get the header
#--------------------------------------------------------;

#-----------------------------------------------------------
#	INITIALIZE SOME VARIBLES. notE THAT TWO mask wordS
#	ARE DEFINED. 'mask4' IS USED TO mask OUT THOSE PORTIONS
#	THE PDP10 wordS THAT CORRESPOND TO THE high AND low
#	4 BIT PACKING OF THE PDP8/E word. SIMILARLY 'mask8'
#	CORRESPONDS TO THOSE PORTIONS OF THE PDP8/E wordS
#	THAT ARE 8 CONTIGUOUS BITS.
#-----------------------------------------------------------;

	If flag
		Then Return(True)
		Else flag_true;
	mask4_'740000000000;
	mask8_'776000000000;
	word_-1;
	sstuffbytecnt_0;

"	Strip off the device name and use it instead of DSK:"
	device!name_"DSK";
	For i_1 Step 1 Until length(io!file!name) Do
		If Equ(io!file!name[i For 1],":")
			Then
			Begin "strip"
			device!name_io!file!name[1 to i-1];
			io!file!name_io!file!name[i+1 to inf];
			End "strip";

	If iheader[0]="N"
		Then iomode_0 Else iomode_'10;
	Open(channum_GETCHAN,
		device!name,iomode,10,0,68000,brchar,eoflag);
	LOOKUP(channum,io!file!name,eoflag);
	If eoflag 
		Then Return(True);
	If header[0]="N"
		Then Return(False);
	bytecounter_0;
	twocounter_2;

#---------------------------------------------------
#	CHECK TO DETERMINE WHETHER FILE CONTAINS A
#	header. If SO EXTRACT IT INTO THE Integer array
#	'iheader'.
#--------------------------------------------------;

  If iheader[0]=1 
	Then
	Begin "BHEAD"
	Integer Temp, Jh1,Jh2;
	For num_0 Step 1 Until 127 Do
	Begin
	jh1_2*num;
	jh2_jh1+1;
	iheader[jh1]_GET8BIT;
	iheader[jh2]_GET8BIT;
	temp_GET8BIT;
	iheader[jh1]_iheader[jh1] Lor
		((temp Lsh 4) Land '7400);
	iheader[jh2]_iheader[jh2] Lor
		((temp Lsh 8) Land '7400);
	End;
	End "BHEAD";

# --------------------------------------------------------
#	Force the header size for earlier DDTG types.
# --------------------------------------------------------;
	i_iheader[5];
	If (i=9) or (i=11)
		Then iheader[80]_255;
	If (i=10) or (i=12)
		Then iheader[80]_1023;

	Return(false);
End "GETDDTG";
COMMENT
.NEXT PAGE
.sss(Procedure CVTHEADER)
.INDEX(Procedure CVTHEADER)
.;
Internal Simple Procedure CVTHEADER(Reference Integer submode;
			 Reference String io!file!name, com;
			 Reference Integer Array iheader);

	Begin "CVTHEADER"

Define CVI7(X) ="(IF ((X) Land '77) <'40 
			Then ((X) Land '77)+'100 
			Else IF ((X) Land '77)=0
				Then '40 Else ((X) Land '77))";

	Integer K,J;
#		- convert a header Array into the
#		submode inFormation (see table 2), the
#		io!file!name, Comment (com) from oheader.;

#	[CH.1] GET THE submode;
	submode_iheader[5];

#	[CH.2] GET THE io!file!name;
	io!file!name_null;
	For k_12 Step 1 Until 15 Do
		Begin "MAKE-io!file!name"
#		TRASH THE FIRST 4 null byteS;
#		CONVERT THE LAST 2 6-BITS TO 7BIT;
		J_iheader[K];
		io!file!name_io!file!name&CVI7(J Lsh -6)&CVI7(J);
		End "MAKE-io!file!name";

#	[CH.3] GET THE Comment FIELD;
	com_null;
	For k_16 Step 1 Until 51 Do
		Begin "MAKE-Comment"
#		TRASH THE FIRST 4 null byteS;
#		CONVERT THE LAST 2 6-BITS TO 7BIT;
		If ((J_iheader[K]) Land '7700)=0 Then Done;
		com_com&CVI7(j Lsh -6);
		If (J Land '77)=0 Then Done;
		com_com&CVI7(J);
		End "MAKE-Comment";



	End "CVTHEADER";
COMMENT
.NEXT PAGE
.sss(Procedure GETPIX)
.INDEX(Procedure GETPIX)
.;
Internal Boolean Simple Procedure GETPIX(
	 Reference Integer Array image3;
		Reference String io!file!name, com;
		Reference Integer Array iheader);

	Begin "GETPIX"

	Integer word,
		i,
		psize,
		asize,
		submode;

"	Get the array size"
	asize_ARRINFO(image3,0);

	"set the header word so that read in the header"
	If iheader[0] neq "N"
		Then iheader[0]_1;

	If GETDDTG(io!file!name,iheader) And iheader[0]=1
		Then 
		Begin "failed"
		CLOSEINDATA;
		Return (True);
		End "failed";

	If iheader[0]="N"
		Then
		Begin "Read numbers"
		Outstr("NUMBER mode"&crlf);
		pz_Sqrt(4*(asize+1))-1;
		For r_0 step 1 until pz Do
		 For c_0 step 1 until pz Do
			Begin "Get datum"
			data_Intin(channum) Land '777;
			If eoflag 
				Then Done;
			PACK2D(image3,r,c,data);
			End "Get datum";
		CLOSEINDATA;
		Return(false);
		End "Read numbers";

"	go convert the header to the string Comment and filetype"
	CVTHEADER(submode,io!file!name,com,iheader);
	If (submode neq 1) And (submode neq 9) And 
		(submode neq 11) And (submode neq 15)
		Then return (true);

"		Determine the file image size"
	If submode=15 
		Then i_iheader[80] Else i_255;

	psize_( ( (((i Land '377)+1)^2)%4) min asize) - 1;

	"Read in array size*4 bytes and store them in array image."
	For word_0 Step 1 Until psize Do
	   image3[word]_(GET8BIT Lsh 27) Lor (GET8BIT Lsh 18) Lor
		(GET8BIT Lsh 9) Lor GET8BIT;
CLOSEINDATA;
Return (false);
	End "GETPIX";
COMMENT
.NEXT PAGE
.sss(Procedure GETBMASK)
.INDEX(Procedure GETBMASK)
.;
Internal Boolean Simple Procedure GETBMASK(
	 Reference Integer Array mask3;
		Reference String io!file!name, com;
		Reference Integer Array iheader);

	Begin "GETBMASK"

	Integer word,
		asize,
		submode;

"	Get the array size"
	asize_ARRINFO(mask3,0)-1;

	"set the header word so that read in the header"
	If iheader[0] neq "N"
		Then iheader[0]_1;

	If GETDDTG(io!file!name,iheader) And iheader[0]=1
		Then 
		Begin "failed"
		CLOSEINDATA;
		Return (True);
		End "failed";

	If iheader[0]="N"
		Then
		Begin "Read numbers"
		Outstr("NUMBER mode"&crlf);
		pz_Sqrt(36*asize)-1;
		For r_0 step 1 until pz Do
		 For c_0 step 1 until pz Do
			Begin "Get datum"
			data_Intin(channum) Land '1;
			If eoflag 
				Then Done;
			MSK!PACK2D(mask3,r,c,data);
			End "Get datum";
		CLOSEINDATA;
		Return(false);
		End "Read numbers";
"	go convert the header to the string Comment and filetype"
	CVTHEADER(submode,io!file!name,com,iheader);
	If (submode neq 14) 
		Then Return(true);

	"Read in array asize words and store them in array mask."
#	note:   must do modulo 36 bit input.....;
For word_0 step 2 until asize Do
	Begin "pack it"
	mask3[word]_(GET8BIT Lsh 28) Lor
		    (GET8BIT Lsh 20) Lor
		    (GET8BIT Lsh 12) Lor 
		    (GET8BIT Lsh 4) Lor
		    (((i_GET8BIT) Lsh -4) Land '17);
"	Protect the mask array from too much garbage data"
	If (word+1) leq asize
		Then 
		Begin "2nd word"
		mask3[word+1]_(i Lsh 32) Lor
		    (GET8BIT Lsh 24) Lor
		    (GET8BIT Lsh 16) Lor
		    (GET8BIT Lsh 8) Lor 
		    GET8BIT;
		End "2nd word";
	End "pack it";
CLOSEINDATA;
Return (false);
	End "GETBMASK";
COMMENT
.NEXT PAGE
.sss(Procedure GETBOUNDARY)
.INDEX(Procedure GETBOUNDARY)
.;
Internal Boolean Simple Procedure GETBOUNDARY( Reference Integer
		Array boundary3;
		Reference String io!file!name, com;
		Reference Integer Array iheader;
		Reference Integer bnd!length);

	Begin "GETBOUNDARY"

#	the boundary is stored as 4 8-bit bytes/36 bit word
	thus two (x,y) pairs are stored from left to right.
	The occurance of (0,0) is illegal and denotes an eof;

	Label all!Done;
	Integer word,
		x1,
		x2,
		y1,
		y2,
		asize,
		submode;

"	Get the array size"
	asize_ARRINFO(boundary3,0)-1;
	"set the header word so that read in the header"
	If iheader[0] neq "N"
		Then iheader[0]_1;

	If GETDDTG(io!file!name,iheader) And iheader[0]=1
		Then 
		Begin "failed"
		CLOSEINDATA;
		Return (True);
		End "failed";

	If iheader[0]="N"
		Then
		Begin "Read numbers"
		Outstr("NUMBER mode"&crlf);
		x1_-1; y1_-1;
		pz_0;
		While not eoflag Do
			Begin "Get datum"
			x2_x1;
			y2_y1;
			x1_Intin(channum) Land '377;
			y1_Intin(channum) Land '377;
			X!BND!PACK(boundary3,pz,x1);
			Y!BND!PACK(boundary3,pz,y1);
			If ((x1=0 and y1=0) And (x2=0 and y2=0)) Or
				 ((pz_pz+1) > 2047)
				Then Done;
			End "Get datum";
		CLOSEINDATA;
		bnd!length_pz;
		Outstr("Read "&CVS(pz)&" points"&crlf);
		Return(false);
		End "Read numbers";

"	go convert the header to the string Comment and filetype"
	CVTHEADER(submode,io!file!name,com,iheader);
	If (submode neq 7) And (submode neq 8) 
		Then Return(true);

	"Read in array size*4 bytes and store them in array boundary."
For word_0 Step 1 Until asize Do
	Begin "pack it"
	boundary3[word]_(x1_(GET8BIT Lsh 27)) Lor
			(y1_(GET8BIT Lsh 18)) Lor
			(x2_(GET8BIT Lsh 9)) Lor 
			(y2_GET8BIT);
	If (x1=0 and y1=0)
		Then 
		Begin "Done even"
		bnd!length_2*(word);
		Goto all!Done;
		End "Done even";
	If (x2=0 and y2=0)
		Then 
		Begin "Done odd"
		bnd!length_2*(word)+1;
		Goto all!Done;
		End "Done odd";
	End "pack it";

all!Done:	CLOSEINDATA;
	Return (false);
	End "GETBOUNDARY";
COMMENT
.NEXT PAGE
.sss(Procedure GETARRAY)
.INDEX(Procedure GETARRAY)
.;
Internal Boolean Simple Procedure GETARRAY( Reference Integer
		Array data!array;
		Reference String io!file!name, com;
		Reference Integer Array iheader;
		Reference Integer total!array!size);

	Begin "GETARRAY"

#	the ARRAY is stored as 3 12-bit bytes/36 bit word;

	Integer word,
		max!array!size,
		submode;

"	Get the maximum array size"
	max!array!size_ARRINFO(data!array,0)-1;
	"set the header word so that read in the header"
	iheader[0]_1;

	If GETDDTG(io!file!name,iheader) 
		Then Return (True);

"	go convert the header to the string Comment and filetype"
        If iheader[0]=1
		Then
		CVTHEADER(submode,io!file!name,com,iheader);
	If (submode neq 16) 
		 Then Return(true);

	"Read in array size and store them in total!array!size"
	total!array!size_iheader[3]+4096*iheader[2];
For word_0 Step 1 Until (total!array!size Min max!array!size)-1 Do
	Begin "pack it"
	data!array[word]_(GET12BIT Lsh 24) Lor
			 (GET12BIT Lsh 12) Lor GET12BIT;
	End "pack it";

	CLOSEINDATA;
	Return (false);
	End "GETARRAY";

End "GET";
COMMENT
.next page
.SS(PUT IO.SAI procedures)
.index(PUT IO.SAI procedures)
.;
Begin "PUT"

#------------------------------------------------------------
#	THIS SECTION OF THE PROGRAM HANDLES OUTPUT TO A DISK
#	FILE. AT EACH CALL, A 256 word BUFFER 'Oline' IS
#	PASSED TO THESE ProcedureS. THE BUFFER IS STORED IN THE 
#	IN THE INTERMEDIATE BUFFER 'ostuff' WHICH WHEN FILLED
#	WITH 270 PACKED byteS WILL BE DUMPED TO DISK FILE.
#	WHEN THE USER HAS comPLETED WRITING THE FILE, A CALL
#	TO THE Procedure closePIC WILL close THE DISK FILE
#	AND MAKE IT AVAILABLE For LATER USE.
#---------------------------------------------------------;




Safe Own Integer Array
	ostuff[1:60];

  Own Integer
	twocounter, oby1, oby2, oby3, 
	i,
	odevice!name,
	obyte,
	k,
	m,
	n,
	Onum,
	ochannum,
	Obrchar,
	Oeoflag,
	Oflag,
	ostuffbytecnt,
	obytecount,
	oword;
COMMENT
.NEXT PAGE
.SSS(Procedure CLOSEOUTDATA)
.INDEX(Procedure CLOSEOUTDATA)
.;
Internal Simple Procedure CLOSEOUTDATA;

#---------------------------------------------------------
#	THIS Procedure WILL close THE CURRENTLY OpenED
#	OUTPUT PICTURE FILE, ForCING THE BUFFER TO BE
#	WRITTEN. Oflag IS ALSO RESET SO THAT
#	A NEW OUTPUT FILE MAY BE OpenED.
#---------------------------------------------------------;


Begin  "CLOSEOUTDATA"
	ARRYOUT(ochannum,ostuff[1],60);
	close(ochannum);
	Oflag_false;
End "CLOSEOUTDATA";
COMMENT
.NEXT PAGE
.SSS(Procedure PUT8BIT)
.INDEX(Procedure PUT8BIT)
.;
Internal Simple Procedure PUT8BIT(Integer obyten);

Begin "PUT8BIT"

#-----------------------------------------------------------
#	THIS Procedure PACKS AN 8-BIT byte obyten INTO BUFFER 'ostuff'.
#	WHENEVER THE BUFFER 'ostuff' IS FILLED (270
#	PACKED byteS) THE BUFFER IS WRITTEN ONTO DISK.
#---------------------------------------------------------;


  Integer
	J,
	K,
	L;

#------------------------------------------------------------
#	INCREMENT COUNT OF TOTAL numBER OF PACKED byteS IN THE
#	INTERMEDIATE BUFFER 'ostuff'.
#-----------------------------------------------------------;

"make sure that it is only 8-bit"
  obyten_obyten Land '377;
  ostuffbytecnt_ostuffbytecnt+1;

#----------------------------------------------------------
#	DETERMINE HOW byte IS TO BE PACKED. A byte WILL BE
#	SPLIT INTO ITS high AND low comPONENTS OR LEFT IN
#	TACK DEPEndING UPON WHERE IT IS TO PLACED IN THE
#	INTERMEDIATE BUFFER 'ostuff'. THE VARIABLE 'L'
#	DETERMINES WHICH DEcomPOSITION OPERATION (If ANY)
#	IS TO BE PERForMED ON THE CURRENT byte. notE THAT
#	L IS CYCLIC MODULO 9 AND 'oword' IS INCREMENTED
#	BY TWO. THIS IS BECAUSE EXACTLY NINE byteS ARE
#	PACKED IN TWO PDP10 wordS.
#---------------------------------------------------------;

	If (obytecount MOD 9)=0 Then oword_oword+2;
	obytecount_obytecount+1;
	L_((obytecount-1) MOD 9);

#----------------------------------------------------------
#	DETERMINE WHICH ONE OF THE NINE possible OPERATIONS
#	TO PERForM.
#---------------------------------------------------------;

  CASE L OF
  Begin "SPLITIT"

"0"	ostuff[oword]_(obyten Lsh 24) Lor ostuff[oword];

"1"	ostuff[oword]_(obyten Lsh 12) Lor ostuff[oword];

"2"	Begin "high1-low1"
	  J_((obyten Land '360) Lsh 28) Lor (k_ostuff[oword]);
	  ostuff[oword]_((obyten Land '17) Lsh 20) Lor J;
	End "high1-low1";

"3"	ostuff[oword]_obyten Lor ostuff[oword];

"4"	ostuff[oword+1]_(obyten Lsh 24) Lor ostuff[oword+1];

"5"	Begin "high2-low2"
	  ostuff[oword]_((obyten Land '360) Lsh 4) Lor ostuff[oword];
	  ostuff[oword+1]_((obyten Land '17) Lsh 32)
		Lor ostuff[oword+1];
	End "high2-low2";

"6"	J_(obyten Lsh 12) Lor (k_ostuff[oword+1]);

"7"	ostuff[oword+1]_obyten Lor J;

"8"	Begin "high3-low3"
	  J_((obyten Land '360) Lsh 16) Lor (k_ostuff[oword+1]);
	 ostuff[oword+1]_((obyten Land '17) Lsh 8) Lor J;
	End "high3-low3";

  End "SPLITIT";

#---------------------------------------------------------
#	If 'ostuffbytecnt' IS 270, THE INTERMEDIATE BUFFER
#	'ostuff' IS FULL. AT THIS POINT THE BUFFER 'ostuff'
#	IS DUMPED TO DISK AND VARIABLE ARE RESET.
#---------------------------------------------------------;

  If ostuffbytecnt=270 Then
  Begin "DUMPIT"
	ARRYOUT(ochannum,ostuff[1],60);
	ARRCLR(ostuff);
	oword_-1;
	ostuffbytecnt_0;
  End "DUMPIT";

End "PUT8BIT";
COMMENT
.NEXT PAGE
.SSS(Procedure PUT12BIT)
.INDEX(Procedure PUT12BIT)
.;
Internal Simple Procedure PUT12BIT(Integer N12BIT);

Begin "PUT12BIT"
#
#	write a 12-bit byte N12BIT into the output buffer
#	already Opened with PUTLINE;

	If twocounter=2 Then
		Begin "write-3-bytes"
		PUT8BIT(oby1);
		PUT8BIT(oby2);
		PUT8BIT(oby3);
		twocounter_0;
		End "write-3-bytes";

	twocounter_twocounter+1;

	If twocounter=1 
		Then
		  Begin "pack-word-1"
		  oby1 _ n12bit Land '377;
		  oby3 _ (n12bit Lsh -4) Land '7400;
		  End "pack-word-1"
		Else
		  Begin "pack-word-2"
		  oby2 _ n12bit Land '377;
		  oby3 _ (n12bit Lsh -8) Land '7400;
		  End "pack-word-2";


End "PUT12BIT";
COMMENT
.NEXT PAGE
.SSS(Procedure PUTLINE)
.INDEX(Procedure PUTLINE)
.;
Internal Simple Procedure PUTLINE(Integer Array Oline);

#-------------------------------------------------------------
#	THIS Procedure ACCEPTS AS ARGUMENTS A 256 word BUFFER
#	'Oline' (THE DATA TO BE WRITTEN IN THE DISK FILE).
#	 THE Procedure IS CALLED WHENEVER
#	THE USER DESIRES TO write A 256 byteS OF DATA TO THE
#	DISK. THE DATA IS WRITTEN SEQUENTIALLY WITH EACH CALL.
#------------------------------------------------------------;


Begin "PUTLINE"
 
#	If Oflag=TRUE Then write out the line;
#------------------------------------------------------------;
	If Oflag Then
	Begin "write-line"
  For Onum_0 Step 1 Until 255 Do
  Begin

#-------------------------------------------------------
#	AFTER EVERY 9 byteS A PAIR OF PDP10 wordS
#	IN THE INTERMEDIATE BUFFER 'ostuff' IS FILLED.
#	THE index INTO THIS BUFFER IS INCREMENTED BY 2
#	WHENEVER THIS OCCURS.
#-------------------------------------------------------;

	PUT8BIT(Oline[Onum]);
  End;
End "write-line";

End "PUTLINE";
COMMENT
.NEXT PAGE
.SSS(Procedure PUTDDTG)
.INDEX(Procedure PUTDDTG)
.;
Internal Boolean Simple Procedure PUTDDTG(String Oio!file!name; 
			Integer Array oheader);

Begin "PUTDDTG"

#	ENTER THE io!file!name Oio!file!name AND RETURN True If not
#	possible, Then write oheader If oheader[0]  not 0;




#------------------------------------------------------------
#	THIS SECTION OF THE PROGRAM HANDLES OUTPUT TO A DISK
#	FILE. AT EACH CALL, A 256 word BUFFER 'Oline' IS
#	PASSED TO THESE ProcedureS. THE BUFFER IS STORED IN THE 
#	IN THE INTERMEDIATE BUFFER 'ostuff' WHICH WHEN FILLED
#	WITH 270 PACKED byteS WILL BE DUMPED TO DISK FILE.
#	WHEN THE USER HAS comPLETED WRITING THE FILE, A CALL
#	TO THE Procedure closePIC WILL close THE DISK FILE
#	AND MAKE IT AVAILABLE For LATER USE.
#---------------------------------------------------------;


#------------------------------------------------------
#	THE FIRST TIME A REQUEST IS MADE TO write A 
#	A BUFFER THE FILE IS OpenED AND VARIABLES ARE
#	INITIALIZED.
#------------------------------------------------------;

  If Oflag Then Return(True);
	oword_-1;
	ostuffbytecnt_0;

"	Strip off the device name and use it instead of DSK:"
	odevice!name_"DSK";
	For i_1 Step 1 Until length(oio!file!name) Do
		If Equ(oio!file!name[i For 1],":")
			Then
			Begin "strip"
			odevice!name_oio!file!name[1 to i-1];
			oio!file!name_oio!file!name[i+1 to inf];
			End "strip";

	Open(ochannum_GETCHAN,odevice!name,'10,0,10,0,Obrchar,Oeoflag);
	ENTER(ochannum,Oio!file!name,Oeoflag);
	If Oeoflag Then RETURN (True);

	obytecount_0;

#------------------------------------------------------
#	If THE header word header[0] IS 0, A header IS not
#	TO BE WRITTEN OTHERWISE write THE header.
#-----------------------------------------------------;

	If oheader[0] neq 0 Then
		Begin "write-HEAD"

			  For Onum_0 Step 1 Until 127 Do
				Begin
				PUT8BIT(oheader[(2*Onum)] Land '377);
				PUT8BIT(oheader[(2*Onum+1)] Land '377);
				PUT8BIT(
				  ((oheader[(2*Onum)] Lsh -4) Land '360)
				Lor
				  ((oheader[(2*Onum+1)] Lsh -8) Land '017));
				End;
		End "write-HEAD";
	Oflag_TRUE;
	RETURN (false);
End "PUTDDTG";
COMMENT
.NEXT PAGE
.SSS(Procedure MAKEHEADER)
.INDEX(Procedure MAKEHEADER)
.;
Internal Simple Procedure MAKEHEADER(Integer submode;
			 String Oio!file!name, com;
			 Reference Integer Array oheader);

	Begin "MAKEHEADER"

	Integer K,L,M;

	Label ext;
	INTEGER date,day,month,year;
	String S1,S2,S,SS;


#		- setup an initial header Array based on the
#		submode inFormation (see table 2), the
#		io!file!name, Comment (com) and store it in oheader.;

#	[MH.1] ZERO THE header;
	ARRCLR(oheader);

#	[MH.2] TEST For ILLEGAL submode;
	If not(1 leq submode leq 16) Then 
			Begin "FAILED"
			OUTSTR("ILLEGAL DDTG submode!"&CRLF);
			RETURN;
			End "FAILED";

#	[WH.3] START PACKING SUBFIELDS (A) THROUGH (H);
	CASE submode OF
	  Begin "SET (i)"
		Begin "0 - illegal"
		Outstr("NEVER IN MAKHEADER"&crlf);
		End "0 - illegal";
		Begin "1- BM 8-BIT"
			oheader[0]_7;
			oheader[1]_171;
			oheader[2]_16;
			oheader[3]_0;
			oheader[4]_'0203;
			oheader[5]_1;
			oheader[6]_0;
			oheader[7]_0;
			oheader[8]_0;
		End "1- BM 8-BIT";
		Begin "2- BM 16-BIT"
			oheader[0]_7;
			oheader[1]_342;
			oheader[2]_16;
			oheader[3]_0;
			oheader[4]_'0403;
			oheader[5]_2;
			oheader[6]_3;
			oheader[7]_0;
			oheader[8]_0;
		End "2- BM 16-BIT";
		Begin "3 mask"
			oheader[0]_10;
			oheader[1]_8;
			oheader[2]_0;
			oheader[3]_1024;
			oheader[4]_2;
			oheader[5]_3;
			oheader[6]_1;
			oheader[7]_3;
			oheader[8]_1;
		End "3 mask";
		Begin "4 QMT"
			oheader[0]_11;
			oheader[1]_8;
			oheader[2]_0;
			oheader[3]_1018;
			oheader[4]_6;
			oheader[5]_4;
			oheader[6]_1;
			oheader[7]_4;
			oheader[8]_1;
		End "4 QMT";
		Begin "5 GRAF-PEN 10-BIT VECTOR"
			oheader[0]_12;
			oheader[1]_0;
			oheader[2]_0;
			oheader[3]_0;
			oheader[4]_2;
			oheader[5]_5;
			oheader[6]_1;
			oheader[7]_1;
			oheader[8]_1;
		End "5 GRAF-PEN 10-BIT VECTOR";
		Begin "6 GRAF-PEN 10-BIT NOVECTOR"
			oheader[0]_12;
			oheader[1]_0;
			oheader[2]_0;
			oheader[3]_0;
			oheader[4]_2;
			oheader[5]_6;
			oheader[6]_1;
			oheader[7]_1;
			oheader[8]_1;
		End "6 GRAF-PEN 10-BIT NOVECTOR";
		Begin "7 GRAF-PEN 8-BIT VECTOR"
			oheader[0]_12;
			oheader[1]_0;
			oheader[2]_0;
			oheader[3]_0;
			oheader[4]_'0403;
			oheader[5]_7;
			oheader[6]_0;
			oheader[7]_1;
			oheader[8]_0;
		End "7 GRAF-PEN 8-BIT VECTOR";
		Begin "8 GRAF-PEN 8-BIT NOVECTOR"
			oheader[0]_12;
			oheader[1]_0;
			oheader[2]_0;
			oheader[3]_0;
			oheader[4]_'0403;
			oheader[5]_8;
			oheader[6]_0;
			oheader[7]_1;
			oheader[8]_0;
		End "8 GRAF-PEN 8-BIT NOVECTOR";
		Begin "9 256 RASTER"
			oheader[0]_13;
			oheader[1]_171;
			oheader[2]_16;
			oheader[3]_0;
			oheader[4]_'0203;
			oheader[5]_9;
			oheader[6]_0;
			oheader[7]_0;
			oheader[8]_0;
		End "9 256 RASTER";
		Begin "10 1024 RASTER"
			oheader[0]_13;
			oheader[1]_1736;
			oheader[2]_64;
			oheader[3]_0;
			oheader[4]_'0203;
			oheader[5]_10;
			oheader[6]_0;
			oheader[7]_0;
			oheader[8]_0;
		End "10 1024 RASTER";
		Begin "11 256 RASTER-maskED"
			oheader[0]_13;
			oheader[1]_171;
			oheader[2]_16;
			oheader[3]_0;
			oheader[4]_'0203;
			oheader[5]_11;
			oheader[6]_0;
			oheader[7]_0;
			oheader[8]_0;
		End "11 256 RASTER-maskED";
		Begin "12 1024 RASTER-maskED"
			oheader[0]_13;
			oheader[1]_1736;
			oheader[2]_64;
			oheader[3]_0;
			oheader[4]_'0203;
			oheader[5]_12;
			oheader[6]_0;
			oheader[7]_0;
			oheader[8]_0;
		End "12 1024 RASTER-maskED";
		Begin "13 STATE"
			oheader[0]_15;
			oheader[1]_1;
			oheader[2]_0;
			oheader[3]_0;
			oheader[4]_2;
			oheader[5]_13;
			oheader[6]_1;
			oheader[7]_4;
			oheader[8]_1;
		End "13 STATE";
		Begin "14 BINARY MASK"
			oheader[0]_16;
			oheader[1]_0;
			oheader[2]_0;
			oheader[3]_0;
			oheader[4]_12;
			oheader[5]_14;
			oheader[6]_4;
			oheader[7]_5;
			oheader[8]_0;
		End "14 BINARY MASK";
		Begin "15 VARIABLE SIZE IMAGE"
			oheader[0]_17;
			oheader[1]_0;
			oheader[2]_0;
			oheader[3]_0;
			oheader[4]_'0203;
			oheader[5]_15;
			oheader[6]_0;
			oheader[7]_0;
			oheader[8]_0;
		End "15 VARIABLE SIZE IMAGE";
		Begin "16 36-BIT PDP10 DATA"
			oheader[0]_18;
			oheader[1]_0;
			oheader[2]_0;
			oheader[3]_0;
			oheader[4]_'0301;
			oheader[5]_16;
			oheader[6]_2;
			oheader[7]_6;
			oheader[8]_1;
		End "16 36-BIT PDP10 DATA";
	  End "SET (i)";

#	[MH.4] SET THE DATE, WONDoW COORDINATES;
	call(0,"DATE");
	day_date-((date%31)*31)+1;
	month_(date%31)-(((date%31)%12)*12)+1;
	year_4+(date%(31*12));
	oheader[9]_((month Lsh 8) Land '7400)
		   Lor ((day Lsh 3) Land '0370)
		   Lor (year Land '0007);
	oheader[10]_0;
	oheader[11]_0;

#	[MH.5] CONVERT THE FILE NAME AND EXTENSION;
"	convert the name to upper case"
	ss_null;
	While length(oio!file!name) Do
	  If (k_lop(oio!file!name)) geq '141 and k leq '172
			Then ss_ss & (k-'40)
			Else ss_ss & k;
	oio!file!name_ss;

	For k_ 12 Step 1 Until 15 Do
		Begin "CVT-io!file!name"
		If (L_LOP(Oio!file!name))="." Then GOTO EXT;
		If (M_LOP(Oio!file!name))="." Then M_null;
		oheader[K]_((L Land '77) Lsh 6) Lor (M Land '77);
		End "CVT-io!file!name";

"		Do THE EXTENSION"
EXT:		L_LOP(Oio!file!name);
		M_LOP(Oio!file!name);
		oheader[K]_((L Land '77) Lsh 6) Lor (M Land '77);
#	[MH.6] CONVERT THE 72 CHARACTER Comment;
"	convert the name to upper case"
	ss_null;
	While length(com) Do
	  If (k_lop(com)) geq '141 and k leq '172
			Then ss_ss & (k-'40)
			Else ss_ss & k;
	com_ss;

	For k_ 16 Step 1 Until 51 Do
		Begin "CVT-Comment"
		L_LOP(com);
		M_LOP(com);
		oheader[K]_((L Land '77) Lsh 6) Lor (M Land '77);
		End "CVT-Comment";


	End "MAKEHEADER";
#	----------------------------------------------------;
COMMENT
.NEXT PAGE
.SSS(Procedure PUTPIX)
.INDEX(Procedure PUTPIX)
.;
Internal Boolean Simple Procedure PUTPIX(
	 Reference Integer Array image1;
	String io!file!name, com; Reference Integer Array oheader);

	Begin "PUTPIX"

	Integer i,
		ddtgtype,
		asize,
		word;


"	write out array size*4 bytes from array image."
	asize_ARRINFO(image1,0)-1;

"	Enter the output file and write the oheader"
"	note that submode 9 and 11 is the packed 256x256 galv.scan,
	only make the oheader If not 9 or 11"
	If (oheader[0]=0) or 
	   ((oheader[5] neq 9) And (oheader[5] neq 11))
		Then 
		Begin "make header"
		If asize < 16000 
			Then ddtgtype_15 
			Else ddtgtype_9;

		MAKEHEADER(ddtgtype,io!file!name,com,oheader);
		End "make header";

"	set the size"
	oheader[80]_sqrt(4*(asize+1))-1;

	If PUTDDTG(io!file!name,oheader) Then Return(True);

	For i_0 Step 1 Until asize Do
		Begin "pack 4 bytes"
		word_image1[i];
		PUT8BIT((word Lsh -27) Land '777);
		PUT8BIT((word Lsh -18) Land '777);
		PUT8BIT((word Lsh -9) Land '777);
		PUT8BIT(word Land '777);
		End "pack 4 bytes";
	CLOSEOUTDATA;
	Return (false);
	End "PUTPIX";
COMMENT
.NEXT PAGE
.SSS(Procedure PUTBMASK)
.INDEX(Procedure PUTBMASK)
.;
Internal Boolean Simple Procedure PUTBMASK(
	 Reference Integer Array mask1;
	String io!file!name, com; Reference Integer Array oheader);

	Begin "PUTBMASK"

	Integer i,
		asize,
		word;

"	write out array asize words from array mask."
	asize_ARRINFO(mask1,0)-1;

"	Enter the output file and write the oheader"
"	note that submode 14 is the packed binary mask,
	only make the oheader If not 14"
	If (oheader[0]=0) or (oheader[5] neq 14) 
		 Then MAKEHEADER(14,io!file!name,com,oheader);

"	set the mask size as (power of 2) -1"
	oheader[80]_sqrt((asize-1)*36);

	If PUTDDTG(io!file!name,oheader) Then Return(True);

For word_0 step 2 until asize Do
	Begin "pack it"
	m_mask1[word];
"	output the first word"
		PUT8BIT(m Lsh -28);
		PUT8BIT(m Lsh -20);
		PUT8BIT(m Lsh -12); 
		PUT8BIT(m Lsh -4);
"	output the 2nd word"
"	dont access array if odd"
	If (word+1) leq asize
		Then
		Begin "2nd word"
		n_mask1[word+1];
		PUT8BIT((m Lsh 4) Lor (n Lsh -32));
		PUT8BIT(n Lsh -24);
		PUT8BIT(n Lsh -16);
		PUT8BIT(n Lsh -8); 
		PUT8BIT(n);
		End "2nd word";
	End "pack it";
	CLOSEOUTDATA;
	Return (false);
	End "PUTBMASK";
COMMENT
.NEXT PAGE
.SSS(Procedure PUTBOUNDARY)
.INDEX(Procedure PUTBOUNDARY)
.;
Internal Boolean Simple Procedure PUTBOUNDARY(
	 Reference Integer Array boundary1;
	String io!file!name, com; Reference Integer Array oheader;
	Integer bnd!length);

	Begin "PUTBOUNDARY"

	Label all!Done;

	Integer i,
		asize,
		bsize,
		notthere,
		x1,
		x2,
		y1,
		y2,
		word;

"	write out array size*4 bytes from array boundary."
	asize_ARRINFO(boundary1,0)-1;

"	Enter the output file and write the oheader"
"	note that submode 7 or 8 is the packed boundary ,
	only make the oheader If not 7 or 8"
	If (oheader[0]=0) or 
	   ((oheader[5] neq 7) And (oheader[5] neq 8))
		Then 
		Begin "make header"
		MAKEHEADER(8,io!file!name,com,oheader);
		End "make header";
"	set the size"
	oheader[80]_bnd!length;

	notthere_PUTDDTG(io!file!name,oheader);
	If notthere
		 Then Return(True);

	bsize_((bnd!length+1)%2 min asize);
	For i_0 Step 1 Until bsize Do
		Begin "pack 4 bytes"
		word_boundary1[i];
		PUT8BIT(x1_((word Lsh -27) Land '777));
		PUT8BIT(y1_((word Lsh -18) Land '777));
		PUT8BIT(x2_((word Lsh -9) Land '777));
		PUT8BIT(y2_(word Land '777));
		If ((x1=0) and (y1=0)) or ((x2=0) and (y2=0))
			Then Goto All!Done;
		End "pack 4 bytes";

all!Done:	
"	write 4 more zeros for eof"
	PUT8BIT(0);
	PUT8BIT(0);
	PUT8BIT(0);
	PUT8BIT(0);
	CLOSEOUTDATA;
	Return (false);
	End "PUTBOUNDARY";
COMMENT
.NEXT PAGE
.SSS(Procedure PUTARRAY)
.INDEX(Procedure PUTARRAY)
.;
Internal Boolean Simple Procedure PUTARRAY(
		Reference Integer Array data!array;
		String io!file!name, com;
		Reference Integer Array oheader;
		Integer total!array!size, array!type, number!tuples);

	Begin "PUTARRAY"


	Integer i,
		word;

"	write out array size*3 bytes from array data!array"

"	Enter the output file and write the oheader"
"	note that submode 16  is the packed 36-bit ARRAY ,
	only make the oheader If not 16"
	If (oheader[5] neq 16)
		 Then MAKEHEADER(16,io!file!name,com,oheader);
"	set the size"
	oheader[2]_total!array!size/4096;
	oheader[3]_(total!array!size Land '7777);
	oheader[80]_array!type;
	oheader[81]_number!tuples;

	If PUTDDTG(io!file!name,oheader) 
		Then Return(True);

	For i_0 Step 1 Until total!array!size Do
		Begin "pack 3 bytes"
		word_data!array[i];
		PUT12BIT(word Lsh -24);
		PUT12BIT(word Lsh -12);
		PUT12BIT(word);
		End "pack 3 bytes";

	CLOSEOUTDATA;
	Return (false);
	End "PUTARRAY";
End "PUT";
End "IO.SAI";