COBOL Question - UNICODE
We are currently looking to convert our legacy COBOL code from ANSII to UNICODE however we have come across a problem where just changing the PIC X fields to PIC N and setting NSYMBOL(NATIONAL) will cause problems when data structures contain a REDEFINES or RENAME statement with elementary DATA items using PIC 9 fields.
01 WS-RECORD PIC N(26).
01 WS-RECORD-1 REDEFINES WS-RECORD.
02 WS-NUM PIC 9(6).
02 WS-DATA PIC N(20).
MOVE N"123456ABCDEFGHIJKLM" TO WS-RECORD.
In the above the string being moved will be in UTF-16 format, therefore the field WS-NUM will be corrupt as it will contain X"310032003300" which is an invalid numeric, WS-DATA will contain X"3400350036004100..etc
The question is, when using NATIONAL (UTF-16) dat开发者_如何转开发a types how can numerics be handled so as to get the correct data after it has been redefined.
I can sort of get this to work doing the following but will get invalid data in other WS-RECORD.
MOVE 123456 TO WS-NUM.
MOVE N"ABCDEFGHIJKLM" TO WS_DATA.
The above will be correct, however if I examine WS-RECORD I will see ???ABCDEFGHIJKLM where ??? is X"313233343536" in hexi-decimal.
Our problem is that we have multiple data records depending on the record type identifier, we also use redefines on many of our LINKAGE ITEMS.
Has anyone had experience moving from legacy ASCII to UNICODE?
02 WS-NUM PIC 9(6) USAGE NATIONAL.
Should work (at least on IBM compilers).
A solution suggested by MicroFocus is below:-
The size of WS-NCHAR-1 and WS-NCHAR-FIELD are different sizes because the size of “pic 9(6)” is half the size of “pic n(6)”.
So the quick but untidy solution is to place a filler and then re-correct the field by using “FUNCTION DISPLAY-OF”, although this works the customer really needs to understand that the size of “pic n” is different to “pic 9”, hence care is needed when you use redefines and during conversion.
A tweaked example that should show you what I mean in code…
01 ONE-PICN PIC N.
01 ONE-PIC9 PIC 9.
01 WS-NCHAR-FIELD PIC N(20).
01 WS-NCHAR-1 REDEFINES WS-NCHAR-FIELD.
02 WS-NUM PIC 9(6).
02 FILLER PIC X(6).
02 WS-REST PIC N(14).
DISPLAY "PIC N SIZE : " length of ONE-PICN
DISPLAY "PIC 9 SIZE : " length of ONE-PIC9
DISPLAY "WS-NCHAR-FIELD : " length of WS-NCHAR-FIELD
DISPLAY "WS-NCHAR-1 : " length of WS-NCHAR-1
DISPLAY "WS-REST : " length of WS-REST
DISPLAY "WS-NUM : " length of WS-NUM
MOVE N"123456ABCDEFGHIJKLM" TO WS-NCHAR-FIELD.
MOVE FUNCTION DISPLAY-OF(WS-NCHAR-FIELD(1:6),1252) TO WS-NUM
DISPLAY "WS-NUM : " WS-NUM DISPLAY "WS-REST : " WS-REST
The above does not work for S9(n) COMP or S9(n)V9(n) ELEMENTRY ITEMS, with VISUAL COBOL I found that I could just MOVE numeric values directly into PIC N(n) ELEMENTS and then use FUNCTION NUMVAL() to obtain the actual numeric, I am yet to try with Signed/COMP and decimal fields.
Thanks all for your help.
If I understand you correctly, you want to convert X'3000' to X'30', X'3100' to X'31, and so on, through X'3900' to X'39'.
I looked through the MicroFocus documentation, and couldn't find an intrinsic function that would do this.
You could define your own procedure to do this.
The working storage for the procedure would look like this:
01 WS-NUMERIC-CONVERSION.
05 WS-LOOP-COUNT PIC S9(04) COMP.
05 WS-NATIONAL-POSITION PIC S9(04) COMP.
05 WS-NUMBER-OF-CHARACTERS PIC S9(04) COMP.
05 WS-NATIONAL-INPUT.
10 WS-NATIONAL-INPUT-BYTE PIC X
OCCURS 40 TIMES.
05 WS-ASCII-OUTPUT.
10 WS-ASCII-OUTPUT-BYTE PIC X
OCCURS 20 TIMES.
The procedure would look like this:
NATIONAL-TO-ASCII.
PERFORM VARYING WS-LOOP-COUNT FROM 1 BY 1
UNTIL WS-LOOP-COUNT > WS-NUMBER-OF-CHARACTERS
COMPUTE WS-NATIONAL-POSITION = WS-LOOP-COUNT + WS-LOOP-COUNT - 1
MOVE WS-NATIONAL-INPUT-BYTE(WS-NATIONAL-POSITION)
TO WS-ASCII-OUTPUT-BYTE(WS-LOOP-COUNT)
END-PERFORM.
Calling the procedure would look like this:
05 WS-NATIONAL-NUMBER-X.
10 WS-NATIONAL-NUMBER PIC N(06).
05 WS-ASCII-NUMBER-X.
10 WS-ASCII-NUMBER PIC 9(06).
MOVE something TO WS-NATIONAL-NUMBER
MOVE WS-NATIONAL-NUMBER-X TO WS-NATIONAL-INPUT
MOVE +6 TO WS-NUMBER-OF-CHARACTERS
PERFORM NATIONAL-TO-ASCII
MOVE WS-ASCII-OUTPUT TO WS-ASCII-NUMBER-X
MOVE WS-ASCII-NUMBER TO something else
The procedure working storage that I defined handles a number up to 20 characters in length. If that's not enough, make the WS-NATIONAL-INPUT
and WS-ASCII-OUTPUT
fields bigger.
You can use the DISPLAY-OF FUNCTION and reference modification and add a filler to ensure the size is balanced, add a 78 to reduce magic number use!
Anyway, as I said its a bit dirty but works..
eg:
MOVE FUNCTION DISPLAY-OF(WS-RECORD-1(
1:LENGTH OF WS-RECORD(1:6)),1252)
With the updated program being:
78 NUM-SIZE VALUE 6.
01 WS-RECORD PIC N(26).
01 WS-RECORD-1 REDEFINES WS-RECORD.
02 WS-NUM PIC 9(NUM-SIZE).
02 FILLER PIC X(NUM-SIZE).
02 WS-DATA PIC N(20).
MOVE N"123456ABCDEFGHIJKLM" TO WS-RECORD.
DISPLAY "WS-NUM : " WS-NUM
DISPLAY "WS-DATA : " WS-DATA
MOVE FUNCTION DISPLAY-OF(WS-RECORD-1(
1:LENGTH OF WS-RECORD(1:NUM-SIZE)),1252)
TO WS-NUM
DISPLAY "WS-NUM : " WS-NUM
DISPLAY "WS-DATA : " WS-DATA
(updated with a better solution)
精彩评论