X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f From: To: djgpp AT delorie DOT com Subject: BTRIEVE support in DJGPP Date: Mon, 21 Jun 2004 11:29:26 +0300 MIME-Version: 1.0 Content-Type: text/plain; charset=windows-1255 Content-Transfer-Encoding: 7bit Message-Id: <20040621082759.SBBU15248.fep15@[212.117.129.234]> Reply-To: djgpp AT delorie DOT com after more than a decade of programming using application generators that save their code using btrieve, i am glad to announce the DJGPP port of the BTRV infrastructure routine. included here are a header file the source file, and a small readme file. p.s. i have ported the btrieve v6.xx also, but i will first upload the source to the site of pervasive, and post a link on this list. well formed djgpp packages are later to come. ####### btr.h ########## #ifndef __btr_h__ #define __btr_h__ /**************************************************/ /* BTRIEVE OPERATION CODES (BTRV.H) */ /**************************************************/ short b_op_code; #define B_OPEN 0 #define B_CLOSE 1 #define B_INSERT 2 #define B_UPDATE 3 #define B_DELETE 4 #define B_GET_EQUAL 5 #define B_GET_NEXT 6 #define B_GET_PREVIOUS 7 #define B_GET_GR 8 #define B_GET_GR_EQ 9 #define B_GET_LESS 10 #define B_GET_LESS_EQ 11 #define B_GET_LOWEST 12 #define B_GET_HIGHEST 13 #define B_CREATE 14 #define B_STAT 15 #define B_EXTEND 16 #define B_SET_DIRECTORY 17 #define B_GET_DIRECTORY 18 #define B_BT 19 #define B_ET 20 #define B_AT 21 #define B_GET_POSITION 22 #define B_GET_DIRECT 23 #define B_STEP_DIRECT 24 #define B_STOP 25 #define B_VERSION 26 #define B_UNLOCK 27 #define B_RESET 28 #define B_SET_OWNER 29 #define B_CLEAR_OWNER 30 #define B_CREATE_INDEX 31 #define B_DROP_INDEX 32 #define B_GET_EQUAL_KEY 55 #define B_GET_NEXT_KEY 56 #define B_GET_PREVIOUS_KEY 57 #define B_GET_GR_KEY 58 #define B_GET_GR_EQ_KEY 59 #define B_GET_LESS_KEY 60 #define B_GET_LESS_EQ_KEY 61 #define B_GET_LOWEST_KEY 62 #define B_GET_HIGHEST_KEY 63 #define B_WAIT 100 #define B_NOWAIT 200 #define B_MUL_WAIT 300 #define B_MUL_NOWAIT 400 /**************************************************/ /* BTRIEVE STATUS PARAMETERS */ /**************************************************/ short b_status; #define B_NO_ERROR 0 #define B_I_O_ERROR 2 #define B_NO_OPEN 3 #define B_NOT_FOUND 4 #define B_DUPLICATE 5 #define B_INVALID_KEY 6 #define B_EOF 9 #define B_FILE_NOT_FOUND 12 #define B_DISK_FULL 18 #define BTR_ERR 20 /* record manager not started */ #define B_BTR_NAME_ERROR 30 #define B_VAR_PAGE_ERROR 54 #define B_CONFLICT 80 #define B_RECORD_IN_USE 84 #define B_FILE_IN_USE 85 #define B_FILE_FULL 86 #define B_MODE_ERROR 88 #define B_SERVER_ERROR 91 #define B_FILE_BUSY 85 /**************************************************/ /* BTRIEVE FLAGS PARAMETERS */ /**************************************************/ #define NOR_TYPE 0 #define DUP 1 #define MOD 2 #define BIN 4 #define NUL 8 #define SEG 16 #define DESC 64 #define EXT_TYPE 256 /**************************************************/ /* BTRIEVE TYPES PARAMETERS */ /**************************************************/ #define B_INT_TYPE 1 #define B_STR_TYPE 0 #define B_ZSTR_TYPE 11 short BTRV (short OP, char POS_BLK[], char DATA_BUF[], short *DATA_LEN, char KEY_BUF[], short KEY_NUM); #endif /*__btr_h__*/ ###### btrv.c ######### /* */ /* DJGPP Version 2.xx interface to the */ /* Btrieve Record Manager, version 4, 5, 5.1 */ /* Port to djgpp (BTI_DOS_32D) Copyright (C) 2004 Alex Bodnaru. Report problems and direct all questions on this port to: alexbodn AT 012 DOT net DOT il */ #include #include #include #include #include "btr.h" #define BTR_INT 0x7B /* Btrieve interrupt vector */ #define BTR2_INT 0x2F /* multi-user interrupt vector */ #define BTR_VECTOR BTR_INT * 4 /* offset for interrupt */ #define BTR_OFFSET 0x33 /* Btrieve offset within segment */ #define VARIABLE_ID 0x6176 /* id for variable length records - 'va' */ #define _2FCODE 0xAB00 /* function code for int 2F to btrieve */ /* ProcId is used for communicating with the Multi Tasking Version of */ /* Btrieve. It contains the process id returned from BMulti and should */ /* not be changed once it has been set. */ static unsigned ProcId = 0; /* initialize to no process id */ static char MULTI = 0; /* flag set to true if MultiUser */ static char VSet = 0; /* flag set to true if checked version */ enum reqparms { in_pos = 0x0001, in_databuf = 0x0002, in_datalen = 0x0004, in_keybuf = 0x0008, out_pos = 0x0010, out_databuf = 0x0020, out_datalen = 0x0040, out_keybuf = 0x0080 }; static unsigned short bufparms[75]; #define has_op_parms(op, parms) (bufparms[(op) % 100] & (parms)) static void bufparms_init() { static int reqparms_init = 0; int c; #define op_parms(op, parms) bufparms[op] = parms if (reqparms_init) return; for (c = sizeof(bufparms) / sizeof(bufparms[0]) - 1; c >= 0; --c) bufparms[c] = 0xffff; op_parms( B_OPEN, in_databuf | in_datalen | in_keybuf | out_pos ); op_parms( B_CLOSE, in_pos ); op_parms( B_INSERT, in_pos | in_databuf | in_datalen | out_pos | out_keybuf ); op_parms( B_UPDATE, in_pos | in_databuf | in_datalen | out_pos | out_keybuf ); op_parms( B_DELETE, in_pos | out_pos ); op_parms( B_GET_EQUAL, in_pos | in_datalen | in_keybuf | out_pos | out_databuf | out_datalen ); op_parms( B_GET_NEXT, in_pos | in_datalen | in_keybuf | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_GET_PREVIOUS, in_pos | in_datalen | in_keybuf | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_GET_GR, in_pos | in_datalen | in_keybuf | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_GET_GR_EQ, in_pos | in_datalen | in_keybuf | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_GET_LESS, in_pos | in_datalen | in_keybuf | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_GET_LESS_EQ, in_pos | in_datalen | in_keybuf | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_GET_LOWEST, in_pos | in_datalen | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_GET_HIGHEST, in_pos | in_datalen | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_GET_EQUAL_KEY, in_pos | in_keybuf | out_pos | out_keybuf ); op_parms( B_GET_NEXT_KEY, in_pos | in_keybuf | out_pos | out_keybuf ); op_parms( B_GET_PREVIOUS_KEY, in_pos | in_keybuf | out_pos | out_keybuf ); op_parms( B_GET_GR_KEY, in_pos | in_keybuf | out_pos | out_keybuf ); op_parms( B_GET_GR_EQ_KEY, in_pos | in_keybuf | out_pos | out_keybuf ); op_parms( B_GET_LESS_KEY, in_pos | in_keybuf | out_pos | out_keybuf ); op_parms( B_GET_LESS_EQ_KEY, in_pos | in_keybuf | out_pos | out_keybuf ); op_parms( B_GET_LOWEST_KEY, in_pos | out_pos | out_keybuf ); op_parms( B_GET_HIGHEST_KEY, in_pos | out_pos | out_keybuf ); op_parms( B_CREATE, in_databuf | in_datalen | in_keybuf ); op_parms( B_STAT, in_pos | in_databuf | in_datalen | in_keybuf | out_databuf | out_datalen | out_keybuf ); op_parms( B_EXTEND, 0xffff ); op_parms( B_SET_DIRECTORY, in_keybuf ); op_parms( B_GET_DIRECTORY, out_keybuf ); op_parms( B_BT, 0 ); op_parms( B_ET, 0 ); op_parms( B_AT, 0 ); op_parms( B_GET_POSITION, in_pos | in_datalen | out_pos | out_databuf | out_datalen ); op_parms( B_GET_DIRECT, in_pos | in_databuf | in_datalen | out_pos | out_databuf | out_datalen | out_keybuf ); op_parms( B_STEP_DIRECT, in_pos | in_datalen | out_pos | out_databuf | out_datalen ); op_parms( B_STOP, 0 ); op_parms( B_VERSION, in_datalen | out_databuf | out_datalen ); op_parms( B_UNLOCK, in_pos | in_databuf | in_datalen ); op_parms( B_RESET, in_keybuf ); op_parms( B_SET_OWNER, in_pos | in_databuf | in_datalen | in_keybuf | out_pos ); op_parms( B_CLEAR_OWNER, in_pos | out_pos ); op_parms( B_CREATE_INDEX, in_pos | in_databuf | in_datalen ); op_parms( B_DROP_INDEX, in_pos); reqparms_init = 1; } short BTRV (short OP, char POS_BLK[], char DATA_BUF[], short *DATA_LEN, char KEY_BUF[], short KEY_NUM) { static int dosdatamem_init = 0; __dpmi_regs regs; static _go32_dpmi_seginfo dosdatamem; struct BTRIEVE_PARMS /* structure passed to Btrieve Record Manager */ { short BUF_OFFSET; /* callers data buffer offset */ short BUF_SEG; /* callers data buffer segment */ short BUF_LEN; /* length of data buffer */ short CUR_OFFSET; /* user position block offset */ short CUR_SEG; /* user position block segment */ short FCB_OFFSET; /* offset of disk FCB */ short FCB_SEG; /* segment of disk FCB */ short FUNCTION; /* requested function */ short KEY_OFFSET; /* offset of user's key buffer */ short KEY_SEG; /* segment of user's key buffer */ unsigned char KEY_LENGTH; /* length of user's key buffer */ char KEY_NUMBER; /* key of reference for request */ short STAT_OFFSET; /* offset of status word */ short STAT_SEG; /* segment of status word */ short XFACE_ID; /* language identifier */ } XDATA; short STAT = 0; /* status of Btrieve call */ bufparms_init(); /* Check to see that the Btrieve Record Manager has been started. */ if (!VSet) /* if we don't know version of Btrieve yet */ { VSet = 1; regs.x.ax = 0x3000; /* check dos version */ __dpmi_int (0x21, ®s); if ((regs.x.ax & 0x00FF) >= 3) /* if DOS version 3 or later */ { regs.x.ax = _2FCODE; __dpmi_int (BTR2_INT, ®s); MULTI = ((regs.x.ax & 0xFF) == 'M');/* if al is M, bmulti is loaded */ } } if (!MULTI) { /* if bmulti not loaded */ regs.x.ax = 0x3500 + BTR_INT; __dpmi_int (0x21, ®s); if (regs.x.bx != BTR_OFFSET) return (BTR_ERR); } /* initialize segment part of addresses to user's data segment. */ XDATA.STAT_SEG = __tb / 16; XDATA.FCB_SEG = __tb / 16; XDATA.KEY_SEG = __tb / 16; XDATA.CUR_SEG = __tb / 16; if (!dosdatamem_init || dosdatamem.size) { dosdatamem.size = (4090 + 15) / 16; if (_go32_dpmi_allocate_dos_memory(&dosdatamem)) return -1; dosdatamem_init = 1; } if (DATA_LEN != NULL && (short)dosdatamem.size < (*DATA_LEN + 15) / 16) { dosdatamem.size = (*DATA_LEN + 15) / 16; if (_go32_dpmi_resize_dos_memory(&dosdatamem)) return -1; } if (has_op_parms(OP, in_databuf) && DATA_BUF != NULL && DATA_LEN != NULL && *DATA_LEN) { dosmemput(DATA_BUF, *DATA_LEN, dosdatamem.rm_segment * 16); } XDATA.BUF_SEG = dosdatamem.rm_segment; /* Move user parameters to XDATA, the block where Btrieve expects them.*/ XDATA.FUNCTION = OP; XDATA.STAT_OFFSET = __tb % 16 + sizeof(XDATA); dosmemput(&STAT, sizeof(STAT), __tb); XDATA.FCB_OFFSET = XDATA.STAT_OFFSET + sizeof(STAT); if (has_op_parms(OP, in_pos)) dosmemput(POS_BLK, 128, __tb + XDATA.FCB_OFFSET); XDATA.CUR_OFFSET = XDATA.FCB_OFFSET + 38; XDATA.KEY_OFFSET = XDATA.FCB_OFFSET + 128; XDATA.KEY_LENGTH = 255; /* use max since we don't know */ if (has_op_parms(OP, in_keybuf) && KEY_BUF != NULL) dosmemput(KEY_BUF, XDATA.KEY_LENGTH, __tb + XDATA.KEY_OFFSET); XDATA.KEY_NUMBER = KEY_NUM; XDATA.BUF_OFFSET = 0; if (DATA_BUF != NULL && DATA_LEN != NULL) XDATA.BUF_LEN = *DATA_LEN; else XDATA.BUF_LEN = 0; XDATA.XFACE_ID = VARIABLE_ID; /* Make call to the Btrieve Record Manager. */ /* parameter block is expected to be in DX */ dosmemput(&XDATA, sizeof(XDATA), __tb); regs.x.dx = __tb % 16; regs.x.es = regs.x.ds = regs.x.ss = __tb / 16; if (MULTI) { /* call bmulti */ while (1) { regs.x.ax = 1; /* assume no proc id obtained yet */ if ((regs.x.bx = ProcId) != 0) /* if we have a proc id */ regs.x.ax = 2; /* tell bmulti that */ regs.x.ax += _2FCODE; __dpmi_int (BTR2_INT, ®s); if ((regs.x.ax & 0x00FF) == 0) /* if call was processed */ break; /* by bmulti, leave loop */ regs.x.ax = 0x0200; /* if multilink advanced is loaded, it */ __dpmi_int (0x7F, ®s); /* will switch processes */ } if (ProcId == 0) ProcId = regs.x.bx; } else __dpmi_int (BTR_INT, ®s); dosmemget(__tb + XDATA.STAT_OFFSET, sizeof(STAT), &STAT); dosmemget(__tb, sizeof(XDATA), &XDATA); if (has_op_parms(OP, out_pos)) dosmemget(__tb + XDATA.FCB_OFFSET, 128, POS_BLK); if (has_op_parms(OP, out_keybuf) && KEY_BUF != NULL && XDATA.KEY_LENGTH) dosmemget(__tb + XDATA.KEY_OFFSET, XDATA.KEY_LENGTH, KEY_BUF); if (has_op_parms(OP, out_databuf) && DATA_BUF != NULL && DATA_LEN != NULL && XDATA.BUF_LEN) { *DATA_LEN = XDATA.BUF_LEN; dosmemget(dosdatamem.rm_segment * 16, *DATA_LEN, DATA_BUF); } if (0 && OP == B_CLOSE && dosdatamem_init) { _go32_dpmi_free_dos_memory(&dosdatamem); dosdatamem_init = 0; } return (STAT); /* return status */ } ####### readme.dj ######### hello friends, after more than a decade of using btrieve based application generator, i am finaly proud to be able to access my older files from c programs. this software is meant to access btrieve 4, 5, and 5.1 only. to use with djgpp: 1. ensure key buffer is allways 255 bytes long. 2. to port 16 bit code to djgpp, where the data files are maintained the same, please use the __attribute__(packed) on the data structures, and substitute int by short. those are general considerations in migrating from 16 bit dos to djgpp. please enjoy, and post your comments and improvements to: alex ######### end