www.pudn.com > at91rm9200vxworksbsp.rar > profile.c


/* 
 *  software/app/common/src/profile.c 
 * 
 *  Copyright (C) 2006 GRENTECH 
 *  All rights reserved. 
 */ 
 
/* 
 * Function: 
 * 	Process INI file. 
 * 
 * Description: 
 * 
 * 
 * Version: 
 * 	1.0.0 
 * 
 * Revision History: 
 * 
 * 2006-12-22		Yang Lifeng 
 *	³õʼ»¯°æ±¾ 
 * 
 */ 
 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#include "profile.h" 
 
#define BOOL	INT32 
/*#ifdef SOLARIS 
typedef boolean_t            BOOL; 
#else 
typedef unsigned int         BOOL; 
#endif*/ 
#define FALSE	0 
#define TRUE	1 
 
/*typedef enum 
{ 
        FALSE=0, 
        TRUE=1 
} BOOL;*/ 
 
typedef struct tagPRO_KEY 
{ 
    INT8                 *value; 
    struct tagPRO_KEY  *next; 
    INT8                  name[1]; 
} 
PRO_KEY; 
 
typedef struct tagPRO_SEC 
{ 
    struct tagPRO_KEY       *key; 
    struct tagPRO_SEC   *next; 
    INT8                       name[1]; 
} 
PRO_SEC; 
 
typedef struct 
{ 
    BOOL             changed; 
    PRO_SEC  *section; 
    INT8           *filename; 
    struct stat stat_info; 
} 
PROFILE; 
 
/*=================================================*/ 
#ifdef VXWORKS 
extern STATUS taskLock (void); 
extern STATUS taskUnlock (void); 
#endif 
/*=================================================*/ 
 
static void pro_cp_entry( 
    INT8 *buffer, 
    INT8 *value, 
    UINT32 len, 
    BOOL strip_quote ); 
 
static BOOL pro_del_sec( PRO_SEC **section, INT8 *name ); 
static BOOL pro_del_key( PRO_SEC **section, 
                         INT8 *section_name, INT8 *key_name ); 
 
static PRO_KEY *pro_find( 
    PRO_SEC **section, 
    INT8 *section_name, 
    INT8 *key_name, 
    BOOL create, 
    BOOL create_always ); 
 
static BOOL pro_flush_file(void); 
 
static void pro_free( PRO_SEC *section ); 
 
static INT32 pro_get_private_pro_str( 
    INT8 *section, 
    INT8 *entry, 
    INT8 *def_val, 
    INT8 *buffer, 
    UINT32 len, 
    INT8 *filename, 
    BOOL win32 ); 
 
static INT32 pro_get_sec( 
    PRO_SEC *section, 
    INT8 *section_name, 
    INT8 *buffer, 
    UINT32 len, 
    BOOL return_values, 
    BOOL return_noequalkeys ); 
 
static INT32 pro_get_sec_names(INT8 *buffer, UINT32 len ); 
 
BOOL pro_open( INT8 *filename ); 
 
static INT32 pro_get_sec_names(INT8 *buffer, UINT32 len ); 
static INT32 pro_get_str( 
    INT8 *section, 
    INT8 *key_name, 
    INT8 *def_val, 
    INT8 *buffer, 
    UINT32 len, 
    BOOL win32); 
 
static __inline INT32 pro_isspace(INT8 c); 
static PRO_SEC *pro_Load(INT32 hFile); 
BOOL pro_open( INT8 *filename ); 
static void pro_release_file(void); 
static void pro_save( INT32 hFile, const PRO_SEC *section); 
static BOOL pro_set_str( INT8 *section_name, INT8 *key_name, 
                         INT8 *value, BOOL create_always ); 
static void pro_write_line( INT32 hFile, INT8 * szLine, UINT32 len); 
 
#define N_CACHED_PROFILES 10 
 
/* Check for comments in profile */ 
#define IS_ENTRY_COMMENT(str)  ((str)[0] == '#') 
 
/* Cached profile files */ 
static PROFILE *cached_pro[N_CACHED_PROFILES]= 
    { 
        NULL 
    }; 
 
#define cur_pro (cached_pro[0]) 
 
static const INT8 rruini[] = 
    { 'r','r','u','.','i','n','i',0 
    }; 
 
 
/*********************************************************************** 
 *           GetProfileStr 
 */ 
INT32 GetProfileStr( INT8*section, INT8 *entry, 
                     INT8 *def_val, INT8 *buffer, 
                     UINT32 len, INT8 *filename ) 
{ 
    return pro_get_private_pro_str( section, entry, def_val, 
                                    buffer, len, filename, TRUE ); 
} 
 
 
/*********************************************************************** 
 *           WriteProfileStr 
 */ 
BOOL WriteProfileStr( INT8 *section, INT8 *entry, 
                      INT8 *string, INT8 *filename ) 
{ 
    BOOL ret = FALSE; 
 
#ifdef VXWORKS 
    taskLock(); 
#endif 
 
    if (!section && !entry && !string) /* documented "file flush" case */ 
    { 
        if (!filename || pro_open( filename )) 
        { 
            if (cur_pro) 
            { 
                pro_release_file();  /* always return FALSE in this case */ 
            } 
        } 
    } 
    else if (pro_open( filename )) 
    { 
        if (!section) 
        { 
            printf("(NULL?,%s,%s,%s)?\n",entry, string, filename); 
        } 
        else 
        { 
            ret = pro_set_str( section, entry, string, FALSE); 
            pro_flush_file(); 
        } 
    } 
 
#ifdef VXWORKS 
    taskUnlock(); 
#endif 
 
    return ret; 
} 
 
 
/*********************************************************************** 
 *           pro_set_str 
 * 
 * Set a profile string. 
 */ 
static BOOL pro_set_str( INT8 *section_name, INT8 *key_name, 
                         INT8 *value, BOOL create_always ) 
{ 
    if (!key_name)  /* Delete a whole section */ 
    { 
        printf("(%s)\n", section_name); 
        cur_pro->changed |= pro_del_sec( &cur_pro->section, 
                                         section_name ); 
        return TRUE;         /* Even if pro_del_sec() has failed, 
                                		                                this is not an error on application's level.*/ 
    } else if (!value)  /* Delete a key */ 
    { 
        printf("(%s,%s)\n", (section_name), (key_name) ); 
        cur_pro->changed |= pro_del_key( &cur_pro->section, 
                                         section_name, key_name ); 
        return TRUE;          /* same error handling as above */ 
    } else  /* Set the key value */ 
    { 
        PRO_KEY *key = pro_find(&cur_pro->section, section_name, 
                                key_name, TRUE, create_always ); 
        /*printf("(%s,%s,%s):\n",(section_name), (key_name), (value) );*/ 
        if (!key) 
        { 
            return FALSE; 
        } 
 
        /* strip the leading spaces. We can safely strip \n\r and 
         * friends too, they should not happen here anyway. */ 
        while (pro_isspace(*value)) value++; 
 
        if (key->value) 
        { 
            if (!strcmp( key->value, value )) 
            { 
                /*printf("  no change needed\n" );*/ 
                return TRUE;  /* No change needed */ 
            } 
            printf("  replacing %s\n", (key->value) ); 
            free(key->value); 
        } 
        else 
        { 
            /*printf("  creating key\n" );*/ 
        } 
        key->value = (INT8 *)malloc( (strlen(value)+1) * sizeof(INT8) ); 
        strcpy( key->value, value ); 
        cur_pro->changed = TRUE; 
    } 
    return TRUE; 
} 
 
 
/*********************************************************************** 
 *           pro_del_sec 
 * 
 * Delete a section from a profile tree. 
 */ 
static BOOL pro_del_sec( PRO_SEC **section, INT8 *name ) 
{ 
    while (*section) 
    { 
        if ((*section)->name[0] && !strcmp( (*section)->name, name )) 
        { 
            PRO_SEC *to_del = *section; 
            *section = to_del->next; 
            to_del->next = NULL; 
            pro_free( to_del ); 
            return TRUE; 
        } 
        section = &(*section)->next; 
    } 
    return FALSE; 
} 
 
 
/*********************************************************************** 
 *           pro_del_key 
 * 
 * Delete a key from a profile tree. 
 */ 
static BOOL pro_del_key( PRO_SEC **section, 
                         INT8 *section_name, INT8 *key_name ) 
{ 
    while (*section) 
    { 
        if ((*section)->name[0] && !strcmp( (*section)->name, section_name )) 
        { 
            PRO_KEY **key = &(*section)->key; 
            while (*key) 
            { 
                if (!strcmp( (*key)->name, key_name )) 
                { 
                    PRO_KEY *to_del = *key; 
                    *key = to_del->next; 
                    free(to_del->value); 
                    free(to_del ); 
                    return TRUE; 
                } 
                key = &(*key)->next; 
            } 
        } 
        section = &(*section)->next; 
    } 
    return FALSE; 
} 
 
 
/* 
 * if win32, copy: 
 *   - Section names if 'section' is NULL 
 *   - Keys in a Section if 'entry' is NULL 
 * 
 */ 
static INT32 pro_get_private_pro_str( INT8 *section, INT8 *entry, 
                                      INT8 *def_val, INT8 *buffer, 
                                      UINT32 len, INT8 *filename, 
                                      BOOL win32 ) 
{ 
    INT32	ret; 
    INT8	*defval_tmp = NULL; 
 
    /* strip any trailing ' ' of def_val. */ 
    if (def_val) 
    { 
        INT8 *p = &def_val[strlen(def_val)]; /* even "" works ! */ 
 
        while (p > def_val) 
        { 
            p--; 
            if ((*p) != ' ') 
                break; 
        } 
        if (*p == ' ') /* ouch, contained trailing ' ' */ 
        { 
            INT32 len = (INT32)(p - def_val); 
 
            defval_tmp = (INT8 *)malloc((len + 1) * sizeof(INT8)); 
            memcpy(defval_tmp, def_val, len * sizeof(INT8)); 
            defval_tmp[len] = '\0'; 
            def_val = defval_tmp; 
        } 
    } 
 
    /* enter critical code */ 
#ifdef VXWORKS 
    taskLock(); 
#endif 
 
    if (pro_open( filename )) 
    { 
        if (win32 && (section == NULL)) 
        { 
            ret = pro_get_sec_names(buffer, len); 
        } 
        else 
        { 
            /* pro_get_str can handle the 'entry == NULL' case */ 
            ret = pro_get_str( section, entry, def_val, buffer, len, win32 ); 
        } 
    } 
    else if (buffer && def_val) 
    { 
        strncpy( buffer, def_val, len ); 
        ret = strlen( buffer ); 
    } 
    else 
    { 
        ret = 0; 
    } 
 
#ifdef VXWORKS 
    taskUnlock(); 
#endif 
 
    free(defval_tmp); 
 
    return ret; 
} 
 
 
/* See GetPrivateProfileSectionNamesA for documentation */ 
static INT32 pro_get_sec_names(INT8 *buffer, UINT32 len ) 
{ 
    INT8 *buf; 
    UINT32 buflen,tmplen; 
    PRO_SEC *section; 
 
    if (!buffer || !len) 
    { 
        return 0; 
    } 
    if (len==1) 
    { 
        *buffer='\0'; 
        return 0; 
    } 
 
    buflen 	= len - 1; 
    buf	= buffer; 
    section = cur_pro->section; 
    while ((section!=NULL)) 
    { 
        if (section->name[0]) 
        { 
            tmplen = strlen(section->name) + 1; 
            if (tmplen >= buflen) 
            { 
                if (buflen > 0) 
                { 
                    memcpy(buf, section->name, (buflen-1) * sizeof(INT8)); 
                    buf += buflen-1; 
                    *buf++='\0'; 
                } 
                *buf='\0'; 
                return len-2; 
            } 
            memcpy(buf, section->name, tmplen * sizeof(INT8)); 
            buf += tmplen; 
            buflen -= tmplen; 
        } 
        section = section->next; 
    } 
    *buf='\0'; 
    return buf - buffer; 
} 
 
 
/*********************************************************************** 
 *           pro_get_str 
 * 
 * Get a profile string. 
 * 
 * Tests with get_profile_str16, W95a, 
 * with filled buffer ("****...") and section "set1" and key_name "1" valid: 
 * section	key_name	def_val		res	buffer 
 * "set1"	"1"		"x"		43	[data] 
 * "set1"	"1   "		"x"		43	[data]		(!) 
 * "set1"	"  1  "'	"x"		43	[data]		(!) 
 * "set1"	""		"x"		1	"x" 
 * "set1"	""		"x   "		1	"x"		(!) 
 * "set1"	""		"  x   "	3	"  x"		(!) 
 * "set1"	NULL		"x"		6	"1\02\03\0\0" 
 * "set1"	""		"x"		1	"x" 
 * NULL		"1"		"x"		0	""		(!) 
 * ""		"1"		"x"		1	"x" 
 * NULL		NULL		""		0	"" 
 * 
 * 
 */ 
static INT32 pro_get_str( 
    INT8 *section, 
    INT8 *key_name, 
    INT8 *def_val, 
    INT8 *buffer, 
    UINT32 len, 
    BOOL win32) 
{ 
    PRO_KEY *key = NULL; 
    static INT8 empty_str[] = 
        { 
            0 
        }; 
 
    if (!buffer) 
    { 
        return 0; 
    } 
 
    if (!def_val) 
    { 
        def_val = empty_str; 
    } 
 
    if (key_name) 
    { 
        if (!key_name[0]) 
        { 
            /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */ 
            return 0; 
        } 
        key = pro_find(&cur_pro->section, section, key_name, FALSE, FALSE); 
        pro_cp_entry(buffer, (key&&key->value)? key->value:def_val, len, TRUE); 
        return strlen( buffer ); 
    } 
 
    /* no "else" here ! */ 
    if (section && section[0]) 
    { 
        INT32 ret = pro_get_sec(cur_pro->section, section, buffer, len, FALSE, !win32); 
        if (!buffer[0]) /* no luck -> def_val */ 
        { 
            pro_cp_entry(buffer, def_val, len, TRUE); 
            ret = strlen(buffer); 
        } 
        return ret; 
    } 
    buffer[0] = '\0'; 
    return 0; 
} 
 
 
 
 
/*********************************************************************** 
 *           pro_get_sec 
 * 
 * Returns all keys of a section. 
 * If return_values is TRUE, also include the corresponding values. 
 */ 
static INT32 pro_get_sec( PRO_SEC *section, INT8 *section_name, 
                          INT8 *buffer, UINT32 len, BOOL return_values, 
                          BOOL return_noequalkeys ) 
{ 
    PRO_KEY *key; 
 
    if (!buffer) 
    { 
        return 0; 
    } 
 
    while (section) 
    { 
        if (section->name[0] && !strcmp( section->name, section_name )) 
        { 
            UINT32 oldlen = len; 
            for (key = section->key; key; key = key->next) 
            { 
                if (len <= 2) 
                { 
                    break; 
                } 
                if (!*key->name) 
                { 
                    continue;  /* Skip empty lines */ 
                } 
                if (IS_ENTRY_COMMENT(key->name)) 
                { 
                    continue;  /* Skip comments */ 
                } 
                if (!return_noequalkeys && !return_values && !key->value) 
                { 
                    continue;  /* Skip lines w.o. '=' */ 
                } 
                pro_cp_entry( buffer, key->name, len - 1, 0 ); 
                len -= strlen(buffer) + 1; 
                buffer += strlen(buffer) + 1; 
                if (len < 2) 
                { 
                    break; 
                } 
                if (return_values && key->value) 
                { 
                    buffer[-1] = '='; 
                    pro_cp_entry ( buffer, key->value, len - 1, 0 ); 
                    len -= strlen(buffer) + 1; 
                    buffer += strlen(buffer) + 1; 
                } 
            } 
 
            *buffer = '\0'; 
            if (len <= 1) 
                /*If either lpszSection or lpszKey is NULL and the supplied 
                  destination buffer is too small to hold all the strings, 
                  the last string is truncated and followed by two null characters. 
                  In this case, the return value is equal to cchReturnBuffer 
                  minus two. */ 
            { 
                buffer[-1] = '\0'; 
                return oldlen - 2; 
            } 
            return oldlen - len; 
        } 
        section = section->next; 
    } 
    buffer[0] = buffer[1] = '\0'; 
    return 0; 
} 
 
 
/*********************************************************************** 
 *           pro_cp_entry 
 * 
 * Copy the content of an entry into a buffer, removing quotes, and possibly 
 * translating environment variables. 
 */ 
static void pro_cp_entry( INT8 *buffer, INT8 *value, UINT32 len, 
                          BOOL strip_quote ) 
{ 
    INT8 quote = '\0'; 
 
    if (!buffer) 
    { 
        return; 
    } 
 
    if (strip_quote&&((*value=='\'')||(*value=='\"'))) 
    { 
        if (value[1]&&(value[strlen(value)-1]==*value)) 
        { 
            quote = *value++; 
        } 
    } 
 
    strncpy(buffer, value, len); 
    if (quote && (len >= strlen(value))) 
    { 
        buffer[strlen(buffer)-1] = '\0'; 
    } 
} 
 
 
/*********************************************************************** 
 *           pro_find 
 * 
 * Find a key in a profile tree, optionally creating it. 
 */ 
static PRO_KEY *pro_find( PRO_SEC **section, INT8 *section_name, 
                          INT8 *key_name, BOOL create, BOOL create_always ) 
{ 
    INT8 *p; 
    INT32 seclen, keylen; 
 
    while (pro_isspace(*section_name)) 
    { 
        section_name++; 
    } 
    p = section_name + strlen(section_name) - 1; 
    while ((p > section_name) && pro_isspace(*p)) 
    { 
        p--; 
    } 
    seclen = p - section_name + 1; 
 
    while (pro_isspace(*key_name)) 
    { 
        key_name++; 
    } 
    p = key_name + strlen(key_name) - 1; 
    while ((p > key_name) && pro_isspace(*p)) 
    { 
        p--; 
    } 
    keylen = p - key_name + 1; 
 
    while (*section) 
    { 
        if (((*section)->name[0]) 
                && (!(strncmp((*section)->name, section_name, seclen))) 
                && (((*section)->name)[seclen] == '\0')) 
        { 
            PRO_KEY **key = &(*section)->key; 
 
            while (*key) 
            { 
                /* If create_always is FALSE then we check if the keyname 
                 * already exists. Otherwise we add it regardless of its 
                 * existence, to allow keys to be added more than once in 
                 * some cases. 
                 */ 
                if (!create_always) 
                { 
                    if ((!(strncmp((*key)->name, key_name, keylen))) 
                            && (((*key)->name)[keylen] == '\0')) 
                        return *key; 
                } 
                key = &(*key)->next; 
            } 
 
            if (!create) 
            { 
                return NULL; 
            } 
 
            if (!(*key = malloc(sizeof(PRO_KEY) + strlen(key_name) * sizeof(INT8)))) 
            { 
                return NULL; 
            } 
 
            strcpy((*key)->name, key_name); 
            (*key)->value = NULL; 
            (*key)->next  = NULL; 
            return *key; 
        } 
        section = &(*section)->next; 
    } 
 
    if (!create) 
    { 
        return NULL; 
    } 
    *section = malloc(sizeof(PRO_SEC) + strlen(section_name) * sizeof(INT8)); 
    if (*section == NULL) 
    { 
        return NULL; 
    } 
    strcpy((*section)->name, section_name); 
    (*section)->next = NULL; 
    if (!((*section)->key  = malloc(sizeof(PRO_KEY) + strlen(key_name) * sizeof(INT8)))) 
    { 
        free(*section); 
        return NULL; 
    } 
    strcpy((*section)->key->name, key_name); 
    (*section)->key->value = NULL; 
    (*section)->key->next  = NULL; 
    return (*section)->key; 
} 
 
 
/*********************************************************************** 
 *           pro_open 
 * 
 * Open a profile file, checking the cached file first. 
 */ 
BOOL pro_open(INT8 *filename) 
{ 
    /*INT8 windirW[255];*/ 
    INT8 buffer[255]; 
    INT32 hFile; 
    struct stat stat_info; 
    INT32 i,j; 
    PROFILE *tempProfile; 
 
    memset(&stat_info, 0, sizeof(struct stat)); 
 
    /* First time around */ 
    if (!cur_pro) 
    { 
        for (i=0;ichanged=FALSE; 
            cached_pro[i]->section=NULL; 
            cached_pro[i]->filename=NULL; 
            /*cached_pro[i]->encoding=ENCODING_ANSI;*/ 
            memset(&cached_pro[i]->stat_info.st_mtime, 0, sizeof(time_t)); 
        } 
    } 
 
    /*GetWindowsDirectoryW( windirW, MAX_PATH );*/ 
 
    if (!filename) 
        /*filename = rruini;                      add comment by lubingjie20070321 */ 
        /*memset(filename, rruini, sizeof(rruini)); add by lubingjie20070321         */ 
        memcpy(filename, rruini, sizeof(rruini)); 
/*	hFile = open(filename, O_RDWR, 0777);*/ 
    hFile = open(filename, O_RDWR|O_CREAT, 0664); 
 
    if ((hFile == -1)) 
    { 
        printf("Error opening file %s\n", filename); 
        return FALSE; 
    } 
 
    for (i=0;ifilename && !strcmp( filename, cached_pro[i]->filename ))) 
        { 
            if (i) 
            { 
                pro_flush_file(); 
                tempProfile=cached_pro[i]; 
                for (j=i;j>0;j--) 
                    cached_pro[j]=cached_pro[j-1]; 
                cur_pro=tempProfile; 
            } 
 
            if (hFile != -1) 
            { 
                close(hFile); 
            } 
            return TRUE; 
        } 
    } 
 
    /* Flush the old current profile */ 
    pro_flush_file(); 
 
    /* Make the oldest profile the current one only in order to get rid of it */ 
    if (i==N_CACHED_PROFILES) 
    { 
        tempProfile=cached_pro[N_CACHED_PROFILES-1]; 
        for (i=N_CACHED_PROFILES-1;i>0;i--) 
            cached_pro[i]=cached_pro[i-1]; 
        cur_pro=tempProfile; 
    } 
    if (cur_pro->filename) 
    { 
        pro_release_file(); 
    } 
 
    /* OK, now that cur_pro is definitely free we assign it our new file */ 
    cur_pro->filename  = (INT8 *)malloc((strlen(filename)+1) * sizeof(INT8) ); 
    strcpy( cur_pro->filename, filename ); 
 
    if (hFile != -1) 
    { 
        cur_pro->section = pro_Load(hFile); 
        fstat(hFile, &cur_pro->stat_info); 
        close(hFile); 
    } 
    else 
    { 
        /* Does not exist yet, we will create it in pro_flush_file */ 
        printf("profile file %s not found\n", buffer); 
    } 
    return TRUE; 
} 
 
 
/*********************************************************************** 
 *           pro_release_file 
 * 
 * Flush the current profile to disk and remove it from the cache. 
 */ 
static void pro_release_file(void) 
{ 
    pro_flush_file(); 
    pro_free( cur_pro->section ); 
    free(cur_pro->filename); 
    cur_pro->changed = FALSE; 
    cur_pro->section = NULL; 
    cur_pro->filename  = NULL; 
    memset(&cur_pro->stat_info, 0, sizeof(struct stat)); 
} 
 
 
/*********************************************************************** 
 *           pro_free 
 * 
 * Free a profile tree. 
 */ 
static void pro_free( PRO_SEC *section ) 
{ 
    PRO_SEC *next_section; 
    PRO_KEY *key, *next_key; 
 
    for ( ; section; section = next_section) 
    { 
        for (key = section->key; key; key = next_key) 
        { 
            next_key = key->next; 
            free(key->value); 
            free(key); 
        } 
        next_section = section->next; 
        free(section); 
    } 
} 
 
 
/*********************************************************************** 
 *           pro_flush_file 
 * 
 * Flush the current profile to disk if changed. 
 */ 
static BOOL pro_flush_file(void) 
{ 
    INT32 hFile; 
    struct stat stat_info; 
 
    if (!cur_pro) 
    { 
        printf("No current profile!\n"); 
        return FALSE; 
    } 
 
    if (!cur_pro->changed) return TRUE; 
 
    hFile = open(cur_pro->filename, O_RDWR|O_CREAT|O_TRUNC, 0777); 
    if (-1 == hFile) 
    { 
        printf("could not save profile file %s\n", cur_pro->filename); 
        return FALSE; 
    } 
 
    pro_save( hFile, cur_pro->section); 
 
    if (fstat (hFile, &stat_info) == -1) 
    { 
        return FALSE; 
    } 
    memcpy(&cur_pro->stat_info, &stat_info, sizeof(struct stat)); 
 
    close(hFile); 
    cur_pro->changed = FALSE; 
    return TRUE; 
} 
 
/*********************************************************************** 
 *           pro_save 
 * 
 * Save a profile tree to a file. 
 */ 
static void pro_save( INT32 hFile, const PRO_SEC *section) 
{ 
    PRO_KEY *key; 
    INT8 *buffer, *p; 
 
    for ( ; section; section = section->next) 
    { 
        INT32 len = 0; 
 
        if (section->name[0]) len += strlen(section->name) + 6; 
 
        for (key = section->key; key; key = key->next) 
        { 
            len += strlen(key->name) + 2; 
            if (key->value) 
            { 
                len += strlen(key->value) + 1; 
            } 
        } 
 
        buffer = (INT8 *)malloc(len * sizeof(INT8)); 
        if (!buffer) 
        { 
            return; 
        } 
 
        memset(buffer, 0, len * sizeof(INT8)); 
 
        p = buffer; 
        if (section->name[0]) 
        { 
            *p++ = '\r'; 
            *p++ = '\n'; 
            *p++ = '['; 
            strcpy( p, section->name ); 
            p += strlen(p); 
            *p++ = ']'; 
            *p++ = '\r'; 
            *p++ = '\n'; 
        } 
        for (key = section->key; key; key = key->next) 
        { 
            strcpy( p, key->name ); 
            p += strlen(p); 
            if (key->value) 
            { 
                *p++ = '='; 
                strcpy( p, key->value ); 
                p += strlen(p); 
            } 
            *p++ = '\r'; 
            *p++ = '\n'; 
        } 
        pro_write_line( hFile, buffer, len); 
        free(buffer); 
    } 
} 
 
 
static void pro_write_line( INT32 hFile, INT8 * szLine, UINT32 len) 
{ 
    write(hFile, szLine, len); 
    /*fputs (szLine, hFile);*/ 
} 
 
 
/*********************************************************************** 
 *           pro_Load 
 * 
 * Load a profile tree from a file. 
 */ 
static PRO_SEC *pro_Load(INT32 hFile) 
{ 
    INT8 *pBuffer; 
    INT8 *szFile; 
    const INT8 *szLineStart, *szLineEnd; 
    const INT8 *szValueStart, *szEnd, *next_line; 
    INT32 line = 0, len; 
 
    PRO_SEC *section, *first_section; 
    PRO_SEC **next_section; 
    PRO_KEY *key, *prev_key, **next_key; 
    INT32 dwFileSize; 
 
    struct stat stat_info; 
 
    if (-1==fstat(hFile, &stat_info)) 
    { 
        return NULL; 
    } 
 
    dwFileSize = stat_info.st_size; 
 
    pBuffer = (INT8 *)malloc(dwFileSize*sizeof(INT8)); 
    if (!pBuffer) 
    { 
        return NULL; 
    } 
 
    /*if (0==fread(pBuffer, sizeof(INT8), dwFileSize, hFile)) {*/ 
    if (-1==read(hFile, pBuffer, dwFileSize)) 
    { 
        free(pBuffer); 
        return NULL; 
    } 
 
    len = dwFileSize; 
 
    szFile = (INT8 *)malloc(len * sizeof(INT8)); 
    if (!szFile) 
    { 
        free(pBuffer); 
        return NULL; 
    } 
    szEnd = szFile + len; 
 
    memcpy(szFile, pBuffer, len); 
 
    first_section = (PRO_SEC *)malloc(sizeof(*section)); 
    if (first_section == NULL) 
    { 
        if (szFile != pBuffer) 
            free(szFile); 
        free(pBuffer); 
        return NULL; 
    } 
 
    first_section->name[0] = 0; 
    first_section->key  = NULL; 
    first_section->next = NULL; 
    next_section = &first_section->next; 
    next_key     = &first_section->key; 
    prev_key     = NULL; 
    next_line    = szFile; 
 
    while (next_line < szEnd) 
    { 
        szLineStart = next_line; 
        next_line = memchr(szLineStart, '\n', szEnd - szLineStart); 
 
        if (!next_line) 
        { 
            next_line = szEnd; 
        } 
        else 
        { 
            next_line++; 
        } 
        szLineEnd = next_line; 
 
        line++; 
 
        /* get rid of white space */ 
        while (szLineStart < szLineEnd && pro_isspace(*szLineStart)) 
        { 
            szLineStart++; 
        } 
        while ((szLineEnd > szLineStart) && 
                ((szLineEnd[-1] == '\n')|| pro_isspace(szLineEnd[-1]))) 
        { 
            szLineEnd--; 
        } 
 
        if (szLineStart >= szLineEnd) 
        { 
            continue; 
        } 
 
        if (*szLineStart == '[')  /* section start */ 
        { 
            const INT8 *szSectionEnd; 
            if (!(szSectionEnd = memchr( szLineStart, ']', szLineEnd - szLineStart ))) 
            { 
                printf("Invalid section header at line %d\n",line); 
            } 
            else 
            { 
                szLineStart++; 
                len = (INT32)(szSectionEnd - szLineStart); 
                /* no need to allocate +1 for NULL terminating character as 
                 * already included in structure */ 
                if (!(section = (PRO_SEC*)malloc(sizeof(*section) + len * sizeof(INT8)))) 
                    break; 
                memcpy(section->name, szLineStart, len * sizeof(INT8)); 
                section->name[len] = '\0'; 
                section->key  = NULL; 
                section->next = NULL; 
                *next_section = section; 
                next_section  = §ion->next; 
                next_key      = §ion->key; 
                prev_key      = NULL; 
 
                continue; 
            } 
        } 
 
        /* get rid of white space after the name and before the start 
         * of the value */ 
        len = szLineEnd - szLineStart; 
        if ((szValueStart = memchr( szLineStart, '=', szLineEnd - szLineStart )) != NULL) 
        { 
            const INT8 *szNameEnd = szValueStart; 
            while ((szNameEnd > szLineStart) && pro_isspace(szNameEnd[-1])) szNameEnd--; 
            len = szNameEnd - szLineStart; 
            szValueStart++; 
            while (szValueStart < szLineEnd && pro_isspace(*szValueStart)) szValueStart++; 
        } 
 
        if (len || !prev_key || *prev_key->name) 
        { 
            /* no need to allocate +1 for NULL terminating character as 
             * already included in structure */ 
            if (!(key = (PRO_KEY *)malloc(sizeof(*key) + len * sizeof(INT8) ))) 
            { 
                break; 
            } 
 
            memcpy(key->name, szLineStart, len * sizeof(INT8)); 
            key->name[len] = '\0'; 
            if (szValueStart) 
            { 
                len = (INT32)(szLineEnd - szValueStart); 
                key->value = malloc((len + 1) * sizeof(INT8) ); 
                memcpy(key->value, szValueStart, len * sizeof(INT8)); 
                key->value[len] = '\0'; 
            } 
            else 
            { 
                key->value = NULL; 
            } 
 
            key->next  = NULL; 
            *next_key  = key; 
            next_key   = &key->next; 
            prev_key   = key; 
        } 
    } 
    if (szFile != pBuffer) 
        free(szFile); 
    free(pBuffer); 
 
    return first_section; 
} 
 
 
/* returns 1 if a character white space else 0 */ 
static __inline INT32 pro_isspace(INT8 c) 
{ 
    if (isspace((INT32)c)) return 1; 
    /* ^Z (DOS EOF) are spaces too  (found on CD-ROMs) */ 
    if (c==0x1a) return 1; 
    return 0; 
}