
/*!--------------------------------------------------------------------
  @file           ven78.cpp
   @author         JoergM
   @brief          DCOM Registry on UNIX: Registry Functions
   @see            

\if EMIT_LICENCE

    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end



\endif
 --------------------------------------------------------------------*/


#include <stdlib.h>
#include <stdio.h>
#if !defined(WIN32)
#include <unistd.h>
#if defined(AIX)
extern "C" int lockf(int, int, off_t);
#endif
#endif
#include <string.h>

/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/

#include "heo01.h"
#include "heo78.h"
#include "geo47.h"
#include "geo60.h"

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/
/* PTS 1103901 jrg 6.9.1999 */
#define DCOM_REGISTRY_MAGIC 0x0FAU
#define DCOM_REGISTRY_FILE  "Registry.dcom"

#define  ERR_TYPE 1
#define  INFO_TYPE 3
#define  ERR_REGISTRY_SEEK_TO_SLOT            11500, ERR_TYPE,_T("REGISTRY"),_T("Seek to offset %ld failed")
#define  ERR_REGISTRY_WRITE_SLOT              11501, ERR_TYPE,_T("REGISTRY"),_T("Write at offset %ld failed")
#define  ERR_REGISTRY_FILE_PATH               11502, ERR_TYPE,_T("REGISTRY"),_T("Failed to get path to register file:%s")
#define  ERR_REGISTRY_PARAMETER_CHECK_SIZE    11503, ERR_TYPE,_T("REGISTRY"),_T("Illegal input parameter size type %d len %ld size %ld")
#define  ERR_REGISTRY_PARAMETER_CHECK_CLSID   11504, ERR_TYPE,_T("REGISTRY"),_T("Illegal class id parameter len %ld != size %ld")
#define  ERR_REGISTRY_PARAMETER_CHECK_ILLEGAL 11505, ERR_TYPE,_T("REGISTRY"),_T("Illegal input parameter type %d")
#define  ERR_REGISTRY_ZERO_LENGTH_PARAMETER   11506, ERR_TYPE,_T("REGISTRY"),_T("Illegal output parameter (zero length)")
#define  ERR_REGISTRY_NULL_PARAMETER          11507, ERR_TYPE,_T("REGISTRY"),_T("Illegal output parameter type (NULL pointer)")
#define  ERR_REGISTRY_OPEN_FAILED             11508, ERR_TYPE,_T("REGISTRY"),_T("Opening registery file %s failed")
#define  ERR_REGISTRY_CREATE_FAILED           11509, ERR_TYPE,_T("REGISTRY"),_T("Creating registery file %s failed")
#define  ERR_REGISTRY_WRITE_MAGIC_FAILED      11510, ERR_TYPE,_T("REGISTRY"),_T("Writing header to %s failed")
#define  ERR_REGISTRY_WRITE_FIRST_SLOT_FAILED 11511, ERR_TYPE,_T("REGISTRY"),_T("Writing first slot to %s failed")
#define  ERR_REGISTRY_SEEK_END                11512, ERR_TYPE,_T("REGISTRY"),_T("Seeking to end of registry failed")
#define  ERR_REGISTRY_READ_NO_HEADER          11513, ERR_TYPE,_T("REGISTRY"),_T("Registry size %ld to small even for header")
#define  ERR_REGISTRY_SEEK_BEGIN              11514, ERR_TYPE,_T("REGISTRY"),_T("Seeking to begin of registry failed")
#define  ERR_REGISTRY_READ_MAGIC              11515, ERR_TYPE,_T("REGISTRY"),_T("Reading registery header failed")
#define  ERR_REGISTRY_WRONG_MAGIC             11516, ERR_TYPE,_T("REGISTRY"),_T("Header information show file is no registry file")
#define  ERR_REGISTRY_READ_SLOT               11517, ERR_TYPE,_T("REGISTRY"),_T("Reading slot %ld failed")
#define  ERR_REGISTRY_LOCK                    11518, ERR_TYPE,_T("REGISTRY"),_T("Locking registry file failed! (mounted via NFS ?)")
#define  INFO_REGISTRY_CREATED                11500,INFO_TYPE,_T("REGISTRY"),_T("Created registry file %s")

/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/

/*===========================================================================*
 *  LOCAL CLASSES, STRUCTURES, TYPES, UNIONS ...                             *
 *===========================================================================*/

typedef char teo78_ProgProject[PROG_ID_PFX_MXEO78 + PROJECT_MXEO78];

typedef struct reg_slot {
	teo78_ProgProject ProgProject;	/* Version independent programmatic ID */
	teo78_Version     Version; /* The given version string */
	teo78_ClsID       ClsID;
	teo78_ModuleName  ModuleName;
	int               is_current;
} reg_slot;

typedef teo78_Result (*parse_func)(reg_slot &, unsigned int idx, void *arg);

struct register_object_arg 
{
	reg_slot         update;	    /* The complete new entry */
	unsigned int     len;			/* Length of ProgProjectField in update */
	int              all_done;      /* Entry with same information found */
	int              has_update;    /* If set idx_update points to slot */
	unsigned int     idx_update;    /* Index of Slot to be used for update */
	int              has_current;   /* Entry with current ProgID found */
	unsigned int     idx_current;   /* Index of Slot with former current flag set */
};

struct unregister_object_arg 
{
	unsigned int      len;
	teo78_ProgProject ProgProject;	/* Version independent programmatic ID */
    char             *pVersion;
	char             *pClsID;
	unsigned int      idx_delete;   /* Index of Slot with former current flag set */
};

struct search_clsid_arg 
{
	char         *pClsID;
	char         *pModuleName;
};

struct search_progid_arg 
{
	unsigned int  len;
	char         *pProgID;
	char         *pClsID;
	char         *pModuleName;
};

enum param_type {
	param_ProgIDPfx,
	param_Project,
	param_Version,
	param_ClsID,
	param_ModuleName,
	param_ProgID
};

/*===========================================================================*
 *  GLOBAL VARIABLES                                                         *
 *===========================================================================*/

/*===========================================================================*
 *  LOCAL VARIABLES                                                          *
 *===========================================================================*/

/*===========================================================================*
 *  LOCAL FUNCTIONS (PROTOTYPES)                                             *
 *===========================================================================*/

static teo78_Result in_param_check(const teo78_Result, 
								   const enum param_type, 
								   const char *,
								   const size_t );
static teo78_Result out_param_check(const teo78_Result, 
									const char *,
									const size_t);
static unsigned int fill_prog_project(char *, 
									  const char *, 
									  const char *);
static FILE *       open_registry();
static FILE *       create_registry();
static void         close_registry(FILE *f);
static int          lock_registry(FILE *f);
static void         unlock_registry(FILE *f);
static reg_slot *   read_registry(FILE *f, unsigned int *pCnt);
static reg_slot *   alloc_registry(unsigned int file_size);
static void         free_registry(reg_slot *buffer);
static int          update_registry(FILE *f, reg_slot *buffer, unsigned int slot_index);

static teo78_Result parse_registry(reg_slot *buffer, unsigned int slot_cnt, parse_func func, void *arg);
/*
 * Parse functions
 */
#ifdef TEST
static teo78_Result dump_slot(reg_slot &current, unsigned int idx, void *arg);
#endif
static teo78_Result register_Object(reg_slot &current, unsigned int idx, void *arg);
static teo78_Result unregister_Object(reg_slot &current, unsigned int idx, void *arg);
static teo78_Result search_ClsID(reg_slot &current, unsigned int idx, void *arg);
static teo78_Result search_ProgID(reg_slot &current, unsigned int idx, void *arg);

/*
 * Interface to SAP_Db.ini
 */
static char *       registry_file(tsp00_Pathc &path);
/*===========================================================================*
 *  GLOBAL FUNCTIONS (CODE)                                                  *
 *===========================================================================*/

extern "C" teo78_Result sqlComObjectRegister( 
						      teo78_ProgIDPfx   ProgIDPfx,
						      teo78_Project     Project,
						      teo78_Version     Version,
						      teo78_ClsID       ClsID,
						      teo78_ModuleName  ModuleName )
{
	teo78_Result res = success_eo78;

	FILE *f;
	reg_slot *buffer;
	unsigned int slot_cnt;
	struct register_object_arg Arg;

	res = in_param_check(res, param_ProgIDPfx, ProgIDPfx, sizeof(teo78_ProgIDPfx));
	res = in_param_check(res, param_Project,   Project,   sizeof(teo78_Project));
	res = in_param_check(res, param_Version,   Version,   sizeof(teo78_Version));
	res = in_param_check(res, param_ClsID,     ClsID,     sizeof(teo78_ClsID));
	res = in_param_check(res, param_ModuleName,ModuleName,sizeof(teo78_ModuleName));

	if ( res == success_eo78 ) 
	{
		memset(&Arg, 0, sizeof(register_object_arg));
		Arg.len = fill_prog_project(&Arg.update.ProgProject[0], &ProgIDPfx[0], &Project[0]);
		strcpy(&Arg.update.Version[0], &Version[0]);
		strcpy(&Arg.update.ClsID[0], &ClsID[0]);
		strcpy(&Arg.update.ModuleName[0], &ModuleName[0]);

		Arg.update.is_current = 1; /* Question to Ferdi: Is last always new current? */

		Arg.all_done    = 0;

		Arg.has_current = 0;
		Arg.idx_current = 0UL;

		f = open_registry();
		if ( !f )
		{
			f = create_registry();
		}

		if ( !f || lock_registry(f) < 0 )
		{
			return access_denied_eo78;
		}

		buffer = read_registry(f, &slot_cnt);

		Arg.has_update   = 0;
		Arg.idx_update   = slot_cnt; /* Behind buffer is free space... */

		res = parse_registry(buffer, slot_cnt, register_Object, &Arg);

		if ( res == entry_not_found_eo78 
		  || res == success_eo78 )
		{
			res = success_eo78;
			if ( !Arg.all_done )
			{
				if ( Arg.has_current )
				{
					buffer[Arg.idx_current].is_current = 0;
					if ( update_registry(f, buffer + Arg.idx_current, Arg.idx_current) < 0 )
					{
						res = system_error_eo78; /* PTS 1113021 */
					}
				}

				if ( update_registry(f, &Arg.update, Arg.idx_update) < 0 )
				{
					res = system_error_eo78; /* PTS 1113021 */
				}
			}
		}

		unlock_registry(f);
		close_registry(f);

		free_registry(buffer);
	}
	return res;
}

extern "C" teo78_Result sqlComObjectUnregister( 
						      teo78_ProgIDPfx ProgIDPfx,
						      teo78_Project   Project,
						      teo78_Version   Version,
						      teo78_ClsID     ClsID )
{
	teo78_Result res = success_eo78;

	FILE *f;
	reg_slot *buffer;
	unsigned int slot_cnt;
	struct unregister_object_arg Arg;

	res = in_param_check(res, param_ProgIDPfx, ProgIDPfx, sizeof(teo78_ProgIDPfx));
	res = in_param_check(res, param_Project,   Project,   sizeof(teo78_Project));
	res = in_param_check(res, param_Version,   Version,   sizeof(teo78_Version));
	res = in_param_check(res, param_ClsID,     ClsID,     sizeof(teo78_ClsID));

	if ( res == success_eo78 ) 
	{
		Arg.len = fill_prog_project(&Arg.ProgProject[0], &ProgIDPfx[0], &Project[0]);
		Arg.pVersion = Version;
		Arg.pClsID   = ClsID;
		Arg.idx_delete = 0UL;

		f = open_registry();

		if ( !f || lock_registry(f) < 0 )
		{
			return access_denied_eo78;
		}

		buffer = read_registry(f, &slot_cnt);

		res = parse_registry(buffer, slot_cnt, unregister_Object, &Arg);

		if ( res == success_eo78 )
		{
			reg_slot clear;
			memset(&clear, 0, sizeof(reg_slot));
			if ( update_registry(f, &clear, Arg.idx_delete) < 0 )
			{
				res = system_error_eo78; /* PTS 1113021 */
			}
		}

		unlock_registry(f);
		close_registry(f);

		free_registry(buffer);
	}
	return res;
}

extern "C" teo78_Result sqlComObjectGet(
						      teo78_ProgID     ProgID,
						      teo78_ClsID      ClsID,
						      teo78_ModuleName ModuleName)
{
	teo78_Result res = success_eo78;
	FILE *f;
	reg_slot *buffer;
	unsigned int slot_cnt;
	struct search_progid_arg Arg;

	res = in_param_check(res, param_ProgID, ProgID, sizeof(teo78_ProgID));
	res = out_param_check(res, ClsID, sizeof(teo78_ClsID));
	res = out_param_check(res, ModuleName, sizeof(teo78_ModuleName));

	if ( res == success_eo78 ) 
	{
        Arg.len         = strlen(&ProgID[0]);
        Arg.pProgID     = ProgID;
		Arg.pClsID      = ClsID;
		Arg.pModuleName = ModuleName;

		f = open_registry();
		if ( !f || lock_registry(f) < 0 )
		{
			return access_denied_eo78;
		}

		buffer = read_registry(f, &slot_cnt);
		unlock_registry(f);
		close_registry(f);

		res = parse_registry(buffer, slot_cnt, search_ProgID, &Arg);
		free_registry(buffer);
	}
	return res;
}

extern "C" teo78_Result sqlComObjectGetByClsID(
						      teo78_ClsID      ClsID,
						      teo78_ModuleName ModuleName )
{
	teo78_Result res = success_eo78;
	FILE *f;
	reg_slot *buffer;
	unsigned int slot_cnt;
	struct search_clsid_arg Arg;

	res = in_param_check(res, param_ClsID, ClsID, sizeof(teo78_ClsID));
	res = out_param_check(res, ModuleName, sizeof(teo78_ModuleName));

	if ( res == success_eo78 )
	{
		Arg.pClsID      = ClsID;
		Arg.pModuleName = ModuleName;

		f = open_registry();
        if ( !f || lock_registry(f) < 0 )
		{
			return access_denied_eo78;
		}

		buffer = read_registry(f, &slot_cnt);
		unlock_registry(f);
		close_registry(f);

		res = parse_registry(buffer, slot_cnt, search_ClsID, &Arg);
		free_registry(buffer);
	}
	return res;
}

#ifdef TEST
extern "C" void en78_DumpRegistry(FILE *out)
{
	FILE *f;
	reg_slot *buffer;
	unsigned int slot_cnt;

	fprintf( out, "Registry Dump :" );

	f = open_registry();
	if ( !f || lock_registry(f) < 0 )
	{
		fprintf(out, "Open failed...\n");
		return;
	}

	buffer = read_registry(f, &slot_cnt);
	unlock_registry(f);
	close_registry(f);

	fprintf( out, "Total Number of slots %ld\n", slot_cnt);
	fprintf( out, "----------------------------------------------------\n");
	(void)parse_registry(buffer, slot_cnt, dump_slot, out);
	free_registry(buffer);

	fprintf( out, "Registry Dump complete\n" );
}
#endif

/*===========================================================================*
 *  LOCAL FUNCTIONS (CODE)                                                   *
 *===========================================================================*/

static teo78_Result out_param_check( const teo78_Result res,
									 const char *       param,
									 const size_t       size)
{
	teo78_Result out_res = res;

	if ( out_res == success_eo78 )
	{
		if ( !param )
		{
            MSGD(( ERR_REGISTRY_NULL_PARAMETER ));
			out_res = illegal_parameter_eo78;
		}
		else
		{
		/* 
		 * How can we check, that space is writable in
		 * a portable way?
		 */
			if ( size == 0 )
			{
                MSGD(( ERR_REGISTRY_ZERO_LENGTH_PARAMETER ));
				out_res = illegal_parameter_eo78;
			}
		}
	}
	return out_res;
}

static teo78_Result in_param_check( const teo78_Result    res,
									const enum param_type type,
									const char *          param,
									const size_t          size)
{
/*
 * More possible checks:
 * Valid name space etc. skipped...
 */
	teo78_Result in_res = res;

	if ( in_res == success_eo78 )
	{
		if ( !param )
		{
			in_res = illegal_parameter_eo78;
		}
		else
		{
			size_t len = strlen(param) + 1;

			switch(type)
			{
				case param_ProgIDPfx:
				case param_ProgID:
				case param_Project:
				case param_Version:
				case param_ModuleName:
					if ( len > size 
					  || len == ((size_t)0) )
					{
                        MSGD(( ERR_REGISTRY_PARAMETER_CHECK_SIZE, type, len, size ));
						in_res = illegal_parameter_eo78;
					}
					break;
				case param_ClsID:
					if ( len != size )
					{
                        MSGD(( ERR_REGISTRY_PARAMETER_CHECK_CLSID, len, size ));
						in_res = illegal_parameter_eo78;
					}
					break;
				default:
                    MSGD(( ERR_REGISTRY_PARAMETER_CHECK_ILLEGAL, type ));
					in_res = illegal_parameter_eo78;
					break;
			}
		}
	}
	return in_res;
}

static unsigned int fill_prog_project(char       * ProgProject, 
									   const char * ProgIDPfx,
								       const char * Project)
{
	strcpy(ProgProject, ProgIDPfx);
	strcat(ProgProject, ".");
	strcat(ProgProject, Project);
	return strlen(ProgProject);
}

#ifdef TEST
static teo78_Result dump_slot(reg_slot &slot, unsigned int idx, void *arg)
{
	FILE *out = (FILE *)arg;

	fprintf( out, "Slot #%ld %s\n", idx, (slot.ProgProject[0] ? "" : "(empty)") );
	fprintf( out, "ProgProject %s\n", slot.ProgProject);
	fprintf( out, "Version     %s\n", slot.Version);
	fprintf( out, "ClsID       %s\n", slot.ClsID);
	fprintf( out, "ModuleName  %s\n", slot.ModuleName);
	fprintf( out, "is_current  %s\n", (slot.is_current ? "CurrentVersion" : "NotCurrentVersion" ) );
	fprintf( out, "----------------------------------------------------\n" );
	return entry_not_found_eo78;
}
#endif

static teo78_Result register_Object(reg_slot &slot, unsigned int idx, void *arg)
{
	teo78_Result res;
	struct register_object_arg *pArg;
	unsigned int len;

	res = entry_not_found_eo78;
	pArg = (struct register_object_arg *)arg;
	len = strlen(&slot.ProgProject[0]);

	if ( len == 0 )
	{
		if ( idx < pArg->idx_update )
		{
			pArg->idx_update = idx;
		}
	}
	else
	{
		int same_clsid = !strcmp(&slot.ClsID[0], &pArg->update.ClsID[0]);
		int same_project = ( len == pArg->len
		  && !memcmp(&slot.ProgProject[0], &pArg->update.ProgProject[0], len) );
		       
		if ( same_project )
		{
			if ( !strcmp(&slot.Version[0], &pArg->update.Version[0]) )
			{
				if ( !strcmp(&slot.ModuleName[0], &pArg->update.ModuleName[0])
				  && slot.is_current )
				{
					pArg->all_done = 1;
					res = success_eo78;
				}
				else
				{
					pArg->has_update = 1;
					pArg->idx_update = idx;

					if ( slot.is_current 
					  || pArg->has_current )
					{
						res = success_eo78;
					}
				}
			}
			else
			{
				if ( same_clsid )
				{
					pArg->all_done = 1;
					res = doubled_clsid_eo78;
				}
				else
				{
					if ( slot.is_current )
					{
						pArg->has_current = 1;
						pArg->idx_current = idx;
						if ( pArg->has_update )
						{
							res = success_eo78;
						}
					}
				}
			}
		}
		else
		{
			if ( same_clsid )
			{
				pArg->all_done = 1;
				res = doubled_clsid_eo78;
			}
		}
	}
	return res;
}

static teo78_Result unregister_Object(reg_slot &slot, unsigned int idx, void *arg)
{
	teo78_Result res;
	struct unregister_object_arg *pArg;
	unsigned int len;

	res = entry_not_found_eo78;
	pArg = (struct unregister_object_arg *)arg;
	len = strlen(&slot.ProgProject[0]);

	if ( len > 0 )
	{
		int same_clsid = !strcmp(&slot.ClsID[0], pArg->pClsID);
	    int same_version = ( len == pArg->len
			              && !memcmp(&slot.ProgProject[0], &pArg->ProgProject[0], len)
			              && !strcmp(&slot.Version[0], pArg->pVersion) );
		if ( same_version && same_clsid )
		{
			pArg->idx_delete = idx;
			res = success_eo78;
		}
		else 
		{
			if ( (same_version && !same_clsid)
			  || (!same_version && same_clsid) )
			{
				res = clsid_version_mismatch_eo78;
			}
		}
	}
	return res;
}

static teo78_Result search_ProgID(reg_slot &slot, unsigned int idx, void *func_arg)
{
	teo78_Result res;
	struct search_progid_arg *pArg;
	unsigned int len;

	res = entry_not_found_eo78;
	pArg = (struct search_progid_arg *)func_arg;
	len = strlen(&slot.ProgProject[0]);

	if ( len > 0 && len <= pArg->len )
	{
		if ( len == pArg->len )
		{
			if ( slot.is_current )
			{
				if ( !_tcsnicmp(&slot.ProgProject[0], pArg->pProgID, len) )
				{
					strcpy(pArg->pModuleName, &slot.ModuleName[0]);
					memcpy(pArg->pClsID, &slot.ClsID[0], sizeof(teo78_ClsID));
					res = success_eo78;
				}
			}
		}
		else
		{
			if ( !_tcsnicmp(&slot.ProgProject[0], pArg->pProgID, len) )
			{
				if ( pArg->pProgID[len] == '.'
				  && !_tcsicmp(&slot.Version[0], pArg->pProgID + len + 1) )
				{
					strcpy(&pArg->pModuleName[0], &slot.ModuleName[0]);
					memcpy(&pArg->pClsID[0], &slot.ClsID[0], sizeof(teo78_ClsID));
					res = success_eo78;
				}
			}
		}
	}
	return res;
}

static teo78_Result search_ClsID(reg_slot &slot, unsigned int idx, void *func_arg)
{
	teo78_Result res;
	struct search_clsid_arg *pArg;

	pArg = (struct search_clsid_arg *)func_arg;
	if ( !memcmp(&slot.ClsID[0], pArg->pClsID, sizeof(teo78_ClsID)) )
	{
		strcpy(pArg->pModuleName, &slot.ModuleName[0]);
		res = success_eo78;
	}
	else
	{
		res = entry_not_found_eo78;
	}
	return res;
}

static FILE *open_registry()
{
	tsp00_Pathc path;
	FILE *f = NULL;

    path.Init();
	registry_file(path);
	if ( path[0] != 0 )
	{
		f = fopen( (char *)path, "r+");
        if ( !f )
        {
            MSGD(( ERR_REGISTRY_OPEN_FAILED, (char *)path ));
        }
	}
	return f;
}

/* 
 * Create empty directoy with MAGIC and an empty slot
 * read_registry will always return a buffer then...
 */
static FILE *create_registry()
{
	tsp00_Pathc path;
	FILE *f = NULL;

    path.Init();
	registry_file(path);
	if ( path[0] != 0 )
	{
		f = fopen( (char *)path, "w+");
        if ( !f )
        {
            MSGD(( ERR_REGISTRY_CREATE_FAILED, (char *)path ));
        }
        else
        {
            MSGD(( INFO_REGISTRY_CREATED, (char *)path ));
        }
	}

	if ( f ) 
	{
		unsigned int magic = DCOM_REGISTRY_MAGIC;

		if ( fwrite(&magic, sizeof(magic), 1, f) != 1 )
		{
            MSGD(( ERR_REGISTRY_WRITE_MAGIC_FAILED, (char *)path ));
			fclose(f);
			f = 0;
		}
		else
		{
			reg_slot empty;
			memset(&empty, 0, sizeof(reg_slot));
			if ( fwrite(&empty, sizeof(reg_slot), 1, f) != 1 )
			{
                MSGD(( ERR_REGISTRY_WRITE_FIRST_SLOT_FAILED, (char *)path ));
				fclose(f);
				f = 0;
			}
			fclose(f);
			f = open_registry();
		}
	}
	return f;
}

static void close_registry(FILE *f)
{
	fclose(f);
}

static int lock_registry(FILE *f)
{
	int res = 0;

	if ( f )
	{
#if !defined(WIN32)
		if ( lockf(fileno(f), F_LOCK, 0) < 0 )
		{
            MSGD(( ERR_REGISTRY_LOCK ));
			res = -1;
		}
#endif
	}
	return res;
}

static void unlock_registry(FILE *f)
{
	if ( f )
	{
#if !defined(WIN32)
		(void)fseek(f, 0, SEEK_SET);
		(void)lockf(fileno(f), F_ULOCK, 0);
#endif
	}
}

static reg_slot *alloc_registry(unsigned int file_size)
{
	char *buffer = (char *)malloc(file_size);
	return (reg_slot *)buffer;
}

static void free_registry(reg_slot *m)
{
	free(m);
}

static reg_slot *read_registry(FILE *f, unsigned int *cnt)
{
	unsigned int file_size;
	unsigned int magic = 0;
	reg_slot *buffer;

	if ( fseek(f, 0, SEEK_END) < 0 )
    {
        MSGD(( ERR_REGISTRY_SEEK_END ));
		return 0;
    }
	file_size = ftell(f);
	if ( file_size < sizeof(magic) )
    {
        MSGD(( ERR_REGISTRY_READ_NO_HEADER, file_size ));
		return 0;
    }
	if ( fseek(f, 0, SEEK_SET) < 0 )
    {
        MSGD(( ERR_REGISTRY_SEEK_BEGIN ));
		return 0;
    }
	if ( fread(&magic, sizeof(magic), 1, f) != 1 )
    {
        MSGD(( ERR_REGISTRY_READ_MAGIC ));
		return 0;
    }
	if ( magic != DCOM_REGISTRY_MAGIC )
    {
        MSGD(( ERR_REGISTRY_WRONG_MAGIC ));
		return 0;
    }
	file_size -= sizeof(magic);

	*cnt = 0;
	buffer = alloc_registry(file_size);
    if ( buffer )
	{
		size_t total_in = 0;
		size_t read_in;
		while ( total_in < (file_size/sizeof(reg_slot)) )
		{
			read_in = fread( buffer + total_in, 
							sizeof(reg_slot), 
							file_size/sizeof(reg_slot), 
							f);
			if ( read_in == ((size_t)-1) )
			{
                MSGD(( ERR_REGISTRY_READ_SLOT, total_in/sizeof(reg_slot) ));
				free_registry(buffer);
				buffer = NULL;
				break;
			}
			total_in += read_in;
		}
		if ( buffer )
		{
			*cnt = total_in;
		}
    }

	return buffer;
}

static int update_registry(FILE *f, reg_slot *slot, unsigned int idx)
{
	if ( fseek(f, sizeof(unsigned int) + sizeof(reg_slot)*idx, SEEK_SET) < 0 )
    {
        MSGD(( ERR_REGISTRY_SEEK_TO_SLOT,
               sizeof(unsigned int) + sizeof(reg_slot)*idx ));
		return -1;
    }
	if ( fwrite(slot, sizeof(reg_slot), 1, f) != 1 )
    {
        MSGD(( ERR_REGISTRY_WRITE_SLOT,
               sizeof(unsigned int) + sizeof(reg_slot)*idx ));
		return -1;
    }
	return 0;
}

static teo78_Result parse_registry(reg_slot *buffer, 
								   unsigned int count,
								   parse_func func,
								   void *func_arg)
{
	teo78_Result res = entry_not_found_eo78;
	unsigned int ii;

	if ( buffer && count > 0 )
	{
		for ( ii = 0; ii < count && res == entry_not_found_eo78; ii++ )
		{
			res = (*func)(buffer[ii], ii, func_arg);
		}
	}
	return res;
}

/*
 * Interface to 'SAP_Db.ini' file:
 */
static char *registry_file(tsp00_Pathc &path)
{
	tsp01_RteError RteError;

//	if ( sqlGetIndependentConfigPath( path, 1, &RteError) )
// PTS 1104030 24.9.1999
    if ( sqlGetDbrootWrkPath( path, 1, &RteError) )
	{
		strcat((char *)path, DCOM_REGISTRY_FILE);
	}
	else
	{
        MSGD(( ERR_REGISTRY_FILE_PATH, (char *)RteError.RteErrText ));
		path[0] = 0;
	}
	return &path[0];
}

/*===========================================================================*
 *  END OF CODE                                                              *
 *===========================================================================*/

