利用FML的强大威力
FML
>是字段控制语言(
style='font-size:9pt;'>Field Manipulation Language)的首字母缩写,是源自BEA Systems
>的数据打包技术。虽然
style='font-size:9pt;'>FML
>本身是一种程序设计组件,但
style='font-size:9pt;'>FML
>的最常见用途是使
style='font-size:9pt;'>Tuxedo
>应用程序中客户机和服务器之间的数据交换更方便。客户机常用
style='font-size:9pt;'>FML缓冲区传递输入信息给服务器,服务器使用缓冲区返回数据给客户机。
本文介绍在商业计算中对
style='font-size:9pt;'>FML的扩展,以增强单对象开发的
style='font-size:9pt;'>FML的可用性。商业应用要求容易编码和维护,因为商业应用支持的过程时常变化。因此,要求用来建立商业应用的
style='font-size:9pt;'>API(应用程序接口)容易学习和使用。此外,扩展的一个主要优点是支持对构造数据的处理,因为大多数的这类应用涉及到关系数据库。
style='font-size:9pt;'>
本文讨论的扩展功能集中在
style='font-size:9pt;'>FML程序设计的两个重要的方面――存储器管理和多字段处理。
style='font-size:9pt;'>
存储器管理
动态存储器管理是
style='font-size:9pt;'>C程序最常见的错误根源之一。
style='font-size:9pt;'>FML API拥有负责这一任务的应用程序代码。虽然这种灵活性有其优势,但保留由单独一个模块来处理存储器管理在主要完成编码的项目中相当危险。在内部构建一个软件层来管理存储器分配不仅开发省力,而且提高代码的整体质量。
通过分别对函数
style='font-size:9pt;'>Fadd和
style='font-size:9pt;'>Fchg进行包装可以实现这种增强作用。正如我们知道的一样,这些函数利用一个缓冲区指针作为输入参数。而包装器可能利用缓冲区指针的地址作为输入
style='font-size:9pt;'>/输出参数,并且通过调用
style='font-size:9pt;'>tpalloc和
style='font-size:9pt;'>/或者
style='font-size:9pt;'>tprealloc在内部管理存储器分配。分配规模可能有一个默认值,但调用代码应该能够通过程序修改它。
style='font-size:9pt;'>
存储器的再分配具有更大的挑战性。如果添加到缓冲区中的某个字段比包装器能够使用的分配空间大,会发生什么事呢?如果调用者需要通过检查字段的值来修改分配空间的大小,其负担与编写代码再分配存储器没有什么区别。一种可供选择的极好的方法是使包装器递归。当由于缺乏缓冲区空间,某次对
style='font-size:9pt;'>Fadd和
style='font-size:9pt;'>Fchg的调用失败时,包装器可以再分配存储器并递归调用自己。使用函数
style='font-size:9pt;'>Fneeded确定存储要求也很好。无论我们选择什么方法,我们仍然需要合适地设置再分配的空间大小,以便使再分配的频率最低。
style='font-size:9pt;'>
处理多个字段 Verdana">
商业数据通常采用由多个字段组成的构造型记录的形式。
style='font-size:9pt;'>FML API是为处理像整数和字符这样的单值简单数据类型设计的。然而,通过应用
style='font-size:9pt;'>FML动态构造数据结构的能力,可以使它支持构造数据。达到这一目的方法有多种。我们将介绍其中的一种。
利用
style='font-size:9pt;'>C语言中现有的可变参数接口可以构造一个函数,该函数可以接收多个
style='font-size:9pt;'>FML字段并通过重复调用
style='font-size:9pt;'>Fadd函数将这些字段添加到一个缓冲区中。同样,我们可以构造函数来修改和获取多个字段。只要在函数中包括一个变量指定要传递的字段的数目,调用一次函数就可以让函数添加、修改或者获取任意多个字段。
style='font-size:9pt;'>
虽然计数字段可以欺骗地告诉包装器要传递多少个字段,但字段定义字符串与函数
style='font-size:9pt;'>scanf和
style='font-size:9pt;'>printf使用的格式控制字符串类似,它具有更大的灵活性。大部分情况下,构造此字符串只需要两条语法规则。
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;
color:black;'>·
单字母标识的数据类型如下:
style='font-size:9pt;'>
字符
style='font-size:9pt;font-family:Verdana;color:black'>
对应的
style='font-size:9pt;font-family:Verdana;color:black'>FML
style='font-size:9pt;font-family:宋体; color:black'>数据类型
style='font-size:9pt;font-family:Verdana;color:black'>
C或
style='font-size:9pt;font-family:Verdana;color:black'>c
字符
style='font-size:9pt;font-family:Verdana;color:black'>
Z或
style='font-size:9pt;font-family:Verdana;color:black'>z
以空字符结束的字符串
style='font-size:9pt;font-family:Verdana;color:black'>
A或
style='font-size:9pt;font-family:Verdana;color:black'>a
C数组
style='font-size:9pt;font-family:Verdana;color:black'>
S或
style='font-size:9pt;font-family:Verdana;color:black'>s
短整型
style='font-size:9pt;font-family:Verdana;color:black'>
L或
style='font-size:9pt;font-family:Verdana;color:black'>l
长整型
style='font-size:9pt;font-family:Verdana;color:black'>
F或
style='font-size:9pt;font-family:Verdana;color:black'>f
单精度浮点数
style='font-size:9pt;font-family:Verdana;color:black'>
D或
style='font-size:9pt;font-family:Verdana;color:black'>d
双精度浮点数
style='font-size:9pt;font-family:Verdana;color:black'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
大写表示必要的字段,小写表示可选字段。当我们从缓冲区中获取字段时,这种差别非常重要。通过指定某个字段是否是强制输入字段,可以增强函数的错误处理能力。
style='font-size:9pt;'>
虽然上述规则提供了大部分我们所需要的功能,但所提出的体系结构为扩充提供了无限的可能性。下边举几个例子:
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
可以使用带有字段类型的计数字段进一步明确并保持字段定义字符串较短。
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
可以添加括号将一组字段分组并指定一个常规的计数字段。例如:
style='font-size:9pt;'>"2(cL)"与 Verdana">"ccLL"
>相同。
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
可以将
style='font-size:9pt;'>FML数据类型分成子类,以创建应用程序专用的数据类型,例如日期、社会保险号等。
style='font-size:9pt;'>
>
>对于添加到缓冲区中的每一个字段,需要传递如下参数:
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
FML字段ID
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
字段值
style='font-size:9pt;'>
对于从缓冲区中获取的每个字段,需要传递如下参数
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
FML字段ID
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
保存读取值的适当变量的指针。
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
上述变量的字节数
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
说明对该字段读取是否成功的整型变量的地址
style='font-size:9pt;'>
代码实例
>作为结论,我们简单地复习一下来自一个实际实现的一些代码段。这些例子的代码基础是一个
style='font-size:9pt;'>C语言库,该库实现上述的
style='font-size:9pt;'>FML API扩展功能。虽然此库包括几个函数,但我们集中在其中的两个函数――
style='font-size:9pt;'>FmlGet (Fget的包装
style='font-size:9pt;'>)和
style='font-size:9pt;'>FmlAdd (Fadd的包装
style='font-size:9pt;'>)上。这两个函数的原型如下
style='font-size:9pt;'>:
int FmlGet ( char *pBuf, int iOcc, char *pzFldSpec, char *pzErrTxt, … );
style='color:black'> int FmlAdd ( char **ppBuf, char *pzFldSpec, char *pzErrTxt, … );
这两个函数都允许传递多个
style='font-size:9pt;'>FML字段。
style='font-size:9pt;'>FmlAdd在内部管理存储器分配。为了保持应用程序接口简单,在原型函数中,用字符指针代替了
style='font-size:9pt;'>FML缓冲区指针。这些函数在内部处理强制类型转换。
style='font-size:9pt;'>
下述调用从一个缓冲区中获取一组字段:
style='font-size:9pt;'>
iErrCd = FmlGet ( pFmlBuf, /* Pointer to buffer to be read */
0, /* Occurrence number to be read */
"LZz", /* Field specification string */
zErrMsg, /* Buffer to receive error message */
/* Variable arguments providing filed-wise parameters */
FLD_INV_NUM, &lInvNum, sizeof long, &iInvNumFound,
FLD_CUST_NM, zCustNm, size of zCustNm, &iCustNmFound,
FLD_INV_DESC, zInvDesc, sizeof zInvDesc, &iInvDescFOund );
前三个参数容易理解,并且加上了简单的注释。在此例中,字段定义字符串的值指定函数应该读取一个长整型字段、两个字符串类型字段,并且指定长整型字段和一个字符串类型字段是必要的输入。对于每个要读取的字段,调用包括
style='font-size:9pt;'>4个参数。这些参数是:
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
FML字段ID
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
接收读取数据的变量的地址
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
上述变量可以保存的数据的字节数
style='font-size:9pt;'>
style='font-size:10.0pt;font-family:Symbol;color:black;
'>·
返回时,表明该字段读取是否成功的整型变量的地址。
style='font-size:9pt;'>
下边给出的第二个调用的例子说明如何向一个缓冲区中添加多个字段。
style='font-size:9pt;'>
iErrCd = FmlAdd ( &pFmlBuf, /* FML buffer pointer address */
"LZ", /* Field specification string */
zErrMsg, /* Buffer to receive error message */
/* Variable arguments providing filed-wise parameters */
FLD_INV_NUM, 100,
FLD_CUST_NM, "ABC Inc" );
第一个参数是一个缓冲区指针的指针。因为如果需要,这个函数重新为该缓冲区分配存储空间。第二和第三个参数与函数
style='font-size:9pt;'>FmlGet相同。至于可变参数,对于每一个要添加的字段,这个函数只需要两个输入――字段
style='font-size:9pt;'>ID和字段的值。
style='font-size:9pt;'>
特别感谢
style='font-size:9pt;'>Anthony Dolce技术上的帮助、工作上的鼓励,
style='font-size:9pt;'>Shekhter对新想法的支持,
style='font-size:9pt;'>Purnesh Rustagi、 Verdana">Srinivas Vemu
>、
style='font-size:9pt;'>Padma Gundampa和
style='font-size:9pt;'>Tribhuwan Kama的帮助与合作。谨以本文献给我的儿子Krishna
>和他的朋友。 |