Multibyte Text Handling
- Last UpdatedNov 10, 2025
- 5 minute read
If a Marine project has been identified as multibyte (PROJECT MBCHARSET in the Admin module), it is possible for users to enter multibyte element names and attributes in some Marine modules. This allows Far Eastern users to enter Kanji text, which is stored in Marine as multibyte text (two bytes per Kanji character). Everything in this section referring to Kanji also applies to Chinese characters. Marine uses the name 'FECs' (Far Eastern Characters) to indicate any multibyte character text. The byte pairs correspond to the appropriate ISO-IR registration. For example, for Kanji, the byte pairs correspond to ISO-IR 87, the Japanese standard registered with the International Standards organization.
FECs text can be input to or returned by DARs routines; for example:
|
D3MNAM: |
in the CD3NAM (element name) input argument |
|
|
D3RNAM: |
in the CD3NAM (element name) return argument |
|
|
D3RTEX: |
in the CD3TEX (text attribute) return argument |
|
|
D3RPTX: |
in the CD3RPT (REPORTER text) return argument |
|
|
D3RPAT: |
in the CD3CRD (coordinate system) input argument |
Within DARs, multibyte text is input or returned as byte-pairs delimited by 'escape sequences'. These are the 'FECS-IN' and 'FECS-OUT' sequences:
|
FECS-IN sequence : |
'&~' |
(ISO 2/6, ISO 7/14) |
|
|
FECS-OUT sequence : |
'&' |
'(ISO 2/0, ISO 2/6) |
These sequences were carefully selected and meet the following criteria:
-
The FECS-IN sequence does not occur frequently in non-FECs usage
-
The FECS-OUT sequence does not exist as a byte-pair
It is possible to freely mix single-byte and multi-byte text in any text string. For example, the text string 'abc&~4A;z & def' is interpreted as follows:
3 characters ‘abc’
2 byte pairs corresponding to '4A' and ';z' (meaning 'kanji')
4 characters ' def'
Genuine occurrences of '&~' are denoted by '&&~'; so that 'abc&&~&~4A;z & def' is interpreted as:
5 characters 'abc&~'
2 byte pairs corresponding to '4A' and ';z' (meaning 'kanji')
4 characters ' def'
It is possible for the byte-pair '&~' to occur within a FECs string. Thus, 'abc&~&~4A;z & def' is interpreted as:
3 characters 'abc'
3 byte pairs corresponding to '&~', '4A' and ';z'
4 characters ' def'
Using these simple rules, Far Eastern DARs programmers should be able to convert output FECs strings from PDMS format to the format corresponding to their host computer and its peripherals (for example, for output to a Kanji terminal or printer). It is not necessary for programmers or DARs users to know the layout of the ISO-IR 87 tabulation.
The following example program may assist programmers. It is a stand-alone program, using no DARs routines. The user is prompted to enter text strings containing FECS-IN and FECS-OUT sequences. The statement converting single-byte to multibyte is machine-specific.
|
PROGRAM FECSRD |
||||||
|
C |
Program to read, translate and print FECs text |
|||||
|
C |
||||||
|
EXTERNAL FECS |
||||||
|
CHARACTER*50 STRING, FECS, STRIN2 |
||||||
|
C |
||||||
|
100 |
CONTINUE |
|||||
|
READ(*,'(A)') STRING |
||||||
|
IF (STRING .EQ. ' ') GOTO 999 |
||||||
|
STRIN2 = FECS(STRING) |
||||||
|
PRINT*, STRIN2 |
||||||
|
GOTO 100 |
||||||
|
999 |
CONTINUE |
|||||
|
CALL EXIT |
||||||
|
END |
||||||
|
CHARACTER*(*) FUNCTION FECS(STRING) |
||||||
|
C |
Function to translate FECs string |
|||||
|
C |
(machine-specific in parts) |
|||||
|
C |
||||||
|
CHARACTER*(*) STRING |
||||||
|
C |
||||||
|
INTEGER IPOS, OPOS, ILEN, OLEN, IPAIR, IPOSM1, IPOSP1 |
||||||
|
LOGICAL LFECS |
||||||
|
C |
INTRINSIC MIN, MAX, LEN, CHAR, ICHAR |
|||||
|
ILEN = LEN(STRING) |
||||||
|
OLEN = LEN(FECS) |
||||||
|
IPOS = 0 |
||||||
|
OPOS = 0 |
||||||
|
FECS = ' ' |
||||||
|
LFECS = .FALSE. |
||||||
|
100 |
CONTINUE |
|||||
|
C |
Consider first (next) character |
|||||
|
IPOS = IPOS + 1 |
||||||
|
IF (IPOS .GT. ILEN) GOTO 999 |
||||||
|
C |
Skip if remainder is blank (to save time) |
|||||
|
IF (STRING(IPOS:) .EQ. ' ') GOTO 999 |
||||||
|
OPOS = OPOS + 1 |
||||||
|
IF (OPOS .GT. OLEN) GOTO 999 |
||||||
|
IF (.NOT. LFECS) THEN |
||||||
|
C |
Not already multibyte |
|||||
|
C |
Test for FECS-IN |
|||||
|
IPOSM1 = MAX(IPOS-1, 1) |
||||||
|
IPOSP1 = MIN(IPOS+1, ILEN) |
||||||
|
IF (STRING(IPOS:IPOSP1) .EQ. '&~' |
||||||
|
+ |
.AND. STRING(IPOSM1:IPOS) .NE. '&&') THEN |
|||||
|
C |
FECS-IN found |
|||||
|
LFECS = .TRUE. |
||||||
|
IPOS = IPOS + 2 |
||||||
|
IF (IPOS .GT. ILEN) GOTO 999 |
||||||
|
IPAIR = 0 |
||||||
|
ENDIF |
||||||
|
ENDIF |
||||||
|
IF (LFECS) THEN |
||||||
|
C |
Multibyte portion of text string |
|||||
|
IPAIR = IPAIR + 1 |
||||||
|
C |
If IPAIR is odd (first of a byte-pair), test for FECS-OUT |
|||||
|
IPOSP1 = MIN(IPOS+1, ILEN) |
||||||
|
IF (2*(IPAIR/2) .NE. IPAIR |
||||||
|
+ |
.AND. STRING(IPOS:IPOSP1) .EQ. ' &') THEN |
|||||
|
C |
FECS-OUT found |
|||||
|
LFECS = .FALSE. |
||||||
|
IPOS = IPOS + 2 |
||||||
|
IF (IPOS .GT. ILEN) GOTO 999 |
||||||
|
ENDIF |
||||||
|
ENDIF |
||||||
|
C |
Copy input string to output string |
|||||
|
IF (LFECS) THEN |
||||||
|
C |
Multibyte portion of text string and not FEC-OUT |
|||||
|
C |
Convert to ASCII, add 128 to ASCII value, convert back |
|||||
|
FECS(OPOS:OPOS) = CHAR(ICHAR(STRING(IPOS:IPOS)) + 128) |
||||||
|
ELSE |
||||||
|
FECS(OPOS:OPOS) = STRING(IPOS:IPOS) |
||||||
|
ENDIF |
||||||
|
C |
Look at next character |
|||||
|
GOTO 100 |
||||||
|
C |
||||||
|
999 |
CONTINUE |
|||||
|
C |
RETURN |
|||||
|
END |
||||||
The following is a DARs example, reading FECs names and text from a FECs project. Character function FECS is the same as that listed above.
|
C------------------- |
|||||
|
PROGRAM FECDAR |
|||||
|
C------------------- |
|||||
|
C |
FECs translation test |
||||
|
CHARACTER*50 |
NAME, FECS, NAME3, CNAME, CNAME3 |
||||
|
CHARACTER*120 |
TEXT |
||||
|
CHARACTER*1 |
CDUM |
||||
|
C |
Optional declarations |
||||
|
INTEGER |
IERR, IPOS |
||||
|
EXTERNAL |
D3INIT, D3ERST, D3MMDB, D3MNAM, D3RTEX, D3RNAM |
||||
|
EXTERNAL |
D3EMSG, D3MNUM, D3FIN, D3FEND, FECS, FECST |
||||
|
C |
Project entry |
||||
|
CALL D3INIT( 'FEC', 'SYSTEM', 'XXXXXX', 'NONE', ' ', IERR ) |
|||||
|
IF (IERR.NE.0) GOTO 9000 |
|||||
|
C |
MDB Selection |
||||
|
CALL D3MMDB ( 'DES/|}~', ' ', IERR ) |
|||||
|
IF ( IERR .NE. 0 ) GOTO 9000 |
|||||
|
C |
Go to zone |
||||
|
CALL D3MNAM('/ZONE1.EQUIP', IERR) |
|||||
|
IF ( IERR .NE. 0 ) GOTO 9000 |
|||||
|
C |
Goto each equipment item and read names |
||||
|
PRINT*,'Equipment in zone /ZONE1.EQUIP:' |
|||||
|
IPOS = 0 |
|||||
|
NAME3 = ' ' |
|||||
|
100 |
CONTINUE |
||||
|
IPOS = IPOS + 1 |
|||||
|
CALL D3MNUM('EQUIP', IPOS, IERR) |
|||||
|
IF ( IERR .EQ. 203) THEN |
|||||
|
CALL D3ERST |
|||||
|
GOTO 200 |
|||||
|
ELSEIF ( IERR .NE. 0 ) THEN |
|||||
|
GOTO 9000 |
|||||
|
ENDIF |
|||||
|
CALL D3RNAM('NAME', NAME, IERR ) |
|||||
|
IF ( IERR .NE. 0 ) GOTO 9000 |
|||||
|
C |
Convert any FECs in name |
||||
|
CNAME = FECS(NAME) |
|||||
|
PRINT*, ' ', CNAME |
|||||
|
C |
Remember 3rd equipment name |
||||
|
IF (IPOS .EQ. 3) THEN |
|||||
|
NAME3 = NAME |
|||||
|
CNAME3 = CNAME |
|||||
|
ENDIF |
|||||
|
GOTO 100 |
|||||
|
200 |
CONTINUE |
||||
|
C |
|||||
|
C |
Get attributes of last equipment |
||||
|
PRINT*,'Text attributes of ', CNAME |
|||||
|
CALL FECST('DSCODE') |
|||||
|
CALL FECST('FUNCTION') |
|||||
|
CALL FECST('PTSPEC') |
|||||
|
CALL FECST('INSCHED') |
|||||
|
C |
|||||
|
C |
Go to 3rd equipment, by name - then attributes |
||||
|
IF (NAME3 .NE. ' ') THEN |
|||||
|
CALL D3MNAM(NAME3, IERR) |
|||||
|
IF ( IERR .NE. 0 ) THEN |
|||||
|
PRINT*, NAME3 |
|||||
|
GOTO 9000 |
|||||
|
ENDIF |
|||||
|
CNAME = CNAME3 |
|||||
|
NAME3 = ' ' |
|||||
|
GOTO 200 |
|||||
|
ENDIF |
|||||
|
IERR = 0 |
|||||
|
C |
|||||
|
C |
Exit |
||||
|
9000 |
CONTINUE |
||||
|
IF (IERR .NE. 0) CALL D3EMSG(IERR, .TRUE., CDUM) |
|||||
|
CALL D3FIN( IERR ) |
|||||
|
CALL D3FEND |
|||||
|
END |
|||||
|
C--------------------------- |
|||||
|
SUBROUTINE FECST(NAME) |
|||||
|
C--------------------------- |
|||||
|
C |
Subroutine to read, translate and print (possible) FECs attribute |
||||
|
C |
|||||
|
CHARACTER*(*) |
NAME |
||||
|
CHARACTER*12 |
0 TEXT, FECS, CTEXT |
||||
|
CHARACTER*1 |
CDUM |
||||
|
INTEGER |
D3ULEN, IERR |
||||
|
EXTERNAL |
D3ULEN, FECS, D3EMSG, D3ERST, D3RTEX |
||||
|
C |
CALL D3RTEX(NAME, TEXT, IERR) |
||||
|
C |
Convert any FECs in name |
||||
|
CTEXT = FECS(TEXT) |
|||||
|
IF (IERR .NE. 0) THEN |
|||||
|
CTEXT = '??????' |
|||||
|
CALL D3EMSG(IERR, .TRUE., CDUM) |
|||||
|
CALL D3ERST |
|||||
|
ENDIF |
|||||
|
IF (CTEXT .EQ. ' ') CTEXT = '**unset**' |
|||||
|
PRINT*, ' ', NAME, ': ', CTEXT(:D3ULEN(CTEXT)) |
|||||
|
RETURN |
|||||
|
END |
|||||
The output from the above program appears as follows. Since Aveva has no Kanji printer, Kanji text in this example is indicated by '@' characters.
|
Equipment in zone /ZONE1.EQUIP: |
||
|
/VESS1 |
||
|
/VESS2 |
||
|
/@@@@@@pump |
||
|
/@@@@@@@@@@@@ |
||
|
/@@@@@@ |
||
|
/@@@@@@111 |
||
|
Text attributes of /@@@@@@111 |
||
|
DSCODE: @@@@ Japan |
||
|
FUNCTION: @@@@@@@@ |
||
|
PTSPEC: Grade 1 @@@@@@ 2 coats |
||
|
INSCHED: @@@@@@ is beautiful |
||
|
Text attributes of /@@@@@@pump |
||
|
DSCODE: **unset** |
||
|
FUNCTION: **unset** |
||
|
PTSPEC: ABNS @@@@@@@@@@ abcv |
||
|
INSCHED: **unset** |
||