/*!================================================================

  module:       irconf.c

 -------------------------------------------------------------------

  responsible:  BurkhardD

  special area: Registration tool to register a client installation

  description:                 


  see also:

  -------------------------------------------------------------------------

  copyright:    (c) 2000-2004 SAP AG




    ========== 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




 ===================================================================*/
#ifdef WIN32
#include <windows.h>
#endif
#include <stdlib.h>
#include <errno.h>
#ifndef WIN32
#include <sys/param.h>
#include <unistd.h>
#endif

#undef sqlgetenv

#include "gsp00.h"
#include "heo02x.h"
#include "vpi01Libpcrl.h"
#include "Interfaces/cpc/irconf.h"
#include "vpr09Config.h"
#include "SAPDBCommon/SAPDB_Names.h"
#include "RunTime/RTE_IniFileHandling.h"

#ifdef WIN32
#define IRCONF_DEFAULTPATH "%INSTROOT%"
#else
#define IRCONF_DEFAULTPATH "$INSTROOT"
#endif

#define ERR_INVALID_OPTION "Invalid option"
#define ERR_OPTION_COMBINATION "Invalid combination of options"
#define ERR_MISSING_DRIVERNAME "Missing drivername"
#define ERR_MISSING_DRIVER "Missing "COMP_NAME_CPC_DRV_IP01" name of"
#define ERR_MISSING_VERSION "Missing version number"
#define ERR_MISSING_PATH   "Missing path name"
#define ERR_MISSING_INSTALL_NAME   "Missing installation name"
#define ERR_INCORRECT_VERSION "The version number of the "COMP_NAME_CPC_DRV_IP01" is unknown"
#define ERR_NO_INSTALLATION "Cannot find any installed version of "COMP_NAME_CPC_DRV_IP01"."
#define ERR_WRONG_LDR_SWITCH "Wrong switch. Use \"on\" or \"off\""
#define ERR_SET_REG_KEY "Error during set registry key"

#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif

#define WARN_VERSION_NOT_EQUAL "Installed driver version different from registration"
#define WARN_INSTALLATION_NOT_FOUND "The specified installation does not exist"

#define IRCONF_DRIVER_NAME_DEFAULT LIBNAME_PI01

#ifdef WIN32
typedef struct {
  WORD   wLength; 
  WORD   wValueLength; 
  WORD   wType; 
  WCHAR  szKey[];
} ResString_tirconf; 

static WCHAR szVS_VERSION_INFO[]= L"VS_VERSION_INFO";

#endif

static tpi01_PathC szSAPDBKey=PI01_SAPDB_KEY;
static tpi01_PathC szDriver=IRCONF_DRIVER_NAME_DEFAULT;
static tsp00_ErrText ErrText;

typedef char* Result_irconf;
static Result_irconf OK_irconf = "OK";
static Result_irconf WarnVersionNotFound_irconf = "Cannot get version info of "COMP_NAME_CPC_DRV_IP01;
static Result_irconf WarnDriverNotExist_irconf = "The specified driver does not exist";
static Result_irconf WarnKeyTooLong_irconf = "The specified key is too long";

#define LOW_WORD(dword)          (WORD) ( (dword) & 0x0000FFFF )
#define HI_WORD(dword)           (WORD) ( (dword) & 0xFFFF0000 )

int irconf_PrintError(char * szString);
int irconf_PrintWarning(char * szString);
int irconf_PrintUsage(int argc, char ** argv);
void irconf_PrintVersion(char *szPath, char *szVersion);
char *irconf_GetVersionOfDriver(char *szPath, char *szDriver, char *szVersion, char *szInstallName);
Result_irconf irconf_GetVersion(char *szDriverName, char *szVersion, char* szInstallName);

int irconf_Remove(int globalMode, char *szPath);
int irconf_Install(int globalMode, char *szPath, char *szDriver, char *szVersion, char *szInstallName);
int irconf_RemoveDuplicates(int globalMode, char *szPath, char *szDriver, char *szVersion, char *szInstallName);
int irconf_Show(boolean globalMode, boolean showAll, char *szVersion, char *szInstallName);

void irconf_MapPath(char *szPath);
char *irconf_BuildPath(char *szPath);
char *irconf_GetParm(char *opt, char *parm, int *arg);
static void irconf_ShowLdrPath ();
static int irconf_SetLdrSwitch (char *szLdr);

int main(int argc, char ** argv)
{
  int i;
  boolean globalMode=FALSE;
  boolean install=FALSE;
  boolean remove=FALSE;
  boolean show=FALSE;
  boolean showAll=FALSE;
  boolean ldrswitch=FALSE;
  tpi01_PathC szPath="";
  tpi01_PathC szInstallName="";
  VersionStr_tpi01 szVersion="";
  char szLdr[64];
  ConfigHandle_tpr09 hConfig;
  ConfigResult_tpr09 ret;
  Result_irconf result;

  RTE_InitIniFileHandling( );
  if ( argc <= 1 ) {
    return(irconf_PrintUsage(argc, argv));
  }
  else {
    char *p = getenv("DBROOT");
    if (p) {
      strcpy(szPath ,p);
    }
    for (i=1; i < argc;) {
      char *opt=argv[i];
      char *parm=argv[i+1];
      if (opt) {
	switch (*opt) {
	case ('-'):{}	
	case ('/'):{
	  opt++;
	  switch(*opt) {
            /* ?hirds:k:p:v: */
	  case ('\0'): {
	    break;
	  }
	  case ('?'): {}
	  case ('h'): {
	    return(irconf_PrintHelp(argc, argv));
	    break;
	  }
	  case ('i'): {
	    install = TRUE;
	    i++;
	    break;
	  }
	  case ('g'): {
	    globalMode = TRUE;
	    i++;
	    break;
	  }
	  case ('s'): {
	    show = TRUE;
	    i++;
	    break;
	  }
	  case ('a'): {
	    showAll = TRUE;
	    i++;
	    break;
	  }
	  case ('r'): {
	    remove = TRUE;
	    i++;
	    break;
	  }
	  case ('d'): {
	    if (parm = irconf_GetParm(opt, parm, &i)) {
	      strcpy(szDriver, parm);
	      i++;
	    }
	    else {
	      return(irconf_PrintError(ERR_MISSING_DRIVER));
	    }	
	    break;
	  }
	  case ('k'): {
	    if (parm = irconf_GetParm(opt, parm, &i)) {
	      strncpy(szInstallName, parm, sizeof(szInstallName));
	      szInstallName[sizeof(szInstallName)-1] = '\0';
	      i++;
	    }
	    else {
	      return(irconf_PrintError(ERR_MISSING_INSTALL_NAME));
	    }	    
	    break;
	  }
	  case ('p'): {
	    if (parm = irconf_GetParm(opt, parm, &i)) {
	      strcpy(szPath, parm);
	      i++;
	    }
	    else {
	      return(irconf_PrintError(ERR_MISSING_PATH));
	    }	    
	    break;
	  }
	  case ('v'): {
	    if (parm = irconf_GetParm(opt, parm, &i)) {
	      strcpy(szVersion, parm);
	      i++;
	    }
	    else {
	      return(irconf_PrintError(ERR_MISSING_VERSION));
	    }	
	    break;
	  }
	  case ('l'): {
	    if (parm = irconf_GetParm(opt, parm, &i)) {
	      strcpy(szLdr, parm);
	      ldrswitch = TRUE;
	    }
	    else {
	      irconf_ShowLdrPath ();
	    }	
	    i++;
	    break;
	  }
	  default: {
	    return(irconf_PrintError(ERR_INVALID_OPTION));
	  }		
	} /* if (opt) */
	break;
	}
	default: {
#ifdef NO_DEFAULT_INI_FILE
	  strcpy(szSAPDBKey, opt);
	  i++;
#else
	  return(irconf_PrintError(ERR_INVALID_OPTION));
#endif
	  break;
	}
	} /* switch */
      } /* if ( opt ) */
    }
  }
  /* check arguments */
  if (install || remove) {
    if (szPath[0] == 0)
      return(irconf_PrintError(ERR_MISSING_PATH));
    if (szDriver[0] == 0)
      return(irconf_PrintError(ERR_MISSING_DRIVER));
  }
  if ( (install + remove + (show | showAll) + ldrswitch) > TRUE )
    return(irconf_PrintError(ERR_OPTION_COMBINATION));

  irconf_BuildPath(szPath);
  irconf_MapPath(szPath);

  if (ldrswitch) 
  {
      RTE_Path ConfigPath;
      RTE_IniFileErrtext ErrText;

      if ( globalMode )
      {
          irconf_PrintError("Only local setting of this switch allowed");
          return -1;
      }
      if (irconf_SetLdrSwitch(szLdr))
      {
          return -1;
      }

      if ( RTE_GetUserSpecificConfigPath ( ConfigPath,
                                           false,
                                           ErrText ) )
      {
          if (!strcmp (szLdr, "on") ||
              !strcmp (szLdr, "ON")) 
          {
               printf ("Writing of loader trace %s"PATHSEP_IP00""TRACE_FILE_NAME" enabled.\n", ConfigPath);
          }
          else
          {
               printf ("Writing of loader trace %s"PATHSEP_IP00""TRACE_FILE_NAME" disabled.\n", ConfigPath);
          }
      }
      return 0;
  }

  if (install) {
    irconf_RemoveDuplicates(globalMode, szPath, szDriver, szVersion, szInstallName);
    if (irconf_Install(globalMode, szPath, szDriver, szVersion, szInstallName))
      return -1;
  }

  if (remove) {
    if (irconf_Remove(globalMode, szPath))
      return -1;
  }

  if (show|showAll) {
    char *tmpVer = szVersion[0] == '\0' ? NULL : szVersion;
    char *tmpInst = szInstallName[0] == '\0' ? NULL : szInstallName;

    if (irconf_Show(globalMode, showAll, tmpVer, tmpInst))
      return -1;
  }
  return(0);
}

int irconf_Show(boolean globalMode, boolean showAll, char *szVersion, char *szInstallName)
{
  ConfigHandle_tpr09 hConfig;
  RTE_RegistryLocation location;           /* location of retrieved entry */
  Result_irconf result;
  hConfig = pr09ConfigOpenRuntimeSection(SAPDB_RUNTIME_SECTION, ErrText);
  if ( hConfig ) {
    tpi01_PathC szRegPath;
    tpi01_VersionID vshow;
    VersionStr_tpi01 szRegVersion="";
    if (szVersion) {
      pi01VersionS2B(szVersion, &vshow);      
    }
    for(;;) {
      ConfigResult_tpr09 ret;        
      ret = pr09ConfigNextRuntimeEntry(hConfig, &location, szRegPath, sizeof(szRegPath), szRegVersion, sizeof(szRegVersion), ErrText);
      if (ret == ERR_NO_MORE_DATA_epr09) {
        pr09ConfigCloseRuntimeSection(hConfig, ErrText);
        break;
      }
      if (ret == ERR_OK_epr09 )
      {
          char const *locationString;
        VersionStr_tpi01 szDriverVersion="";
        boolean match = true;
        tpi01_VersionID vreg;

          if ( !showAll )
          {
              locationString = "";
              if ( globalMode )
              {
                  if ( RTE_GlobalRegistry != location )
                      continue;
              }
              else
              {
                  if ( RTE_UserRegistry != location )
                      continue;
              }
          }
          else
          {
            switch(location)
            {
            case RTE_UserRegistry:
                locationString = " from user registration";
                break;
            case RTE_GlobalRegistry:
                locationString = " from global registration";
                break;
            case RTE_OldUNIXRegistry:
                locationString = " from old registration";
                break;
            default:
                locationString = " from ? registration";
                break;
            }
          }


        pi01VersionS2B(szRegVersion, &vreg);
        /* show only version where SAPDBINSTKEY matches */
        if (szInstallName && strcmp(vreg.szKey, szInstallName))
          match = false;
        /* show only version that matches the given version */
        if (szVersion && pi01IsEqualVersion(&vshow, &vreg))
          match = false;
        if (!match)
          continue;

        if (szInstallName)
          result = irconf_GetVersionOfDriver(szRegPath, szDriver, szDriverVersion, szInstallName);
        else
          result = irconf_GetVersionOfDriver(szRegPath, szDriver, szDriverVersion, "");
        if (result != OK_irconf) {
          irconf_PrintVersion(szRegPath, szRegVersion);
          printf("%s\n", locationString);
          irconf_PrintWarning(result);
        }
        else {
          tpi01_VersionID vdriver;
          pi01VersionS2B(szDriverVersion, &vdriver);
          if (!pi01IsEqualVersion(&vdriver, &vreg)) {
            irconf_PrintVersion(szRegPath, szRegVersion);
            printf("%s\n", locationString);
          }	    
          else {
            irconf_PrintVersion(szRegPath, szRegVersion);
            printf("%s\n", locationString);
            irconf_PrintWarning(WARN_VERSION_NOT_EQUAL);
            printf("Installed driver version is ");
            irconf_PrintVersion(NULL, szDriverVersion);
            printf(".\n");
          }
        }
        continue;
      }
      else {
        return(irconf_PrintError((char*)ErrText));
      }
    }
  }
  else
    return(irconf_PrintError(ERR_NO_INSTALLATION));      
  return 0;
}

int irconf_Install(int globalMode, char *szPath, char *szDriver, char *szVersion, char *szInstallName)
{
    RTE_IniFileErrtext ErrText;
    RTE_IniFileResult  Ok;

    Result_irconf result;
    if (szVersion[0] == '\0')
    {
        result = irconf_GetVersionOfDriver(szPath, szDriver, szVersion, szInstallName);
        if (result != OK_irconf)
        {
            irconf_PrintWarning(result);
        }
    }
    if (szVersion[0] == 0)
        return(irconf_PrintError(ERR_INCORRECT_VERSION));
    if ( globalMode )
    {
        RTE_PutConfigString (SAPDB_RUNTIMES_INI_FILE, SAPDB_RUNTIME_SECTION, szPath, szVersion, ErrText, &Ok);
        if ( SAPDB_INIFILE_RESULT_OK != Ok )
        {
            return(irconf_PrintError(ErrText));
        }
    }
    else
    {
        RTE_PutUserConfigString (SAPDB_RUNTIMES_INI_FILE, SAPDB_RUNTIME_SECTION, szPath, szVersion, ErrText, &Ok);
        if ( SAPDB_INIFILE_RESULT_OK != Ok )
        {
            return(irconf_PrintError(ErrText));
        }
    }
    irconf_PrintVersion(szPath, szVersion);
    printf(" registered.\n");      
    return 0;
}

int irconf_Remove(int globalMode, char *szPath)
{
    RTE_IniFileErrtext ErrText;
    RTE_IniFileResult  Ok;
    VersionStr_tpi01 szRegVersion="";
    SAPDB_Bool foundVersion;

    if ( globalMode )
    {
        RTE_GetGlobalConfigString( SAPDB_RUNTIMES_INI_FILE,
                                   SAPDB_RUNTIME_SECTION, 
                                   szPath, 
                                   szRegVersion, 
                                   sizeof(szRegVersion),
                                   ErrText,
                                   &Ok);
        foundVersion = ( SAPDB_INIFILE_RESULT_OK == Ok );
        if ( foundVersion )
        {
            RTE_RemoveConfigString( SAPDB_RUNTIMES_INI_FILE,
                                    SAPDB_RUNTIME_SECTION, 
                                    szPath, 
                                    ErrText, 
                                    &Ok);
        }
    }
    else
    {
        RTE_GetUserConfigString( SAPDB_RUNTIMES_INI_FILE,
                                 SAPDB_RUNTIME_SECTION, 
                                 szPath, 
                                 szRegVersion, 
                                 sizeof(szRegVersion),
                                 ErrText,
                                 &Ok);
        foundVersion = ( SAPDB_INIFILE_RESULT_OK == Ok );
        if ( foundVersion )
        {
            RTE_RemoveUserConfigString( SAPDB_RUNTIMES_INI_FILE,
                                        SAPDB_RUNTIME_SECTION, 
                                        szPath,
                                        ErrText,
                                        &Ok);
        }
    }

    if ( SAPDB_INIFILE_RESULT_OK == Ok )
    {
        irconf_PrintVersion(szPath, szRegVersion);
        printf(" registration removed.\n");
    }
    else
    {
        if ( foundVersion )
        {
            return(irconf_PrintError(ErrText)); 
        }
        else
        {
            irconf_PrintWarning(WARN_INSTALLATION_NOT_FOUND);
        }
    }
    return 0;
}

int irconf_RemoveDuplicates(int globalMode, char *szPath, char *szDriver, char *szVersion, char *szInstallName)
{
    RTE_IniFileErrtext ErrText;
    RTE_IniFileResult  Ok;
    ConfigHandle_tpr09 hConfig;
    RTE_RegistryLocation location;           /* location of retrieved entry */
    Result_irconf result;
    if ( globalMode )
    {
        hConfig = RTE_OpenGlobalConfigEnum(SAPDB_RUNTIMES_INI_FILE, SAPDB_RUNTIME_SECTION, ErrText, &Ok);
    }
    else
    {
        hConfig = RTE_OpenUserConfigEnum(SAPDB_RUNTIMES_INI_FILE, SAPDB_RUNTIME_SECTION, ErrText, &Ok);
    }

    if ( hConfig ) 
    {
        tpi01_PathC szRegPath;
        tpi01_VersionID vshow;
        VersionStr_tpi01 szRegVersion="";
        if (szVersion) {
          pi01VersionS2B(szVersion, &vshow);      
        }
        for(;;) {
          ConfigResult_tpr09 ret;        
          RTE_NextConfigEnum(hConfig, szRegPath, sizeof(szRegPath), szRegVersion, sizeof(szRegVersion),  &location, ErrText, &Ok);
          if (SAPDB_INIFILE_RESULT_EOF == Ok) {
            RTE_CloseConfigEnum(hConfig, ErrText, &Ok);
            break;
          }
          if (SAPDB_INIFILE_RESULT_OK == Ok) {
            tpi01_VersionID vreg;
            pi01VersionS2B(szRegVersion, &vreg);
            if (szInstallName && szInstallName[0] != '\0' && !strcmp(vreg.szKey, szInstallName))
#ifdef WIN32
              if (szPath && stricmp(szRegPath, szPath)) {
#else
              if (szPath && strcmp(szRegPath, szPath)) {
#endif
                if ( globalMode )
                {
                    RTE_RemoveConfigString(SAPDB_RUNTIMES_INI_FILE, SAPDB_RUNTIME_SECTION, szRegPath, ErrText, &Ok);
                }
                else
                {
                    RTE_RemoveUserConfigString(SAPDB_RUNTIMES_INI_FILE, SAPDB_RUNTIME_SECTION, szRegPath, ErrText, &Ok);
                }
                if (SAPDB_INIFILE_RESULT_OK == Ok) {
                  irconf_PrintVersion(szRegPath, szRegVersion);
                  printf(" duplicate key removed.\n", szPath);
                }
                else {
                  RTE_IniFileErrtext DummyErrText;
                  RTE_CloseConfigEnum(hConfig, DummyErrText, &Ok);
                  return(irconf_PrintError((char*)ErrText));            
                }
              }
          }
          else {
            RTE_IniFileErrtext DummyErrText;
            RTE_CloseConfigEnum(hConfig, DummyErrText, &Ok);
            return(irconf_PrintError((char*)ErrText));
          }
        }
    }
    return 0;
}

char *irconf_GetParm(char *opt, char *parm, int *arg)
{
  if (*(opt+1) != '\0') {
    (*arg)--;
    parm = opt+1;  
  }
  if (parm && (*parm != '-' || *parm != '/')) {
    (*arg)+=1;
    return parm;
  }
  return NULL;
}

char *irconf_BuildPath(char *szPath)
{
  return szPath;
}

void irconf_MapPath(char *szPath)
{
  char *p;
  if (szPath)
    for(p=szPath;*p != '\0'; p++)
      *p = (*p == '\\') ? '/' : *p;
}

static void irconf_ShowLdrPath ()
{
  ConfigResult_tpr09 res1, res2;
  tsp00_ErrText ErrText;
  RTE_IniFileErrtext iniErrText;
  char szLdr[32];
  tsp00_Pathc userDataPath;

  res1 = pr09ConfigGetRuntimeStringEx (SAPDB_GLOBALS_SECTION, PI01_LDRDIAG_KEY, szLdr, sizeof(szLdr), ErrText);
  res2 = ( RTE_GetUserSpecificConfigPath(userDataPath, false, iniErrText ) ? ERR_OK_epr09 : ERR_NOT_OK_epr09 );
  if (!strcmp (szLdr, "YES") &&
      (res1 == ERR_OK_epr09) &&
      (res2 == ERR_OK_epr09)) {
    printf ("Writing of loader trace %s"PATHSEP_IP00""TRACE_FILE_NAME" enabled.\n", userDataPath);
  } else {
    printf ("Writing of loader trace %s"PATHSEP_IP00""TRACE_FILE_NAME" disabled.\n", userDataPath);
  }
}

static boolean irconf_SetRegLdrSwitch (char *Value)
{
  ConfigResult_tpr09 res;
  tsp00_ErrText ErrText;

  res = pr09ConfigPutRuntimeStringEx (SAPDB_GLOBALS_SECTION, PI01_LDRDIAG_KEY, Value, ErrText);
  if (res != ERR_OK_epr09) {
    return(irconf_PrintError(ERR_SET_REG_KEY));
  }

  return 0;
}

static int irconf_SetLdrSwitch (char *szLdr)
{
  if (strcmp (szLdr, "on") &&
      strcmp (szLdr, "off") &&
      strcmp (szLdr, "ON") &&
      strcmp (szLdr, "OFF")) {
    return(irconf_PrintError(ERR_WRONG_LDR_SWITCH));
  }
  if (!strcmp (szLdr, "on") ||
      !strcmp (szLdr, "ON"))
    return (irconf_SetRegLdrSwitch ("YES"));
  else
    return (irconf_SetRegLdrSwitch ("NO"));
}

void irconf_IfAppendPathSep(char *szPath)
{
  static char *PathSep = PATHSEP_IP00;
  int len = (int)strlen(szPath);
  if (len > 0) {
    if (szPath[len-1] != PathSep[0]) {
      strcat(szPath, PathSep);
    }
  }  
}

Result_irconf irconf_GetVersionOfDriver(char *szPath, char *szDriver, char *szVersion, char *szInstallName)
{
  tpi01_PathC szString="";
  Result_irconf ret;
  if ( szPath[0] != '\0' ) {
    strcpy(szString, szPath);
    irconf_IfAppendPathSep(szString);
    strcat(szString, SHLPATH_IP00);
  }
  irconf_IfAppendPathSep(szString);
  strcat(szString, szDriver);
  ret = irconf_GetVersion(szString, szVersion, szInstallName);
  if (ret == OK_irconf)
    return ret;
#ifdef BIT64
  /* try 64 bit */
  if ( szPath[0] != '\0' ) {
    strcpy(szString, szPath);
    irconf_IfAppendPathSep(szString);
    strcat(szString, SHLPATH_IP00);
    irconf_IfAppendPathSep(szString);
    strcat(szString, SHL64PATH_IP00);
    irconf_IfAppendPathSep(szString);
  }
  strcat(szString, szDriver);
  ret = irconf_GetVersion(szString, szVersion, szInstallName);
#endif  
  return ret;
}

static void (*sqlgetver)(char *szVersion, char* szMinVersion);

#ifndef WIN32
Result_irconf irconf_GetVersion(char *szDriverName, char *szVersion, char* szInstallName)
{
  tsp00_ErrText errtext;
  char szVer1[8], szVer2[8];
  HANDLE hLib = sqlLoadLibrary(szDriverName, (char*)errtext, sizeof(tsp00_ErrText));
  if (!hLib)
    return WarnDriverNotExist_irconf;
  sqlgetver = (void (*)(char*,char*))sqlGetProcAddress(hLib, "sqlgetver", 
				(char*)&errtext, sizeof(errtext));
  if (sqlgetver) {
    int ver[3];
    sqlgetver(szVer1, szVer2);
    sqlFreeLibrary(hLib, (char*)&errtext, sizeof(errtext));
    pi01UnpackVersion(szVersion, szVer1);
    if ( sizeof(VersionStr_tpi01) > strlen(szVersion)+strlen(szInstallName)+ 3)
    /*only if enough space in szVersion*/
    {
      /*#define PI01_VERSION_FMT "%u.%u.%u.%u,%s"*/
      sprintf(szVersion, "%s.%u,%s",szVersion, 0, szInstallName);
    }  
    else
    {
       return WarnKeyTooLong_irconf;        
    }
    return OK_irconf;
  }  
  return WarnVersionNotFound_irconf;
}
#else
Result_irconf irconf_GetVersion(char *szDriverName, char *szVersion, char* szInstallName)
{
  HINSTANCE hModule;
  VS_FIXEDFILEINFO *pFileInfo = NULL;
  hModule = LoadLibraryEx(szDriverName, NULL, LOAD_LIBRARY_AS_DATAFILE);
  if ( hModule ) {
    LONG lParam=0;
    HRSRC hRes;
    hRes = FindResource( hModule, MAKEINTRESOURCE(1), RT_VERSION );  
    if (hRes) {
      HGLOBAL hMem;
      hMem = LoadResource(hModule, hRes);
      if (hMem) {
	ResString_tirconf *pVersionInfo = hMem;
	if (pVersionInfo && pVersionInfo->wValueLength) {
	  if (!wcscmp(pVersionInfo->szKey, szVS_VERSION_INFO)) {
	    int cbA = sizeof(ResString_tirconf) + sizeof(szVS_VERSION_INFO);
	    /* Align to 32 bit */
	    cbA += cbA%4;	    
	    pFileInfo = malloc(sizeof(VS_FIXEDFILEINFO));
	    memcpy(pFileInfo, (VS_FIXEDFILEINFO*)((char*)pVersionInfo+cbA), sizeof(VS_FIXEDFILEINFO));
	    if (pFileInfo->dwSignature != 0xfeef04bd) {
	      free(pFileInfo);
	      pFileInfo = NULL;
	    }
	  }
	}
      }
    }
    FreeLibrary(hModule);
  }
  else {
    return WarnDriverNotExist_irconf;
  }
  if (pFileInfo) {
    WORD *MS = (WORD*)&pFileInfo->dwFileVersionMS;
    WORD *LS = (WORD*)&pFileInfo->dwFileVersionLS;
    if (szVersion)
      sprintf(szVersion, PI01_VERSION_FMT, MS[1], MS[0], LS[1], LS[0], szInstallName);
    return OK_irconf;
  }
  return WarnVersionNotFound_irconf;
}
#endif

int irconf_PrintError(char * szString)
{
  printf("Error : %s.\n", szString);
  return(-1);
}

int irconf_PrintWarning(char * szString)
{
  printf("Warning : %s.\n", szString);
  return(-1);
}

char *irconf_Arg0(int argc, char ** argv)
{
  char *p=argv[0];
  char *a;
  int pos=0;
  if (a=strrchr(p, '\\')) {
    return a+1;
  }
  else
    if (a=strrchr(p, '/')) {
      return a+1;
    }
  return p;
}

int irconf_PrintUsage(int argc, char ** argv)
{
  printf("Usage : %s %s-i[v:d:p:k:] | -r[p:] | -s[v:k:] | -l [on|off] | -l | -h\n\n"
	 "Options:\n"
	 "           -i Installs (register) a driver\n"
	 "           -r Removes (unregister) a driver\n"
	 "           -s Shows installed versions\n"
	 "           -a Shows all installed versions\n"
	 "           -g use global configuration instead of user configuration\n"
	 "           -v <##.##.##.##> default version of "COMP_NAME_CPC_DRV_IP01"\n"
	 "           -d <"COMP_NAME_CPC_DRV_IP01">\t default '%s'\n"
	 "           -p <path> \t default '%s'\n"
	 "           -k <key> \t name for the installation\n"
     "           -l [on|off] \t enables/disables writing of "TRACE_FILE_NAME"\n"
     "           -l Shows status of writing of "TRACE_FILE_NAME"\n"
	 "           -h Prints help\n\n"
#ifdef NO_DEFAULT_INI_FILE
	 "The default for the <sapdb key> is \""IRCONF_SAPDB_KEY"\"\n",
#endif
	 , irconf_Arg0(argc, argv), 
#ifdef NO_DEFAULT_INI_FILE
	 "[<sapdb key>] "
#else
	 ""
#endif
	 , IRCONF_DRIVER_NAME_DEFAULT, IRCONF_DEFAULTPATH);
  return(-1);
}

int irconf_PrintHelp(int argc, char ** argv)
{
  char *pname = irconf_Arg0(argc, argv);
  printf("%s: %s registers a previously installed version of the client runtime.\n"
	 "It also checks the installed version of the driver against the registered\n"
	 "version.\n"
	 "You can use the -s option to show all installed versions. The -i option\n"
	 "registers or updates the configuration of the  installed version specified\n"
	 "by the -p option.\n"
	 "If -p is not set, %s will default the <path> argument to the environment\n"
	 "variable %s.\n"
	 "The -r option will remove the configuration.\n"
	 "If -v is set the versioncheck for the driver will ignore and the given version\n"
	 "will be used by %s.\n"
     "The -l option triggers the writing of a loader trace file for the precompiler\n"
     "runtime library.\n\n",
         pname, pname, pname, IRCONF_DEFAULTPATH, pname);
  return irconf_PrintUsage(argc, argv);
}

void irconf_PrintVersion(char *szPath, char *szVersion)
{
  tpi01_VersionID version;
  pi01VersionS2B(szVersion, &version);	  
  if (szPath) 
    printf("%s -> ", szPath);
  printf("%u.%u.%u.%u", version.No[0], version.No[1], version.No[2], version.No[3]);
  if (version.szKey[0] != '\0') {
    printf(",%s", version.szKey);
  }
}
