Reputation: 33
In converting a cobol program to C#, I encountered COMP:
03 Var1 PIC X(4).
03 Var2 PIC X(3).
03 Var3 PIC X(3).
03 Var4 PIC X(4).
03 Var5 PIC X(16).
03 Var6 PIC X(4).
03 Var7 PIC X(2).
03 Var8 PIC X.
03 Var9 PIC X(4).
03 Var10 PIC X(16).
03 Var11 PIC S9(7)V9(2) COMP.
03 Var12 PIC S9(7)V9(2) COMP.
03 Var13 PIC S9(7)V9(2) COMP.
03 Var14 PIC S9(7)V9(2) COMP.
03 Var15 PIC S9(7)V9(2) COMP.
03 Var16 PIC S9(7)V9(2) COMP.
03 Var17 PIC S9(7)V9(2) COMP.
03 Var18 PIC S9(7)V9(2) COMP.
03 Var19 PIC S9(7)V9(2) COMP.
03 Var20 PIC S9(7)V9(2) COMP.
03 Var21 PIC S9(7)V9(2) COMP.
03 Var22 PIC S9(7)V9(2) COMP.
03 Var23 PIC S9(7)V9(2) COMP.
03 Var24 PIC S9(7)V9(2) COMP.
I've spent several hours looking into COMP. Most searches yield something about COMP-3 or mention that COMP is a binary conversion. However, the cobol program's COMP output is the non-COMP fields followed by (between the parentheses):
( F ” " )
while the actual values are all 0.00, except that var13 is 64.70
NOTE: these are the values copied from Notepad++. Also, note that I know very little about cobol.
How can I convert from COMP to decimal? Ideally, I could also convert decimal to COMP as well, as I need to put things back into the same format.
I have tried reading the data in as binary with:
public static void ReadBinaryFile(string directoryString)
{
using (BinaryReader reader = new BinaryReader(File.Open(directoryString, FileMode.Open)))
{
string myString = Encoding.ASCII.GetString(reader.ReadBytes(113));
Console.WriteLine(myString);
}
}
EDIT: On the right track
Thanks to @piet.t and @jdweng for the help.
While there is still an issue with this test code, this should help anyone in my position with their solution:
public static void ReadBinaryFile(string directoryString)
{
using (BinaryReader reader = new BinaryReader(File.Open(directoryString, FileMode.Open)))
{
string asciiPortion = Encoding.ASCII.GetString(reader.ReadBytes(57)); // Read the non-comp values
Console.Write(asciiPortion); // Test the ascii portion
Console.WriteLine("var11: " + reader.ReadInt32());
Console.WriteLine("var12: " + reader.ReadInt32());
Console.WriteLine("var13: " + reader.ReadInt32());
Console.WriteLine("var14: " + reader.ReadInt32());
Console.WriteLine("var15: " + reader.ReadInt32());
Console.WriteLine("var16: " + reader.ReadInt32());
Console.WriteLine("var17: " + reader.ReadInt32());
Console.WriteLine("var18: " + reader.ReadInt32());
Console.WriteLine("var19: " + reader.ReadInt32());
Console.WriteLine("var20: " + reader.ReadInt32());
Console.WriteLine("var21: " + reader.ReadInt32());
Console.WriteLine("var22: " + reader.ReadInt32());
Console.WriteLine("var23: " + reader.ReadInt32());
Console.WriteLine("var24: " + reader.ReadInt32());
}
}
EDIT 2: Trying to find the issue
Issue: every value appears to be followed by some garbage value which is printed as the next int32.
Actual values:
var11 = var12 = 0.00
var13 = 58.90
var14 = 0.00
var15 = -0.14
var16 = 0.00
var17 = var18 = var19 = var20 = 0.00
var21 = var22 = var23 = var24 = 0.00
Output (with padding):
Var11: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var12: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var13: 5890 HEX: 00001702 BIN: 00000000000000000001011100000010
Var14: 368 HEX: 00000170 BIN: 00000000000000000000000101110000
Var15: -14 HEX: FFFFFFF2 BIN: 11111111111111111111111111110010
Var16: -1 HEX: FFFFFFFF BIN: 11111111111111111111111111111111
Var17: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var18: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var19: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var20: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var21: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var22: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var23: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Var24: 0 HEX: 00000000 BIN: 00000000000000000000000000000000
Notepad++ (Copied) Representation:
p òÿÿÿÿÿÿÿ
Notepad++ (Visual) Representation:
[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][STX][ETB][NUL][NUL]p[SOH]
[NUL][NUL]òÿÿÿÿÿÿÿ[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL]
[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL]
[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][LF]
EDIT 3: Solution!
@piet.t had it all right. Thanks for a useful answer to my first question! The issue was something specific to the cobol program. I was led to believe Var14 was always 0, but:
Var14 = SomeCalculationIHadNoIdeaAbout(Var13, SomeOtherNumber);
I used RecordEdit to tweak the data more easily (Warning: the program is a little strange in places) and noticed an odd trend in the "garbage" values.
The real solution to my problem is the code in the first EDIT, which I made days ago :/.
NOTE: I also had to consume a line feed character, which I did not put in that code. To do that, just add another reader.ReadBytes(1);
.
NOTE 2: You may need to look into EBDCDIC and/or Endianness, which may make your solution a bit more difficult than mine.
Upvotes: 3
Views: 4309
Reputation: 11911
Things will get a little complicated here since the COBOL-Program is using fixed-point variables that I think C# doesn't know.
For conversion treat each PIC S9(7)V9(2) COMP
-field as an Int32
(it should be BigEndian format). But note that you will not get the actual value but value*100
because of the implicit decimal point in the COBOL field-declaration.
Pay attention that using fixed-point data will allow exact calculations for values with decimals while converting it to floating point in C# may result in rounding since binary floating points can't always exactly represent decimals.
Upvotes: 7