帆子
作者帆子·2021-08-29 22:13
售前技术支持·国内某服务器生产商

IBM i 上的转码程序示例

字数 6869阅读 1334评论 0赞 0

早期的 AS400 所使用的编码方案,是和 IBM 大型主机一样的 EBCDIC 。而在普通 PC 上运行的 Windows 、 Linux ,使用的编码方案则是 ASCII 。 GB2312 、 GBK 、 GB18030 这些字符集标准的推出,让汉字信息的处理能力得到了不断地提升。在主机端, GB18030 字符集所对应的代码页为 1388 ,它是一个混合代码页, 由单字节代码页 13124 和双字节代码页 4933 两部分共同组成 。相应地,而在 PC 端, GB18030 字符集所对应的代码页为 1386 ,它也是一个 混合代码页,由单字节代码页 1114 和双字节代码页 1385 两部分组成。

上世纪 90 年代,随着 Unicode ( ISO/IEC 10646 )标准的推出,各国的字符有机会在不同语言环境中得以完整准确地表达。 IBM i 系统从 V5R3 以后,就全面支持了基于 Unicode 的各种代码页,包括 UCS-2 (代码页 13488 ), UTF-16 (代码页 1200 ), UTF-8 (代码页 1208 )。

如果用户的操作局限在主机端,也就是用户是通过仿真软件来输入输出含有简体中文的信息,那么一般只需要确保在仿真软件的连接设置里选择了 GB18030 (扩展简体中文)作为主机代码页,以及选择了合适的字体(比如宋体),就能无需考虑其它因素。

如果用户的操作涉及对 PC 端的传输,那么我们就需要检查主机端的设置是否合乎规范。所谓主机端的设置,主要指的是传输处理所使用的用户,以及传输处理所涉及的文件。所谓的合乎规范,主要是希望用户的 COUNTRYID 为 CN , LANGID 为 CHS , CCSID 为 1388 (或者是 65535 );而用以存放简体中文的文件及字段的 CCSID 也应为 1388 ,或者是那些 Unicode 代码页。如果上述要求得以满足,那么无论是 ODBC 或是 JDBC ,期间的数据传输将选择的转码方式,整个转码过程对用户透明的,完全无需用户干预。

当然,有时候也需要我们显式地进行转码,比如当我们需要将信息分发给 UNIX 平台的时候,可能需要我们将相关信息转换成 UNIX 系统可以接收的代码。在 IBM i 上,有两个涉及代码转换的主要 API , iconv() 和 QDCXLATE() ,这也是我们的转码程序示例所要展示的。

首先是 iconv() 。下面的我们的示例程序,其主要作用就是针对我们所关心那几个字符,将它们的 1200 ( UTF-16 )代码,转换为 1388 ( GB18030_Host )和 1386 ( GB18030_PC )中相对应的代码:

#include <stdio.h>
#include <string.h>
#include <iconv.h>

void x1200t1386(char *tostr, char *fromstr, size_t inbyte) {

  static char fromcode[]="IBMCCSID01200000000000000000000000";
  static char tocode[]=  "IBMCCSID01386000000000000000000000";

  iconv_t cond;
  char **ptostr, **pfromstr;
  size_t outbyte=inbyte;
  size_t *pinbyte, *poutbyte;

  ptostr=&tostr;   pfromstr=&fromstr;
  pinbyte=&inbyte; poutbyte=&outbyte;

  cond=iconv_open(tocode, fromcode);
  iconv(cond, pfromstr, pinbyte, ptostr, poutbyte);
  iconv_close(cond);

}

void x1200t1388(char *tostr, char *fromstr, size_t inbyte) {

  static char fromcode[]="IBMCCSID01200000000000000000000000";
  static char tocode[]=  "IBMCCSID01388000000000000000000000";

  iconv_t cond;
  char **ptostr, **pfromstr;
  size_t outbyte=inbyte+2;
  size_t *pinbyte, *poutbyte;

  ptostr=&tostr;   pfromstr=&fromstr;
  pinbyte=&inbyte; poutbyte=&outbyte;

  cond=iconv_open(tocode, fromcode);
  iconv(cond, pfromstr, pinbyte, ptostr, poutbyte);
  iconv_close(cond);

}

void getcode(unsigned char i, unsigned char j, \\
             char *sc, char *tc1, char *tc2)
{
  unsigned int s, t1, t2;

  s=i*256+j;
  sc[0]= i;
  sc[1]= j;
  sc[2]= '\\0';

  memset(tc1, 0x00, 3);
  memset(tc2, 0x00, 5);

  x1200t1386(tc1, sc, 2);
  t1=tc1[0]*256+tc1[1];
  x1200t1388(tc2, sc, 2);
  t2=tc2[1]*256+tc2[2];

  printf("%04x  %04x  %04x  %s\\n", s, t1, t2, tc2);

}

void main()
{

  unsigned char i, j;
  unsigned int s1200, t1386, t1388;
  char srccd1200[2+1]="";
  char tgtcd1386[2+1]="";
  char tgtcd1388[4+1]="";

  printf("C1200 C1386 C1388 GBKCHAR\\n");

  i=0x20; j=0x14;
  getcode(i, j, srccd1200, tgtcd1386, tgtcd1388);

  i=0x20; j=0x15;
  getcode(i, j, srccd1200, tgtcd1386, tgtcd1388);

  i=0xe8; j=0x1e;
  getcode(i, j, srccd1200, tgtcd1386, tgtcd1388);

  i=0xe8; j=0x2c;
  getcode(i, j, srccd1200, tgtcd1386, tgtcd1388);

  i=0x20; j=0x32;
  getcode(i, j, srccd1200, tgtcd1386, tgtcd1388);

  i=0xff; j=0x07;
  getcode(i, j, srccd1200, tgtcd1386, tgtcd1388);

  i=0x20; j=0x35;
  getcode(i, j, srccd1200, tgtcd1386, tgtcd1388);

  i=0xff; j=0x40;
  getcode(i, j, srccd1200, tgtcd1386, tgtcd1388);

}          

这是程序运行的结果:

iconv() API 非常灵活,可以指定代码转换所涉及的 from 代码页和 to 代码页。它也是在 V3R1 以后引入到 IBM i 平台上的。关于 iconv() API 的详细信息,可以参考下面的网址:

https://www.ibm.com/docs/api/v1/content/ssw_ibm_i_74/apis/iconv.htm

其次是 QDCXLATE() 。 下面的示例程序,其主要作用就是针对我们所关心那几个字符,将它们的 1388 ( GB18030_Host )代码转换为 1386 ( GB18030_PC )中相对应的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <decimal.h>
#pragma linkage(QDCXLATE,OS)

int main()
{
    decimal(5,0) inlen, buflen, outlen;
    char info[4+1]="";
    char table[10] = "Q037337437";
    char tablib[10] = "QUSRSYS   ";
    char *data  = "";
    char dbcs[10] = "*SCGBK    ";
    char shift[1] = "Y";
    char type[10] = "*EA       ";

    printf("C1388 C1386 GBKCHAR\\n");

    info[0]=0x0E;
    info[1]=0xCD;
    info[2]=0x45;
    info[3]=0x0F;
    info[4]='\\0';

    inlen  = strlen(info);
    buflen = inlen +10;
    outlen = inlen +10;

    QDCXLATE(inlen,info,table,tablib,data, \\
             buflen, outlen, dbcs, shift, type);

    printf("%2x%2x  %2x%2x  %s\\n", info[1], info[2], \\
                   data[0], data[1], info);

    info[0]=0x0E;
    info[1]=0x44;
    info[2]=0x4a;
    info[3]=0x0F;
    info[4]='\\0';

    inlen  = strlen(info);
    buflen = inlen +10;
    outlen = inlen +10;

    QDCXLATE(inlen,info,table,tablib,data, \\
             buflen, outlen, dbcs, shift, type);

    printf("%2x%2x  %2x%2x  %s\\n", info[1], info[2], \\
                   data[0], data[1], info);

    info[0]=0x0E;
    info[1]=0xce;
    info[2]=0x5f;
    info[3]=0x0F;
    info[4]='\\0';

    inlen  = strlen(info);
    buflen = inlen +10;
    outlen = inlen +10;

    QDCXLATE(inlen,info,table,tablib,data, \\
             buflen, outlen, dbcs, shift, type);

    printf("%2x%2x  %2x%2x  %s\\n", info[1], info[2], \\
                   data[0], data[1], info);

    info[0]=0x0E;
    info[1]=0xce;
    info[2]=0x6d;
    info[3]=0x0F;
    info[4]='\\0';

    inlen  = strlen(info);
    buflen = inlen +10;
    outlen = inlen +10;

    QDCXLATE(inlen,info,table,tablib,data, \\
             buflen, outlen, dbcs, shift, type);

    printf("%2x%2x  %2x%2x  %s\\n", info[1], info[2], \\
                   data[0], data[1], info);

    info[0]=0x0E;
    info[1]=0x42;
    info[2]=0x7d;
    info[3]=0x0F;
    info[4]='\\0';

    inlen  = strlen(info);
    buflen = inlen +10;
    outlen = inlen +10;

    QDCXLATE(inlen,info,table,tablib,data, \\
             buflen, outlen, dbcs, shift, type);

    printf("%2x%2x  %2x%2x  %s\\n", info[1], info[2], \\
                   data[0], data[1], info);

    info[0]=0x0E;
    info[1]=0xcd;
    info[2]=0x46;
    info[3]=0x0F;
    info[4]='\\0';

    inlen  = strlen(info);
    buflen = inlen +10;
    outlen = inlen +10;

    QDCXLATE(inlen,info,table,tablib,data, \\
             buflen, outlen, dbcs, shift, type);

    printf("%2x%2x  %2x%2x  %s\\n", info[1], info[2], \\
                   data[0], data[1], info);

    info[0]=0x0E;
    info[1]=0x42;
    info[2]=0x79;
    info[3]=0x0F;
    info[4]='\\0';

    inlen  = strlen(info);
    buflen = inlen +10;
    outlen = inlen +10;

    QDCXLATE(inlen,info,table,tablib,data, \\
             buflen, outlen, dbcs, shift, type);

    printf("%2x%2x  %2x%2x  %s\\n", info[1], info[2], \\
                   data[0], data[1], info);

}

这是程序运行的结果:

QDCXLATE() 支持的转码方式就显得相对固定了。对于简体中文,我们只能选择 *SCGBK 这个参数。另外,由于它引入 AS400 比较早,看似和 iconv() 使用的不是一个转码机制。有关 QDCXLATE() API 的详细信息,可以参考下面的网址:

https://www.ibm.com/docs/api/v1/content/ssw_ibm_i_74/apis/QDCXLATE.htm

总之。这里给出的仅仅是这两个 API ,在处理简体中文转码方面的一个示例,供大家参考。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

0

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

X社区推广