Apple Swift and D-ISAM

As with any standard C library, D-ISAM is fully supported in Apple Xcode and therefore Swift as covered in Using Swift with Cocoa and Objective-C.

Pure C libraries like D-ISAM and the system libraries are core components of Objective-C, and are imported in the same way (but without most of the fuss) and the real details are covered in Interacting with C APIs.

Building D-ISAM in the Xcode IDE is a guide to working with D-ISAM in the Xcode Integrated Developer Environment, while Building D-ISAM in Xcode from the command line covers the manual installation details.

For quite sensible reasons, Swift Strings will not convert directly to character pointer arrays, unless these are declared as constant, and unfortunately the current D-ISAM library does not include this syntax, although it should. An Update for Constant Chars is available.

Makefile for D-ISAM dynamic library in Xcode

This makefile differs from a static build in the following ways:

The library filename extension is .dylib

-fPIC is added to compiler flags.

-dynamiclib is added to linker flags.

INSTALL_NAME is set to the full destination path and name of the library, as finally installed.

Without setting install_name it would be necessary to link the library directly into the install folder, or to use the install_name_tool to set this value later. The Xcode linker refers to this value when setting the library load path in your applications.

Please see Building D-ISAM in Xcode from the command line for more details.

# ------------------------------------------------------------------------
# DISAM                                                           MAKEFILE 
# ------------------------------------------------------------------------
#
# this version is designed to operate from your disam root folder,
# and does NOT require moving everything into a common folder
#
# ------------------------------------------------------------------------

INSTALL_NAME = /Library/Disam72/libdisam72.dylib

ISLIBNAME = disam72
ISLIBWHAT = shared
ISEXTWHAT = dylib
ISCFWHAT = -fPIC
ISLFWHAT =
ISCFOFFB = -D_FILE_OFFSET_BITS=64
ISLFOFFB =
ISBINLIBS =
ISCFLAGS =
ISLFLAGS =

# ------------------------------------------------------------------------

ISINCLUDE = -Ihead -Ibase -Idecs -Iutil -Itest -Iexport

NAME = $(ISLIBNAME)
WHAT = $(ISLIBWHAT)
TYPE = $(ISEXTWHAT)

WHERE= target/$(NAME)_$(WHAT)

ISAM = $(WHERE)/lib/lib$(NAME)

LIBS = -l$(NAME) $(ISBINLIBS)

CFLG = $(ISCFWHAT) $(ISCFOFFB) $(ISCFLAGS) $(CFLAGS)
LFLG = $(ISLFWHAT) $(ISLFOFFB) $(ISLFLAGS) $(LDFLAGS)

BASE =	base/isaccess.o \
	base/isapface.o \
	base/isremote.o \
	base/isadmin.o \
	base/isaudit.o \
	base/isbuild.o \
	base/ischeck.o \
	base/isclustr.o \
	base/iscomp.o \
	base/iscustom.o \
	base/isdatio.o \
	base/isdelete.o \
	base/isentry.o \
	base/iserase.o \
	base/isfree.o \
	base/isglobal.o \
	base/isgrow.o \
	base/ishead.o \
	base/isidxdel.o \
	base/isidxio.o \
	base/isindex.o \
	base/isinfo.o \
	base/iskey.o \
	base/islast.o \
	base/islocate.o \
	base/islock.o \
	base/ismemory.o \
	base/ismif.o \
	base/isnode.o \
	base/isopen.o \
	base/ispath.o \
	base/isprune.o \
	base/isread.o \
	base/isrepair.o \
	base/issquash.o \
       	base/isbytes.o \
	base/isdebug.o \
	base/issystem.o \
	base/isnetsys.o \
	base/isschema.o \
	base/istrans.o \
	base/istree.o \
	base/isunique.o \
	base/isupdate.o \
	base/isvarlen.o \
	base/iswrite.o

WRAP =	wrap/stdbuild.o \
	wrap/stdcheck.o \
	wrap/stdextra.o \
	wrap/stdinfo.o \
	wrap/stdlast.o \
	wrap/stdlock.o \
	wrap/stdmif.o \
	wrap/stdread.o \
	wrap/stdtrans.o \
	wrap/stdwrap.o \
	wrap/stdwrite.o

DECS = 	decs/dec_roun.o \
	decs/decadd.o \
	decs/deccmp.o \
	decs/decconv.o \
	decs/deccvasc.o \
	decs/decdiv.o \
	decs/dececvt.o \
	decs/decefcvt.o \
	decs/decextra.o \
	decs/decfcvt.o \
	decs/decmul.o \
	decs/decsub.o \
	decs/dectoasc.o

CO = $(CC) $(ISINCLUDE) $(CFLG)
CL = $(CC) $(LFLG) -L$(WHERE)/lib
AR = ar 
# RANLIB = $(AR) ts
RANLIB = ranlib

.c.o:
	$(CO) -c $*.c -o $*.o

$(ISAM).a:	$(BASE) $(WRAP) $(DECS)
	$(AR) r $(ISAM).$(TYPE) $(BASE) $(WRAP) $(DECS)
	$(RANLIB) $(ISAM).$(TYPE)

$(ISAM).dylib:	$(BASE) $(WRAP) $(DECS)
	$(CO) -dynamiclib $(BASE) $(WRAP) $(DECS) -o $(ISAM).$(TYPE) -install_name $(INSTALL_NAME)

lib:	$(ISAM).$(TYPE)

test_A:	test/bench.o test/auto.o test/mult.o test/user.o test/lock.o test/dups.o
	$(CL) test/auto.o test/bench.o $(LIBS) -o $(WHERE)/bin/auto_test
	$(CL) test/mult.o test/bench.o $(LIBS) -o $(WHERE)/bin/mult_test
	$(CL) test/user.o test/bench.o $(LIBS) -o $(WHERE)/bin/user_test
	$(CL) test/lock.o test/bench.o $(LIBS) -o $(WHERE)/bin/lock_test
	$(CL) test/dups.o test/bench.o $(LIBS) -o $(WHERE)/bin/dups_test

test_B:	test/mifs.o test/bash.o test/life.o
	$(CL) test/mifs.o              $(LIBS) -o $(WHERE)/bin/mifs_test
	$(CL) test/bash.o              $(LIBS) -o $(WHERE)/bin/bash_test
	$(CL) test/life.o              $(LIBS) -o $(WHERE)/bin/life_test

test:	test_A test_B

util_base: util/utility.o util/dcheck.o util/dstats.o util/dpack.o util/dbugscan.o
	$(CL) util/dcheck.o	util/utility.o	$(LIBS) -o $(WHERE)/bin/dcheck
	$(CL) util/dstats.o	util/utility.o	$(LIBS) -o $(WHERE)/bin/dstats
	$(CL) util/dpack.o	util/utility.o	$(LIBS) -o $(WHERE)/bin/dpack
	$(CL) util/dbugscan.o	                $(LIBS) -o $(WHERE)/bin/dbugscan

util_core: util/dsplit.o util/dlist.o util/dschema.o
	$(CL) util/dsplit.o	util/utility.o	$(LIBS) -o $(WHERE)/bin/dsplit
	$(CL) util/dlist.o	util/utility.o	$(LIBS) -o $(WHERE)/bin/dlist
	$(CL) util/dschema.o	util/utility.o	$(LIBS) -o $(WHERE)/bin/dschema

remote: util/disamnet.o util/dswabnet.o
	$(CL) util/disamnet.o	$(LIBS) -o $(WHERE)/bin/disamnet
	$(CL) util/dswabnet.o	$(LIBS) -o $(WHERE)/bin/dswabnet

util:	util_base util_core

export:	export/isreport.o export/isfield.o export/isload.o export/dreport.o
	$(CL) export/isreport.o export/isfield.o export/isload.o \
	      export/dreport.o $(LIBS) -o $(WHERE)/bin/dreport

check:  test
	$(WHERE)/bin/dstats
	$(WHERE)/bin/dcheck
	$(WHERE)/bin/mifs_test
	$(WHERE)/bin/bash_test
	$(WHERE)/bin/dcheck bashfile
	$(WHERE)/bin/auto_test
	$(WHERE)/bin/dcheck autofile
	rm -f autofile.dat autofile.idx
	rm -f bashfile.idx bashfile.dat

parts: lib util test check export

squeaky:
	rm -rf target/*

clean:	
	rm -rf base/*.o wrap/*.o decs/*.o test/*.o util/*.o export/*.o server/*.o

new:
	rm -rf $(WHERE)
	mkdir -p $(WHERE)/lib $(WHERE)/bin
	cp head/isconfig.h $(WHERE)

all: squeaky clean new lib util test remote

Update for Constant Chars

This replaces D-ISAM head/isbase.h and includes an option to declare char * arguments as const, where this is appropriate.

In Xcode Swift this allows String types to be passed directly to D-ISAM, as a pointer to an immutable character array.

Without this change Swift will require that all C strings are copied to a writeable first, which is wasteful in cases like file pathnames and such, where D-ISAM only needs to read the string in.

To activate this option you must define ISCONSTCHAR when including this file, for example:

#define ISCONSTCHAR 1
#include "isbase.h"
#undef ISCONSTCHAR

Download the update here.

/*
-----------------------------------------------------------------------------
isam base library header file
-----------------------------------------------------------------------------
*/

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * *
 * Worldwide Copyright (c) Byte Designs Ltd (2015) *
 * Version 7.2 (build 2015/03/10) (xcode) *
 * *
 * Byte Designs Ltd. *
 * 20568 - 32 Avenue *
 * LANGLEY, BC *
 * V2Z 2C8 CANADA *
 * *
 * Sales: sales@bytedesigns.com *
 * Support: support@bytedesigns.com *
 * Phone: (604) 534 0722 Fax: (604) 534 2601 *
 * *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */


#include "isconfig.h" /* library configuration */
#include "isintstd.h" /* see read/stdint.ref */

#include <setjmp.h> /* error handling */
#include <stdarg.h> /* standard arguments */

/* note ----------------------------------------------------------- *
 the following is pulled from a common source in the disam master,
 and is *identical* from here through #endif ISAUTOLOCK below, in
 both isbase.h and iswrap.h
 ---------------------------------------------------------------- */

#ifndef ISAUTOLOCK /* avoid multiple inclusions */

/* structures ----------------------------------------------------- */

struct keypart /* key component description */
 {
 short kp_start; /* offset within data record */
 short kp_leng; /* physical length */
 short kp_type; /* isam key type */
 };

struct keydesc /* full key description */
 {
 short k_flags; /* key characteristics */
 short k_nparts; /* number of parts in key */
 struct keypart k_part[ISMAXPARTS]; /* description of each part */
#if( defined ISINTERNAL || ISDANGEROUS )
 short k_len; /* complete key length */
 uint32_t k_rootnode; /* root node record number */
#endif
 };
 
struct dictinfo /* information about file */
 {
 short di_nkeys; /* number of indexes */
 short di_curidx; /* current index number */
 short di_recsize; /* data record (max) length */
 short di_idxsize; /* index record block size */
 uint32_t di_nrecords; /* current record count */
 };

struct audhead /* audit record header format */
 {
 char au_type[2]; /* record type (aa/dd/rr/ww) */
 char au_time[4]; /* date and time */
#if( ISLONGID == 1 )
 char au_procid[4]; /* process id */
 char au_userid[4]; /* user id */
#else
 char au_procid[2]; /* process id */
 char au_userid[2]; /* user id */
#endif
 char au_recnum[4]; /* record number */
 char au_reclen[2]; /* record length if variable */
 };

#define AUDHEADSIZE 14
#define VAUDHEADSIZE 16

/* defines ------------------------------------------------------- */

/* file handling modes */

#define ISINPUT 0x00 /* input only */
#define ISOUTPUT 0x01 /* output only */
#define ISINOUT 0x02 /* input and output */
#define ISTRANS 0x04 /* transaction processing */
#define ISNOLOG 0x08 /* turn off logging */
#define ISFIXLEN 0x00 /* dummy */
#define ISVARLEN 0x10 /* variable length data */
#define ISVARCMP 0x30 /* compressed varlen */
#define ISSYNCWR 0x40 /* synchronous writes */
#define ISMASKED 0x80 /* masking active */
#define ISNOCARE 0x8000 /* set mode to match file */

/* locking methods */

#define ISRDONLY 0x100 /* read only - no locking */
#define ISAUTOLOCK 0x200 /* automatic lock on read */
#define ISMANULOCK 0x400 /* manual locking */
#define ISEXCLLOCK 0x800 /* exclusive access to file */
#if( SEMILOCK == 1 )
#define ISSEMILOCK 0x1000 /* C-ISAM compatible semi-lock */
#endif

/* key types */
 
#define CHARTYPE 0 /* array of bytes/characters */
#define DECIMALTYPE 0 /* handled as per char type */
#define INTTYPE 1 /* two byte (short) integer */
#define LONGTYPE 2 /* four byte (long) integer */
#define DOUBLETYPE 3 /* ieee double floating point */
#define FLOATTYPE 4 /* ieee single floating point */
#define MINTTYPE 5 /* machine (native) short */
#define MLONGTYPE 6 /* machine (native) long */
#define STRINGTYPE 7 /* null terminated byte string */

#define ISDESC 0x80 /* add for descending order */

/* key atomic sizes */

#define CHARSIZE 1
#define INTSIZE 2
#define LONGSIZE 4
#define DOUBLESIZE 8
#define FLOATSIZE 4
#define MINTSIZE 2
#define MLONGSIZE 4
#define STRINGSIZE 1

/* shortcuts for single part keys */

#define k_start k_part[0].kp_start
#define k_leng k_part[0].kp_leng
#define k_type k_part[0].kp_type

#define NPARTS ISMAXPARTS

/* index management flags */

#define ISNODUPS 0x00 /* no duplicates permitted */
#define ISDUPS 0x01 /* duplicates permitted */
#define DCOMPRESS 0x02 /* compress duplicates */
#define LCOMPRESS 0x04 /* leading compression */
#define TCOMPRESS 0x08 /* trailing compression */
#define COMPRESS 0x0E /* full compression */
#define TNULL 0x10 /* compress trailing nulls */
#define NULLKEY 0x20 /* null key masking */

#define ISMASK(I) ( 1L << ((I)-1) ) /* index masking bit flags */

/* access control */

#define ISFIRST 0 /* first record */
#define ISLAST 1 /* last record */
#define ISNEXT 2 /* next record */
#define ISPREV 3 /* previous record */
#define ISCURR 4 /* current record */
#define ISEQUAL 5 /* find match */
#define ISGREAT 6 /* greater than current */
#define ISGTEQ 7 /* greater than or equal */

/* record locking */

#define ISLOCK 0x100 /* lock record or fail */
#if( ISCISAM != 0 )
# define ISSKIPLOCK 0x200 /* skip record if locked */
#endif
#define ISWAIT 0x400 /* wait until free */
#define ISLCKW 0x500 /* wait and lock */
#define ISKEEPLOCK 0x800 /* isstart keep lock */

/* audit trace control */

#define AUDSETNAME 0 /* set audit file name */
#define AUDGETNAME 1 /* get audit file name */
#define AUDSTART 2 /* begin audit logging */
#define AUDSTOP 3 /* stop audit logging */
#define AUDINFO 4 /* logging status */

#define USERINFOSIZE 10 /* userinfo pad size */

/* isam specific error codes (iserrno) */

#define EDUPL ( ISERRBASE + 0 ) /* illegal duplicate */
#define ENOTOPEN ( ISERRBASE + 1 ) /* file not open */
#define EBADARG ( ISERRBASE + 2 ) /* illegal argument */
#define EBADKEY ( ISERRBASE + 3 ) /* illegal key description */
#define ETOOMANY ( ISERRBASE + 4 ) /* out of isam file handles */
#define EBADFILE ( ISERRBASE + 5 ) /* isam file is corrupt */
#define ENOTEXCL ( ISERRBASE + 6 ) /* can't get exclusive access */
#define ELOCKED ( ISERRBASE + 7 ) /* record is locked */
#define EKEXISTS ( ISERRBASE + 8 ) /* index already defined */
#define EPRIMKEY ( ISERRBASE + 9 ) /* illegal primary key operation */
#define EENDFILE ( ISERRBASE + 10 ) /* start or end file reached */
#define ENOREC ( ISERRBASE + 11 ) /* record not found */
#define ENOCURR ( ISERRBASE + 12 ) /* no current record */
#define EFLOCKED ( ISERRBASE + 13 ) /* file is locked */
#define EFNAME ( ISERRBASE + 14 ) /* file name is too long */
#define ENOLOK ( ISERRBASE + 15 ) /* not used */
#define EBADMEM ( ISERRBASE + 16 ) /* can't allocate memory */
#define EBADCOLL ( ISERRBASE + 17 ) /* not used, see next */
#define EBADIO ( ISERRBASE + 17 ) /* trouble in IO */
#define ELOGREAD ( ISERRBASE + 18 ) /* error reading log file */
#define EBADLOG ( ISERRBASE + 19 ) /* log file is corrupt */
#define ELOGOPEN ( ISERRBASE + 20 ) /* unable to open log */
#define ELOGWRIT ( ISERRBASE + 21 ) /* unable to write log */
#define ENOTRANS ( ISERRBASE + 22 ) /* transaction not found */
#define ENOSHMEM ( ISERRBASE + 23 ) /* out of shared memory */
#define ENOBEGIN ( ISERRBASE + 24 ) /* no current transaction */
#define ENONFS ( ISERRBASE + 25 ) /* not used */
#define EBADROWID ( ISERRBASE + 26 ) /* not used */
#define ENOPRIM ( ISERRBASE + 27 ) /* no primary key */
#define ENOLOG ( ISERRBASE + 28 ) /* logging not allowed */
#define EUSER ( ISERRBASE + 29 ) /* too many users */
#define ENODBS ( ISERRBASE + 30 ) /* not used */
#define ENOFREE ( ISERRBASE + 31 ) /* not used */
#define EROWSIZE ( ISERRBASE + 32 ) /* varlen record too big */
#define EAUDIT ( ISERRBASE + 33 ) /* existing audit trail */
#define ENOLOCKS ( ISERRBASE + 34 ) /* out of room in lock table */
#define EEXPIRED ( ISERRBASE + 35 ) /* evaluation library has expired */
#define ENOCONNECT ( ISERRBASE + 36 ) /* no connect with remote server */
#define ENETORDER ( ISERRBASE + 37 ) /* server has wrong endian order */
#define EREPAIR ( ISERRBASE + 38 ) /* auto repair in progress */
#define EBADADDR ( ISERRBASE + 39 ) /* bad network address */
#define ENOSCHEMA ( ISERRBASE + 40 ) /* no schema defined */
#define EEXSCHEMA ( ISERRBASE + 41 ) /* schema already defined */
#define ENOTAVAIL ( ISERRBASE + 42 ) /* remote function not available */

/* on system error - iserrio = IO_call + IO_file */

#define IO_OPEN 0x10 /* open */
#define IO_CREA 0x20 /* create */
#define IO_SEEK 0x30 /* seek */
#define IO_READ 0x40 /* read */
#define IO_WRIT 0x50 /* write */
#define IO_LOCK 0x60 /* lock */
#define IO_OTHER 0x70 /* other */

#define IO_IDX 0x01 /* index file */
#define IO_DAT 0x02 /* data file */
#define IO_AUD 0x03 /* audit trace */
#define IO_RAW 0x04 /* any other file */
#define IO_REP 0x05 /* auto repair file */
#define IO_LOG 0x06 /* transaction log */
#define IO_LCK 0x07 /* offline lock file */

#define IO_LOK 0x04 /* cisam, not used */
#define IO_SEM 0x05 /* cisam, not used */

/* cobol isstat4 values --------------------------------------------*/

#define STATNULL ' ' /* empty isstat4 value */
#define STAT1 '1'
#define STAT2 '2'
#define STAT3 '3'
#define STAT4 '4'
#define STAT5 '5'
#define STAT6 '6'
#define STAT7 '7'
#define STAT8 '8'
#define STAT9 '9'
#define STAT0 '0'

/* self check facility ------------------------------------------- */

#define IC_DATREAD 0 /* data file read error */
#define IC_BADDATA 1 /* data record corrupt */
#define IC_DATFREE 2 /* data free list is corrupt */

#define IC_IDXREAD 3 /* index file read error */
#define IC_ORDER 4 /* key out of order */
#define IC_COUNT 5 /* index count mismatch */
#define IC_BADMAGIC 6 /* bad index node magic number */
#define IC_MATCH 7 /* index/data mismatch */
#define IC_SANITY 8 /* compiler sanity check */
#define IC_DUPSEQ 9 /* bad duplicate sequence */

#if( ISVARIABLE )

#define IC_VLHASHZERO 11 /* hash table zero loaded */
#define IC_VLMISFILE 12 /* node misfiled in hash table */
#define IC_VLHASHLINK 13 /* mangled link in hash list */
#define IC_VLMISSING 14 /* nodes missing or unaccounted */
#define IC_VLBADDATA 15 /* data length mismatch */
 
struct IsVarStat /* variable length statistics */
 {
 uint32_t hashcount;
 uint32_t hashspace;
 uint32_t fullcount;
 uint32_t fullspace;
 uint32_t filecount;
 uint32_t filespace;
 };
 
#endif 

#endif /*ISAUTOLOCK*/

/* ---------------------------------------------------------------- *
 above is pulled from common source, see #ifdef ISAUTOLOCK above.
 ---------------------------------------------------------------- */

/* useful defines ----------------------------------------------- */

#define ISTRUE 1
#define ISFALSE 0

/* convenient shortcuts ----------------------------------------- */

typedef struct IsamFile IsFile;
typedef struct keydesc IsKdsc;
typedef struct keypart IsKprt;

#if( defined ISINTERNAL || defined ISDANGEROUS )

/* base library internal definitions ----------------------------- */

#define TRUE 1
#define FALSE 0

#define SETBIT( F, O ) ( F | ( 1 << ( O ) ) )
#define UNSBIT( F, O ) ( F & ~( 1 << ( O ) ) )
#define BITSET( F, O ) ( F & ( 1 << ( O ) ) )

#define ISREALLOC(S,P,O,N) ( struct S * )is_realloc( ( char * )P, O, N )
#define ISALLOC(S) ( struct S * )is_malloc( sizeof( struct S ) )
#define ISFREE(S,P) ( struct S * )is_free( ( char * )P )

#define ISNODEMAX ( isam->idxlen - 4 )

#define ISFAIL(I,M) ( ! isEntry( I, M ) || setjmp( I->trap ) )
 
#define ISFATAL is_fatal( "fatal isam error %s(%d)", __FILE__, __LINE__ )

/* path handling ------------------------------------------------- */

#define ISAMPRIME(I) ( (I)->maxidx ? (I)->path[0]->kdsc : NULL )
#define ISAMINDEX(I) ( ( (I)->curidx < (I)->maxidx ) ? (I)->path[(I)->curidx]->kdsc : NULL )

/* to be deprecated */
#define ISPATH ( isam->path[isam->curidx] )
#define ISKDSC ( isam->path[isam->curidx]->kdsc )

#define ISTAIL ( ISPATH->tail )
#define TAIL path->tail

#define ISEMPTY(P) ( P->tail->used == 2 )
 

/* specialised machine independant integers ---------------------- */

#define LDRECD(P) ( ldMint( P, 4 ) & 0x7FFFFFFFL )
#define LDDUP(P,L) ( ldMint( P, L ) )
#define STDUP(P,L,D) ( stMint( P, L, D ) )


/* structure specific flags and state values --------------------- */

#define ISREALFILE 0 /* stored on file system */
#define ISIPSOCKET 1 /* mounted on network socket */
#define ISNAMEPIPE 2 /* mounted on named pipe */
#define ISEXECPIPE 3 /* mounted on process pipe */

/* IsamFile - bit flags */
#define ISNOPRIM 0 /* primary is natural order */
#define ISNOTNEXT 1 /* read/start next dislocate */
#define ISNOTPREV 2 /* read/start prev dislocate */
#define ISWRLOCK 3 /* lock records on write */
#define ISPRECIOUS 4 /* do not reuse data slots */
#define ISLOCKCHECK 5 /* check locked on update/delete */
#define ISNOCURRENT 6 /* current is not viable */
#define ISLOGDEFER 7 /* open/close deferred logging */

/* IsamNode - state values */
#define ISNDREF 0 /* image must be refreshed */
#define ISNDOK 1 /* image is current */
#define ISNDUPD 2 /* image has been updated */

/* index file records -------------------------------------------- */

struct IsamNode /* index file record */
 {
 struct IsamNode *prev; /* parent node */
 struct IsamNode *split; /* sibling */

 uint32_t idxrec; /* idx file record number */
 char *image; /* disk image */
 char state; /* current status */
 int used; /* number of bytes used */
 int level; /* zero is leaf node */
 
 int keyoff; /* current key offset */
 int keyend; /* end of compressed key */
 uint32_t recnum; /* current record number */
 uint32_t dupnum; /* current duplicate number */
 char *keyval; /* key contents */
 };


/* schema/record layout ------------------------------------------ */

struct IsamRec
 {
 char *image; /* current node image */
 uint32_t root; /* root recnum */
 uint32_t last; /* last recnum */
 };


/* index handling ------------------------------------------------ */

struct IsamPath /* index details */
 {
 struct keydesc *kdsc; /* key description */
 struct IsamNode *tail; /* current path tail */
 struct IsamNode *buf[ISMAXBUF]; /* buffering system */
 
 int slotlen; /* key slot length */
 int duplen; /* valid if dups */
 int partial; /* active partial length */
 char current[ISMAXKEY]; /* current key value */
 uint32_t recnum; /* current record number */
 uint32_t dupnum; /* current dupnum i/a */
 int cmplen; /* current compare */
 char flags; /* bit flags */
 };


/* free list control structure ----------------------------------- */

struct IsamFree
 {
 char *image; /* index node image */
 char *split; /* hold for update */
 char state; /* update status */
 uint32_t root; /* list root record */
 uint32_t last; /* last used recnum */
 int used; /* bytes used in node */
 };

 
/* typedefs */

typedef struct IsamPath IsPath;
typedef struct IsamNode IsNode;
typedef struct IsamFree IsFree;


#endif /* ISINTERNAL || ISDANGEROUS */

/* isam file descriptor ------------------------------------------ */

struct IsamFile /* isam file description */
 {
 /* IO block HEAD - this structure matches on all sources */

 char *name; /* isam path and name */
 char where; /* source switch case */

#if( ISADMIN )
 int admid; /* admin table offset */
#endif

 /* IO block DATA - openmode through maxlen, should not change */

 int openmode; /* open mode bit flags */

 int idxlen; /* index node size */
 int duplen; /* duplicate sequence width */
 int maxidx; /* number of indexes */
 int curidx; /* current index number */
 uint32_t mask; /* index masking bit array */

 uint32_t isrecnum; /* current record number */
 int isreclen; /* current record length */
 int iserrno; /* failure code */
 int iserrio; /* what and where */

 int datlen; /* data record length */
 int datblk; /* data file record block */
 int maxlen; /* variable length max */

#if( ISMFCOBOL > 0 )
 char isstat1; /* cobol status variables */
 char isstat2;
 char isstat3;
 char isstat4;
#endif

#if( ISEXTENDED )
 int32_t ispid; /* pid of blocking lock */
#endif
 
 /* IO block END, remainder is local and specific to source */

#if( defined ISINTERNAL || defined ISDANGEROUS )

 int flags; /* all internal bit flags */

 int datfd; /* data file handle */
 int idxfd; /* index file handle */

 int ( *rdfilter )( int, char *, int );/* read filtering callback */

 uint32_t natcurr; /* natural order current */

 uint32_t kdsc; /* key desc list root node */
 uint32_t delta; /* concurrency control */
 uint32_t unique; /* unique id value */

 struct IsamPath *path[ISMAXIDX]; /* active path array */

 struct IsamFree idxfree; /* index free list */
 struct IsamFree datfree; /* data free list */
 
 struct IsamRec schema; /* schema pointers */

 uint32_t *lklist; /* list of record locks */
 uint32_t lkllen; /* current list length */
 char lkstate; /* locking state flags */
 
 char *image; /* header record image */
 char *data; /* current data image */
 
 int workmode; /* reading or writing */
 jmp_buf trap; /* longjump trap point */

#if( ISAUDIT )
 uint32_t audit; /* audit control node */
 char audinfo[69]; /* allocated info block */
 int audfd; /* trace file handle */
#endif
 
#if( ISLOGGING )
 int txnpid; /* transaction process id */
 int txnfile; /* transaction file id */
#endif 
 
#if( ISVARIABLE ) 
 uint32_t *hashtab; /* hash table array */
 char *varnode; /* varlen node image */
 char hashload; /* refresh flag */
 char *vcbuf; /* vl compression temp buffer */
 int vclen; /* vl compression temp length */
#endif 

#if( ISVARIABLE > 1 ) 
 uint32_t hashrecd; /* hash table record */
 char *hashnode; /* hash table image */
#endif 

#if( ISLOCKING == 3 )
 int lokfd; /* lock file handle */
 int32_t lokid; /* unique locking id */
#endif
 
#if( ISLKINFO == 1 )
 char *lockinfo; /* lock information block */
#endif
 
#if( ISTHREADED )
 int gotmtseek;
 int gotmtread;
 int gotmtlock;
 int gotmtwrite;
 int gotmtmast;
#endif

#endif /* ISINTERNAL || ISDANGEROUS */
 };


/* custom details ------------------------------------------------ */

#if( ISCUSTOM == 1 )
# include <iscustom.h>
#endif

/* entry function prototypes ------------------------------------- */

#if( ISDECLARE )
# define ISD3(s) s
#else
# define ISD3(s) ()
#endif

#if( ISDATAVOID )
# define ISDD void
#else
# define ISDD char
#endif

#if( ISCONSTCHAR )
# define ISCC const char
#else
# define ISCC char
#endif

#if( ISDYNAMIC == 0 || ISDYNAMIC == 3 || ISDYNAMIC == 4 )
# if( defined ISINTERNAL )
# define ISD1 
# else
# define ISD1 extern
# endif
# define ISD2
#endif

#if( ISDYNAMIC == 1 )
# if( defined ISINTERNAL )
# define ISD1
# define ISD2 __far __pascal __export
# else
# define ISD1 extern
# define ISD2 __far __pascal
# endif
#endif

#if( ISDYNAMIC == 2 )
# if( defined ISINTERNAL )
# define ISD1 __declspec( dllexport )
# else
# define ISD1 __declspec( dllimport )
# endif
# define ISD2
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if( ! defined ISINTERNAL )
# if( ISDYNAMIC < 3 )
# ifdef ISEXPIRE
ISD1 ISCC * ISD2 isevaluation;
# endif
ISD1 ISCC * ISD2 isversnumber;
ISD1 ISCC * ISD2 isverstring;
ISD1 ISCC * ISD2 iscopyright;
ISD1 int ISD2 is_nerr;
ISD1 ISCC * ISD2 is_errlist[43];
ISD1 ISCC * ISD2 isCheckMsg[16];
# endif
#endif

ISD1 int ISD2 isLock ISD3((IsFile *isam));
ISD1 int ISD2 isUnLock ISD3((IsFile *isam));
ISD1 int ISD2 isRelease ISD3((IsFile *isam));
ISD1 int ISD2 isRelRec ISD3((IsFile *isam, uint32_t recnum));
ISD1 int ISD2 isRelCurr ISD3((IsFile *isam));

ISD1 int ISD2 isThreaded ISD3((void));
ISD1 int ISD2 isThreadedDone ISD3((void));
ISD1 int ISD2 isAdmDtoI ISD3((IsFile *isam));
ISD1 IsFile * ISD2 isAdmItoD ISD3((int id));
ISD1 int ISD2 isCleanUp ISD3((void));
ISD1 int ISD2 isRemoteFree ISD3((void));
ISD1 IsFile * ISD2 isAdmTxnLast ISD3((void));

ISD1 IsFile * ISD2 isBuild ISD3((ISCC *name, int dlen, int mlen, IsKdsc *kdsc, int mode));
ISD1 int ISD2 isPrecious ISD3((IsFile *isam, int flag));
ISD1 int ISD2 isAddIndex ISD3((IsFile *isam, IsKdsc *kdsc));
ISD1 int ISD2 isUserInfo ISD3((IsFile *isam, int mode, char *pad));

ISD1 int ISD2 isDelete ISD3((IsFile *isam, ISDD *pad));
ISD1 int ISD2 isDelCurr ISD3((IsFile *isam));
ISD1 int ISD2 isDelRec ISD3((IsFile *isam, uint32_t recnum));

ISD1 int ISD2 isErase ISD3((ISCC *name));
ISD1 int ISD2 isRename ISD3((ISCC *oname, ISCC *nname));

ISD1 int ISD2 isDelIndex ISD3((IsFile *isam, IsKdsc *kdsc));

ISD1 int ISD2 isIndexInfo ISD3((IsFile *isam, IsKdsc *kdsc, int idx));
ISD1 int ISD2 isIsamInfo ISD3((IsFile *isam, struct dictinfo *dict));

ISD1 int ISD2 isErrno ISD3((IsFile *isam));
ISD1 int ISD2 isErrio ISD3((IsFile *isam));
ISD1 int ISD2 isCount ISD3((IsFile *isam));
ISD1 int ISD2 isRecnum ISD3((IsFile *isam));
ISD1 int ISD2 isReclen ISD3((IsFile *isam));
ISD1 int ISD2 isSetrec ISD3((IsFile *isam, uint32_t recnum));
ISD1 int ISD2 isSetlen ISD3((IsFile *isam, short reclen));

ISD1 IsFile * ISD2 isOpen ISD3((ISCC *name, int mode));
ISD1 int ISD2 isClose ISD3((IsFile *isam));
ISD1 int ISD2 isLockCheck ISD3((IsFile *isam, int flag));
ISD1 int ISD2 isSetMode ISD3((IsFile *isam, int mode));

ISD1 IsFile * ISD2 isCluster ISD3((IsFile *isam, IsKdsc *kdsc));
ISD1 IsFile * ISD2 isClone ISD3((IsFile *isam, ISCC *name ));
ISD1 int ISD2 isCopy ISD3((IsFile *dest, IsFile *source, IsKdsc *kdsc));

ISD1 int ISD2 isRead ISD3((IsFile *isam, ISDD *pad, int mode));
ISD1 int ISD2 isStart ISD3((IsFile *isam, IsKdsc *key, int len, ISDD *pad, int mode));
ISD1 int ISD2 isIndex ISD3((IsFile *isam, int idx));
ISD1 int ISD2 isGoto ISD3((IsFile *isam, uint32_t recnum));
ISD1 int ISD2 isPush ISD3((IsFile *isam, int *idx, uint32_t *rec));
ISD1 int ISD2 isPop ISD3((IsFile *isam, int idx, uint32_t rec));
ISD1 int ISD2 isData ISD3((IsFile *isam, ISDD *pad, uint32_t recnum));

ISD1 int ISD2 isLdSchema ISD3((IsFile *isam, ISCC *path));
ISD1 int ISD2 isDpSchema ISD3((IsFile *isam));
ISD1 int ISD2 isStSchema ISD3((IsFile *isam, ISCC *loadfile));
ISD1 int ISD2 isRmSchema ISD3((IsFile *isam));

ISD1 int ISD2 isSetUnique ISD3((IsFile *isam, uint32_t value));
ISD1 int ISD2 isUniqueId ISD3((IsFile *isam, uint32_t *dest));

ISD1 int ISD2 isGetLastRec ISD3((IsFile *isam, uint32_t *last));
ISD1 int ISD2 isSetLastRec ISD3((IsFile *isam, uint32_t last));
ISD1 int ISD2 isLastRec ISD3((IsFile *isam, uint32_t *last));

ISD1 int ISD2 isRewrite ISD3((IsFile *isam, ISDD *newpad));
ISD1 int ISD2 isRewCurr ISD3((IsFile *isam, ISDD *newpad));
ISD1 int ISD2 isRewRec ISD3((IsFile *isam, uint32_t recnum, ISDD *newpad));
ISD1 int ISD2 isRewNxt ISD3((IsFile *isam, ISDD *newpad));

ISD1 int ISD2 isWrite ISD3((IsFile *isam, ISDD *pad));
ISD1 int ISD2 isWrLock ISD3((IsFile *isam, ISDD *pad));
ISD1 int ISD2 isWrCurr ISD3((IsFile *isam, ISDD *pad));

ISD1 int ISD2 isAudit ISD3((IsFile *isam, char *pad, int mode));

ISD1 int ISD2 isTxnInit ISD3((short ( *call )(void) ));
ISD1 int ISD2 isLogOpen ISD3((ISCC *name));
ISD1 int ISD2 isLogClose ISD3((void));
ISD1 int ISD2 isBegin ISD3((void));
ISD1 int ISD2 isCommit ISD3((void));
ISD1 int ISD2 isRollBack ISD3((void));
ISD1 int ISD2 isRecover ISD3((void));
ISD1 int ISD2 isSuspLog ISD3((void));
ISD1 int ISD2 isResumLog ISD3((void));
ISD1 int ISD2 isTxnId ISD3((int value));

ISD1 uint32_t ISD2 isFreeCount ISD3((IsFile *isam, int which, int (*call )(char *node )));

ISD1 int ISD2 isAmSane ISD3((void));
ISD1 int ISD2 isCheckData ISD3((IsFile *isam));
ISD1 int ISD2 isCheckIndex ISD3((IsFile *isam, int idx));
ISD1 int ISD2 isRebuildFree ISD3((IsFile *isam, int which));
ISD1 int ISD2 isRebuildIdx ISD3((IsFile *isam, int idx));
#if( ISVARIABLE )
ISD1 int ISD2 isCheckVarlen ISD3((IsFile *isam, struct IsVarStat *stats));
#endif

ISD1 void ISD2 isFatal ISD3((void(*call)(char *)));

ISD1 int ISD2 isStartUp ISD3((void));

ISD1 ISCC * ISD2 isSeeKey ISD3((int isfd));

ISD1 int64_t ISD2 ldHint ISD3((char *pad, int len));
ISD1 int ISD2 stHint ISD3((char *pad, int len, int64_t val));
ISD1 int32_t ISD2 ldMint ISD3((char *pad, int len));
ISD1 int ISD2 stMint ISD3((char *pad, int len, int32_t val));

ISD1 int ISD2 ldInt ISD3((char *pad));
ISD1 int ISD2 stInt ISD3((int value, char *pad));
ISD1 int32_t ISD2 ldLong ISD3((char *pad));
ISD1 int ISD2 stLong ISD3((int32_t value, char *pad));
ISD1 int ISD2 stChar ISD3((char *str, char *pad, int len));
ISD1 int ISD2 ldChar ISD3((char *pad, int len, char *str));
ISD1 float ISD2 ldFloat ISD3((char *pad)); 
ISD1 int ISD2 stFloat ISD3((float value, char *pad));
ISD1 double ISD2 ldDbl ISD3((char *pad)); 
ISD1 int ISD2 stDbl ISD3((double value, char *pad));
ISD1 int ISD2 stFltNull ISD3((float value, char *pad, short null));
ISD1 float ISD2 ldFltNull ISD3((char *pad, short *null));
ISD1 int ISD2 stDblNull ISD3((double value, char *pad, short null));
ISD1 double ISD2 ldDblNull ISD3((char *pad, short *null));

#if 0 /* deprecated, please contact Byte Designs if needed */
ISD1 int ISD2 stDate ISD3((Date *dest, char *src));
ISD1 char * ISD2 ldDate ISD3((char *dest, Date *src));
ISD1 int ISD2 stTime ISD3((Time *dest, char *src));
ISD1 char * ISD2 ldTime ISD3((char *dest, Time *src));
#endif

/* base/isdebug.c */
ISD1 const char * ISD2 isWhere ISD3(( int work ));
ISD1 const char * ISD2 isWhat ISD3(( int which ));
ISD1 void ISD2 isDebug ISD3(( IsFile *isam, int level, ISCC *fmt, ... ));
ISD1 void ISD2 isvDebug ISD3(( IsFile *isam, int level, ISCC *fmt, va_list ap ));
ISD1 void ISD2 isDebugAsc ISD3(( IsFile *isam, int level, ISCC *tag, ISCC *dat, int len ));
ISD1 void ISD2 isDebugHex ISD3(( IsFile *isam, int level, ISCC *tag, ISCC *dat, int len ));

#ifdef __cplusplus
};
#endif

#if( defined ISINTERNAL )
#else
# undef ISD1
# undef ISD2
# undef ISD3
# undef ISDD
#endif

/* end header ---------------------------------------------------- */

Building a D-ISAM framework for Xcode

Note that this post covers the manual process of creating a framework – please refer to Building D-ISAM in the Xcode IDE for the integrated approach.

Before starting please see Update for Constant Chars.

To make a D-ISAM framework you must first create a public directory called (for example) Disam72.framework, and create a symbolic link in this directory named Disam72, which points to your D-ISAM dylib, as installed.

Note that the name of the framework and the name of the dylib pointer are the same. This defines the import name of your framework.

mkdir /Library/Disam72.dylib
cp target/disam72_shared/lib/libdisam72.dylib /Library/Disam72
ln -s /Library/Disam72/libdisam72.dylib /Library/Disam72/Disam72.framework/Disam72

You then need to create a Header directory inside Disam72.framework, containing your disam header files, together with an “umbrella” header to organise them – in this example it is named disam_xcode.h

/* disam umbrella header */
#define ISCONSTCHAR 1"
#import "isbase.h"
#undef ISCONSTCHAR"

And finally, create a file called module.map in Disam72.framework

framework module $DISAM [system] {
  umbrella header "disam_xcode.h"
  export *
}

The above presents a bare minimum of steps needed to create a framework that will import easily into Xcode and Swift.  However it leaves out quite a few details that are probably important, and which are generally included automatically when Building D-ISAM in the Xcode IDE.

The whole process is documented in Guidelines for Creating Frameworks.

Python and D-ISAM

D-ISAM is fully supported in Python by way of the ctypes library.

This is documented at The Python Software Foundation as A foreign function library for Python.

D-ISAM is easily imported as a shared library (or apple dylib, or windows dll) as follows:

from ctypes import CDLL
d7 = CDLL( "libdisam72.so" )

In addition to importing the library, you will also (most probably) wish to add the standard ISAM constants, and at least an instance of the ISAM key description structure, and deploy the results as a module.

An example module is available here.

A simple demonstration is available here.