BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Super User Tom
Super User

Run a simple test program.

Copy the SAS log and post it into the window that opens when you click on the Insert Code icon (looks like < / > ) on the menu bar above the text box.


So assuming the field you want to read starts at position 533 this data step will read the first observation only.  The LIST statement will dump the actual contents of the line (as seen by SAS).

The OBS=1 will make it just do one line.  If the probably is not on that line you could try looking at other lines of the file by using combination of the FIRSTOBS= and OBS= settings.

data _null_:
  infile myfile lrecl=1000 recfm=f encoding='any' obs=1;
   @533 string1 $char2.  
   @533 string2 $ascii2.
   @533 number1 pib2.
   @533 number2 s370fpib2.
 put string1= $hex4. 
   / string2= $hex4.
   / number1= comma12.
   / number2= comma12.
Obsidian | Level 7
I can do this but it is never (in my world) *simple*. The code I have been sharing is snippets from a much longer and more involved process. The file itself is a multi-record file meaning that there are four different record definitions in the file. Each record has a different layout and the file is absolutely ginormous. Plus the values that I am keying off of do not appear in every record, they are somewhat hard to find. Nonetheless I really appreciate the time you are spending on this to help me. I will try to set this up as a test and report back. Also, it is 5:11 EST and i have an appointment I need to get to. Next post will be tomorrow. Thanks again.
Super User

I haven't worked with SAS on a mainframe for a long time now, but I still work with (quasi-) mainframe data.


Just so we don't overlook anything:

  • the file is stored as FB
  • you read it with RECFM=F in SAS
  • the LRECL in SAS is the same as displayed in the PDF (program development facility)


To allow us to somehow recreate your issue, I want to ask for this: determine the line number of an offending line, and then run

data _null_;
infile ..... recfm=f lrecl=... firstobs=X obs=X;
length string $40;
i = 1;
do until (i > length(_infile_) - 40;
  string = substr(_infile_,i,40);
  put i=;
  put string $hex80.;
  i + 40;

X is your offending line number.

After that, you should have a hex listing of the input buffer of that line in the log in nicely readable 40-byte chunks, from which we can then try to recreate that input buffer and apply possible solutions, so please post the log of that step into a log box opened with this button:

Bildschirmfoto 2020-04-07 um 08.32.59.jpg

Edit out the filename if that is sensitive.

Super User Tom
Super User

@MarkATremel wrote:

Um, no offense, but I did not accept this as the solution.  This is twice now where I am not even on the page and the question I have posted is marked as solve. The first time I thought I may have done it accidentally, but not this time.


You should see a button to unselect the answer.  You might want to try a different browser if the current one is not interacting well with the site.

Super User Tom
Super User

I don't understand what the goal of this exercise is.


If you want to read and write the values without modification use the $CHAR or $VARYING informat to read and the $CHAR or $VARYING format to write.


Do you want to modify the value being read?  What type of modification are you trying to do?


Make sure that SAS is not trying to transcode the records in your source file as if they were characters stored in some encoding.  If you are reading the file using RECFM=F on the INFILE statement then that should not be a problem.  If you are not reading the file using RECFM=F then you will have other problems in addition to transcoding.  For example if you use RECFM=V and some byte that is part of a binary field happens to be the hex code '0A'x then SAS will treat that as the linrefeed character that marks the end of the record.



Obsidian | Level 7

Well, the goal is this:  I need to decipher the contents of those two bytes.  I was told that in order for me to decipher the information, I needed to evaluate the first or high order nibble separately from the lower three nibbles.  Here is what I was told:  "Convert 2 byte hex value of message to an actual condition code. Example '2118'x converts to a character value of 'E280.  You get this by taking the last three bits of the '118'x and converting them to decimal (which is 280). Then take the first bit of '2'x and concatenate '0'x to it to make '20'x which can then be converted by using the table below. You can now see that '20'x equals a decimal '32' which is an 'E' code. Overridden an overridden E280 would be seen as '2918'. As a general rule, anything over '8' in the second bit would need to have '8' subtracted from it to find out what the true suspense code was. Another example -- X'3001' which would be a 'P001'. If it were an overridden 'P001' it would look like X'3801' on the hex dumped claim."


I am not trying to defend this code or change it (which it cannot be).  The file is a million years old and has many other coded values done in similar (but always different) manners.  However, someone in my group had already done this conversion in SAS but retired last year and did not tell anyone where the code is to decipher this mess.  So, I am sure it is just hitting on the right informat and conversion statement or function to get me a string that contains the hex equivalent of the value I read in.  Of course, now that I have this lovely problem to solve, I too am considering retirement!!!  (Just kidding....)

Super User Tom
Super User

They don't seem to understand the difference between a bit and nibble.   A bit is one binary digit.  A nibble is 4 binary digits.  There are 8 bits in a bytes and two nibbles in a byte.  There are 16 bits in two bytes and 4 nibbles in 2 bytes.


Let's look at the two byte string with the hex code of '2118'x.  If you read that using S370FPIB informat you get the number 8,472. If you take the remainder when dividing by 16**3 you get the 3 least significant digits, which is 280.

If you want the first nibble take integer value of dividing by 16**3.  If you want to treat that as a digit in the 16s place of your hex number then just multiply by 16.  Or subtract the number you found that has the last three nibbles and divide by 2**8 to remove the second byte (which will be all zeros).

102   data test;
103     string='2118'x ;
104     number = input(string,s370fpib2.);
105     number1 = mod(number,16**3);
106     number2 = (number - number1)/256;
107     put (_all_) (=/);
108     format string $hex4.;
109   run;



Obsidian | Level 7
This was what eventually got me the right answer. I was able to see the results more clearly than when I used other methods (like Proc Print) to see the results. Thank you Tom, for your patience and persistence in helping me to resolve this gnarly problem.
Obsidian | Level 7
Oh. And the file is FB. And I have double and triple checked the position of the fields. Those are not the problems. It is interpreting the packed values as a string that is challenging me.


Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.


Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 23 replies
  • 4 in conversation