Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Embedded Systems

Your Own Endian Engine


NOV95: Your Own Endian Engine

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.
In BSD notation, the byte order for a 4-byte, Big-endian value would be 4321. The equivalent array of MAU references is {4,3,2,1}. The DEC PDP-11 (a Middle-endian machine) would have an array of MAU references of {3,4,1,2} for a 32-bit integer on that machine. (The pointer to this array must be NULL for the BigEndian and LittleEndian MAU_Order_T values.)

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.
Also, the total number of bits (MAU sizexMAU count) for the destination and source must be identical.

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.

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 "";
    }        
}


Copyright © 1995, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.