• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 307
  • Last Modified:

Reading variable length EBCDIC in SAS

I am trying to read an incoming mainframe file that contains a variable length field that contains EBCDIC data.

To read this field, I am currently using $VARYING informat, but this is only suitable for reading variable length ASCII fields. What I am looking for is an informat that reads a variable length field AND converts to readable format in the output.

Here is my code :-

			/* P31 - NAME_LINE_1 */
			if Bitmap_1a='..............................1.'B then
			do;
				input
				b_ADDESS_LINE_1_len $370FIB2.
				b_ADDESS_LINE_1 $VARYING23. b_ADDESS_LINE_1_len
				@;
				data_length = data_length - b_NAME_LINE_1_len - 2;
			end;

Open in new window


The problem with the above code is that it populates the output with the EBCDIC, but I need the variable field converting to ASCII. Is there a way to convert a variable length field from EBCDIC to ASCII without relying on the informat / format statements?
0
Martin r
Asked:
Martin r
  • 4
  • 2
  • 2
  • +1
1 Solution
 
ThommyCommented:
You should read the book Reading External Data Files Using SAS: Examples Handbook

Check the table of contents. There are a lot of examples including reading EBCDIC data...
0
 
ThommyCommented:
And also check this from SAS Knowledge Base...
Reading EBCDIC Files on ASCII Systems
0
 
Martin rAuthor Commented:
Thanks for the comments Thommy, but I have already looked at the recommended documentation online, and this is really a last resort for me - as there is nothing anywhere that indicates SAS is actually capable of reading variable length EBCDIC informats. In fact, I don't think it is....:-|

I have no difficulty reading  fixed-length EBCDIC fields, as well as the binary fields that specify the record-length and segment-length - this is all working. It's just there is no INFORMAT that will allow me to read and convert EBCDIC to ASCII for a variable length field.

I did just have a thought though - I could read the field as "FIXED EBCDIC" and then reset the pointer back to the correct position according to the value of the b_ADDESS_LINE_1_len field. It would only be a simple matter of chopping the surplus data from the end of the field.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
ShannonEECommented:
Even better would be -

		/* P31 - NAME_LINE_1 */
			if Bitmap_1a='..............................1.'B then
			do;
				input
				b_ADDESS_LINE_1_len $370FIB2.
				b_ADDESS_LINE_EBCDIC $VARYING23. b_ADDESS_LINE_1_len
				@;
				data_length = data_length - b_NAME_LINE_1_len - 2;
				b_ADDESS_LINE_1 = inputc(b_ADDRESS_LINE_EBCDIC,  $EBCDIC. b_ADDRESS_LINE_1_len);
			end;

Open in new window


Note that you need to specify both a type ( $ ) and max width for both

b_ADDESS_LINE_1  and
b_ADDRESS_LINE_EBCDIC

Failure to specify a width can lead to very mysterious run time problems.

Maybe that max length is 23 as you have on the $VARYING informat, but it is best also to have a statement

length   b_ADDESS_LINE_1  b_ADDRESS_LINE_EBCDIC $ 23;

Open in new window


This does the varying field length issue in the input statement and then uses the INPUTC function to do the conversion from EBCDIC.

Regards,

Ian
1
 
theo kouwenhovenCommented:
Hi Martin,

I don't know if this will help, but normally the Ebcdic to Ascii translation will be automatically don by the DB-driver, unless it's Binary-data (Bitmap).
The Varlength fields in a DB2 database has the first 2-positions filled with the length of the data.
0
 
Martin rAuthor Commented:
Thanks ShannonEE!

The solution is exactly what I was after. The solution ShannonEE provided is for RUNTIME FUNCTION to allow conversion during the loop.

http://support.sas.com/kb/50/013.html

I have managed to convert the variable length field now so can ensure the output is all formatted in ASCII. The final code was as follows :-

                  /* P31 - REFERENCIA DEL ADQUIRENTE */
                  if Bitmap_1a='..............................1.'B then
                  do;
                        input
                        b_acquirer_reference_len $EBCDIC2.
                        b_acquirer_reference_ebcdic $VARYING23. b_acquirer_reference_len
                        @;
                        data_length = data_length - b_acquirer_reference_len - 2;
                        b_acquirer_reference_ascii = inputc(b_acquirer_reference_ebcdic, "$EBCDIC23.");
                  end;

Thanks all for your help!!
0
 
Martin rAuthor Commented:
****UPDATED****

The above solution worked, but produced excessive notes due to specifying the maximum length for format. Therefore I used a concatenation to enable the length variable to be used in the format construction. The final code was as follows :-

                  /* P31 - REFERENCIA DEL ADQUIRENTE */
                  if Bitmap_1a='..............................1.'B then
                  do;
                        length b_acquirer_reference_ebcdic b_acquirer_reference_ascii $ 23;
                        input
                        b_acquirer_reference_len $EBCDIC2.
                        b_acquirer_reference_ebcdic $VARYING23. b_acquirer_reference_len
                        @;
                        data_length = data_length - b_acquirer_reference_len - 2;
                        b_acquirer_reference_ascii = inputc(b_acquirer_reference_ebcdic, "$EBCDIC" || b_acquirer_reference_len || "." );
                  end;
0
 
ShannonEECommented:
Martinr,

The posted code missed a comma.  With the INPUTC  function sas makes the format up at run time (which you did), but if you specify the 3rd parameter (which I attempted to do) then it should construct the format without any NOTES or WARNINGS.  As in

		b_ADDESS_LINE_1 = inputc(b_ADDRESS_LINE_EBCDIC,  $EBCDIC.   ,   b_ADDRESS_LINE_1_len);

Open in new window


(A comma after $EBCDIC and before b_ADDRESS_LINE_1_LEN  was missing)
I didn't test out the code because currently I don't have access to a mainframe to write test data and the code is quite specific to your situation.

As an aside, note that on the mainframe the record format and length is specified in the DCB and (from what I remember) includes F, FB, V, VB, VBA, D, DB, U, (and probably a host of other formats).  Obtaining the record length will be different for each record format.

In your case it appears that the field length is in another field within the record and so getting the record length from the data structure as read in an ASCII environment will be useless for inputting the variable length field that you need to do here.
1
 
Martin rAuthor Commented:
Thanks ShannonEE, that's a neater expression. I should point out that I am using SAS Enterprise Guide (Windows) - hence requiring the output in ASCII; so I have to specify the format in quotes.

/* P31 - REFERENCIA DEL ADQUIRENTE */
if Bitmap_1a='..............................1.'B then
do;
	length b_acquirer_reference_ebcdic b_acquirer_reference_ascii $ 23;
	input
	b_acquirer_reference_len $EBCDIC2.
	b_acquirer_reference_ebcdic $VARYING23. b_acquirer_reference_len
	@;
	data_length = data_length - b_acquirer_reference_len - 2;
	b_acquirer_reference_ascii = inputc(b_acquirer_reference_ebcdic, "$EBCDIC." , b_acquirer_reference_len);
end;

Open in new window

0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 4
  • 2
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now