/***********************************************************/
/*                                                         */
/*        registry.h  - Bad Seal registry functions        */
/*                                                         */
/*                          version 0.3                    */
/*                                                         */
/*                    Copyright (C) 2001                   */
/*          by Kostas Michalopoulos aka Bad Sector         */
/*                                                         */
/* WWW: http://www.badseal.org/                            */
/* e-mail: michalopoylos@hotmail.com                       */
/*                                                         */
/***********************************************************/

#ifdef WANT_REGISTRY 
#ifndef __REGISTRY_H_INCLUDED__
#define __REGISTRY_H_INCLUDED__

/* Default registry file. Default is badseal.reg and this value is
 recommended for all SEAL/BadSeal programs for better compatibility
 between versions and distributions. */

#define default_registry_file "badseal.reg"

/* Key types */
#define KT_UNKNOWN      0   // unknown key type (not loaded or error)
#define KT_NODATA       1   // doesn't contain data
#define KT_BYTE         2   // 8 bit unsigned integer
#define KT_SMALL        3   // 16 bit integer
#define KT_INTEGER      4   // 32 bit integer
#define KT_BIG          5   // 64 bit integer
#define KT_FLOAT        6   // 32 bit float point number (real)
#define KT_STRING       7   // null terminated string (up to 255 characters)
#define KT_DATA       127   // data (up to 256 bytes)
#define KT_LINK       254   // link to another key   - not implemented yet
#define KT_DELETED    255   // deleted key

/* error codes that functions can return */
#define RE_UNKOWN               0   // unknown error
#define RE_SUCCESS              1   // no error
#define RE_KEY_NOT_FOUND        2   // key not found
#define RE_PATH_NOT_FOUND       3   // path in registry not found
#define RE_READ_ONLY_KEY        4   // tried to write on a read-only key
#define RE_NO_KEY_SPECIFIED     5   // no key has specified
#define RE_ROOT_KEY_SPECIFIED   6   // tried to write/delete a root key

/* standard keys */
#define KEY_USERS       "USERS"     // Settings depending on user
#define KEY_CURRENT     "CURRENT"   // Use this if you want to save a setting
                                    // for your program.
#define KEY_GLOBAL      "GLOBAL"    // Global settings for all users
#define KEY_CONFIG      "CONFIG"    // SEAL configuration
#define KEY_SOFTWARE    "SOFTWARE"  // Place for SEAL software
#define KEY_SYSTEM      "SYSTEM"    // System place (includes seal/kernel info)

/* t_registry_key struct is key record in registry file */
typedef struct t_registry_key
{
  char name[128];       // name
  int type;             // type
  char data[256];       // data (depends on type)
  int size;             // size in bytes

  int parent;           // parent's position
  int child;            // first child's position (if no childs, then child = -1)
  int prev;             // previus child of parent
  int next;             // next child of parent

  char reserved[102];   // reserved for future use
} t_registry_key;

/* t_registry_get_info is used from get_data_and_type function */
typedef struct t_registry_get_info
{
  char data[256];       // key data
  int type;             // key type
  int size;             // key size in bytes
  int err;              // if any error occurs (check it always)
  char reserved[32];    // reserved for future use
} t_registry_get_info;

/* t_registry_search is used from reg_find_first and reg_find_next */
typedef struct t_registry_search *p_registry_search;
typedef struct t_registry_search
{
  t_registry_key key;   // key info
  char *parent_name;    // key's parent name (the place where we're searching)
    /* note: for stability reasons, reg_find_first allocates memory to store
    parent_name's value. This memory is freed when reg_find_next reaches at
    the end. However sometimes you need only the first child or you don't
    need all childs. In that case you have to free this value by yourself */
  char *name;           // full key path (Warning! Must be FREED after use)
  int pos;              // key's position
  char reserved[32];    // reserved for future use
} t_registry_search;

/* just if you want to know registry file's name */
extern char *registry_file;


/***********************
*  Registry functions  *
***********************/

/*
Combines path and key and returns the result.
Example:
    key_in_path("system/seal", "distribution")

    returns "system/seal/distribution"

you must free allocated memory after
*/
char *key_in_path(char *path, char *key);

/*
Returns 1 (true) if key exists, else 0 (false).
*/
int key_exists(char *key);

/*
Creates a new key named `name' in `path'. if 'use_links' is 1 then
uses links for finding path. F.e.

key 'current' is defined as link to 'users/default'. if you want to
create a key in 'current' you must enable links or you'll just waste
disk space because created key will not be visible.

If success returns RE_SUCCESS
*/
int create_key_ex(char *path, char *name, int use_links);

/*
Like create_key_ex but always uses links.
*/
int create_key(char *path, char *name);

/*
Creates a new link named `name' to a key `dest'. Link key is created
in `path'
*/
int create_link_key(char *path, char *name, char *dest);

/*
Changes/sets the data of key `key' to `data' and it's type to `type'.
`size' is the size of `data' in bytes.
*/
int set_data_and_type(char *key, int type, void *data, int size);

/*
Sets key `key''s data to `str' and it's type to KT_STRING
*/
int set_key(char *key, char *str);

/*
Sets key `key''s data to `b' and it's type to KT_BYTE
*/
int set_key_byte(char *key, unsigned char b);

/*
Sets key `key''s data to `s' and it's type to KT_SMALL
*/
int set_key_small(char *key, short s);

/*
Sets key `key''s data to `i' and it's type to KT_INTEGER
*/
int set_key_integer(char *key, long i);

/*
Sets key `key''s data to `big' and it's type to KT_BIG
*/
int set_key_big(char *key, long long big);

/*
Sets key `key''s data to `f' and it's type to KT_FLOAT
*/
int set_key_float(char *key, float f);

/*
Sets key `key''s data to `data', it's type to KT_DATA and it's size to `size'
*/
int set_key_data(char *key, void *data, int size);

/*
Returns data, type and size from key `key'.
*/
t_registry_get_info get_data_and_type(char *key);

/*
Returns key `key''s value as string
*/
char *get_key(char *key);

/*
Returns key `key''s value as byte (char)
*/
char get_key_byte(char *key);

/*
Returns key `key''s value as small (short)
*/
short get_key_small(char *key);

/*
Returns key `key''s value as integer (long)
*/
long get_key_integer(char *key);

/*
Returns key `key''s value as big integer (long long)
*/
long long get_key_big(char *key);

/*
Returns key `key''s value as float
*/
float get_key_float(char *key);

/*
Returns key `key''s value as data
*/
void *get_key_data(char *key);

/*
Returns key `key''s size (usually used with get_key_data)
*/
int get_key_size(char *key);

/*
Deletes key `key' and it's childs.
*/
int delete_key(char *key);

/*
With reg_find_next is used to return all childs of key `path'. Returns 0
if no key found or there are no childs. Information about current key
is stored in `info'.
*/
int reg_find_first(char *path, p_registry_search info);

/*
See reg_find_first for info about using those two functions.
*/
int reg_find_next(p_registry_search info);
#define iffound(a,b) ({l_color c=b;if(c!=-1) a=c;})
#endif
#else
#ifndef __REGISTRY_H_INCLUDED__
#define __REGISTRY_H_INCLUDED__
/* inlined translations for bad's registry functions to use the preexisting dataini interface
translates badseals requests for registry keys eg current/junk/whatnot into ini file section thus
[current/junk/whatnot]
the_value_is_some_kind_of_data_here
[morejunk/stuff/things]
stuff1
stuff2
stuff3
[morejunk/stuff/things/stuff1]
other
[morejunk/stuff/things/stuff2]
junk
[morejunk/stuff/things/stuff3]
looked_up_via_morejunk/stuff/things


the latter three are look-ups the registry functions get_first and get_next read the lines in key
morejunk/stuff/things
to find names of the sub-keys-: stuff1,stuff2 and stuff3 which will have the data - silly but it works
*/
extern char *strtoend ( char *str, char endchar );

#define registry_file INI_MAINFILE
#define registry_color(x) color_get_from_ini(x)
#define get_key(s) ({char *ret=NULL;char *a;     if((a=getinidata_fromfile(INI_MAINFILE,(s)))){ret=strtoend(a+1,'\n');_free(a);}ret;})
#define get_key_byte(s) ({char ret=0;char *a;    if((a=getinidata_fromfile(INI_MAINFILE,(s)))){ret=a[1];_free(a);}ret;})
#define get_key_num(s) ({long ret=0;char *a;     if((a=getinidata_fromfile(INI_MAINFILE,(s)))){ret=atol(a);_free(a);}ret;})
#define get_key_float(s) ({char *a;float ret=0.0;if((a=getinidata_fromfile(INI_MAINFILE,(s)))){ret=atof(a);_free(a);}ret;})
#define get_key_small(s) ((short)get_key_num(s))
#define get_key_integer(s) ((int)get_key_num(s))
#define get_key_big(s) ((long)get_key_num(s))
#define key_exists(s) ({int ret;char *a=getinidata_fromfile(INI_MAINFILE,(s));ret=(a!=NULL);if(a)_free(a);ret;})
#define init_registry()
typedef struct t_registry_search *p_registry_search;
typedef struct t_registry_search
{
  char *parent_name;
  char *name;
  int pos;
} t_registry_search;

#define reg_find_first(s,inf) ({char *ret=NULL;char *a=getinidata_fromfile(INI_MAINFILE,(s));(inf)->parent_name=_strdup((s));if(a){if((ret=strtoend(a+1,'\n'))){(inf)->pos=strlen(ret)+2;(inf)->name=key_in_path((s),ret);ret=(inf)->name;}_free(a);}ret;})
#define reg_find_next(inf) ({char *ret;char *a=getinidata_fromfile(INI_MAINFILE,(inf)->parent_name);_free((inf)->name);if((ret=strtoend(a+inf->pos,'\n'))){(inf)->pos+=strlen(ret)+1;(inf)->name=key_in_path((inf)->parent_name,ret);_free(ret);ret=(inf)->name;}else _free((inf)->parent_name);_free(a);ret;})
#define key_in_path(n1,n2) ({char *s=_malloc(strlen(n1)+strlen(n2)+2);strcpy(s,n1);strcat(s,"/"),strcat(s,n2);s;})

/* a slight modification to setini_toline() (cf) allows us to emulate set_key and set_key_integer with a macro */
#define set_key(x,y) (setini_tofile(INI_MAINFILE,(x),(y),NULL,INI_STRING))
#define set_key_integer(x,y) ({char s[256];sprintf(s,"%ld",(long)(y));set_key((x),s);})

/* macro without side effects for setting colors from the ini file
   tests its result first so we dont remove our defaults if not found in in the file 
*/
#define iffound(a,b) ({l_color c=b;if(c!=-1) a=c;})
#endif
#endif
