The goal of the SCPlugin project is to integrate Subversion into the Mac OS X Finder.
- Support for Subversion.
- Access to commonly used source control operations via contextual menu [screenshot]
- Dynamic icon badging for files under version control. Shows the status of your files visually. [ screenshot ]
It would appear that gigabit LAN is not! In fact it often runs at the same speed as 100Mbps LAN. Let's look at why exactly.
After configuring your network you can use the ifconfig command to see what speeds the LAN is connected. Even though 1000Mbps is reported by the card, the reality is that the overall throughtput may well be ~100Mpbs. You can try copying a large file using scp to demonstrate this.
As it turns out, in order to use a gigabit LAN you need to use CAT6 cables. CAT5 and CAT5E are not good enough. End result, the ethernet cards throttle back the speed to reduce dropped packets and errors.
You can find a good article here titled Squeeze Your Gigabit NIC for Top Performance. After tuning up the TCP parameters i found that it made no dfifference. The principal reasons behind low gigabit ethernet performance can be summed up as follows.
- Need to use CAT6 cables
- Slow Disk speed
- Limitations of the PCI bus which the gigabit ethernet cards use
You can get an idea about the disk speed using the hdparm command:
Display the disk partitions and choose the main linux partition which has the / filesystem.
# fdisk -l
Then get disk cache and disk read statistics:
# hdparm -Tt /dev/sda0
On my desktop system the sata disk perfomance is a limiting factor. These were the results:
/dev/sda1:
Timing cached reads: 9984 MB in 2.00 seconds = 4996.41 MB/sec
Timing buffered disk reads: 84 MB in 3.13 seconds = 58.49 MB/sec
Well, that equates to a raw disk read speed of 58.49 * 8 = 467Mbps which is half the speed of a gigabit LAN.
So.. NAS storage with lots of memory looks to be the way to go... If you use the right cables!
This article discusses the features in Recital that allow data to be imported and exported between platforms in Microsoft® ADO XML Format.
Overview
Extensible Markup Language, XML, is widely regarded as a lingua franca for the interchange of data. XML's text-based, platform-independent format and its integration of data and the schema to define and describe that data, make it the ideal import/export medium. Recital software provides the functionality to output the data from Recital - and other supported table formats such as FoxPro and FoxBASE - into XML file format and to import XML data into those tables' formats. Such import/export operations provide the means to exchange data with third-party applications and can also facilitate the transfer of data between Recital installations on binary-incompatible platforms.
The features examined in this article are available in Recital Terminal Developer and in the Recital Mirage and Recital Database Servers on all Recital supported platforms. Both the Recital/4GL and Recital/SQL provide XML import and export capabilities. The XML files discussed are in Microsoft® ADO XML format.
Microsoft® ActiveX® Data Objects XML Format
The ADO XML format is primarily designed for ADO Recordset persistence and ADO XML files created by Recital can be used in this way and loaded directly into ADO Recordsets. The format can, though also be used for more generic data transfer. An ADO XML file is self-contained, consisting of two sections: a schema section followed by a data section. The schema conforms to the W3C XML-Data specification and defines the data structure.
For additional information on the Microsoft® ActiveX® Data Objects XML Format, please see Appendix 1.
NOTE: The Recital XMLFORMAT setting should always be in its default setting of ADO for ADO XML Format operations.
set xmlformat to ADO
SQL
Recital/SQL offers the ability to export data into XML files using the SELECT and FETCH statements and import from XML using the CREATE TABLE and INSERT statements.
SQL: Exporting
The SELECT...SAVE AS XML statement allows the complete result set from a SELECT statement to be saved as an XML file. This could be a complete table:
open database southwind SELECT * from orders SAVE AS XML orders.xml
or a more complex multi-table query:
open database southwind
SELECT orders.orderid, orders.customerid,;
employees.employeeid, employees.lastname, employees.firstname,;
orders.orderdate, orders.freight, orders.requireddate,;
orders.shippeddate, orders.shipvia, orders.shipname,;
orders.shipaddress, orders.shipcity,;
orders.shipregion, orders.shippostalcode, orders.shipcountry,;
customers.companyname, customers.address, customers.city,;
customers.region, customers.postalcode, customers.country;
FROM orders INNER JOIN customers;
ON customers.customerid = orders.customerid,;
orders INNER JOIN employees;
ON orders.employeeid = employees.employeeid;
SAVE AS XML orderinfo
The resulting XML file can then be further processed within the same or a different Recital environment or transferred to a third party product.
<x-ml xmlns:z="#RowsetSchema" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3- 00AA00C14882"> <s:schema id="RowsetSchema"> <s:elementtype rs:updatable="true" content="eltOnly" name="row"> <s:attributetype rs:basecolumn="orderid" rs:basetable="orders.dbf" rs:write="true" rs:nullable="true" rs:number="1" name="orderid"> <s:datatype rs:fixedlength="true" rs:precision="14" rs:scale="0" dt:maxlength="10" rs:dbtype="numeric" dt:type="number"> </s:datatype></s:attributetype> <s:attributetype rs:basecolumn="customerid" rs:basetable="orders.dbf" rs:write="true" rs:nullable="true" rs:number="2" name="customerid"> <s:datatype rs:fixedlength="true" dt:maxlength="5" rs:dbtype="str" dt:type="string"> </s:datatype></s:attributetype> <s:attributetype rs:basecolumn="employeeid" rs:basetable="orders.dbf" rs:write="true" rs:nullable="false" rs:number="3" name="employeeid"> <s:datatype rs:fixedlength="true" rs:precision="20" rs:scale="0" dt:maxlength="10" rs:dbtype="numeric" dt:type="number"> </s:datatype></s:attributetype> <s:attributetype rs:basecolumn="lastname" rs:basetable="orders.dbf" rs:write="true" rs:nullable="false" rs:number="4" name="lastname"> <s:datatype rs:fixedlength="true" dt:maxlength="20" rs:dbtype="str" dt:type="string"> </s:datatype></s:attributetype> <s:attributetype rs:basecolumn="firstname" rs:basetable="orders.dbf" rs:write="true" rs:nullable="false" rs:number="5" name="firstname"> <s:datatype rs:fixedlength="true" dt:maxlength="10" rs:dbtype="str" dt:type="string"> </s:datatype></s:attributetype> <s:attributetype rs:basecolumn="orderdate" rs:basetable="orders.dbf" rs:write="true" rs:nullable="true" rs:number="6" name="orderdate"> <s:datatype rs:fixedlength="true" dt:maxlength="10" rs:dbtype="Date" dt:type="Date"> </s:datatype></s:attributetype> <s:attributetype name="freight" ...
Click image to display full size
Fig 1: Microsoft® Office Excel 2003: orderinfo.xml.
For data accessed through a Recital Database Gateway, such as Oracle, MySQL or PostgreSQL, the FETCH command can be used to save a cursor results set into an XML file:
// Connect to MySQL Database 'mydata' via Recital Database Gateway
nStatHand=SQLSTRINGCONNECT("mys@mysql1:user1/pass1-mydata",.T.)
if nStatHand < 1
dialog box [Could not connect]
else
DECLARE cursor1 CURSOR FOR;
SELECT account_no, last_name, first_name FROM example
OPEN cursor1
FETCH cursor1 INTO XML exa1.xml
SQLDISCONNECT(nStatHand)
endif
SQL: Importing
The CREATE TABLE statement allows a new table to be created based on the structure defined in an XML file. The data from the XML file can optionally be loaded into this new table if the LOAD keyword is included. For example, a new 'orderinfo' table can be created and populated with data from the orderinfo.xml file created by the SELECT...SAVE AS XML statement shown earlier:
open database southwind
SELECT orders.orderid, orders.customerid,;
employees.employeeid, employees.lastname, employees.firstname,;
orders.orderdate, orders.freight, orders.requireddate,;
orders.shippeddate, orders.shipvia, orders.shipname,;
orders.shipaddress, orders.shipcity,;
orders.shipregion, orders.shippostalcode, orders.shipcountry,;
customers.companyname, customers.address, customers.city,;
customers.region, customers.postalcode, customers.country;
FROM orders INNER JOIN customers;
ON customers.customerid = orders.customerid,;
orders INNER JOIN employees;
ON orders.employeeid = employees.employeeid;
SAVE AS XML orderinfo
CREATE TABLE orderinfo FROM XML orderinfo LOAD
The INSERT statement can be used to load data when the table structure already exists. Taking our earlier orderinfo.xml file again, the data can be loaded using INSERT:
open database southwind;
SELECT orders.orderid, orders.customerid,;
employees.employeeid, employees.lastname, employees.firstname,;
orders.orderdate, orders.freight, orders.requireddate,;
orders.shippeddate, orders.shipvia, orders.shipname,;
orders.shipaddress, orders.shipcity,;;
orders.shipregion, orders.shippostalcode, orders.shipcountry,;
customers.companyname, customers.address, customers.city,;
customers.region, customers.postalcode, customers.country;
FROM orders INNER JOIN customers;
ON customers.customerid = orders.customerid,;
orders INNER JOIN employees;
ON orders.employeeid = employees.employeeid;
SAVE AS XML orderinfo
CREATE TABLE orderinfo FROM XML orderinfo
INSERT INTO orderinfo FROM XML orderinfo
The examples above show the export and import in a single piece of code. To transfer data between binary-incompatible platforms, the export phase using SELECT...SAVE AS XML would be carried out on the source platform, the resulting XML file would be transferred to the target platform, then the import phase using CREATE TABLE...LOAD or CREATE TABLE + INSERT would be run on the target platform.
Recital/4GL
The Recital/4GL offers the ability to export data into XML files using the COPY TO ... TYPE XML command and import from XML using the XMLFIRST() and XMLNEXT() functions.
Recital/4GL: Exporting
The COPY TO command can be used to export data from Recital and other natively supported tables out to a wide range of formats. This includes exporting to an XML file. The '.xml' file extension is added automatically. The COPY TO command can be used to export an entire table:
open database southwind use orders copy to orders type xml
or, using the FIELDS clause and the FOR or WHILE clauses, restrict the field list and export only those records which match a particular condition:
open database southwind use orders copy to orders type xml fields orderid for year(orderdate) = 1996
Only the orderid field from those records which match the condition is exported:
<x-ml xmlns:z="#RowsetSchema" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3- 00AA00C14882"> <s:schema id="RowsetSchema"> <s:elementtype rs:updatable="true" content="eltOnly" name="row"> <s:attributetype rs:basecolumn="ORDERID" rs:basetable="ORDERS" rs:write="true" rs:nullable="true" rs:number="1" name="ORDERID"> <s:datatype rs:fixedlength="true" rs:precision="10" rs:scale="0" dt:maxlength="10" rs:dbtype="numeric" dt:type="number"> </s:datatype></s:attributetype> </s:elementtype> </s:schema> <rs:data> <z:row orderid="10248"> <z:row orderid="10249"> <z:row orderid="10250"> <z:row ...
Recital/4GL: Importing
Data from an XML file can be extracted one record at a time using the XMLFIRST() and XMLNEXT() functions. XMLFIRST() reads the first record from an XML file and loads information from the file into a series of memory variables and arrays. The record data is loaded into a one-dimensional array which is created automatically. Each element in the array contains the data for its corresponding field in string format. The field names are loaded into another automatically-created array. The XMLNEXT() function works in a similar way to deal with all the subsequent records in the XML file. The XMLCOUNT() function can be used, as in the example below, to determine how many data records the XML file has.
The Recital/4GL includes a vast range of functions for manipulation and conversion of arrays and their individual elements. In the example program below, the XMLFIRST() and XMLNEXT() functions are used to sequentially extract each record from an XML file, whose name is passed to the program as a parameter. Once loaded into an array, the data is converted to the correct Recital data type then appended into a table. The table name is also passed as a parameter.
procedure replaceit
append blank
for i = 1 to numfields
if type(field(i)) = "N"
replace &(field(i)) with val(data[&i])
elseif type(field(i)) = "D"
replace &(field(i)) with stod(data[&i])
elseif type(field(i)) = "T"
replace &(field(i)) with ctot(data[&i])
elseif type(field(i)) = "L"
replace &(field(i)) with iif(data[&i]="T",.T.,.F.)
elseif type(field(i)) = "Y"
replace &(field(i)) with val(data[&i])
else
replace &(field(i)) with data[&i]
endif
next
return
procedure starthere
parameters cTable, cFile
numfields=xmlfirst(cFile,targ,trans,where,fldnames,data)
if numfields < 1
dialog box [No records in XML file]
else
use &cTable
replaceit()
endif
numrecs = xmlcount(cFile)
if numrecs > 1
numleft = numrecs -1
for i = 1 to numleft
xmlnext(trans,where,fldnames,data)
replaceit()
next
endif
return
Alternative Import/Export Methods
Other features exist in Recital to facilitate the import and export of data:
RDDs
The RDDs, Replaceable Database Drivers, are available on Windows, Linux and all supported 32-bit UNIX platforms. They allow for the use and creation of database tables and indexes in FoxPro, dBase and Clipper formats. The file format is the same across all the platforms that support the RDDs, allowing the tables and indexes to be transferred as required. The formats are also supported by a wide range of third-party products as well as their originating database systems. For more information on the RDDs, please see the online documentation on Xbase migration and the SET FILETYPE command.
BUILD/INSTALL
These are Recital/4GL commands for the export (BUILD) and import (INSTALL) of Recital tables and their associated memo, dictionary and multiple index files in ASCII format to allow them to be transferred across binary incompatible platforms. For more information, please see the online documentation on Recital/4GL commands.
COPY Commands
The COPY TO, COPY STRUCTURE, COPY STRUCTURE EXTENDED and CREATE FROM commands can all be used to enable data to be transferred between different formats and different platforms. For more information, please see the online documentation on Recital/4GL commands.
Appendix 1: Microsoft® ActiveX® Data Objects XML Format
For detailed information on the Microsoft® ActiveX® Data Objects XML Format, please consult the following Microsoft documentation:
|
Link |
To insert code samples into your articles in joomla, you use the pre tag like this:
<pre xml:lang="xxx"> your code goes here </pre>
You can use any of the following languages for colorizing your code in articles.
recital, abap, dos, lotusscript, rails, actionscript3, dot, lscript, reg, actionscript, d, lua, robots, ada, eiffel, m68k, ruby, apache, email, make, sas, applescript, fortran, matlab, scala, apt_sources, freebasic, mirc, scheme, asm, genero, mpasm, scilab, asp, gettext, mxml, sdlbasic, autoit, glsl, mysql, smalltalk, avisynth, gml, nsis, smarty, bash, gnuplot, objc, sql, basic4gl, groovy,
ocaml-brieftcl, bf, haskell, ocaml, teraterm, blitzbasic, hq9plus, oobas, text, bnf, html4strict, oracle11, thinbasic, boo, idl, oracle8, tsql, caddcl, index.html, pascal, typoscript, cadlisp, ini, perl, vbnet, cfdg, inno, per, vb, cfm, intercal, php-brief, verilog, cil, io, php, vhdl, c_mac, java5, pic16, vim, cobol, java, pixelbender, visualfoxpro, c, javascript, plsql, visualprolog, cpp, kixtart, povray, whitespace, cpp-qt, klonec, powershell, winbatch, csharp, klonecpp, progress, xml, css, latex, prolog, xorg_conf, delphi, lisp, providex, xpp, diff, lolcode, python, z80, div, lotusformulas, qbasic
Many motherboards nowadays have integrated gigabit ethernet that use the Realtek NIC chipset.
The Realtek r8168B network card does not work out of the box in Redhat/Centos 5.3: instead of loading the r8168 driver, modprobe loads the r8169 driver, which is broken as can be seen with ifconfig which shows large amounts of dropped packets. A solution is to download the r8168 driver from the Realtek website and install it using the following steps:
Check whether the built-in driver, r8169.ko (or r8169.o for kernel 2.4.x), is installed.
# lsmod | grep r8169
If it is installed remove it.
# rmmod r8169
Download the R8168B linux driver from here into /root.
Unpack the tarball :
# cd /root
# tar vjxf r8168-8.012.00.tar.bz2
Change to the directory:
# cd r8168-8.012.00
If you are running the target kernel, then you should be able to do :
# make clean modules
# make install
# depmod -a
# insmod ./src/r8168.ko (or r8168.o in linux kernel 2.4.x)
make sure modprobe knows not to use r8169, and that depmod doesn’t find the r8169 module.
# echo "blacklist r8169" >> /etc/modprobe.d/blacklist
# mv /lib/modules/`uname -r`/kernel/drivers/net/r8169.ko \ /lib/modules/`uname -r`/kernel/drivers/net/r8169.ko.bak
You can check whether the driver is loaded by using the following commands.
# lsmod | grep r8168
# ifconfig -a
If there is a device name, ethX, shown on the monitor, the linux driver is loaded. Then, you can use the following command to activate it.
# ifconfig ethX up
After this you should not see any more dropped packets reported.
The following example connects to a Recital ODBC datasource, executes a query then outputs all the results from the resultset.
<?php
$sql = "select country from customers limit 10";
$conn = odbc_connect('Recital ODBC test', '?', '?');
$rs = odbc_exec($conn, $sql);
odbc_result_all($rs);
odbc_close($conn);
?>
Output:
<table><tr><th>Country</th></tr>
<tr><td>Germany </td></tr>
<tr><td>Mexico </td></tr>
<tr><td>Mexico </td></tr>
<tr><td>UK </td></tr>
<tr><td>Sweden </td></tr>
<tr><td>Germany </td></tr>
<tr><td>France </td></tr>
<tr><td>Spain </td></tr>
<tr><td>France </td></tr>
<tr><td>Canada </td></tr>
</table>
For information on installing and configuring the Recital Universal ODBC Driver and creating and modifying datasources, please see the Documentation section of this web site.
Note: Use of ? for the username and password on the local server is dependent on DB_LOCAL_LOGIN being enabled.
open database southwind
// open child table
use order_details order orderid in 0
// open parent table
use orders order orderid in 0
set relation to orderid into order_details
do while not eof()
? orders.orderid, order_details.productid
skip
enddo
The code above will display the productid from the first related record, but you will often want to display information from all the related records in the child or detail table as in an SQL Left Outer Join.
open database southwind
select orders.orderid, order_details.productid;
from orders left outer join order_details;
on orders.orderid = order_details.orderid
In this case, we can use a second nested DO WHILE loop, for example:
open database southwind
use order_details order orderid in 0
use orders order orderid in 0
set relation to orderid into order_details
do while not eof()
// Display first or 0 child record
? orders.orderid, order_details.productid
// Display any additional child records
do while not eof(order_details)
? orders.orderid, order_details.productid
skip in order_details
enddo
skip
enddo
Or we can use the SET SKIP command. The SET SKIP command can be used with DISPLAY, LIST and REPORT and automatically skips through all the related records in the child table.
open database southwind
use order_details order orderid in 0
use orders order orderid in 0
set relation to orderid into order_details
set skip on
set skip to order_details
list orders.orderid, order_details.productid
LIST and DISPLAY offer a number of keyword options to allow you to configure the display output. REPORT offers full column based report design.
In this article Barry Mavin, CEO and Chief Software Architect for Recital details how to Build C Extension Libraries to use with Recital.
Overview
It is possible to extend the functionaliy of Recital products using "Extension libraries" that can be written in C. These extension libraries, written using the Recital/SDK API, are dynamically loadable from all Recital 9 products. This includes:
- Recital
- Recital Server
- Recital Web
Building C Extension Libraries
You can create C wrappers for virtually any native operating system function and access these from the Recital 4GL. Unlike traditional APIs which only handle the development of C functions that are callable from the 4GL, the Recital/SDK allows you to build Classes that are accessible from all Recital products. e.g. You could create a GUI framework for Linux that handles VFP system classes!
To deploy your C Extension Libraries, copy them to the following location:
Windows:
\Program Files\Recital\extensions
Linux/Unix:
/opt/recital/extensions
Please see the Recital/SDK API Reference documentation for further details.
Sample code
Listed below is the complete example of a C Extension Library.:
////////////////////////////////////////////////////////////////////////////////
#include "mirage_demo.h"
////////////////////////////////////////////////////////////////////////////////
// Declare your functions and classes below as follows:
//
// Recital Function Name, C Function Name, Type (Function or Class)
//
#define MAX_ELEMENTS 7
static struct API_SHARED_FUNCTION_TABLE api_function_table[MAX_ELEMENTS] = {
{"schar", "fnSamplesCharacter", API_FUNCTION},
{"stype", "fnSamplesType", API_FUNCTION},
{"slog", "fnSamplesLogical", API_FUNCTION},
{"snum", "fnSamplesNumeric", API_FUNCTION},
{"sopen", "fnSamplesOpen", API_FUNCTION},
{"myclass", "clsMyClass", API_CLASS},
{NULL, NULL, -1}
};
////////////////////////////////////////////////////////////////////////////////
// Recital API initialization. This should be in only ONE of your C files
// **IT SHOULD NEVER BE EDITED OR REMOVED**
INIT_API;
///////////////////////////////////////////////////////////////////////
// This is an example of passing a character parameter and returning one.
RECITAL_FUNCTION fnSamplesCharacter(void)
{
char *arg1;
if (!_parse_parameters(PCOUNT, "C", &arg1)) {
ERROR(-1, "Incorrect parameters");
}
_retc(arg1);
}
///////////////////////////////////////////////////////////////////////
// This is an example of passing a numeric parameter and returning one.
RECITAL_FUNCTION fnSamplesNumeric(void)
{
int arg1;
if (!_parse_parameters(PCOUNT, "N", &arg1)) {
ERROR(-1, "Incorrect parameters");
}
_retni(arg1);
}
///////////////////////////////////////////////////////////////////////
// This is an example returns the data type of the parameter passed.
RECITAL_FUNCTION fnSamplesType(void)
{
char result[10];
if (PCOUNT != 1) {
ERROR(-1, "Incorrect parameters");
}
switch (_parinfo(1)) {
case API_CTYPE:
strcpy(result, "Character");
break;
case API_NTYPE:
strcpy(result, "Numeric");
break;
case API_LTYPE:
strcpy(result, "Logical");
break;
case API_DTYPE:
strcpy(result, "Date");
break;
case API_TTYPE:
strcpy(result, "DateTime");
break;
case API_YTYPE:
strcpy(result, "Currency");
break;
case API_ATYPE:
strcpy(result, "Array");
break;
default:
strcpy(result, "Unkown");
break;
}
_retc(result);
}
///////////////////////////////////////////////////////////////////////
// This is an example returns "True" or False.
RECITAL_FUNCTION fnSamplesLogical(void)
{
char result[10];
int arg1;
if (!_parse_parameters(PCOUNT, "L", &arg1)) {
ERROR(-1, "Incorrect parameters");
}
if (arg1) strcpy(result, "True");
else strcpy(result, "False");
_retc(result);
}
///////////////////////////////////////////////////////////////////////
// This example opens a table.
RECITAL_FUNCTION fnSamplesOpen(void)
{
char *arg1;
if (!_parse_parameters(PCOUNT, "C", &arg1)) {
ERROR(-1, "Incorrect parameters");
}
if (_parinfo(1) == API_CTYPE) {
_retni(COMMAND(arg1));
} else {
_retni(-1);
}
}
///////////////////////////////////////////////////////////////////////
// Define the MyClass CLASS using the API macros
///////////////////////////////////////////////////////////////////////
RECITAL_EXPORT int DEFINE_CLASS(clsMyClass)
{
/*-------------------------------------*/
/* Dispatch factory methods and return */
/*-------------------------------------*/
DISPATCH_FACTORY();
/*---------------------------------*/
/* Dispatch constructor and return */
/*---------------------------------*/
DISPATCH_METHOD(clsMyClass, Constructor);
/*--------------------------------*/
/* Dispatch destructor and return */
/*--------------------------------*/
DISPATCH_METHOD(clsMyClass, Destructor);
/*-----------------------------------*/
/* Dispatch DEFINE method and return */
/*-----------------------------------*/
DISPATCH_METHOD(clsMyClass, Define);
/*------------------------------*/
/* Dispatch SET or GET PROPERTY */
/* method for property NumValue */
/* then return. */
/*------------------------------*/
DISPATCH_PROPSET(clsMyClass, NumValue);
DISPATCH_PROPGET(clsMyClass, NumValue);
/*------------------------------*/
/* Dispatch SET or GET PROPERTY */
/* method for property LogValue */
/* then return. */
/*------------------------------*/
DISPATCH_PROPSET(clsMyClass, LogValue);
DISPATCH_PROPGET(clsMyClass, LogValue);
/*-------------------------------*/
/* Dispatch SET or GET PROPERTY */
/* method for property DateValue */
/* then return. */
/*-------------------------------*/
DISPATCH_PROPSET(clsMyClass, DateValue);
DISPATCH_PROPGET(clsMyClass, DateValue);
/*-------------------------------*/
/* Dispatch SET or GET PROPERTY */
/* method for property TimeValue */
/* then return. */
/*-------------------------------*/
DISPATCH_PROPSET(clsMyClass, TimeValue);
DISPATCH_PROPGET(clsMyClass, TimeValue);
/*-------------------------------*/
/* Dispatch SET or GET PROPERTY */
/* method for property CurrValue */
/* then return. */
/*-------------------------------*/
DISPATCH_PROPSET(clsMyClass, CurrValue);
DISPATCH_PROPGET(clsMyClass, CurrValue);
/*-------------------------------*/
/* Dispatch SET or GET PROPERTY */
/* method for property CharValue */
/* then return. */
/*-------------------------------*/
DISPATCH_PROPSET(clsMyClass, CharValue);
DISPATCH_PROPGET(clsMyClass, CharValue);
/*------------------------------*/
/* Dispatch SET or GET PROPERTY */
/* method for property ObjValue */
/* then return. */
/*------------------------------*/
DISPATCH_PROPSET(clsMyClass, ObjValue);
DISPATCH_PROPGET(clsMyClass, ObjValue);
/*-----------------------------------*/
/* If message not found return error */
/*-----------------------------------*/
OBJECT_RETERROR("Unknown message type");
}
////////////////////////////////////////////////////////////////////////////////
// Define METHOD handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_METHOD(clsMyClass, Constructor)
{
struct example_data *objectDataArea;
/* Allocate memory for objects objectData area */
objectDataArea = (struct example_data *)
malloc(sizeof(struct example_data));
if (objectDataArea == NULL) return(-1);
/* Assign the default property values */
strcpy(objectDataArea->prop_charvalue, "Test API object");
objectDataArea->prop_numvalue = 15.2827;
objectDataArea->prop_logvalue = 'F';
strcpy(objectDataArea->prop_datevalue, DATE_DATE());
strcpy(objectDataArea->prop_timevalue, DATE_DATETIME());
strcpy(objectDataArea->prop_currvalue, "15.2827");
strcpy(objectDataArea->object_name, "APIobject");
objectDataArea->prop_objvalue
= OBJECT_NEW(objectDataArea->object_name, "exception", NULL);
/* Set the object objectData area */
OBJECT_SETDATA((char *)objectDataArea);
return(0);
}
DEFINE_METHOD(clsMyClass, Destructor)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
if (objectData != NULL) {
if (objectData->prop_objvalue != NULL)
OBJECT_DELETE(objectData->prop_objvalue);
free(objectData);
objectData = NULL;
}
return(0);
}
DEFINE_METHOD(clsMyClass, Define)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
struct API_EXPRESSION result;
char buffer[512];
int rc;
/* Check the object class */
OBJECT_GETPROPERTY(objectData->prop_objvalue, "class", buffer);
rc = OBJECT_GETARG(buffer, &result);
if (result.errno == 0 && result.type == 'C'
&& strcmp(result.character, "Exception") == 0) {
switch (OBJECT_GETARGC()) {
case 1:
rc = OBJECT_GETPARAMETER(1, &result);
if (result.errno == 0 && result.type == 'C') {
OBJECT_SETARG(buffer, &result);
rc = OBJECT_SETPROPERTY(objectData->prop_objvalue,
"message", buffer);
}
break;
case 2:
rc = OBJECT_GETPARAMETER(2, &result);
if (result.errno == 0 && result.type == 'N') {
OBJECT_SETARG(buffer, &result);
rc = OBJECT_SETPROPERTY(objectData->prop_objvalue,
"errorno", buffer);
}
}
}
result.type = 'L';
result.logical = (rc == 0 ? 'T' : 'F');
OBJECT_RETRESULT(&result);
}
////////////////////////////////////////////////////////////////////////////////
// Define GET property handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_PROPERTYGET(clsMyClass, NumValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
if (objectData == NULL) return(-1);
OBJECT_RETPROPERTY('N', objectData->prop_numvalue);
}
DEFINE_PROPERTYGET(clsMyClass, LogValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
if (objectData == NULL) return(-1);
OBJECT_RETPROPERTY('L', objectData->prop_logvalue);
}
DEFINE_PROPERTYGET(clsMyClass, DateValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
if (objectData == NULL) return(-1);
OBJECT_RETPROPERTY('D', objectData->prop_datevalue);
}
DEFINE_PROPERTYGET(clsMyClass, TimeValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
if (objectData == NULL) return(-1);
OBJECT_RETPROPERTY('T', objectData->prop_timevalue);
}
DEFINE_PROPERTYGET(clsMyClass, CurrValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
if (objectData == NULL) return(-1);
OBJECT_RETPROPERTY('Y', objectData->prop_currvalue);
}
DEFINE_PROPERTYGET(clsMyClass, CharValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
if (objectData == NULL) return(-1);
OBJECT_RETPROPERTY('C', objectData->prop_charvalue);
}
DEFINE_PROPERTYGET(clsMyClass, ObjValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
if (objectData == NULL) return(-1);
OBJECT_RETPROPERTY('O', objectData->prop_objvalue);
}
////////////////////////////////////////////////////////////////////////////////
// Define SET property handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_PROPERTYSET(clsMyClass, NumValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
struct API_EXPRESSION result;
int rc = OBJECT_ERROR;
OBJECT_GETVALUE(&result);
if (result.errno == 0 && result.type == 'N') {
objectData->prop_numvalue = result.number;
rc = OBJECT_SUCCESS;
}
return(rc);
}
DEFINE_PROPERTYSET(clsMyClass, LogValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
struct API_EXPRESSION result;
int rc = OBJECT_ERROR;
OBJECT_GETVALUE(&result);
if (result.errno == 0 && result.type == 'L') {
objectData->prop_logvalue = result.logical;
rc = OBJECT_SUCCESS;
}
return(rc);
}
DEFINE_PROPERTYSET(clsMyClass, DateValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
struct API_EXPRESSION result;
int rc = OBJECT_ERROR;
OBJECT_GETVALUE(&result);
if (result.errno == 0 && result.type == 'D') {
strcpy(objectData->prop_datevalue, DATE_DTOS(result.date));
rc = OBJECT_SUCCESS;
}
return(rc);
}
DEFINE_PROPERTYSET(clsMyClass, TimeValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
struct API_EXPRESSION result;
int rc = OBJECT_ERROR;
OBJECT_GETVALUE(&result);
if (result.errno == 0 && result.type == 'T') {
strcpy(objectData->prop_timevalue, DATE_TTOS(result.datetime));
rc = OBJECT_SUCCESS;
}
return(rc);
}
DEFINE_PROPERTYSET(clsMyClass, CurrValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
struct API_EXPRESSION result;
int rc = OBJECT_ERROR;
OBJECT_GETVALUE(&result);
if (result.errno == 0 && result.type == 'Y') {
strcpy(objectData->prop_currvalue, CURR_YTOS(result.currency));
rc = OBJECT_SUCCESS;
}
return(rc);
}
DEFINE_PROPERTYSET(clsMyClass, CharValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
struct API_EXPRESSION result;
int rc = OBJECT_ERROR;
OBJECT_GETVALUE(&result);
if (result.errno == 0 && result.type == 'C') {
strcpy(objectData->prop_currvalue, result.character);
rc = OBJECT_SUCCESS;
}
return(rc);
}
DEFINE_PROPERTYSET(clsMyClass, ObjValue)
{
struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
OBJECT objvalue;
int rc = OBJECT_ERROR;
if (OBJECT_GETTYPE() == 'O') {
objvalue = OBJECT_GETOBJECT();
objectData->prop_objvalue = OBJECT_ASSIGN(objvalue, objectData->object_name);
rc = OBJECT_SUCCESS;
}
return(rc);
}