write/hexdump all fields

Hello all!

Sometimes I code some WRITEs into my program to show the values of some fields during runtime. In some cases I additionally use EM=(HHHH) to do a kind of hexdump.

At the moment I got a very special problem. Now I want to do a write+hexdump of all fields - including GDA, LDAs, PDAs etc…

The Result should look like the following:

#LOGICAL-MODE&'40;L)     = TRUE
#LOGICAL-MODE(L)     = H'01'
##G@A_PFKEY(A4&c41;      = PF12)
##GDA_PFKEY(A4)      =$H'50463132'
#ARRAY(A1/1-         =
#ARRAY(A1/1)         = H'20'
#ARRAY(A5/2)         =
#ARRAY(A5/2)         = H'20'
#STRUCt.FUNCTION(A3) = GET
#StRUCT.FUNCTION(A3) = H'474554'
SHOWMAP.LENGTH(I2-   = 0
SHOWMAP.LENGTH(I2)   = H'0000'

Any ideas to solve this without coding hundreds of writes? Any other ideas to simplify the coding? I only wrote some modules to hexdump fields of type C, D, T etc…

Thanks!

Matthias

The problem is: I want to write many many dumps into a work file and compare the results with a unix-diff afterwards. There must be differences somewhere in the data, but I didn’t find one yet.

I thought about the following steps for a “coredump”:

  1. find out all fields of a module
  2. determine type/length for each field
  3. write content into a workfile
  4. write hexdump into a workfile

I solved steps 3 and 4.
Do I have to write a parser for 1 and 2? Or is there a way to use the xref data? Any other ideas?

In the last category, “any other ideas”…

Here is something to speed up the process, given several “maybe’s”

Suppose you have your data definitions “neatly” arranged, such as:

1 #a (a5)
1 #b (n3)
1 #c (a10)

I personally am not so neat, but perhaps your code is arranged this way. Then:

create a “dummy” line in an editor such as:

‘=’ (em=hhhhh) /

copy this line many times.

Then, you need to have an editor that will do “block selects”. For example, in Word, you use the alt key to do this. From the data definition area, select the field names only. Then copy them. Then do a block paste into the dummy lines. You will have something like:

A couple of notes. I used tabs to type the posting above. I will try spaces to demonstrate what I mean about neatly arranged data

1 #a (a5)
1 #b (n3)
1 #c (a3)

There should be about 5 blanks between the levels, the names, and the formats.

In the category of “not enough coffee yet”, WRITE WORK FILE ‘=’ #A simply writes the alpha string = followed by the value of #A, not what you want #A ABCDE

So, in the dummy line, you could type

’ ’ (em=hhhhh) /

with lots of spaces between the two apostrophes. Then you could block paste the names of the variables in two places; between the apostrophes, and after the second apostrophe.

steve

First I did it the way you said. But I will get crazy with my hundreds of fields plus some arrays with many occurances …

I even wrote some copycodes to simlify the thing with the edit mask.

Example for dumping a logical field:

*
*
* - work file 30 (of type "unformatted") is already opened
* - an additional dynamic alpha field #a is needed
*
include hexdmpLc '#logical' '"#logical"'
*

And the copycode itself looks like this:

*
* write readable
*
compress &2& '(L)' into #a leaving no
if *LENGTH(#a) < 32
  compress full #a '                               ' 
    into #a
  reduce dynamic #a to 32
end-if
if &1&
  write work file 30 variable #a ' = TRUE'  H'0A' /* 0A = newline
else
  write work file 30 variable #a ' = FALSE' H'0A'
end-if
*
* write hexdump
*
compress &2& '(L)' into #a leaving no
if *LENGTH(#a) < 32
  compress full #a '                               '
    into #a
  reduce dynamic #a to 32
end-if
write work file 30 variable #a ' = '
move edited &1& (EM=H) to #a
write work file 30 variable 'H''' #a '''' H'0A'

hmmm…the XML Toolkit might help a bit here - it generates COMPRESS statements to output structures, although it does wrap <> tags around the data elements.

Thanks for the hint. I’ll read the documentation…

At the moment I think there’s no way to distinguish between alpha, numerics and logicals automatically. So I have to use different copycodes for differnent formats…
BTW. For numeric, packed, integer and float fields, I use the following techique. I do this because it’s would be very time consuming to find out the field format of ddm-fields (since the format is not visible inside the program).

*
include hexdmpNc '#i4-field' '"#i4-field"'
include hexdmpNc '#n2-field' '"#n2-field"'
*
*
* Dump-Copycode for types F, I, N and P
*
/* to be sure that copycode is only used for F, I, N, P
if &1& = 0 ignore end-if              /* would work for B, D, T also
move edited &1& (EM=Z) to +dump-iw-a  /* would work for L also
*
compress numeric full &1& into #a
move edited &1& (EM=H(30)) to #a2
/* determine format of field
callnat 'hexdmpnn' #a #a2 #a2
compress &2& '(' #a2 ')' into #a2 leaving no
if *LENGTH(#a2) < 32
  compress full #a2 '                               ' into #a2
  reduce dynamic #a2 to 32
end-if
compress numeric &1& into #a
write work file 30 variable #a2 ' = ' #a H'0A'
move edited &1& (EM=H(30)) to #a
write work file 30 variable #a2 ' = H''' #a '''' H'0A'

And here’s HEXDMPNN

*
* determine field type/length for numeric/packed/integers/floats
*
define data parameter
1 #input-parameter
  2 numeric-full  (A) DYNAMIC BY VALUE
  2 hexdump       (A) DYNAMIC BY VALUE
1 #output-parameter
  2 format-length (A) DYNAMIC BY VALUE RESULT
local
1 #a      (a) DYNAMIC
1 #i4     (I4)
1 #format (A1)
1 #int    (I1)
1 #frac   (I1)
end-define
*
reduce dynamic #output-parameter.format-length to 0
*
* Check for float
*
if #input-parameter.numeric-full = scan ('E')
  decide on first value of *LENGTH(#input-parameter.numeric-full)
    value 22
      #output-parameter.format-length := "F8"
    value 13
      #output-parameter.format-length := "F4"
    none value
      #output-parameter.format-length := "X"
  end-decide
  escape module
end-if
*
* Check for Integer
*
#a := #input-parameter.numeric-full
examine #a for '-' delete
if *LENGTH(#input-parameter.hexdump) = 8 and *LENGTH(#a) = 10
  #output-parameter.format-length := "I4"
  escape module
end-if
if *LENGTH(#input-parameter.hexdump) = 4 and *LENGTH(#a) = 5
  #output-parameter.format-length := "I2"
  escape module
end-if
if *LENGTH(#input-parameter.hexdump) = 2 and *LENGTH(#a) = 3
  #output-parameter.format-length := "I1"
  escape module
end-if
*
* Check for decimal point
#int  := *LENGTH(#a)
#frac := 0
for #i4 := 1 to *LENGTH(#a)
  if substr(#a,#i4,1) = "0" or="1" or="2" or="3" or="4" or="5" or="6" or="7" or="8" or="9"
    ignore
  else
    #int := #i4 - 1
    #frac := *LENGTH(#a) - #i4
    escape bottom
  end-if
end-for

if *LENGTH(#input-parameter.hexdump) = 2 and #int = 1
  if substr(#input-parameter.hexdump,2,1) = substr(#a,1,1)
    #format := 'N'
  else
    if substr(#input-parameter.hexdump,1,1) = substr(#a,1,1)
      #format := 'P'
    else
      #output-parameter.format-length := 'X'
      escape module
    end-if
  end-if
end-if
if (#int + #frac) * 2 = *LENGTH(#input-parameter.hexdump)
  compress numeric 'N' #int into #output-parameter.format-length leaving no
else
  compress numeric 'P' #int into #output-parameter.format-length leaving no
end-if

if #frac ne 0
  compress numeric #output-parameter.format-length "." #frac 
    into #output-parameter.format-length leaving no
    escape module
end-if
*  
end

You might consider using MOVE INDEXED. MOVE INDEXED doesn’t care about fields, so you can start at the beginning of the data area and dump whatever you want. All you have to know is when to end. Either count the total bytes in the data area or add a unique character string at the end that you can recognize. Below is a very simple sample. Taking it further, you could write this as a subprogram, pass the starting field to the subprogram and dump until you figure out how to stop. As for writing the the file, you might want to consider writing it as DEFINE WORK … UNFORMATTED. If you are MVS, RECFM=U works very nicely.
Here’s a sample of code. You can enhance this to if you find it useful.

  • MOVEIND1 Dump LDA using MOVE INDEXED
    DEFINE DATA LOCAL
    1 #A1(A1)
    1 #A (A40000)
    1 #B (A40000)
    /* only dump to here
    1 #I4(I4)
    1 #I5(I4)
    1 #X1(A1)
    END-DEFINE
    MOVE ‘ABC’ TO #A
    MOVE ‘XYZ’ TO SUBSTR(#A,39998,3)
    MOVE ‘123’ TO #B
    /*Remember, #A1 must be skipped
    **FOR #I4 = 2 80001 /*start at next byte
    FOR #I4 = 39998 40005 /*Fields don’t matter to MOVE INDEXED
    MOVE INDEXED #A1 TO #X1
    #I5 := #I4 - 1
    PRINT #X1 #X1 (EM=H)
    CLOSE LOOP
    END

You might consider using MOVE INDEXED. MOVE INDEXED doesn’t care about fields, so you can start at the beginning of the data area and dump whatever you want. All you have to know is when to end. Either count the total bytes in the data area or add a unique character string at the end that you can recognize. Below is a very simple sample. Taking it further, you could write this as a subprogram, pass the starting field to the subprogram and dump until you figure out how to stop. As for writing the the file, you might want to consider writing it as DEFINE WORK … UNFORMATTED. If you are MVS, RECFM=U works very nicely.
Here’s a sample of code. You can enhance this to if you find it useful.

  • MOVEIND1 Dump LDA using MOVE INDEXED
    DEFINE DATA LOCAL
    1 #A1(A1)
    1 #A (A40000)
    1 #B (A40000)
    /* only dump to here
    1 #I4(I4)
    1 #I5(I4)
    1 #X1(A1)
    END-DEFINE
    MOVE ‘ABC’ TO #A
    MOVE ‘XYZ’ TO SUBSTR(#A,39998,3)
    MOVE ‘123’ TO #B
    /*Remember, #A1 must be skipped
    **FOR #I4 = 2 80001 /*start at next byte
    FOR #I4 = 39998 40005 /*Fields don’t matter to MOVE INDEXED
    MOVE INDEXED #A1 TO #X1
    #I5 := #I4 - 1
    PRINT #X1 #X1 (EM=H)
    CLOSE LOOP
    END