/*
 *
 *  (c) COPYRIGHT INRIA, 1996-2003
 *  Please first read the full copyright statement in file COPYRIGHT.
 *
 */

/*
 * registry.c : common access method for all the configuration
 *              dependancies of Thot.
 *
 * On the Unix platforms, the registry entries are stored in
 * appname.ini file, appname standing for the real application
 * name, e.g. thot.ini or amaya.ini . This file is store in the
 * user home directory or in a system wide configuration directory
 * e.g. /usr/local/thot/bin/thot.ini .
 *
 * On Windows platforms, this is of course based on the standard
 * registry mechanism.
 *
 * Author: D. Veillard (INRIA)
 * Extensions: J. KAHAN (INRIA/W3C)
 *
 */

#include "thotkey.h"
#include "thot_sys.h"
#include "constmedia.h"
#include "typemedia.h"
#include "registry.h"
#include "application.h"
#define THOT_EXPORT
#include "platform_tv.h"
#include "applicationapi_f.h"
#include "fileaccess_f.h"
#include "memory_f.h"
#include "platform_f.h"
#include "uconvert_f.h"
/* #define DEBUG_REGISTRY enable the Registry debug messages */

/* for Marc.Baudoin@hsc.fr (Marc Baudoin) */
#ifdef _WINDOWS
#include <direct.h>
#include <winbase.h>
#include "winsys.h"
#define WIN_DEF_USERNAME       "default"
#define THOT_INI_FILENAME      "win-thot.rc"
#define WIN_USERS_HOME_DIR     "users"
#define DEF_TMPDIR             "c:\\temp"
static char         EnVar[MAX_PATH];	/* thread unsafe! */
#else /* _WINDOWS */
#define THOT_INI_FILENAME      "unix-thot.rc"
#define DEF_TMPDIR             "/tmp"
#endif /*  _WINDOWS */

#define THOT_RC_FILENAME      "thot.rc"
#define THOT_CONFIG_FILENAME  "config"
#define THOT_BIN_FILENAME     "bin"
#define THOT_LIB_DEFAULTNAME  "thot_lib"
#define MAX_REGISTRY_ENTRIES 100

typedef enum
{
  REGISTRY_USER,	/* values which can be redefined by the user */
  REGISTRY_SYSTEM,	/* values fetched from the system config     */
  REGISTRY_INSTALL,	/* installation value e.g. THOTDIR, VERSION  */
  REGISTRY_MAX_CATEGORIES
}
RegistryLevel;

typedef struct struct_RegistryEntry
{
  struct struct_RegistryEntry *next;  /* chaining ! */
  RegistryLevel                level; /* exact level */
  char                        *appli; /* corresponding section */
  char                        *name;  /* name of the entry     */
  char                        *orig;  /* original value (to be saved back) */
  char                        *value; /* user-level value */
}
RegistryEntryBlk , *RegistryEntry;

static int           AppRegistryInitialized = 0;
static int           AppRegistryModified = 0;
static RegistryEntry AppRegistryEntry = NULL;
static char         *AppRegistryEntryAppli = (char*) 0;
static char         *AppNameW;
static char          CurrentDir[MAX_PATH];
static char         *Thot_Dir;

#ifndef _WINDOWS
char  UCOMPILED_IN_THOTDIR[MAX_TXT_LEN];
char  UCOMPILED_IN_THOTDIR2[MAX_TXT_LEN];
char  UMACHINE[MAX_TXT_LEN];
#endif  /* _WINDOWS */         

PathBuffer execname;
PathBuffer path;

#ifdef _WINDOWS
/* @@why do we need this here? */
int errno;
#endif

/*----------------------------------------------------------------------
  ----------------------------------------------------------------------*/
static char *SkipToEqual (char *ptr)
{
  while (*ptr != EOS && *ptr != '=' && *ptr != EOL && *ptr != __CR__)
    ptr++;
  return (ptr);
}

/*----------------------------------------------------------------------
   TtaSkipBlanks skips all spaces, tabs, linefeeds and newlines at the
   beginning of the string and returns the pointer to the new position. 
  ----------------------------------------------------------------------*/
char *TtaSkipBlanks (char *ptr)
{
  while (*ptr == SPACE || *ptr == BSPACE || *ptr == EOL ||
	  *ptr == TAB || *ptr == __CR__)
    ptr++;
  return (ptr);
}

/*----------------------------------------------------------------------
   TtaIsBlank returns True if the first character is a space, a tab, a
   linefeed or a newline.
  ----------------------------------------------------------------------*/
ThotBool TtaIsBlank (char *ptr)
{
  if (*ptr == SPACE || *ptr == BSPACE || *ptr == EOL ||
      *ptr == TAB || *ptr == __CR__)
    return (TRUE);
  else
    return (FALSE);
}


/*----------------------------------------------------------------------
 DoVariableSubstitution : do the substitution on an input
    string of all $(xxx) references by the values of xxx.
   and return a modified output string.
  ----------------------------------------------------------------------*/
static void DoVariableSubstitution (char *input, int i_len, char *output,
				    int o_len)
{
  char *cour = input;
  char *base = input;
  char *res  = output;
  char *value;
  char  save;

#define CHECK_OVERFLOW (cour - input > i_len || res - output >= o_len - 1)
  while (*cour)
    {
      if CHECK_OVERFLOW
	break;
      if (*cour != '$')
	{
	  *res++ = *cour++;
	  continue;
	}
      base = cour;		/* save the position to the $ */
      cour++;
      if CHECK_OVERFLOW
	break;
      if (*cour != '(')
	{
	  *res++ = '$';
	  if CHECK_OVERFLOW
	    break;
	  *res++ = *cour++;
	  continue;
	}

      /* Ok, that the beginning of a variable name ... */
      base += 2;		/* skip the $(  header */
      do
	{
	  cour++;
	  if CHECK_OVERFLOW
	    break;
	}
      while (*cour != ')' && !TtaIsBlank (cour));
      if CHECK_OVERFLOW
	break;
      
      save = *cour;
      *cour = EOS;
      if (save != ')')
	fprintf (stderr, "invalid variable name %s in %s\n", base, THOT_INI_FILENAME);

      /* We are ready to fetch the base value from the Registry */
      value = TtaGetEnvString (base);
      if (value == NULL)
	{
	  fprintf (stderr, "%s referencing undefined variable %s\n", THOT_INI_FILENAME, base);
	  *cour = save;
	  cour++;
	  if CHECK_OVERFLOW
	    break;
	  continue;
	}
      *cour = save;
      while (*value)
	{
	  *res++ = *value++;
	  if CHECK_OVERFLOW
	    break;
	}
      cour++;
      if CHECK_OVERFLOW
	break;
    }
  if CHECK_OVERFLOW
    fprintf (stderr, "DoVariableSubstitution : Overflow on \"%s\"\n", input);
  *res = EOS;
}


/*----------------------------------------------------------------------
 NewRegisterEntry : add a fresh new entry in the Register.
  ----------------------------------------------------------------------*/
static int NewRegisterEntry (char *appli, char *name, char *value,
			     RegistryLevel level)
{
   char        resu[2000];
   RegistryEntry cour, ptr, previous;

   if (AppRegistryInitialized == 0)
      return (-1);

   /*
    * do not register volatile informations like the
    * home dir or the current working directory.
    */
   if (!strcasecmp (name, "pwd"))
      return (0);
   if (!strcasecmp (name, "home"))
      return (0);
   if (!strcasecmp (name, "user"))
      return (0);
   if (!strcasecmp (name, "cwd"))
      return (0);

   /*
    * substitute the $(xxxx) with their values.
    */
   DoVariableSubstitution (value, strlen (value), resu, sizeof (resu) / sizeof (char));

   /*
    * allocate an entry, fill it and chain it.
    */

   cour = (RegistryEntry) TtaGetMemory (sizeof (RegistryEntryBlk));
   if (cour == NULL)
      return (-1);
   cour->appli = TtaStrdup (appli);
   cour->name  = TtaStrdup (name);
   cour->orig  = TtaStrdup (value);
   cour->value = TtaStrdup (resu);
   cour->level = level;

   /*
    * sort the new entry according to its level
    */

   if (!AppRegistryEntry)
     /* it's the first entry */
     {
       cour->next = NULL;
       AppRegistryEntry = cour;
     }
   else
     {
       /* find the first level entry */
       ptr = AppRegistryEntry;
       previous = AppRegistryEntry;
       while (ptr && ptr->level < level)
	 {
	   previous = ptr;
	   ptr = ptr->next;

	 }
       if (!ptr)
	 /* insert it at the end*/
	 {
	   cour->next = NULL;
	   previous->next = cour;
	 }
       else if (level <= ptr->level)
	 /* insert cour before ptr */
	 {
	   cour->next = ptr;
	   if (AppRegistryEntry == ptr)
	     /* it's the first item in the list */
	     AppRegistryEntry = cour;
	   else
	     previous->next = cour;
	 }
       else if (level > ptr->level)
	 /* insert cour after ptr */
	 {
	   cour->next = ptr ->next;
	   ptr->next = cour;
	 }
     }
   AppRegistryModified++;
   return (0);
}


/*----------------------------------------------------------------------
 AddRegisterEntry : add an entry in the Register, we first check
 that it doesn't already exist especially if the value is empty.
  ----------------------------------------------------------------------*/
static int AddRegisterEntry (char *appli, char *name, char *value,
			     RegistryLevel level, int overwrite)
{
  char        resu[2000];
  RegistryEntry cour;

  if (AppRegistryInitialized == 0)
    return (-1);

#ifdef DEBUG_REGISTRY
  fprintf (stderr, "AddRegisterEntry(\"%s\",\"%s\",\"%s\", %d, %d)\n",
	   appli, name, value, level, overwrite);
#endif

  /*
   * Lookup in the application defaults.
   */
   cour = AppRegistryEntry;
   while (cour != NULL)
     {
       if (!strcmp (cour->name, name))
	 {
	     /* Cannot superseed and INSTALL value */
	   if (cour->level == REGISTRY_INSTALL)
	     return (0);
	   else if (!strcasecmp (cour->appli, appli) && cour->level == level)
	     break;
	 }
       cour = cour->next;
     }

   if (cour != NULL)
     {
       /* there is aleady an entry */
       if (!overwrite)
	 return (0);

       DoVariableSubstitution (value, strlen (value), resu, sizeof (resu) / sizeof (char));
       if (cour->value)
	 TtaFreeMemory (cour->value);
       if (cour->orig)
	 TtaFreeMemory (cour->orig);
       cour->orig = TtaStrdup (value);
       cour->value = TtaStrdup (resu);
       AppRegistryModified++;
     }
   else
     {
       /*
	* If the value is empty, we add it only if it's not present
	* in the thot library section.
	*/
       if (!overwrite && (value == NULL || *value == EOS))
	 {
	   cour = AppRegistryEntry;
	   while (cour != NULL)
	     {
	       if ((!strcasecmp (cour->appli, THOT_LIB_DEFAULTNAME)) &&
		   (!strcmp (cour->name, name)))
		 return (0);
	       cour = cour->next;
	     }
	 }

       return NewRegisterEntry (appli, name, value, level);
     }
   return (0);
}

/*----------------------------------------------------------------------
 PrintEnv : print the Registry to an open File.
  ----------------------------------------------------------------------*/
static void PrintEnv (FILE *output)
{
  RegistryEntry       cour, next;
  
  if (AppRegistryInitialized == 0)
    return;

  cour = AppRegistryEntry;
  while (cour != NULL)
    {
      /* don't save any system entry */
      if (!strcasecmp (cour->appli, "System"))
	{
	  cour = cour->next;
	  continue;
	}

      /* print out the section */
      fprintf (output, "[%s]\n", cour->appli);
      /* add all the entries under the same appli name */
      if (cour->level == REGISTRY_USER 
#ifdef _WINDOWS
		  && strcasecmp (cour->name, "TMP")
		  && strcasecmp (cour->name, "TEMP")
		  && strcasecmp (cour->name, "TEMPDIR")
#endif /* _WINDOWS */
		  && strcasecmp (cour->name, "TMPDIR")
		  && strcasecmp (cour->name, "APP_TMPDIR")
		  && strcasecmp (cour->name, "APP_HOME"))
	fprintf (output, "%s=%s\n", cour->name, cour->orig);
      next = cour->next;
      while (next != NULL && !strcasecmp (next->appli, cour->appli))
	{
	  if (next->level == REGISTRY_USER
	      && strcasecmp (cour->name, "TMPDIR")
#ifdef _WINDOWS
		  && strcasecmp (cour->name, "TMP")
		  && strcasecmp (cour->name, "TEMP")
		  && strcasecmp (cour->name, "TEMPDIR")
#else
	      && strcasecmp (next->name, "APP_TMPDIR")
#endif /* _WINDOWS */
	      && strcasecmp (next->name, "APP_HOME"))
	    fprintf (output, "%s=%s\n", next->name, next->orig);
	  next = next->next;
	}
      cour = next;
      fprintf (output, "\n");
    }
}

/*----------------------------------------------------------------------
 SortEnv : sort the Registry by application and name entries.
  ----------------------------------------------------------------------*/
static void SortEnv (void)
{
  RegistryEntry       prev, cour, tmp;
  RegistryEntry      *start;
  int                 cmp;

  if (AppRegistryInitialized == 0)
    return;
#ifdef DEBUG_REGISTRY
  fprintf (stderr, "SortEnv()\n");
#endif

  start = &AppRegistryEntry;
  while (*start != NULL)
    {
      prev = *start;
      cour = prev->next;
      if (cour == NULL)
	return;
      while (cour != NULL)
	{
	  /* sorting order : First by appli name, then by entry name */
	  cmp = strcasecmp (cour->appli, (*start)->appli);
	  if (cmp <= 0 ||
	      (cmp == 0 &&
	       (strcasecmp (cour->name, (*start)->name) < 0)))
	    {
	      /* swap *start and cour */
	      prev->next = *start;
	      *start = cour;
	      tmp = cour->next;
	      cour->next = prev->next->next;
	      prev->next->next = tmp;
	      cour = prev->next;
	    }

	  /* next in the list */
	  prev = cour;
	  if (cour != NULL)
	    cour = cour->next;
	}
      start = &((*start)->next);
    }
}

/*----------------------------------------------------------------------
  TtaGetEnvInt : read the integer value associated to an 
  environment string.
  Returns TRUE if the env variables exists or FALSE if it isn't the case.
  ----------------------------------------------------------------------*/
ThotBool TtaGetEnvInt (char *name, int *value)
{
  char *strptr;

  if (!name || *name == EOS)
   {
     *value = 0;
     return FALSE;
   }
  strptr = TtaGetEnvString (name);
  /* the name entry doesn't exist */
  if (!strptr || *strptr == EOS)
   {
     *value = 0;
     return FALSE;
   }
 /* make the convertion */
 *value = atoi (strptr);
 return TRUE;
}

/*----------------------------------------------------------------------
  TtaGetEnvBoolean : read the ThotBool value associated to an 
  environment string.
  Returns TRUE if the env variables exists or FALSE if it isn't the case.
  ----------------------------------------------------------------------*/
ThotBool TtaGetEnvBoolean (char *name, ThotBool *value)
{
 char *strptr;

 if (!name || *name == EOS)
   {
     *value = FALSE;
     return FALSE;
   }

 strptr = TtaGetEnvString (name);

 /* the name entry doesn't exist */
 if (!strptr || *strptr == EOS)
   {
     *value = FALSE;
     return FALSE;
   }

 /* make the convertion */
 if ( strcasecmp (strptr, "yes"))
   *value = FALSE;
 else
   *value = TRUE;

 return TRUE;
}


/*----------------------------------------------------------------------
  TtaGetEnvString : read the value associated to an environment string
  if not present return NULL.
  ----------------------------------------------------------------------*/
char *TtaGetEnvString (char *name)
{
   RegistryEntry  cour;
   char          *value;

   if (AppRegistryInitialized == 0)
         return getenv (name);

      /* appname allows to get the application name */
   if (!strcasecmp ("appname", name))
      return(AppRegistryEntryAppli);

   if (!strcasecmp (name, "cwd") || !strcasecmp (name, "pwd"))
      return (getcwd (&CurrentDir[0], sizeof(CurrentDir)));

   /* first lookup in the System defaults */
   cour = AppRegistryEntry;
   while (cour != NULL)
     {
         if (!strcasecmp (cour->appli, "System") &&
	     !strcmp (cour->name, name) && cour->value[0] != EOS)
	   {
#ifdef DEBUG_REGISTRY
            fprintf (stderr, "TtaGetEnvString(\"%s\") = %s\n", name, cour->value);
#endif
            return (cour->value);
	   }
         cour = cour->next;
     }

   /* then lookup in the application user preferences */
   cour = AppRegistryEntry;
   while (cour != NULL)
 {
         if (!strcasecmp (cour->appli, AppRegistryEntryAppli)      && 
             !strcmp (cour->name, name) && cour->value[0] != EOS && 
             cour->level == REGISTRY_USER)
 {
#ifdef DEBUG_REGISTRY
            fprintf (stderr, "TtaGetEnvString(\"%s\") = %s\n", name, cour->value);
#endif
            return (cour->value);
		 }
         cour = cour->next;
   } 

   /* then lookup in the application defaults */
   cour = AppRegistryEntry;
   while (cour != NULL) {
         if (!strcasecmp (cour->appli, AppRegistryEntryAppli)      && 
             !strcmp (cour->name, name) && cour->value[0] != EOS && 
             cour->level == REGISTRY_SYSTEM) {
#ifdef DEBUG_REGISTRY
            fprintf (stderr, "TtaGetEnvString(\"%s\") = %s\n", name, cour->value);
#endif
            return (cour->value);
		 }
         cour = cour->next;
   } 

   /* then lookup in the Thot library defaults */
   cour = AppRegistryEntry;
   while (cour != NULL) {
         if (!strcasecmp (cour->appli, THOT_LIB_DEFAULTNAME) && !strcmp (cour->name, name) && cour->value[0] != EOS) {
#ifdef DEBUG_REGISTRY
            fprintf (stderr, "TtaGetEnvString(\"%s\") = %s\n", name, cour->value);
#endif
            return (cour->value);
		 }
         cour = cour->next;
   }

   /*
    * If still not found, look in the environment variables.
    * Hopefully this will be stored to the user registry
    * next time it will be saved.
    */

   value = getenv (name);

   if (value == NULL)
      TtaSetEnvString (name, "", FALSE); 
   else
       TtaSetEnvString (name, value, FALSE);
  
#ifdef DEBUG_REGISTRY
   fprintf (stderr, "TtaGetEnvString(\"%s\") = %s\n", name, value);
#endif
   return (value);
}

/*----------------------------------------------------------------------
 TtaClearEnvString : clears the value associated with an environment
                     string, in the user registry.
  ----------------------------------------------------------------------*/
void TtaClearEnvString (char *name)
{
   AddRegisterEntry (AppRegistryEntryAppli, name, "", REGISTRY_USER, TRUE);
}

/*----------------------------------------------------------------------
 TtaSetEnvInt : set the value associated to an environment string,
                for the current application.
  ----------------------------------------------------------------------*/
void TtaSetEnvInt (char *name, int value, int overwrite)
{
   /* hardcoded so that the biggest integer value has 5 digits: 65535 */
   char ptr[6];
   int    r_val;

   r_val = value % 65537;
   sprintf (ptr, "%d", r_val);
   AddRegisterEntry (AppRegistryEntryAppli, name, ptr, REGISTRY_USER, overwrite);
}

/*----------------------------------------------------------------------
 TtaSetEnvBoolean : set the value associated to an environment string,
                    for the current application.
  ----------------------------------------------------------------------*/
void TtaSetEnvBoolean (char *name, ThotBool value, int overwrite)
{
   char *ptr;

   if (value)
     ptr = "yes";
   else
     ptr = "no";
   AddRegisterEntry (AppRegistryEntryAppli, name, ptr, REGISTRY_USER, overwrite);
}

/*----------------------------------------------------------------------
 TtaSetEnvString : set the value associated to an environment string,
                   for the current application.
  ----------------------------------------------------------------------*/
void TtaSetEnvString (char *name, char *value, int overwrite)
{
   char *tmp = value;
  
   /* make sure that value isn't NULL */
   if (!tmp)
     tmp = "";
   
   AddRegisterEntry (AppRegistryEntryAppli, name, tmp, REGISTRY_USER, overwrite);
}

/*----------------------------------------------------------------------
 TtaSetDefEnvString : set the defaul value associated to an environment
                      string, for the current application.
  ----------------------------------------------------------------------*/
void TtaSetDefEnvString (char *name, char *value, int overwrite)
{
  char *tmp = value;
             
  /* make sure that value isn't NULL */
  if (!tmp)
    tmp = "";

  AddRegisterEntry (AppRegistryEntryAppli, name, tmp, REGISTRY_SYSTEM, overwrite);
}

/*----------------------------------------------------------------------
  TtaGetDefEnvInt : read the default integer value associated to an 
  environment string.
  Returns TRUE if the env variables exists or FALSE if it isn't the case.
  ----------------------------------------------------------------------*/
ThotBool TtaGetDefEnvInt (char *name, int *value)
{
 char *strptr;

 if (!name || *name == EOS)
   {
     *value = 0;
     return FALSE;
   }
 strptr = TtaGetDefEnvString (name);
 /* the name entry doesn't exist */
 if (!strptr || *strptr == EOS)
   {
     *value = 0;
     return FALSE;
   }
 /* make the convertion */
 *value = atoi (strptr);
 return TRUE;
}

/*----------------------------------------------------------------------
  TtaGetDefEnvBoolean : read the ThotBool value associated to an 
  environment string.
  Returns TRUE if the env variables exists or FALSE if it isn't the case.
  ----------------------------------------------------------------------*/
ThotBool TtaGetDefEnvBoolean (char *name, ThotBool *value)
{
 char   *strptr;

 if (!name || *name == EOS)
   {
     *value = FALSE;
     return FALSE;
   }

 strptr = TtaGetDefEnvString (name);

 /* the name entry doesn't exist */
 if (!strptr || *strptr == EOS)
   {
     *value = FALSE;
     return FALSE;
   }

 /* make the convertion */
 if (strcasecmp (strptr, "yes"))
   *value = FALSE;
 else
   *value = TRUE;

 return TRUE;
}

/*----------------------------------------------------------------------
  TtaGetDefEnvString : read the default value associated to an 
  environment string. If not present, returns NULL.
  ----------------------------------------------------------------------*/
char *TtaGetDefEnvString (char *name)
{
  RegistryEntry  cour;
  char          *value;

  if (AppRegistryInitialized == 0)
     return getenv (name);

  /* appname allows to get the application name */
  if (!strcasecmp ("appname", name))
     return(AppRegistryEntryAppli);

  if (!strcasecmp (name, "cwd") || !strcasecmp (name, "pwd"))
      return (getcwd (&CurrentDir[0], sizeof(CurrentDir)));

  /* First lookup in the System defaults */
  cour = AppRegistryEntry;
  while (cour != NULL)
    {
      if (!strcasecmp (cour->appli, "System") && !strcmp (cour->name, name) 
	  && cour->level == REGISTRY_SYSTEM && cour->value[0] != EOS)
	{
#ifdef DEBUG_REGISTRY
	  fprintf (stderr, "TtaGetDefEnvString(\"%s\") = %s\n", name, cour->value);
#endif
	  return (cour->value);
	}
      cour = cour->next;
    }

  /* Then lookup in the application defaults */
  cour = AppRegistryEntry;
  while (cour != NULL)
    {
      if (!strcasecmp (cour->appli, AppRegistryEntryAppli) 
	  && !strcmp (cour->name, name) 
	  && cour->level == REGISTRY_SYSTEM && cour->value[0] != EOS)
	{
#ifdef DEBUG_REGISTRY
	  fprintf (stderr, "TtaGetDefEnvString(\"%s\") = %s\n", name, cour->value);
#endif
	  return (cour->value);
	}
      cour = cour->next;
    }
  
  /* Then lookup in the Thot library defaults */
  cour = AppRegistryEntry;
  while (cour != NULL)
    {
      if (!strcasecmp (cour->appli, THOT_LIB_DEFAULTNAME) 
	  && !strcmp (cour->name, name) 
	  && cour->level == REGISTRY_SYSTEM && cour->value[0] != EOS)
	{
#ifdef DEBUG_REGISTRY
	  fprintf (stderr, "TtaGetDefEnvString(\"%s\") = %s\n", name, cour->value);
#endif
	  return (cour->value);
	}
      cour = cour->next;
    }

   /*
    * If still not found, look in the environment variables.
    * Hopefully this will be stored to the user registry
    * next time it will be saved.
    */
  value = getenv (name);
  
#ifdef DEBUG_REGISTRY
  fprintf (stderr, "TtaGetDefEnvString(\"%s\") = %s\n", name, value);
#endif
  return (value);
}

/*----------------------------------------------------------------------
     IsThotDir : Check whether the given string is the THOTDIR value.    
         The heuristic is to find a subdir named "config" and containing 
         the registry file.                                              
  ----------------------------------------------------------------------*/
static int          IsThotDir (CONST char *path)
{
  char           filename[MAX_PATH];

  if (path == NULL)
    return (0);
  strcpy (filename, path);
  strcat (filename, DIR_STR);
  strcat (filename, THOT_CONFIG_FILENAME);
  strcat (filename, DIR_STR);
  strcat (filename, THOT_INI_FILENAME);
#ifdef DEBUG_REGISTRY
  fprintf (stderr, "TtaFileExist (%s)\n", filename);
#endif
  if (TtaFileExist (filename))
    {
#ifdef DEBUG_REGISTRY
      fprintf (stderr, "IsThotDir(%s) : True\n", path);
#endif
      return (1);
    }
  else
    {
#ifdef DEBUG_REGISTRY
      fprintf (stderr, "IsThotDir(%s) : False\n", path);
#endif
      return (0);
    }
}

#ifdef _WINDOWS
#ifndef __GNUC__
/*----------------------------------------------------------------------
  WINReg_get - simulates getenv in the WIN32 registry
  looks for <env> in HKEY_CURRENT_USER\Software\Amaya\<var>
  ----------------------------------------------------------------------*/
static char *WINReg_get (CONST char *env)
{
  char           textKey[MAX_PATH];
  HKEY           hKey;
  DWORD          type;
  LONG           success;
  DWORD          retLen = sizeof (EnVar);

  sprintf (textKey, "Software\\%s\\%s", AppNameW, env);    
  success = RegOpenKeyEx (HKEY_CURRENT_USER, textKey, 0, KEY_ALL_ACCESS, &hKey);
  if (success == ERROR_SUCCESS)
    {
      success = RegQueryValueEx (hKey, NULL, NULL, &type, (LPVOID)EnVar, &retLen);
      RegCloseKey (hKey);
    }
  return (success == ERROR_SUCCESS) ? EnVar : NULL;
}

/*----------------------------------------------------------------------
   WINReg_set - stores a value in the WIN32 registry           
   
   stores <key, value> in                                                 
   HKEY_CURRENT_USER\Software\app-name\<key>                                      
  ----------------------------------------------------------------------*/
static ThotBool WINReg_set (CONST char *key, CONST char *value)
{
  char             textKey[MAX_PATH];
  HKEY             hKey;
  LONG             success;
  char             protValue[MAX_PATH];
  DWORD            protValueLen = sizeof (protValue);
  DWORD            dwDisposition;
 
  /* protect against values bigger than what we can write in
     the registry */
  strncpy (protValue, value, protValueLen - 1);
  protValue[protValueLen-1] = EOS;
  sprintf (textKey,"Software\\%s\\%s", AppNameW, key);
  success = RegCreateKeyEx (HKEY_CURRENT_USER, textKey, 0,
			    "", REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
			    NULL, &hKey, &dwDisposition);  
  if (success == ERROR_SUCCESS)
    /* create the userBase entry */
    {
      success = RegSetValueEx (hKey, NULL, 0, REG_SZ, (LPVOID)protValue,
			       protValueLen);
      RegCloseKey (hKey);
    }
  return (success == ERROR_SUCCESS) ? TRUE : FALSE;
}

/*----------------------------------------------------------------------
   WINIni_get - simulates getenv in the Windows/Amaya.ini file     
  ----------------------------------------------------------------------*/
static char *WINIni_get (CONST char *env)
{
  DWORD               res;

  res = GetPrivateProfileString ("Amaya", env, "", EnVar, sizeof (EnVar),
				 "Amaya.ini");
  return res ? EnVar : NULL;
}
#endif
#endif /* _WINDOWS */


/*----------------------------------------------------------------------
  TtaSaveAppRegistry : Save the Registry in the THOT_RC_FILENAME located
  in the user's directory.
  ----------------------------------------------------------------------*/
void TtaSaveAppRegistry ()
{
  char              filename[MAX_PATH];
  char             *app_home;
  FILE             *output;

  if (!AppRegistryInitialized)
    return;
   if (!AppRegistryModified)
     return;
   app_home = TtaGetEnvString ("APP_HOME");
   if (app_home != NULL)
     sprintf (filename, "%s%c%s", app_home, DIR_SEP, THOT_RC_FILENAME);
   else
     {
       fprintf (stderr, "Cannot save Registry no APP_HOME dir\n");
       return;
     }
   output = fopen (filename, "w");
   if (output == NULL)
     {
       fprintf (stderr, "Cannot save Registry to %s :\n", filename);
       return;
     }
   SortEnv ();
   PrintEnv (output);
   AppRegistryModified = 0;
   fclose (output);
}


/*----------------------------------------------------------------------
  ImportRegistryFile : import a registry file.
  ----------------------------------------------------------------------*/
static void ImportRegistryFile (char *filename, RegistryLevel level)
{
  FILE     *input;
  char     *str; 
  char     *base;
  char      string[MAX_LENGTH];
  char      appli[MAX_LENGTH];
  char     *name;
  char     *value;

  strcpy (appli, THOT_LIB_DEFAULTNAME);
  input = fopen (filename, "r");
  if (input == NULL)
    {
      fprintf (stderr, "Cannot read Registry from %s :\n", filename);
      return;
    }

  while (1)
    {
      /* read one line in string buffer */
      if (fgets (&string[0], sizeof (string) - 1, input) == NULL)
	break;

      str = string;
      str = TtaSkipBlanks (str);
      string[sizeof (string) - 1] = EOS;
      /* Comment starts with a semicolumn */
      if (*str == ';' || *str == '#')
	continue;
      /* sections are indicated between brackets, e.g. [amaya] */
      if (*str == '[')
	{
	  str++;
	  str = TtaSkipBlanks (str);
	  base = str;
	  while ((*str != EOS) && (*str != ']'))
	    str++;
	  if (*str == EOS)
	    {
	      fprintf (stderr, "Registry %s corrupted :\n\t\"%s\"\n", filename, string);
	      continue;
	    }
	  *str = EOS;
	  strcpy (&appli[0], base);
#ifdef DEBUG_REGISTRY
	  fprintf (stderr, "TtaInitializeAppRegistry section [%s]\n", appli);
#endif
	  continue;
	}

      /* entries have the following form : name=value */
      name = str;
      str = SkipToEqual (str);
      if (*str != '=')
	continue;
      *str++ = EOS;
      str = TtaSkipBlanks (str);
      value = str;
      str = SkipToEqual (str);
      *str = EOS;
      AddRegisterEntry (appli, name, value, level, TRUE);
    }
  fclose (input);
}


/*----------------------------------------------------------------------
  InitEnviron : initialize the standard environment (i.e global	
  variables) with values stored in the registry.			
  ----------------------------------------------------------------------*/
static void         InitEnviron ()
{
   char *pT;
   char *Thot_Sys_Sch;
   char *Thot_Sch;

   /* default values for various global variables */
   FirstCreation = FALSE;
   CurSaveInterval = 0;
   pT = TtaGetEnvString ("AUTOSAVE");
   if (pT != NULL)
     CurSaveInterval = atoi (pT);
   if (CurSaveInterval <= 0)
     CurSaveInterval = DEF_SAVE_INTVL;
   HighlightBoxErrors = FALSE;
   InsertionLevels = 4;
#ifndef _WINDOWS
   TtaSetDefEnvString ("DOUBLECLICKDELAY", "500", TRUE);
   pT = TtaGetEnvString ("DOUBLECLICKDELAY");
   if (pT != NULL)
     DoubleClickDelay = atoi (pT);
   else 
       DoubleClickDelay = 500;
#endif /* _WINDOWS */

   /* The base of the Thot directory */
   Thot_Dir = TtaGetEnvString ("THOTDIR");
   if (Thot_Dir == NULL)
      fprintf (stderr, "missing environment variable THOTDIR\n");

   /* The predefined path to documents */
   pT = TtaGetEnvString ("THOTDOC");
   if (pT == NULL)
      DocumentPath[0] = EOS; 
   else
      strncpy (DocumentPath, pT, MAX_PATH);

   /* Read the schemas Paths */
   Thot_Sch = TtaGetEnvString ("THOTSCH");
   Thot_Sys_Sch = TtaGetEnvString ("THOTSYSSCH");

   /* set up SchemaPath accordingly */
   if ((Thot_Sch != NULL) && (Thot_Sys_Sch != NULL))
     {
       strncpy (SchemaPath, Thot_Sch, MAX_PATH);
       strcat (SchemaPath, PATH_STR);
       strcat (SchemaPath, Thot_Sys_Sch);
     }
   else if (Thot_Sch != NULL)
       strncpy (SchemaPath, Thot_Sch, MAX_PATH);
   else if (Thot_Sys_Sch != NULL)
       strncpy (SchemaPath, Thot_Sys_Sch, MAX_PATH);
   else
       SchemaPath[0] = EOS;

   /* set up the default values common to all the thotlib applications */
   TtaSetDefEnvString ("LANG", "en-us", FALSE);
   TtaSetDefEnvString ("ZOOM", "0", FALSE);
   TtaSetDefEnvString ("TOOLTIPDELAY", "500", FALSE);
   TtaSetDefEnvString ("FontMenuSize", "12", FALSE);
   TtaSetDefEnvString ("ForegroundColor", "Black", FALSE);
   TtaSetDefEnvString ("BackgroundColor", "#c0c0c0", FALSE);
   TtaSetDefEnvString ("InserPointColor", "Red", FALSE);
   TtaSetDefEnvString ("DocSelectColor", "LightCoral3", FALSE);
   TtaSetDefEnvString ("MenuFgColor", "Black", FALSE);
   TtaSetDefEnvString ("MenuBgColor", "Grey", FALSE);

   /*
   ** set up the defaul TMPDIR 
   */

   /* get the tmpdir from the registry or use the default name if it
      doesn't exist */
   pT = TtaGetEnvString ("TMPDIR");
#ifdef _WINDOWS
   /* on WIN32, the default directory may be defined on several environment variables */
   if (!pT)
	   pT = TtaGetEnvString ("TMP");
   if (!pT)
	   pT = TtaGetEnvString ("TEMP");
   if (!pT)
	   pT = TtaGetEnvString ("TEMPDIR");
#endif /* _WINDOWS */
   if (!pT)
     pT = DEF_TMPDIR;
   /* set up a default TMPDIR in the registry in case it wasn't defined before */
   TtaSetDefEnvString ("TMPDIR", pT, FALSE);

   /* create the TMPDIR dir if it doesn't exist */
   if (!TtaMakeDirectory (pT))
     {
       /* try to use the default tmpdir */
       pT = DEF_TMPDIR;
       if (!TtaMakeDirectory (pT))
	 {
	   fprintf (stderr, "Couldn't create directory %s\n", pT);
	   ThotExit (1);
	 }	 
       /* update the registry entry */
       TtaSetEnvString ("TMPDIR", pT, TRUE);
     }
}

/*----------------------------------------------------------------------
  TtaInitializeAppRegistry : initialize the Registry, the only argument
  given is a copy of the argv[0] received from the main().
  From this, we can deduce the installation directory of the programm,
  (using the PATH environment value if necessary) and the application
  name.
  We load the ressources file from the installation directory and
  the specific user values from the user HOME dir.
  ----------------------------------------------------------------------*/
void TtaInitializeAppRegistry (char *appArgv0)
{
  char      app_home[MAX_PATH];
  char      filename[MAX_PATH];
  char     *my_path;
  char     *dir_end = NULL;
  char     *appName;
  char     *ptr;
#ifdef _WINDOWS
  /* name in Windows NT 4 is 20 chars */
  char      username[MAX_LENGTH];
  char      windir[MAX_PATH+1];
  DWORD       dwSize;
  ThotBool    status;
  char        *ptr2, *ptr3;
#else /*  _WINDOWS */
  struct stat stat_buf;
  char        c_execname[MAX_LENGTH];
  char        c_filename[MAX_LENGTH];
  char       *c_end;
#endif /* _WINDOWS */
  int         execname_len;
  int         len, round;
  ThotBool    found, ok;
  
#ifdef _WINDOWS
  _fmode = _O_BINARY;
#endif /* _WINDOWS */
  if (AppRegistryInitialized != 0)
    return;
  AppRegistryInitialized++;
  /* Sanity check on the argument given. An error here should be
   * detected by programmers, since it's a application coding error.
   */
  if ((appArgv0 == NULL) || (*appArgv0 == EOS))
    {
#ifdef _WINDOWS
      MessageBox (NULL, "TtaInitializeAppRegistry called with invalid argv[0] value", "Amaya", MB_OK);
#else  /* _WINDOWS */
      fprintf (stderr, "TtaInitializeAppRegistry called with invalid argv[0] value\n");
#endif /* _WINDOWS */
      ThotExit (1);
    }

  /*
   * We are looking for the absolute pathname to the binary of the
   * application.
   *
   * First case, the argv[0] indicate that it's an absolute path name.
   * i.e. start with / on unixes or \ or ?:\ on Windows.
   */

#ifdef _WINDOWS
  if (appArgv0[0] == DIR_SEP || (appArgv0[1] == ':' && appArgv0[2] == DIR_SEP))
     strncpy (&execname[0], appArgv0, sizeof (execname) / sizeof (char));
#else  /* _WINDOWS */
  if (appArgv0[0] == DIR_SEP)
     strncpy (&execname[0], appArgv0, sizeof (execname) / sizeof (char));
#endif /* _WINDOWS */
   
  /*
   * second case, the argv[0] indicate a relative path name.
   * The exec name is obtained by appending the current directory.
   */
  else if (TtaFileExist (appArgv0))
    {
      getcwd (&execname[0], sizeof (execname) / sizeof (char));
      strcat (execname, DIR_STR);
      strcat (execname, appArgv0);
    }
  else
    {
      /*
       * Last case, we were just given the application name.
       * Use the PATH environment variable to search the exact binary location.
       */
      my_path = getenv("PATH");
      if (my_path == NULL)
	{
	  fprintf (stderr, "TtaInitializeAppRegistry cannot found PATH environment\n");
	  ThotExit (1);
	}
      /*
       * make our own copy of the string, in order to preserve the
       * enviroment variables. Then search for the binary along the
       * PATH.
       */
      len = (sizeof (path) / sizeof (char)) - 1;
      strncpy (path, my_path, len);
      path[len] = EOS;
       
      execname_len = sizeof (execname) / sizeof (char);
#ifdef _WINDOWS
      MakeCompleteName (appArgv0, "EXE", path, execname, &execname_len);
#else
      MakeCompleteName (appArgv0, "", path, execname, &execname_len);
#endif
      if (execname[0] == EOS)
	{
	  fprintf (stderr, "TtaInitializeAppRegistry internal error\n");
	  fprintf (stderr, "\tcannot find path to binary : %s\n", appArgv0);
	  ThotExit (1);
	}
    }
   
  /*
   * Now that we have a complete path up to the binary, extract the
   * application name.
   */
  appName = execname;
  while (*appName) /* go to the ending NUL */
    appName++;
  do
    appName--;
  while (appName > execname && *appName != DIR_SEP);
  
  if (*appName == DIR_SEP)
    /* dir_end used for relative links ... */
    dir_end = appName++;
   
#ifdef _WINDOWS
  /* remove the .exe extension. */
  ptr = strchr (appName, '.');
  if (ptr && !strcasecmp (ptr, ".exe"))
    *ptr = EOS;
  ptr = appName;
  while (*ptr)
    {
      *ptr = tolower (*ptr);
      ptr++;
    }
#endif /* _WINDOWS */

  AppRegistryEntryAppli = TtaStrdup (appName);
  AppNameW = TtaStrdup (appName);

#ifdef HAVE_LSTAT
   /*
    * on Unixes, the binary path started may be a softlink
    * to the real app in the real dir.
    */
  len = 1;
  strcpy (c_execname, execname);
  while (lstat (c_execname, &stat_buf) == 0 &&
	 S_ISLNK (stat_buf.st_mode) &&
	 len > 0)
    {
      len = readlink (c_execname, c_filename,
		      sizeof (filename) / sizeof (char));
      if (len > 0)
	{
	  /*
	   * Two cases : can be an absolute link to the binary
	   * or a relative link.
	   */
	  c_filename[len] = 0;
	  if (c_filename[0] == DIR_SEP)
	    strcpy (c_execname, c_filename);
	  else
	    {
	      c_end = c_execname;
	      while (*c_end)
		c_end++; /* go to the ending NUL */
	      while (c_end > c_execname && *c_end != DIR_SEP)
		c_end--;
	      strcpy (c_end + 1, c_filename);
	    }
	} 
    }
  strcpy (execname, c_execname);
#endif /* HAVE_LSTAT */
   
#ifdef DEBUG_REGISTRY
   fprintf (stderr, "path to binary %s : %s\n", appName, execname);
#endif
   
   /* get the THOTDIR for this application. It's under a bin dir */
   dir_end = execname;
   while (*dir_end) /* go to the ending NUL */
     dir_end++;
   
   /* remove the application name */
   ok = FALSE;
   do
     {
       dir_end--;
       ok = (dir_end <= execname || *dir_end == DIR_SEP);
     }
   while (!ok);

   if (*dir_end == DIR_SEP)
     {
       /* the name has been found */
       found = TRUE;
       *dir_end = EOS;
       /* save the binary directory in BinariesDirectory */
       strncpy (BinariesDirectory, execname,
		sizeof (BinariesDirectory) / sizeof (char));
       /* remove the binary directory */
       found = FALSE;
       ok = FALSE;
       round = 2;
       while (!found || round != 0)
	 {
	   do
	     {
               dir_end--;
               ok = (dir_end <= execname || *dir_end == DIR_SEP);
	     } while (!ok);

	   if (*dir_end == DIR_SEP)
	     {
               *dir_end = EOS;
               if (!strcmp (&dir_end[1], ".."))
		 round ++;
               else if (strcmp (&dir_end[1], "."))
		 {
		   round --;
		   /* a directory name has been found */
		   found = TRUE;
		 } 
	     }
	   else
	     {
	       /* no directory has been found */
	       found = TRUE;
	       ok = FALSE;
	     }
	 } 
       if (ok)
	 {
	   *dir_end = EOS;
	   if (IsThotDir (execname))
	     AddRegisterEntry ("System", "THOTDIR", execname,
			       REGISTRY_INSTALL, TRUE);
	 }
#ifdef COMPILED_IN_THOTDIR
       /* Check a compiled-in value */
       else if (IsThotDir (UCOMPILED_IN_THOTDIR))
	 {
           strcpy (UCOMPILED_IN_THOTDIR, COMPILED_IN_THOTDIR);
           strcpy (execname, UCOMPILED_IN_THOTDIR);
           AddRegisterEntry ("System", "THOTDIR", UCOMPILED_IN_THOTDIR,
			     REGISTRY_INSTALL, TRUE);
	 } 
#else /* COMPILED_IN_THOTDIR */
#ifdef COMPILED_IN_THOTDIR2
       /* Check a compiled-in value */
       else if (IsThotDir (UCOMPILED_IN_THOTDIR2))
	 {
           strcpy (UCOMPILED_IN_THOTDIR2, COMPILED_IN_THOTDIR2);
           strcpy (execname, COMPILED_IN_THOTDIR2);
           AddRegisterEntry ("System", "THOTDIR", UCOMPILED_IN_THOTDIR2,
			     REGISTRY_INSTALL, TRUE);
	 }
#endif /* COMPILED_IN_THOTDIR2 */
#endif /* COMPILED_IN_THOTDIR */
      else
	{
	  fprintf (stderr, "Cannot find THOTDIR\n");
	  ThotExit (1);
	} 
     }
   
#ifdef MACHINE
   /* if MACHINE is set up, add it to the registry */
   strcpy (UMACHINE, MACHINE);
   AddRegisterEntry ("System", "MACHINE", UMACHINE, REGISTRY_INSTALL, TRUE);
#endif

   /* load the system settings, stored in THOTDIR/config/thot.ini */
   sprintf (filename, "%s%c%s%c%s", execname, DIR_SEP, THOT_CONFIG_FILENAME,
	    DIR_SEP, THOT_INI_FILENAME);
   if (TtaFileExist (filename))
     {
#ifdef DEBUG_REGISTRY
       fprintf (stderr, "reading system %s from %s\n", THOT_INI_FILENAME, filename);
#endif
       ImportRegistryFile (filename, REGISTRY_SYSTEM);
       *dir_end = EOS;
       dir_end -= 3;
     }
   else
     fprintf (stderr, "System wide %s not found at %s\n", THOT_INI_FILENAME,
	      &filename[0]);
   
   /*
   ** find the APP_HOME directory name:
   ** Unix: $HOME/.appname,
   ** Win95: $THOTDIR/users/login-name/
   ** WinNT: c:\WINNT\profiles\login-name
   ** Win2000/XP: $HOMEDRIVE\$HOMEPATH
   **              or
   **             Documents and settings\All Users\login-name
   **              or
   **             the same thing as WinNT.
   */
   /* No this should NOT be a call to TtaGetEnvString */
#ifdef _WINDOWS
   /* compute the default app_home value from the username and thotdir */
   dwSize = sizeof (username);
   status = GetUserName (username, &dwSize);
   if (status)
     {
       if (strchr (username, '*'))
	 /* don't use a username that include stars */
	 ptr = WIN_DEF_USERNAME;
       else
	 ptr = username;
     }
   else
     /* under win95, there may be no user name */
     ptr = WIN_DEF_USERNAME;
   if (IS_NT)
     /* winnt: apphome is windowsdir\profiles\username\appname */
     {
       dwSize = MAX_PATH;
       app_home[0] = EOS;
#if 0
       /* JK: commented as it needs installing a SP */
       /* this function will fail if dwSize is inferior to the buffer size.
	  As we gave it the maximum possible value, we don't control
	  the return code */
       GetUserProfileDirectory (AccessTokenHandle, app_home, &dwSize);
#endif
       /* check if a previous app_home directory existed. If yes, use it. If it didn't
	  exist, then we try to create it using the new conventions. */
       GetWindowsDirectory (windir, dwSize);
       /* the Windows NT convention */
       sprintf (app_home, "%s\\profiles\\%s\\%s", windir, ptr, AppNameW);
       if (!TtaDirExists (app_home))
	 app_home[0] = EOS;

       if (app_home[0] == EOS)
	 {
	   /* the Windows 2000/XP convention */
	   sprintf (app_home, "%s\\Documents and Settings\\%s\\%s", windir, ptr, AppNameW);
	   if (!TtaDirExists (app_home))
	     app_home[0] = EOS;
	 }

       /* At this point app_home has a value if the directory existed. Otherwise,
	  we'll try to create a new one */
       
       if (app_home[0] == EOS)
	 {
	   /* use the HOMEDRIVE and HOMEPATH environment variables first */
	   ptr2 = getenv ("HOMEDRIVE");
	   ptr3 = getenv ("HOMEPATH");
	   if (ptr2 && *ptr2 && ptr3)
	     {
	       sprintf (windir, "%s%s", ptr2, ptr3);
	       if (TtaDirExists (windir))
		 sprintf (app_home, "%s\\%s", windir, AppNameW);
	       else
		 app_home[0] = EOS;
	     }
	 }

       if (app_home[0] == EOS)
	 {
	   /* try to use one of the system home dirs */
	   GetWindowsDirectory (windir, dwSize);
	   /* the Windows 2000/XP convention */
	   sprintf (app_home, "%s\\Documents and Settings", windir);
	   if (! TtaDirExists (app_home))
	     {
	       /* the Windows NT convention */
	       sprintf (app_home, "%s\\profiles", windir);
	     }
	   /* add the end suffix */
	   sprintf (windir, "\\%s\\%s", ptr, AppNameW);
	   strcat (app_home, windir);
	 }
     }
   else
     /* win95: apphome is  thotdir\users\username */
     sprintf (app_home, "%s\\%s\\%s", execname, WIN_USERS_HOME_DIR, ptr);   
#else /* _WINDOWS */
   ptr = getenv ("HOME");
   sprintf (app_home, "%s%c.%s", ptr, DIR_SEP, AppNameW); 
#endif /*_WINDOWS*/
   /* store the value of APP_HOME in the registry */
   AddRegisterEntry (AppRegistryEntryAppli, "APP_HOME", app_home,
		     REGISTRY_SYSTEM, FALSE);

   /* get the app_home again from the registry, as the user may have
      overriden it using the global configuration files */
   ptr = TtaGetEnvString ("APP_HOME");
   if (ptr)
     strcpy (app_home, ptr);
   else
     app_home[0] = EOS;

    /* read the user's preferences (if they exist) */
   if (app_home != NULL && *app_home != EOS)
     {
       sprintf (filename, "%s%c%s", app_home, DIR_SEP, THOT_RC_FILENAME);
       if (TtaFileExist (&filename[0]))
	 {
#ifdef DEBUG_REGISTRY
	   fprintf (stderr, "reading user's %s from %s\n",
		    THOT_RC_FILENAME, filename);
#endif
	   ImportRegistryFile (filename, REGISTRY_USER);
	 }
#ifdef DEBUG_REGISTRY
       else
	 fprintf (stderr, "User's %s not found\n", app_home);
#endif
     }
#ifdef DEBUG_REGISTRY
   else
     fprintf (stderr, "User's %s not found\n", THOT_RC_FILENAME);
#endif
   
#ifdef DEBUG_REGISTRY
   PrintEnv (stderr);
#endif
   /* initialize the standard environment (i.e global variables) with 
	  values stored in the registry. */
   InitEnviron ();
  /* set the default APP_TMPDIR */
#ifdef _WINDOWS
   /* the tmpdir is DEF_TMPDIR\app-name */
   ptr = TtaGetEnvString ("TMPDIR");
   sprintf (filename, "%s%c%s", ptr, DIR_SEP, AppNameW);
   AddRegisterEntry (AppRegistryEntryAppli, "APP_TMPDIR", filename,
		     REGISTRY_SYSTEM, TRUE);
#else
   /* under Unix, APP_TMPDIR == APP_HOME */
   AddRegisterEntry (AppRegistryEntryAppli, "APP_TMPDIR", app_home,
		     REGISTRY_SYSTEM, TRUE);
#endif /* _WINDOWS */
   /* reset the status flag to say we don't need to save the registry right now */
   AppRegistryModified = 0;
}

/*----------------------------------------------------------------------
  TtaFreeAppRegistry : frees the memory associated with the
  registry
  ----------------------------------------------------------------------*/
void                TtaFreeAppRegistry (void)
{
  RegistryEntry cour, next;

  if (AppRegistryInitialized == 0)
    return;

  cour = AppRegistryEntry;
  
  while (cour) {
    if (cour->appli)
      TtaFreeMemory (cour->appli);
    if (cour->name)
      TtaFreeMemory (cour->name);
    if (cour->orig)
      TtaFreeMemory (cour->orig); 
    if (cour->value)
      TtaFreeMemory (cour->value);
    next = cour->next;
    TtaFreeMemory (cour);
    cour = next;
  }
  TtaFreeMemory (AppRegistryEntryAppli);
  TtaFreeMemory (AppNameW);
  AppRegistryInitialized = 0;
}

/*----------------------------------------------------------------------
   SearchFile look for a file following the guideline given by dir
   Returns 1 with fullName set to the absolute pathname if found,
   0 otherwise.                                   
   Depending on dir value, the file is looked for in:
   - 0 : /                                                 
   - 1 : ThotDir                                           
   - 2 : ThotDir/bin                                       
   - 3 : ThotDir/compil                                    
  ----------------------------------------------------------------------*/
int SearchFile (char *fileName, int dir, char *fullName)
{
   char                tmpbuf[200];
   char               *imagepath;
   int                 i, j;
   int                 ret;

   if (Thot_Dir != NULL)
      strcpy (fullName, Thot_Dir);
   else
      *fullName = EOS;
   switch (dir)
	 {
	    case 1:
	       /* Lookup in schema and documents path */
	       strcat (fullName, fileName);
	       ret = TtaFileExist (fullName);
	       /* lookup in shemas path */
	       i = 0;
	       j = 0;
	       imagepath = SchemaPath;
	       while (ret == 0 && imagepath[i] != EOS)
		 {
		    while (imagepath[i] != EOS && imagepath[i] != PATH_SEP && i < 200)
		       tmpbuf[j++] = imagepath[i++];

		    tmpbuf[j] = EOS;
		    i++;
		    j = 0;
		    sprintf (fullName, "%s%s%s", tmpbuf, DIR_STR, fileName);
		    ret = TtaFileExist (fullName);
		 }

	       /* lookup in document path */
	       i = 0;
	       j = 0;
	       imagepath = SchemaPath;
	       while (ret == 0 && imagepath[i] != EOS)
		 {
		    while (imagepath[i] != EOS && imagepath[i] != PATH_SEP && i < 200)
		       tmpbuf[j++] = imagepath[i++];

		    tmpbuf[j] = EOS;
		    i++;
		    j = 0;
		    sprintf (fullName, "%s%s%s", tmpbuf, DIR_STR, fileName);
		    ret = TtaFileExist (fullName);
		 }
	       break;

	    case 2:
	       /* lookup in config */
	       strcat (fullName, DIR_STR);
	       strcat (fullName, "config");
	       strcat (fullName, DIR_STR);
	       strcat (fullName, fileName);
	       break;

	    case 3:
	       /* lookup in batch */
	       strcat (fullName, DIR_STR);
	       strcat (fullName, "batch");
	       strcat (fullName, DIR_STR);
	       strcat (fullName, fileName);
	       break;

	    default:
	       strcat (fullName, DIR_STR);
	       strcat (fullName, fileName);
	 }

   /* general search */
   ret = TtaFileExist (fullName);
   if (ret == 0)
     {
        strcpy (fullName, fileName);
        ret = TtaFileExist (fullName);
     }
   return ret;
}
