John, a programmer in the Seattle area, can be contacted on CompuServe at 72634,2402.
Back in the days before heterogeneous networks and client/server architectures, life was relatively simple for programmers. IBM-supplied mainframes ruled the roost, a byte was eight bits, and numbers were always in Big-endian order. Now, however, there are C compilers in which char takes nine bits. There are even rumors of 10-bit byte machines. It wouldn't surprise me to see 16-bit char implementations (for Unicode) in a couple of years. Furthermore, today's computers can switch between Big- and Little-endian at boot time, and even juggle different byte orders between data and program space. Moreover, Big- and Little-endian aren't the only byte-ordering schemes--there are also Middle-endian systems, such as the DEC VAX.
Most computers address memory by byte, although word-addressable computers have been around for decades. For C programmers, the term "byte" has become shorthand for "the smallest chunk of addressable memory." The best alternative term I've seen for this is "minimum addressable unit" (MAU), from the IEEE standard for a portable object file format (MUFOM). Consequently, I now use the term "MAU order" in place of "byte order."
To alleviate the confusion caused by differing orders and sizes, I've developed an "endian engine" that handles every byte order (including every possible Middle-endian order) and every byte size, native or not. I've even used this engine to simulate a 36-bit machine with 9-bit bytes on a 32-bit machine with 8-bit bytes. In this article, I'll show how the engine can be used to implement big-integer routines. The engine and the routines are building blocks for a simulator I hope to write that would emulate Knuth's upcoming 64-bit computer (MMIX) with just about any ANSI/ISO C compiler.
Two Things Not To Do
There are a couple of familiar workarounds for the byte-ordering problems; neither is recommended, however. The first is the swab (swap bytes) function provided in many versions of UNIX, as far back as Version 7 (1979) and as recently as 4.4BSD-Lite (1994). The swab function only exchanges pairs of adjacent char values--useful in the days of the 16-bit PDP-11, but it's a relic now.
The other method is to use a union in C. However, the ANSI C standard says, "if a member of a union object is accessed after a value has been stored in a different member of the object, the behavior is implementation-defined." (Section 3.3.2.3, which also lists one exception that doesn't help this particular problem.) Elsewhere, ANSI C says that strictly conforming programs shall not depend on any implementation-defined behavior.
BSD Notation
Several schemes exist for byte-ordering notation. Both Bolsky and Plauger notations, for instance, can have a leading zero (0123 is a 4-byte, Little-endian value in Plauger notation). This can cause subtle problems in C, where a leading 0 indicates an octal value.
"BSD notation" is my name for the byte orders returned by the 4.4BSD sysctl library function. In BSD notation, 4321 is a 4-byte, Big-endian value. Leading zeros are not possible, so octal confusion is avoided. The 4.4BSD-Lite source CD-ROM (available from O'Reilly & Associates) includes various endian.h header files that define equates in this notation. (The files are for kernel use only.)
Unfortunately, since the three notations I've mentioned are all in decimal, none work well with 16-byte entities. BSD notation is handy for simple things and is available from a 4.4BSD library routine (sysctl), but it isn't powerful enough to completely describe the format of something in memory. For convenience, I've provided a way to use BSD notation with the endian engine, via a routine that accepts BSD notation.
Table 1 is a list of the byte orders for a number of systems. The list uses BSD notation where necessary. Please e-mail me any additions or corrections to the list.
Describing Memory Format
Listing Two, end.h, contains Memory_Format_T, a structure that describes the format of the memory for a given entity. Memory_Format_T has four members:
- The size of a minimum addressable unit (MAU) in bits.
- MAU_Order_T, an enum type that is shorthand for the MAU order. MAU_Order_T is declared in the rep.h header, and its values are BigEndian, LittleEndian, and MiddleEndian; see Listing One.
- The number of MAUs in the entity.
- A pointer to an array of references indicating exactly which MAU goes where. This is necessary only if MAU_Order_T is MiddleEndian.
Example 1 is C code that initializes Memory_Format_T structures for four different systems, including the Middle-endian PDP-11 and the 36-bit Honeywell 6000 (which has 9-bit char values).
Swapping "Bytes": EndSwap
The main routine in the endian engine (EndSwap) copies data and swaps MAUs as it goes. EndSwap requires two memory formats: one for the destination and another for the source. All the routines I declared in end.h can be used outside the endian engine, but EndSwap is the only one an application must call. Listing Two is the end.h source. EndSwap is in Listing Three. A call to it appears in Listing Four (the BigSwap routine).
Other Ways to Build Memory Formats
Besides building them directly in the application, I've provided two other means to create Memory_Format_T values. Given a byte order in BSD notation, EndBSDByteOrderToFormat will allocate and fill in a Memory_Format_T structure. EndLearnNativeUnsignedLongFormat will build a Memory_Format_T structure for the native unsigned long type in data space; this order may not apply in program space or to other data types. Both routines return NULL if out of memory or an error occurs. Callers should deallocate the memory allocated by those routines via the standard C free function. The source code for these functions is available electronically; see "Availability," page 3.
Big-Integer Routines
Eventually, I want the assembler and simulator that I write for the 64-bit Big-endian MMIX computer to run on my 32-bit Little-endian computer. In the middle, I envision a set of big-integer routines that would perform (at least) 64-bit integer math on any ANSI/ISO C system. The big-integer routines would be useful for compilers, debuggers, encryption, and the like. (Contact me at [email protected] if you'd like to examine the "draft standard" for these routines.) My implementation of the big-integer library uses the endian engine; other implementations may vary.
Sample big-integer routines are available electronically. The BigAdd routine adds two big integers using an optional layout. BigAdd calls BigSwap to convert each number to native layout. BigSwap uses the endian engine (EndSwap) to do the actual swap. Then BigAdd does the addition and calls BigSwap to convert the sum from native layout back to the caller's layout. The current version of BigAdd only supports one of the four usual representations for integers. In the future, I'll add support for two's complement, one's complement, and signed magnitude.
The rep.h header (Listing One) is shared between the big-integer routines and the endian engine. bigimpl.h (available electronically) and anything beginning with the prefix Big_ are not intended for use outside my big-integer code.
Endian-Engine Limitations
I faced a dilemma when I wrote the endian engine. What should it do if asked to process an entity that isn't an exact multiple of the number of bits in a char in that implementation of C? Consequently, if, when swapping data, a destination is not an integral number of char values, then:
- Destination size is rounded up to an integral number of char values.
- Additional bits of the destination have unspecified values after the swap.
- Additional bits are located as if they were simply more high-order bits in their usual positions.
Design Decisions
This version of the endian engine includes optimizations for the most common combinations of formats. EndSwap uses EndSameFormat (available electronically) to determine if a straight memory copy would be correct; if so, EndSwap calls EndCopy (also available electronically). The next optimization EndSwap tries is for simply reversed char order; it uses routines in EndRev.c (see "Availability") to check for and handle that case.
If it can't use either of those optimizations for a given case, EndSwap calls EndSmallestMoveSize to determine the maximum number of bits that it can move together in a single chunk. EndSmallestMoveSize bases this computation on the number of bits in a destination MAU, the source MAU size, and the native char size in bits. The smallest size into which those three things can be divided is the greatest common denominator (GCD) of those three numbers. EndSwap loops for each chunk of this number of bits. For the actual bit processing (such as moving groups of bits in the EndSwap routine), I use the bit-operation macros I described in my article "Bit Operations with C Macros" (Dr. Dobb's Sourcebook of PowerPC Programming, September/October 1995). The MVBITS (move bits) bitops.h macro is one used in the endian engine.
Another possible optimization would be to build a table of "moves" for any given pair of formats. Each "move" would describe a set of contiguous bits in the source and how and where that set of bits would end up in the destination. Finally, the resulting table could be ordered so that only one pass over the destination would be necessary. (Perhaps this use of fewer writes would speed up some hardware caches.) Having built the moves table for a given pair of formats, I would cache it for later use. All this may seem like a lot of work, but it would probably only need to be done once.
Picking Up the Pieces
The only missing piece of the endian engine is a routine to compute the GCD of two unsigned numbers. The book C: A Reference Manual, Third Edition, by Samuel P. Harbison and Guy L. Steele, Jr. (Prentice-Hall, 1991), provides listings of GCD functions in C. The endimpl.h header (available electronically) declares EndGCD as a function. I suspect you could "#define EndGCD gcd" or whatever the name of your GCD routine is.
You'll also need the bitops.h header (described in my previous article, which contains the MVBITS (move bits), BTEST (bit test), and IBSET (bit set) bit-operation macros.
The Future: Prevention
If you design a computer architecture, file formats, I/O interface, protocol, or the like, I strongly recommend you specify Big-endian order. In his classic paper "On Holy Wars And A Plea For Peace," Danny Cohen said:
To the best of my knowledge only the Big-Endians...have built systems with a consistent order which works across chunk-boundaries, registers, instructions and memories. I failed to find a Little-Endians' system which is totally consistent.
References
ANSI X3.159-1989. American National Standard for Information Systems--Programming Language--C.
4.4BSD-Lite Berkeley Software Distribution CD-ROM. Sebastopol, CA: O'Reilly & Associates, 1994.
Bolsky, M.I. The C Programmer's Handbook. Englewood Cliffs, NJ: Prentice-Hall, 1985.
Cohen, Danny. "On Holy Wars And A Plea For Peace." USC Information Sciences Institute (ISI) IEN 137. (April 1, 1980).
Cullens, Chane. "Serialization and MFC." Dr. Dobb's Journal (April 1995).
Erdelsky, Philip J. "Portable Byte Ordering in C++." C/C++ Users Journal (January 1995).
Fairman, William and Randal Hoff. "Cross-Platform Database Programming." Dr. Dobb's Journal (March 1995).
Gillig, James R. "Endian-Neutral Software." Dr. Dobb's Journal (October andNovember 1994).
Harbison, Samuel P. and Guy L. Steele, Jr. C: A Reference Manual, Third Edition. Englewood Cliffs, NJ: Prentice-Hall, 1991.
IEEE Std 695-1990. IEEE Standard for Microprocessor Universal Format for Object Modules.
Plauger, P.J. "You Must be Joking." Computer Language (April 1987).
Rogers, John. Draft Standard for Big Integer Routines for the C Programming Language. Draft 0.1 (December, 1994). E-mail at [email protected].
--------. "Bit Operations with C Macros." Dr. Dobb's Sourcebook of PowerPC Programming (September/October 1995).
Table 1: Byte-order master list. Notation: 4321 is Big-endian, and so on.
Copyright © 1995, Dr. Dobb's Journal
Processor OS Order References
AT&T 3B Any Big-endian Bolsky
AT&T 3B2 Any * Plauger
DEC PDP-11 Any ** Bolsky, 4.4BSD-Lite source, Cohen, Plauger
DECsystem-10 Any Big-endian Cohen
DEC VAX Any *** Bolsky, Cohen, DEC VAX-11 Programming Card, Plauger
Honeywell 6000 All **** Bolsky
HP-PA 7100 NT Little-endian Cullens
HP-PA 7100 UNIX Big-endian Cullens
IBM AS/400 Any Big-endian Gillig
IBM System/360 Any Big-endian Cohen
IBM System/370 Any Big-endian Cohen, Gillig, Plauger
Intel 80x86 Any Little-endian Bolsky, Cullens, Erdelsky, Fairman, Gillig
MIPS NT Little-endian Cullens
MIPS UNIX Big-endian Cullens
MMIX Any Big-endian Knuth (1992 draft)
Motorola 680x0 Any Big-endian Cohen, Cullens, Erdelsky, Fairman, Gillig, Plauger
NSC16000 Any Little-endian? Bolsky
NSC32016 Any ***** Plauger
PowerPC NT Little-endian Cullens, Gillig
PowerPC Any Big-endian Cullens, Gillig
RS/6000 Any Big-endian Cullens, Fairman
SPARC UNIX Big-endian Cullens
Zilog 8000 Any Big-endian Bolsky
*AT&T 3B2: Depends on where data is stored: 32-bit integer (data space) 4321
32-bit integer (program space) 1234
**DEC PDP-11: Middle-endian: 16-bit integer 12
32-bit integer 3412
32-bit float (F) 3412
64-bit float (D?) 78563412
***DEC VAX: Middle-endian: 16-bit integer 12
32-bit integer 1234
64-bit integer 12345678
128-bit integer 123456789(10)(11)(12)(13)(14)(15)(16)
32-bit float (F) 3412
64-bit float (D) 78563412
64-bit float (G) ?
128-bit float (H) ?
Packed decimal 78563412
****Honeywell: Big-endian, 36-bit system, with 9-bit characters!
*****NSC32016: Depends on where data is stored: 32-bit integer (data space) 1234
32-bit integer (program space) 4321
Example 1: Initializing Memory_Format_T structures for four different systems.
Memory_Format_T BE_36_Format; /* Big-endian 36-bit format. */
Memory_Format_T Intel_32_Bit_Format;
Memory_Format_T Motorola_32_Bit_Format;
Memory_Format_T PDP11_Format;
MAU_Number_T PDP11_Order[4] = {3,4,1,2};
/* Fill in big-endian 36-bit format, with 9-bit MAUs.
* The Honeywell 6000 uses this format.
*/
BE_36_Format.MAU_Size_In_Bits = (Bit_Number_T) 9;
BE_36_Format.MAU_Order = BigEndian;
BE_36_Format.MAU_Count = (MAU_Number_T) 4;
BE_36_Format.MAU_References_Array = NULL;
/* Fill in Intel 32-bit (little-endian) format. */
Intel_32_Bit_Format.MAU_Size_In_Bits = (Bit_Number_T) 8;
Intel_32_Bit_Format.MAU_Order = LittleEndian;
Intel_32_Bit_Format.MAU_Count = (MAU_Number_T) 4;
Intel_32_Bit_Format.MAU_References_Array = NULL;
/* Fill in Motorola 32-bit (big-endian) format. */
Motorola_32_Bit_Format.MAU_Size_In_Bits = (Bit_Number_T) 8;
Motorola_32_Bit_Format.MAU_Order = BigEndian;
Motorola_32_Bit_Format.MAU_Count = (MAU_Number_T) 4;
Motorola_32_Bit_Format.MAU_References_Array = NULL;
/* Fill in PDP-11 middle-endian format. */
PDP11_Format.MAU_Size_In_Bits = (Bit_Number_T) 8;
PDP11_Format.MAU_Order = MiddleEndian;
PDP11_Format.MAU_Count = (MAU_Number_T) 4;
PDP11_Format.MAU_References_Array = PDP11_Order;
Listing One
/* Rep.h -- Copyright (c) 1995 by JR (John Rogers). All rights reserved.
* AUTHOR - JR (John Rogers), [email protected] */
/* Gracefully allow multiple includes of this file. */
#ifndef REP_H
#define REP_H
typedef enum {
NoSign, OnesComplement, SignedMagnitude, TwosComplement
} Int_Rep_T;
typedef enum {
BigEndian, LittleEndian, MiddleEndian
} MAU_Order_T;
/* This must have a range of at least 0..64 */
typedef unsigned char Bit_Number_T;
/* This must have a range of at least 0..64 */
typedef unsigned char MAU_Number_T;
typedef struct {
MAU_Order_T MauOrder;
Int_Rep_T IntRep;
Bit_Number_T BitsPerMau;
/* This next field must be NULL if MauOrder is
* BigEndian or LittleEndian. */
MAU_Number_T * MAU_References_Array;
} Int_Rep_And_Format_T;
#endif
Listing Two
/* End.h -- Copyright (c) 1995 by JR (John Rogers). All rights reserved.
* AUTHOR - JR (John Rogers) [email protected] */
/* Gracefully allow multiple includes of this file. */
#ifndef END_H
#define END_H
/******************* I N C L U D E S *****************/
#include <boolean.h> /* Boolean_T. */
#include <rep.h> /* MAU_Number_T, etc. */
/************************ T Y P E S ******************/
typedef struct {
MAU_Order_T MAU_Order;
Bit_Number_T MAU_Size_In_Bits;
MAU_Number_T MAU_Count;
/* This next field must be NULL if MAU_Order is BigEndian or LittleEndian.
* A big-endian value would be treated as equivalent as an array of
* {4,3,2,1} values for this, if MAU_Count happens to be 4. */
MAU_Number_T * MAU_References_Array;
} Memory_Format_T;
/******************* R O U T I N E S ****************/
Memory_Format_T * /* Return NULL on error. Use free() when done. */
EndBSDByteOrderToFormat(
int Byte_Order_Digits); /* 4321 = big-endian. */
Memory_Format_T * /* Return NULL on error. Use free() when done. */
EndLearnNativeUnsignedLongFormat(
void);
/* Boolean_T
* EndMAUReferenceValid(
* MAU_Number_T ref,
* MAU_Number_T number_of_MAUs);
*/
#define EndMAUReferenceValid( ref, number_of_MAUs ) \
( \
( (ref) > (MAU_Number_T) 0 ) \
&& ( (ref) <= (number_of_MAUs) ) \
)
Boolean_T
EndSameFormat(
const Memory_Format_T * One,
const Memory_Format_T * Another);
void
EndSwap(
void * Dest,
const void * Src,
const Memory_Format_T * Dest_Format,
const Memory_Format_T * Src_Format);
/* Bit_Number_T
* EndTotalBits(
* Memory_Format_T * Format);
*/
#define EndTotalBits(Format) \
( (Bit_Number_T) ( \
((Format)->MAU_Count) \
* ((Format)->MAU_Size_In_Bits) ) )
Boolean_T
EndValidFormat(
const Memory_Format_T * Format);
#endif
Listing Three
/* EndSwap.c -- Copyright (c) 1995 by JR (John Rogers). All rights reserved.
* POLICIES - This version of the endian engine implements the
* following policies when swapping data: If a destination is not an
* integral number of parts (chars), then:
* a) the destination size is rounded up to an integral number of parts.
* b) the additional bits have unspecified values after the swap.
* The total number of bits (MAU size times MAU count) for the destination
* and source must be identical.
* AUTHOR - JR (John Rogers) [email protected]
*/
#include <assert.h> /* assert */
#include "bitops.h" /* MVBITS(). */
#include <end.h> /* EndSameFormat(). */
#include "endimpl.h" /* Moves_T, etc. */
#include <stddef.h> /* NULL */
void
EndSwap(
void * Dest,
const void * Src,
const Memory_Format_T * Dest_Format,
const Memory_Format_T * Src_Format)
{
Bit_Number_T Bits_Left;
Part_T * Dest_Parts = (Part_T *) Dest;
Bit_Number_T Dest_Total_Bits;
Bit_Number_T Low_Logical_Bit_Of_Chunk;
Bit_Number_T Smallest_Move;
const Part_T * Src_Parts = (Part_T *) Src;
Bit_Number_T Src_Total_Bits;
/* Validate caller's arguments. */
assert( EndValidFormat( Dest_Format ) );
Dest_Total_Bits = EndTotalBits(Dest_Format);
assert( Dest_Total_Bits > (Bit_Number_T) 0 );
assert( EndValidFormat( Src_Format ) );
Src_Total_Bits = EndTotalBits(Src_Format);
assert( Src_Total_Bits > (Bit_Number_T) 0 );
assert( Src_Total_Bits == Dest_Total_Bits );
assert( Src != Dest );
/* Handle easiest case: same format. */
if (EndSameFormat( Dest_Format, Src_Format)) {
EndCopy( Dest, Src, Dest_Format );
return;
}
/* Handle next most easy case: one format is reverse of the other. */
if (EndIsReversePartsFormat(Dest_Format, Src_Format)) {
EndReverseParts(
Dest, Src, EndNumberOfParts(Dest_Format) );
return;
}
/* Compute smallest chunk size we can move and not overlap two MAUs
* or two parts. */
Smallest_Move = EndSmallestMoveSize(
Dest_Format, Src_Format);
assert( Smallest_Move > (Bit_Number_T) 0 );
/* Loop for each same-size chunk. */
Low_Logical_Bit_Of_Chunk = (Bit_Number_T) 0;
for (Bits_Left = Dest_Total_Bits;
Bits_Left > (Bit_Number_T) 0;
Bits_Left = Bits_Left - Smallest_Move) {
Bit_Number_T Dest_Raw_Bit_Number_In_Part;
MAU_Number_T Dest_Raw_Part_Index;
Bit_Number_T Src_Raw_Bit_Number_In_Part;
MAU_Number_T Src_Raw_Part_Index;
assert( Low_Logical_Bit_Of_Chunk < Src_Total_Bits );
/* Find this dest bit. */
EndFindRawBit(
Low_Logical_Bit_Of_Chunk, & Dest_Raw_Part_Index,
& Dest_Raw_Bit_Number_In_Part, Dest_Format);
/* Find this source bit. */
EndFindRawBit(
Low_Logical_Bit_Of_Chunk, & Src_Raw_Part_Index,
& Src_Raw_Bit_Number_In_Part, Src_Format);
/* At last, move a chunk! */
MVBITS(
Src_Parts[Src_Raw_Part_Index], /* src */
Src_Raw_Bit_Number_In_Part, /* srcindex */
Smallest_Move, /* len */
& Dest_Parts[Dest_Raw_Part_Index], /* destptr */
Dest_Raw_Bit_Number_In_Part, /* destindex */
Part_T); /* type */
/* Bump to next chunk. */
Low_Logical_Bit_Of_Chunk += Smallest_Move;
}
}
Listing Four
/* BigSwap.c -- Copyright (c) 1995 by JR (John Rogers). All rights reserved.
* POLICIES - This version of the endian engine implements the
* following policies when swapping data: If a destination is not an
* integral number of parts (chars), then:
* a) the destination size is rounded up to an integral number of parts.
* b) the additional bits have unspecified values after the swap.
* The total number of bits (MAU size times MAU count) for the
* destination and source must be identical.
* AUTHOR - JR (John Rogers) [email protected] */
#include <assert.h> /* assert */
#include "bigimpl.h" /* Big_LayoutToFormat(). */
#include <bigint.h> /* Big_Int_T, my prototype, etc. */
#include <end.h> /* EndSameFormat(). */
#include <stddef.h> /* NULL */
void BigSwap(
Big_Int_T * Dest, const Big_Int_T * Src,
const Int_Rep_And_Format_T * Dest_Layout,
const Int_Rep_And_Format_T * Src_Layout)
{
Memory_Format_T Dest_Format;
Memory_Format_T Src_Format;
/* Set global native format, just in case. */
if ( !Big_Done_Global_Setup ) {
Big_GlobalSetup();
}
assert( Big_Native_Layout != NULL ); /* out of memory? */
assert( Big_End_Native_Format != NULL );
/* Need format (for dest) that endian engine can handle. */
if (Dest_Layout != NULL) {
Big_LayoutToFormat( &Dest_Format, Dest_Layout );
} else {
Dest_Format = *Big_End_Native_Format;
}
assert( EndValidFormat( &Dest_Format ) );
/* Repeat that for the source. */
if (Src_Layout != NULL) {
Big_LayoutToFormat( &Src_Format, Src_Layout );
} else {
Src_Format = *Big_End_Native_Format;
}
assert( EndValidFormat( &Src_Format ) );
/* Call endian engine to swap the bits. */
EndSwap(
Dest, Src, &Dest_Format, &Src_Format);
}
ORACLE CALL INTERFACE
Listing One
//////////////////////////////////////////////////////////////////////
// DBConnection Implementation
//////////////////////////////////////////////////////////////////////
#include <dbobject.h>
// Default Constructor
DBConnection::DBConnection()
{
m_pLoginCursor = 0;
Reset();
}
// Constructor with access string
DBConnection::DBConnection(const char *AccessString)
{
m_pLoginCursor = 0;
Connect(AccessString);
}
DBConnection::~DBConnection()
{
if (IsConnected()) {
Disconnect();
}
delete m_pLoginCursor;
}
short DBConnection::Disconnect()
{
if (IsConnected()) {
if (ologof(m_pLoginCursor)) {
SetDBError(m_pLoginCursor->csrarc,DBErrorMsg(m_pLoginCursor->csrrc));
SetError(-210, m_pUserName);
return 0;
}
else {
Reset();
m_nIsConnected = 0;
return 1;
}
}
else {
SetError(-203, NOLOGIN_CURSOR );
return 0;
}
}
short DBConnection::Connect(const char *pAccess)
{
if (! m_pLoginCursor) {
m_pLoginCursor = new DBOBJLOGIN;
if (!m_pLoginCursor) {
SetError(-100, ALLOCATION_ERROR);
return 0;
}
}
if (!*pAccess) {
SetError(-200, NULLACCESSS_STRING);
return 0;
}
char *pPassWrd = strchr(pAccess, '/');
if (!pPassWrd) {
SetError(-201, NOPASSWORD);
return 0;
}
pPassWrd++; // past the '/'
int UserLen = strlen(pAccess) - strlen(pPassWrd);
char User[30];
if (UserLen > 30) UserLen = 30; // truncate
strncpy(User, pAccess, UserLen-1 );
User[UserLen-1] = 0;
// Copy to member
strcpy(m_pUserName, User);
if (orlon(m_pLoginCursor, hda, (char*)pAccess)) {
SetDBError(m_pLoginCursor->csrarc, DBErrorMsg(m_pLoginCursor->csrrc) );
SetError(-205, m_pUserName);
return 0;
}
Reset();
m_nIsConnected = 1;
return 1;
}
short DBConnection::Commit()
{
if (m_pLoginCursor) {
if (ocom(m_pLoginCursor)) {
SetDBError(m_pLoginCursor->csrarc,DBErrorMsg(m_pLoginCursor->csrrc));
SetError(-206, m_pUserName);
return 0;
}
Reset();
return 1;
}
else {
SetDBError(m_pLoginCursor->csrarc,DBErrorMsg(m_pLoginCursor->csrrc));
SetError(-202, m_pUserName);
}
Reset();
return 1;
}
short DBConnection::SetAutoCommit(short OnOrOff)
{
if (m_pLoginCursor) {
if (OnOrOff == 1) {
if (ocon(m_pLoginCursor)) {
SetDBError(m_pLoginCursor->csrarc,DBErrorMsg(m_pLoginCursor->csrrc));
SetError(-206, m_pUserName);
return 0;
}
else {
Reset();
return 1;
}
}
else {
if (ocof(m_pLoginCursor)) {
SetDBError(m_pLoginCursor->csrarc,DBErrorMsg(m_pLoginCursor->csrrc));
SetError(-206, m_pUserName);
return 0;
}
else {
Reset();
return 1;
}
}
}
else {
SetDBError(m_pLoginCursor->csrarc, DBErrorMsg(m_pLoginCursor->csrrc) );
SetError(201, "No Oracle Login Object Defined");
return 0;
}
}
short DBConnection::Rollback()
{
if (m_pLoginCursor) {
if (orol(m_pLoginCursor)) {
SetDBError(m_pLoginCursor->csrarc,DBErrorMsg(m_pLoginCursor->csrrc));
SetError(-206, m_pUserName);
return 0;
}
else {
Reset();
return 1;
}
}
else {
SetDBError(m_pLoginCursor->csrarc, DBErrorMsg(m_pLoginCursor->csrrc));
SetError(201, NOLOGIN_CURSOR);
return 0;
}
}
const char* DBConnection::DBErrorMsg(int ErrorNo)
{
if (m_pLoginCursor) {
static char ExceptionBuffer[MAX_DBMSG];
memset(ExceptionBuffer,0, MAX_DBMSG);
oerhms(m_pLoginCursor, ErrorNo, ExceptionBuffer, MAX_DBMSG-1);
return ExceptionBuffer;
}
else {
SetError(-203, NOLOGIN_CURSOR);
return "";
}
}