Ignore:
Timestamp:
Oct 20, 1999, 10:09:05 AM (26 years ago)
Author:
sandervl
Message:

Odin ini changes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel32/profile.cpp

    r573 r1370  
    1 /* $Id: profile.cpp,v 1.18 1999-08-19 10:48:49 sandervl Exp $ */
    2  
    3 /* 
    4  * Project Odin Software License can be found in LICENSE.TXT 
    5  * 
    6  * Win32 profile API functions 
    7  * 
    8  * Copyright 1993 Miguel de Icaza 
    9  * Copyright 1996 Alexandre Julliard 
    10  * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl) 
    11  * Copyright 1998 Patrick Haller 
    12  * Copyright 1999 Christoph Bratschi 
    13  */ 
    14  
    15 #include <os2win.h> 
    16 #include <ctype.h> 
    17 #include <stdlib.h> 
    18 #include <string.h> 
    19 #include <stdio.h> 
    20 #include <unicode.h> 
     1/* $Id: profile.cpp,v 1.19 1999-10-20 08:09:05 sandervl Exp $ */
     2
     3/*
     4 * Project Odin Software License can be found in LICENSE.TXT
     5 *
     6 * Win32 profile API functions
     7 *
     8 * Copyright 1993 Miguel de Icaza
     9 * Copyright 1996 Alexandre Julliard
     10 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
     11 * Copyright 1998 Patrick Haller
     12 * Copyright 1999 Christoph Bratschi
     13 */
     14
     15#include <os2win.h>
     16#include <ctype.h>
     17#include <stdlib.h>
     18#include <string.h>
     19#include <stdio.h>
     20#include <unicode.h>
    2121#include <odinwrap.h>
    22 #include "heap.h"
    23 #include "heapstring.h"
    24  
    25 #include <sys/stat.h>
    26  
    27 #include "winbase.h"
    28 //#include "wine/winbase16.h"
    29 #include "winuser.h"
    30 #include "winnls.h"
    31  
    32  
     22#include "heap.h"
     23#include "heapstring.h"
     24
     25#include <sys/stat.h>
     26
     27#include "winbase.h"
     28#include "winuser.h"
     29#include "winnls.h"
     30
     31
    3332ODINDEBUGCHANNEL(PROFILE)
    3433
    35 // -------------------------
    36 // WINE compatibility macros
    37 // -------------------------
    38  
    39 #ifndef MAX_PATHNAME_LEN
    40 #define MAX_PATHNAME_LEN 260
    41 #endif
    42  
    43 #define SystemHeap               GetProcessHeap()
    44 #define strcasecmp               strcmp
    45 #define DOSFS_GetFullName(a,b,c) strcpy(c,a)
    46 //#define lstrcpynA(a,b,c)         strncpy((char*)a,(char*)b,(int)c)
    47 #define CharLowerA(a)            (a)
    48  
    49  
    50 typedef struct tagPROFILEKEY
    51 {
    52     char                  *name;
    53     char                  *value;
    54     struct tagPROFILEKEY  *next;
    55 } PROFILEKEY;
    56  
    57 typedef struct tagPROFILESECTION
    58 {
    59     char                       *name;
    60     struct tagPROFILEKEY       *key;
    61     struct tagPROFILESECTION   *next;
    62 } PROFILESECTION;
    63  
    64  
    65 typedef struct
    66 {
    67     BOOL             changed;
    68     PROFILESECTION  *section;
    69     char            *filename; //first open name
    70     char            *fullname; //name with path
    71     time_t           mtime;
    72 } PROFILE;
    73  
    74  
    75 #define N_CACHED_PROFILES 10
    76  
    77 /* Cached profile files */
    78 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
    79  
    80 #define CurProfile (MRUProfile[0])
    81  
    82 /* wine.ini profile content */
    83 static PROFILESECTION *PROFILE_WineProfile;
    84  
    85 #define PROFILE_MAX_LINE_LEN   1024
    86 #define WINININAME "WIN.INI"
    87  
    88 /* Wine profile name in $HOME directory; must begin with slash */
    89 static const char PROFILE_WineIniName[] = "/.winerc";
    90  
    91 /* Wine profile: the profile file being used */
    92 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
    93  
    94 /* Check for comments in profile */
    95 #define IS_ENTRY_COMMENT(str)  ((str)[0] == ';')
    96  
    97 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
    98  
    99 static LPCWSTR wininiW = NULL; //CB: never freed
    100  
    101 static CRITICAL_SECTION PROFILE_CritSect;
    102  
    103  
    104 /***********************************************************************
    105  *           PROFILE_CopyEntry
    106  *
    107  * Copy the content of an entry into a buffer, removing quotes, and possibly
    108  * translating environment variables.
    109  */
    110 static void PROFILE_CopyEntry( char *buffer,
    111                                const char *value,
    112                                int len,
    113                                int handle_env )
    114 {
    115     char quote = '\0';
    116     const char *p;
    117  
    118     if ((*value == '\'') || (*value == '\"'))
    119     {
    120         if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
    121     }
    122  
    123     if (!handle_env)
    124     {
    125         lstrcpynA( buffer, value, len );
    126         if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
    127         return;
    128     }
    129  
    130     for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
    131     {
    132         if ((*p == '$') && (p[1] == '{'))
    133         {
    134             char env_val[1024];
    135             const char *env_p;
    136             const char *p2 = strchr( p, '}' );
    137             if (!p2) continue;  /* ignore it */
    138             lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
    139             if ((env_p = getenv( env_val )) != NULL)
    140             {
    141                 lstrcpynA( buffer, env_p, len );
    142                 buffer += strlen( buffer );
    143                 len -= strlen( buffer );
    144             }
    145             p = p2 + 1;
    146         }
    147     }
    148     *buffer = '\0';
    149 }
    150  
    151  
    152 /***********************************************************************
    153  *           PROFILE_Save
    154  *
    155  * Save a profile tree to a file.
    156  */
    157 static void PROFILE_Save( FILE *file, PROFILESECTION *section )
    158 {
    159     PROFILEKEY *key;
    160  
    161     for ( ; section; section = section->next)
    162     {
    163         if (section->name) fprintf( file, "\n[%s]\n", section->name );
    164         for (key = section->key; key; key = key->next)
    165         {
    166             fprintf( file, "%s", key->name );
    167             if (key->value) fprintf( file, "=%s", key->value );
    168             fprintf( file, "\n" );
    169         }
    170     }
    171 }
    172  
    173  
    174 /***********************************************************************
    175  *           PROFILE_Free
    176  *
    177  * Free a profile tree.
    178  */
    179 static void PROFILE_Free( PROFILESECTION *section )
    180 {
    181     PROFILESECTION *next_section;
    182     PROFILEKEY *key, *next_key;
    183  
    184     for ( ; section; section = next_section)
    185     {
    186         if (section->name) HeapFree( SystemHeap, 0, section->name );
    187         for (key = section->key; key; key = next_key)
    188         {
    189             next_key = key->next;
    190             if (key->name) HeapFree( SystemHeap, 0, key->name );
    191             if (key->value) HeapFree( SystemHeap, 0, key->value );
    192             HeapFree( SystemHeap, 0, key );
    193         }
    194         next_section = section->next;
    195         HeapFree( SystemHeap, 0, section );
    196     }
    197 }
    198  
    199 static int
    200 PROFILE_isspace(char c) {
    201    if (isspace(c)) return 1;
    202    if (c=='\r' || c==0x1a) return 1;
    203    /* CR and ^Z (DOS EOF) are spaces too  (found on CD-ROMs) */
    204    return 0;
    205 }
    206  
    207  
    208 /***********************************************************************
    209  *           PROFILE_Load
    210  *
    211  * Load a profile tree from a file.
    212  */
    213 static PROFILESECTION *PROFILE_Load( FILE *file )
    214 {
    215     char buffer[PROFILE_MAX_LINE_LEN];
    216     char *p, *p2;
    217     int line = 0;
    218     PROFILESECTION *section, *first_section;
    219     PROFILESECTION **next_section;
    220     PROFILEKEY *key, *prev_key, **next_key;
    221  
    222     first_section = (PROFILESECTION *)HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
    223     first_section->name = NULL;
    224     first_section->key  = NULL;
    225     first_section->next = NULL;
    226     next_section = &first_section->next;
    227     next_key     = &first_section->key;
    228     prev_key     = NULL;
    229  
    230     while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
    231     {
    232         line++;
    233         p = buffer;
    234         while (*p && PROFILE_isspace(*p)) p++;
    235         if (*p == '[')  /* section start */
    236         {
    237             if (!(p2 = strrchr( p, ']' )))
    238             {
    239                 dprintf(("Kernel32:Profile:Invalid section header at line %d: '%s'\n",
    240            line, p ));
    241             }
    242             else
    243             {
    244                 *p2 = '\0';
    245                 p++;
    246                 section = (PROFILESECTION*)HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
    247                 section->name = HEAP_strdupA( SystemHeap, 0, p );
    248                 section->key  = NULL;
    249                 section->next = NULL;
    250                 *next_section = section;
    251                 next_section  = &section->next;
    252                 next_key      = &section->key;
    253                 prev_key      = NULL;
    254  
    255                 dprintf(("Kernel32:Profile:New section: '%s'\n",section->name));
    256  
    257                 continue;
    258             }
    259         }
    260  
    261         p2=p+strlen(p) - 1;
    262         while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
    263  
    264         if ((p2 = strchr( p, '=' )) != NULL)
    265         {
    266             char *p3 = p2 - 1;
    267             while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
    268             *p2++ = '\0';
    269             while (*p2 && PROFILE_isspace(*p2)) p2++;
    270         }
    271  
    272         if(*p || !prev_key || *prev_key->name)
    273           {
    274            key = (PROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
    275            key->name  = HEAP_strdupA( SystemHeap, 0, p );
    276            key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
    277            key->next  = NULL;
    278            *next_key  = key;
    279            next_key   = &key->next;
    280            prev_key   = key;
    281  
    282            dprintf(("Kernel32:Profile:New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)"));
    283           }
    284     }
    285     return first_section;
    286 }
    287  
    288  
    289 /***********************************************************************
    290  *           PROFILE_DeleteSection
    291  *
    292  * Delete a section from a profile tree.
    293  */
    294 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
    295 {
    296     while (*section)
    297     {
    298         if ((*section)->name && !strcasecmp( (*section)->name, name ))
    299         {
    300             PROFILESECTION *to_del = *section;
    301             *section = to_del->next;
    302             to_del->next = NULL;
    303             PROFILE_Free( to_del );
    304             return TRUE;
    305         }
    306         section = &(*section)->next;
    307     }
    308     return FALSE;
    309 }
    310  
    311  
    312 /***********************************************************************
    313  *           PROFILE_DeleteKey
    314  *
    315  * Delete a key from a profile tree.
    316  */
    317 static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
    318                 LPCSTR section_name, LPCSTR key_name )
    319 {
    320     while (*section)
    321     {
    322         if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
    323         {
    324             PROFILEKEY **key = &(*section)->key;
    325             while (*key)
    326             {
    327                 if (!strcasecmp( (*key)->name, key_name ))
    328                 {
    329                     PROFILEKEY *to_del = *key;
    330                     *key = to_del->next;
    331                     if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
    332                     if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
    333                     HeapFree( SystemHeap, 0, to_del );
    334                     return TRUE;
    335                 }
    336                 key = &(*key)->next;
    337             }
    338         }
    339         section = &(*section)->next;
    340     }
    341     return FALSE;
    342 }
    343  
    344  
    345 /***********************************************************************
    346  *           PROFILE_Find
    347  *
    348  * Find a key in a profile tree, optionally creating it.
    349  */
    350 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
    351                                  const char *section_name,
    352                                  const char *key_name, int create )
    353 {
    354     while (*section)
    355     {
    356         if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
    357         {
    358             PROFILEKEY **key = &(*section)->key;
    359             while (*key)
    360             {
    361                 if (!strcasecmp( (*key)->name, key_name )) return *key;
    362                 key = &(*key)->next;
    363             }
    364             if (!create) return NULL;
    365             *key = (PROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
    366             (*key)->name  = HEAP_strdupA( SystemHeap, 0, key_name );
    367             (*key)->value = NULL;
    368             (*key)->next  = NULL;
    369             return *key;
    370         }
    371         section = &(*section)->next;
    372     }
    373     if (!create) return NULL;
    374     *section = (PROFILESECTION*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
    375     (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
    376     (*section)->next = NULL;
    377     (*section)->key  = (tagPROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
    378     (*section)->key->name  = HEAP_strdupA( SystemHeap, 0, key_name );
    379     (*section)->key->value = NULL;
    380     (*section)->key->next  = NULL;
    381     return (*section)->key;
    382 }
    383  
    384  
    385 /***********************************************************************
    386  *           PROFILE_FlushFile
    387  *
    388  * Flush the current profile to disk if changed.
    389  */
    390 static BOOL PROFILE_FlushFile(void)
    391 {
    392     FILE *file = NULL;
    393     struct stat buf;
    394  
    395     if(!CurProfile)
    396     {
    397         dprintf(("Kernel32:Profile:No current profile!\n"));
    398         return FALSE;
    399     }
    400  
    401     // not changed, return immediately
    402     if (!CurProfile->changed)
    403       return TRUE;
    404  
    405     // try to open file
    406     file = fopen(CurProfile->fullname, "w");
    407     if (!file)
    408     {
    409         dprintf(("Kernel32:Profile:could not save profile file %s\n", CurProfile->fullname));
    410         return FALSE;
    411     }
    412  
    413     dprintf(("Kernel32:Profile:Saving %s\n", CurProfile->fullname ));
    414     PROFILE_Save( file, CurProfile->section );
    415     fclose( file );
    416     CurProfile->changed = FALSE;
    417     if(!stat(CurProfile->fullname,&buf))
    418        CurProfile->mtime=buf.st_mtime;
    419     return TRUE;
    420 }
    421  
    422  
    423 /***********************************************************************
    424  *           PROFILE_ReleaseFile
    425  *
    426  * Flush the current profile to disk and remove it from the cache.
    427  */
    428 static void PROFILE_ReleaseFile(void)
    429 {
    430     PROFILE_FlushFile();
    431     PROFILE_Free( CurProfile->section );
    432     if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
    433     if (CurProfile->fullname) HeapFree(SystemHeap,0,CurProfile->fullname);
    434     CurProfile->changed   = FALSE;
    435     CurProfile->section   = NULL;
    436     CurProfile->filename  = NULL;
    437     CurProfile->fullname  = NULL;
    438     CurProfile->mtime     = 0;
    439 }
    440  
    441  
    442 /***********************************************************************
    443  *           PROFILE_Open
    444  *
    445  * Open a profile file, checking the cached file first.
    446  */
    447 static BOOL PROFILE_Open( LPCSTR filename )
    448 {
    449     FILE *file = NULL;
    450     int i,j;
    451     struct stat buf;
    452     PROFILE *tempProfile;
    453  
    454     if (!filename || filename[0] == 0) return FALSE;
    455  
    456     /* First time around */
    457  
    458     if(!CurProfile)
    459        for(i=0;i<N_CACHED_PROFILES;i++)
    460          {
    461           MRUProfile[i]= (PROFILE*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
    462           MRUProfile[i]->changed=FALSE;
    463           MRUProfile[i]->section=NULL;
    464           MRUProfile[i]->filename=NULL;
    465           MRUProfile[i]->fullname=NULL;
    466           MRUProfile[i]->mtime=0;
    467          }
    468  
    469     /* Check for a match */
    470  
    471     for(i=0;i<N_CACHED_PROFILES;i++)
    472       {
    473        if (MRUProfile[i]->filename && (!strcmp(filename,MRUProfile[i]->filename) || !strcmp(filename,MRUProfile[i]->fullname)))
    474          {
    475           if(i)
    476             {
    477              PROFILE_FlushFile();
    478              tempProfile=MRUProfile[i];
    479              for(j=i;j>0;j--)
    480                 MRUProfile[j]=MRUProfile[j-1];
    481              CurProfile=tempProfile;
    482             }
    483           if(!stat(CurProfile->fullname,&buf) && CurProfile->mtime==buf.st_mtime)
    484              dprintf(("Kernel32:Profile:(%s): already opened (mru=%d)\n",
    485                               filename, i ));
    486           else
    487               dprintf(("Kernel32:Profile:(%s): already opened, needs refreshing (mru=%d)\n",
    488                              filename, i ));
    489      return TRUE;
    490          }
    491       }
    492  
    493     /* Rotate the oldest to the top to be replaced */
    494  
    495     if(i==N_CACHED_PROFILES)
    496       {
    497        tempProfile=MRUProfile[N_CACHED_PROFILES-1];
    498        for(i=N_CACHED_PROFILES-1;i>0;i--)
    499           MRUProfile[i]=MRUProfile[i-1];
    500        CurProfile=tempProfile;
    501       }
    502  
    503     /* Flush the profile */
    504  
    505     if(CurProfile->filename) PROFILE_ReleaseFile();
    506  
    507     CurProfile->filename  = HEAP_strdupA(SystemHeap,0,filename);
    508  
    509     /* check for path */
    510  
    511     if ((!strchr( filename,'/') &&
    512          !strchr( filename,'\\')) ||
    513         !strchr( filename,':'))
    514     {
    515       char fullname[MAX_PATHNAME_LEN];
    516  
    517       GetWindowsDirectoryA(fullname,sizeof(fullname));
    518       strcat(fullname,"\\");
    519       strcat(fullname,filename);
    520       CurProfile->fullname  = HEAP_strdupA(SystemHeap,0,fullname);
    521     } else CurProfile->fullname  = HEAP_strdupA(SystemHeap,0,filename);
    522  
    523     file = fopen(CurProfile->fullname,"r");
    524     if (file)
    525     {
    526       dprintf(("Kernel32:Profile:(%s): found it in %s\n",
    527                filename, CurProfile->fullname ));
    528  
    529         CurProfile->section = PROFILE_Load( file );
    530         fclose( file );
    531         if(!stat(CurProfile->fullname,&buf))
    532            CurProfile->mtime=buf.st_mtime;
    533     }
    534     else
    535     {
    536         /* Does not exist yet, we will create it in PROFILE_FlushFile */
    537         dprintf(("Kernel32:Profile:profile file %s not found\n", CurProfile->fullname ));
    538     }
    539     return TRUE;
    540 }
    541  
    542  
    543 /***********************************************************************
    544  *           PROFILE_GetSection
    545  *
    546  * Returns all keys of a section.
    547  * If return_values is TRUE, also include the corresponding values.
    548  */
    549 static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
    550                 LPSTR buffer, UINT len, BOOL handle_env,
    551                 BOOL return_values )
    552 {
    553     PROFILEKEY *key;
    554     while (section)
    555     {
    556         if (section->name && !strcasecmp( section->name, section_name ))
    557         {
    558             UINT oldlen = len;
    559             for (key = section->key; key; key = key->next)
    560             {
    561                 if (len <= 2) break;
    562                 if (!*key->name) continue;  /* Skip empty lines */
    563                 if (IS_ENTRY_COMMENT(key->name)) continue;  /* Skip comments */
    564                 PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
    565                 len -= strlen(buffer) + 1;
    566                 buffer += strlen(buffer) + 1;
    567       if (return_values && key->value) {
    568          buffer[-1] = '=';
    569          PROFILE_CopyEntry ( buffer,
    570             key->value, len - 1, handle_env );
    571          len -= strlen(buffer) + 1;
    572          buffer += strlen(buffer) + 1;
    573                 }
    574             }
    575             *buffer = '\0';
    576             if (len <= 1)
    577                 /*If either lpszSection or lpszKey is NULL and the supplied
    578                   destination buffer is too small to hold all the strings,
    579                   the last string is truncated and followed by two null characters.
    580                   In this case, the return value is equal to cchReturnBuffer
    581                   minus two. */
    582             {
    583       buffer[-1] = '\0';
    584                 return oldlen - 2;
    585             }
    586             return oldlen - len;
    587         }
    588         section = section->next;
    589     }
    590     buffer[0] = buffer[1] = '\0';
    591     return 0;
    592 }
    593  
    594  
    595 static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
    596 {
    597     LPSTR buf = buffer;
    598     WORD l, cursize = 0;
    599     PROFILESECTION *section;
    600  
    601     for (section = CurProfile->section; section; section = section->next)
    602    if (section->name) {
    603        l = strlen(section->name);
    604        cursize += l+1;
    605        if (cursize > len+1)
    606       return len-2;
    607  
    608        strcpy(buf, section->name);
    609        buf += l+1;
    610    }
    611  
    612     *buf=0;
    613     buf++;
    614     return buf-buffer;
    615 }
    616  
    617  
    618 /***********************************************************************
    619  *           PROFILE_GetString
    620  *
    621  * Get a profile string.
    622  */
    623 static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
    624                LPCSTR def_val, LPSTR buffer, UINT len )
    625 {
    626     PROFILEKEY *key = NULL;
    627  
    628     if (!def_val) def_val = "";
    629     if (key_name && key_name[0])
    630     {
    631         key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
    632         PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
    633                            len, FALSE );
    634         dprintf(("Kernel32:Profile:('%s','%s','%s'): returning '%s'\n",
    635                          section, key_name, def_val, buffer ));
    636         return strlen( buffer );
    637     }
    638     if (section && section[0])
    639         return PROFILE_GetSection(CurProfile->section, section, buffer, len,
    640             FALSE, FALSE);
    641     /* undocumented; both section and key_name are NULL */
    642     return PROFILE_GetSectionNames(buffer, len);
    643 }
    644  
    645  
    646 /***********************************************************************
    647  *           PROFILE_SetString
    648  *
    649  * Set a profile string.
    650  */
    651 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
    652                 LPCSTR value )
    653 {
    654     if (!key_name)  /* Delete a whole section */
    655     {
    656         dprintf(("Kernel32:Profile:('%s')\n", section_name));
    657         CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
    658                                                       section_name );
    659         return TRUE;         /* Even if PROFILE_DeleteSection() has failed,
    660                                 this is not an error on application's level.*/
    661     }
    662     else if (!value)  /* Delete a key */
    663     {
    664         dprintf(("Kernel32:Profile:('%s','%s')\n",
    665                          section_name, key_name ));
    666         CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
    667                                                   section_name, key_name );
    668         return TRUE;          /* same error handling as above */
    669     }
    670     else  /* Set the key value */
    671     {
    672         PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
    673                                         key_name, TRUE );
    674         dprintf(("Kernel32:Profile:('%s','%s','%s'): \n",
    675                          section_name, key_name, value ));
    676         if (!key) return FALSE;
    677         if (key->value)
    678         {
    679             if (!strcmp( key->value, value ))
    680             {
    681                 dprintf(("Kernel32:Profile:  no change needed\n" ));
    682                 return TRUE;  /* No change needed */
    683             }
    684             dprintf(("Kernel32:Profile:  replacing '%s'\n", key->value ));
    685             HeapFree( SystemHeap, 0, key->value );
    686         }
    687         else dprintf(("Kernel32:Profile:  creating key\n" ));
    688         key->value = HEAP_strdupA( SystemHeap, 0, value );
    689         CurProfile->changed = TRUE;
    690     }
    691     return TRUE;
    692 }
    693  
    694  
    695 /***********************************************************************
    696  *           PROFILE_GetWineIniString
    697  *
    698  * Get a config string from the wine.ini file.
    699  */
    700 int PROFILE_GetWineIniString( const char *section, const char *key_name,
    701                               const char *def, char *buffer, int len )
    702 {
    703     int  ret;
    704  
    705     EnterCriticalSection( &PROFILE_CritSect );
    706  
    707     if (key_name)
    708     {
    709         PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
    710         PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
    711                            len, TRUE );
    712         dprintf(("Kernel32:Profile:('%s','%s','%s'): returning '%s'\n",
    713                          section, key_name, def, buffer ));
    714         ret = strlen( buffer );
    715     }
    716     else
    717     {
    718        ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
    719     }
    720     LeaveCriticalSection( &PROFILE_CritSect );
    721  
    722     return ret;
    723 }
    724  
    725  
    726 /***********************************************************************
    727  *           PROFILE_GetWineIniInt
    728  *
    729  * Get a config integer from the wine.ini file.
    730  */
    731 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
    732 {
    733     char buffer[20];
    734     char *p;
    735     long result;
    736     PROFILEKEY *key;
    737     int  ret;
    738  
    739     EnterCriticalSection( &PROFILE_CritSect );
    740  
    741     key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
    742     if (!key || !key->value) {
    743        ret = def;
    744     } else {
    745        PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
    746        result = strtol( buffer, &p, 0 );
    747        ret = (p == buffer) ? 0  /* No digits at all */ : (int)result;
    748     }
    749  
    750     LeaveCriticalSection( &PROFILE_CritSect );
    751  
    752     return ret;
    753 }
    754  
    755  
    756 /******************************************************************************
    757  *
    758  *   int  PROFILE_EnumerateWineIniSection(
    759  *     char const  *section,  #Name of the section to enumerate
    760  *     void  (*cbfn)(char const *key, char const *value, void *user),
    761  *                            # Address of the callback function
    762  *     void  *user )          # User-specified pointer.
    763  *
    764  *   For each entry in a section in the wine.conf file, this function will
    765  *   call the specified callback function, informing it of each key and
    766  *   value.  An optional user pointer may be passed to it (if this is not
    767  *   needed, pass NULL through it and ignore the value in the callback
    768  *   function).
    769  *
    770  *   The callback function must accept three parameters:
    771  *      The name of the key (char const *)
    772  *      The value of the key (char const *)
    773  *      A user-specified parameter (void *)
    774  *   Note that the first two are char CONST *'s, not char *'s!  The callback
    775  *   MUST not modify these strings!
    776  *
    777  *   The return value indicates the number of times the callback function
    778  *   was called.
    779  */
    780 int  PROFILE_EnumerateWineIniSection(
    781     char const  *section,
    782     void  (*cbfn)(char const *, char const *, void *),
    783     void  *userptr )
    784 {
    785     PROFILESECTION  *scansect;
    786     PROFILEKEY  *scankey;
    787     int  calls = 0;
    788  
    789     EnterCriticalSection( &PROFILE_CritSect );
    790  
    791     /* Search for the correct section */
    792     for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
    793    if(scansect->name && !strcasecmp(scansect->name, section)) {
    794  
    795        /* Enumerate each key with the callback */
    796        for(scankey = scansect->key; scankey; scankey = scankey->next) {
    797  
    798       /* Ignore blank entries -- these shouldn't exist, but let's
    799          be extra careful */
    800       if(scankey->name[0]) {
    801           cbfn(scankey->name, scankey->value, userptr);
    802           ++calls;
    803       }
    804        }
    805  
    806        break;
    807    }
    808     }
    809     LeaveCriticalSection( &PROFILE_CritSect );
    810  
    811     return calls;
    812 }
    813  
    814  
    815 /******************************************************************************
    816  *
    817  *   int  PROFILE_GetWineIniBool(
    818  *      char const  *section,
    819  *      char const  *key_name,
    820  *      int  def )
    821  *
    822  *   Reads a boolean value from the wine.ini file.  This function attempts to
    823  *   be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
    824  *   (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
    825  *   true.  Anything else results in the return of the default value.
    826  *
    827  *   This function uses 1 to indicate true, and 0 for false.  You can check
    828  *   for existence by setting def to something other than 0 or 1 and
    829  *   examining the return value.
    830  */
    831 int  PROFILE_GetWineIniBool(
    832     char const  *section,
    833     char const  *key_name,
    834     int  def )
    835 {
    836     char  key_value[2];
    837     int  retval;
    838  
    839     PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
    840  
    841     switch(key_value[0]) {
    842     case 'n':
    843     case 'N':
    844     case 'f':
    845     case 'F':
    846     case '0':
    847    retval = 0;
    848    break;
    849  
    850     case 'y':
    851     case 'Y':
    852     case 't':
    853     case 'T':
    854     case '1':
    855    retval = 1;
    856    break;
    857  
    858     default:
    859    retval = def;
    860     }
    861  
    862     dprintf(("Kernel32:Profile:(\"%s\", \"%s\", %s), "
    863           "[%c], ret %s.\n", section, key_name,
    864           def ? "TRUE" : "FALSE", key_value[0],
    865           retval ? "TRUE" : "FALSE"));
    866  
    867     return retval;
    868 }
    869  
    870  
    871 #if 0
    872 /***********************************************************************
    873  *           PROFILE_LoadWineIni
    874  *
    875  * Load the wine.ini file.
    876  */
    877 int PROFILE_LoadWineIni(void)
    878 {
    879     char buffer[MAX_PATHNAME_LEN];
    880     const char *p;
    881     FILE *f;
    882  
    883     InitializeCriticalSection( &PROFILE_CritSect );
    884     MakeCriticalSectionGlobal( &PROFILE_CritSect );
    885  
    886     if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
    887     {
    888       /* Open -config specified file */
    889       PROFILE_WineProfile = PROFILE_Load ( f);
    890       fclose ( f );
    891       strncpy(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN-1);
    892       return 1;
    893     }
    894  
    895     if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
    896     {
    897    PROFILE_WineProfile = PROFILE_Load( f );
    898    fclose( f );
    899    strncpy(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN-1);
    900    return 1;
    901     }
    902     if ((p = getenv( "HOME" )) != NULL)
    903     {
    904         lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
    905         strcat( buffer, PROFILE_WineIniName );
    906         if ((f = fopen( buffer, "r" )) != NULL)
    907         {
    908             PROFILE_WineProfile = PROFILE_Load( f );
    909             fclose( f );
    910        strncpy(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN-1);
    911             return 1;
    912         }
    913     }
    914     else dprintf(("Kernel32:Profile:could not get $HOME value for config file.\n" ));
    915  
    916     /* Try global file */
    917  
    918     if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
    919     {
    920         PROFILE_WineProfile = PROFILE_Load( f );
    921         fclose( f );
    922    strncpy(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN-1);
    923         return 1;
    924     }
    925     MESSAGE( "Can't open configuration file %s or $HOME%s\n",
    926     WINE_INI_GLOBAL, PROFILE_WineIniName );
    927     return 0;
    928 }
    929  
    930  
    931 /***********************************************************************
    932  *           PROFILE_UsageWineIni
    933  *
    934  * Explain the wine.ini file to those who don't read documentation.
    935  * Keep below one screenful in length so that error messages above are
    936  * noticed.
    937  */
    938 void PROFILE_UsageWineIni(void)
    939 {
    940     MESSAGE("Perhaps you have not properly edited or created "
    941    "your Wine configuration file.\n");
    942     MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
    943     MESSAGE("  or it is determined by the -config option or from\n"
    944         "  the WINE_INI environment variable.\n");
    945     if (*PROFILE_WineIniUsed)
    946    MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
    947     /* RTFM, so to say */
    948 }
    949 #endif
    950  
    951 /***********************************************************************
    952  *           PROFILE_GetStringItem
    953  *
    954  *  Convenience function that turns a string 'xxx, yyy, zzz' into
    955  *  the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
    956  */
    957 char* PROFILE_GetStringItem( char* start )
    958 {
    959     char* lpchX, *lpch;
    960  
    961     for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
    962     {
    963         if( *lpchX == ',' )
    964         {
    965             if( lpch ) *lpch = '\0'; else *lpchX = '\0';
    966             while( *(++lpchX) )
    967                 if( !PROFILE_isspace(*lpchX) ) return lpchX;
    968         }
    969    else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
    970         else lpch = NULL;
    971     }
    972     if( lpch ) *lpch = '\0';
    973     return NULL;
    974 }
    975  
    976 /********************* API functions **********************************/
    977  
    978 /***********************************************************************
    979  *           GetProfileInt32A   (KERNEL32.264)
    980  */
    981 ODINFUNCTION3(UINT, GetProfileIntA,
    982               LPCSTR, section,
    983               LPCSTR, entry,
    984               INT, def_val)
    985 {
    986     return GetPrivateProfileIntA( section, entry, def_val, WINININAME );
    987 }
    988  
    989 /***********************************************************************
    990  *           GetProfileInt32W   (KERNEL32.264)
    991  */
    992 ODINFUNCTION3(UINT, GetProfileIntW,
    993               LPCWSTR, section,
    994               LPCWSTR, entry,
    995               INT, def_val)
    996 {
    997     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
    998     return GetPrivateProfileIntW( section, entry, def_val, wininiW );
    999 }
    1000  
    1001 /***********************************************************************
    1002  *           GetProfileString32A   (KERNEL32.268)
    1003  */
    1004 ODINFUNCTION5(INT, GetProfileStringA,
    1005               LPCSTR, section,
    1006               LPCSTR, entry,
    1007               LPCSTR, def_val,
    1008               LPSTR, buffer,
    1009               UINT, len)
    1010 {
    1011     return GetPrivateProfileStringA( section, entry, def_val,
    1012                  buffer, len, WINININAME );
    1013 }
    1014  
    1015 /***********************************************************************
    1016  *           GetProfileString32W   (KERNEL32.269)
    1017  */
    1018 ODINFUNCTION5(INT, GetProfileStringW,
    1019               LPCWSTR, section,
    1020               LPCWSTR, entry,
    1021               LPCWSTR, def_val,
    1022               LPWSTR, buffer,
    1023               UINT, len)
    1024 {
    1025     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
    1026     return GetPrivateProfileStringW( section, entry, def_val,
    1027                  buffer, len, wininiW );
    1028 }
    1029  
    1030 /***********************************************************************
    1031  *           WriteProfileString32A   (KERNEL32.587)
    1032  */
    1033 ODINFUNCTION3(BOOL, WriteProfileStringA,
    1034               LPCSTR, section,
    1035               LPCSTR, entry,
    1036               LPCSTR, string)
    1037 {
    1038     return WritePrivateProfileStringA( section, entry, string, WINININAME );
    1039 }
    1040  
    1041 /***********************************************************************
    1042  *           WriteProfileString32W   (KERNEL32.588)
    1043  */
    1044 ODINFUNCTION3(BOOL, WriteProfileStringW,
    1045               LPCWSTR, section,
    1046               LPCWSTR, entry,
    1047               LPCWSTR, string)
    1048 {
    1049     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
    1050     return WritePrivateProfileStringW( section, entry, string, wininiW );
    1051 }
    1052  
    1053 /***********************************************************************
    1054  *           GetPrivateProfileInt32A   (KERNEL32.251)
    1055  */
    1056 ODINFUNCTION4(UINT, GetPrivateProfileIntA,
    1057               LPCSTR, section,
    1058               LPCSTR, entry,
    1059               INT, def_val,
    1060               LPCSTR, filename)
    1061 {
    1062     char buffer[20];
    1063     char *p;
    1064     long result;
    1065  
    1066     GetPrivateProfileStringA( section, entry, "",
    1067                                 buffer, sizeof(buffer), filename );
    1068     if (!buffer[0]) return (UINT)def_val;
    1069     result = strtol( buffer, &p, 0 );
    1070     if (p == buffer) return 0;  /* No digits at all */
    1071     return (UINT)result;
    1072 }
    1073  
    1074 /***********************************************************************
    1075  *           GetPrivateProfileInt32W   (KERNEL32.252)
    1076  */
    1077 ODINFUNCTION4(UINT, GetPrivateProfileIntW,
    1078               LPCWSTR, section,
    1079               LPCWSTR, entry,
    1080               INT, def_val,
    1081               LPCWSTR, filename)
    1082 {
    1083     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1084     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
    1085     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1086     UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
    1087     HeapFree( GetProcessHeap(), 0, sectionA );
    1088     HeapFree( GetProcessHeap(), 0, filenameA );
    1089     HeapFree( GetProcessHeap(), 0, entryA );
    1090     return res;
    1091 }
    1092  
    1093 /***********************************************************************
    1094  *           GetPrivateProfileString32A   (KERNEL32.255)
    1095  */
    1096 ODINFUNCTION6(INT, GetPrivateProfileStringA,
    1097               LPCSTR, section,
    1098               LPCSTR, entry,
    1099               LPCSTR, def_val,
    1100               LPSTR, buffer,
    1101               UINT, len,
    1102               LPCSTR, filename)
    1103 {
    1104     int     ret;
    1105  
    1106     if (!filename)
    1107    filename = WINININAME;
    1108  
    1109     EnterCriticalSection( &PROFILE_CritSect );
    1110  
    1111     if (PROFILE_Open( filename )) {
    1112         ret = PROFILE_GetString( section, entry, def_val, buffer, len );
    1113     } else {
    1114        lstrcpynA( buffer, def_val, len );
    1115        ret = strlen( buffer );
    1116     }
    1117  
    1118     LeaveCriticalSection( &PROFILE_CritSect );
    1119  
    1120     return ret;
    1121 }
    1122  
    1123 /***********************************************************************
    1124  *           GetPrivateProfileString32W   (KERNEL32.256)
    1125  */
    1126 ODINFUNCTION6(INT, GetPrivateProfileStringW,
    1127               LPCWSTR, section,
    1128               LPCWSTR, entry,
    1129               LPCWSTR, def_val,
    1130               LPWSTR, buffer,
    1131               UINT, len,
    1132               LPCWSTR, filename)
    1133 {
    1134     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1135     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
    1136     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1137     LPSTR def_valA  = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
    1138     LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
    1139     INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
    1140                                             bufferA, len, filenameA );
    1141     lstrcpynAtoW( buffer, bufferA, len );
    1142     HeapFree( GetProcessHeap(), 0, sectionA );
    1143     HeapFree( GetProcessHeap(), 0, entryA );
    1144     HeapFree( GetProcessHeap(), 0, filenameA );
    1145     HeapFree( GetProcessHeap(), 0, def_valA );
    1146     HeapFree( GetProcessHeap(), 0, bufferA);
    1147     return ret;
    1148 }
    1149  
    1150 /***********************************************************************
    1151  *           GetPrivateProfileSection32A   (KERNEL32.255)
    1152  */
    1153 ODINFUNCTION4(INT, GetPrivateProfileSectionA,
    1154               LPCSTR, section,
    1155               LPSTR, buffer,
    1156               DWORD, len,
    1157               LPCSTR, filename)
    1158 {
    1159     int     ret = 0;
    1160  
    1161     EnterCriticalSection( &PROFILE_CritSect );
    1162  
    1163     if (PROFILE_Open( filename ))
    1164         ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
    1165              FALSE, TRUE);
    1166  
    1167     LeaveCriticalSection( &PROFILE_CritSect );
    1168  
    1169     return ret;
    1170 }
    1171  
    1172 /***********************************************************************
    1173  *           GetPrivateProfileSection32W   (KERNEL32.256)
    1174  */
    1175  
    1176 ODINFUNCTION4(INT, GetPrivateProfileSectionW,
    1177               LPCWSTR, section,
    1178               LPWSTR, buffer,
    1179               DWORD, len,
    1180               LPCWSTR, filename)
    1181  
    1182 {
    1183     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1184     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1185     LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
    1186     INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
    1187                   filenameA );
    1188     MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
    1189     HeapFree( GetProcessHeap(), 0, sectionA );
    1190     HeapFree( GetProcessHeap(), 0, filenameA );
    1191     HeapFree( GetProcessHeap(), 0, bufferA);
    1192     return ret;
    1193 }
    1194  
    1195 /***********************************************************************
    1196  *           GetProfileSection32A   (KERNEL32.268)
    1197  */
    1198 ODINFUNCTION3(INT, GetProfileSectionA,
    1199               LPCSTR, section,
    1200               LPSTR, buffer,
    1201               DWORD, len)
    1202 {
    1203     return GetPrivateProfileSectionA( section, buffer, len, WINININAME );
    1204 }
    1205  
    1206 /***********************************************************************
    1207  *           GetProfileSection32W   (KERNEL32)
    1208  */
    1209 ODINFUNCTION3(INT, GetProfileSectionW,
    1210               LPCWSTR, section,
    1211               LPWSTR, buffer,
    1212               DWORD, len)
    1213 {
    1214     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
    1215     return GetPrivateProfileSectionW( section, buffer, len, wininiW );
    1216 }
    1217  
    1218 /***********************************************************************
    1219  *           WritePrivateProfileString32A   (KERNEL32.582)
    1220  */
    1221 ODINFUNCTION4(BOOL, WritePrivateProfileStringA,
    1222               LPCSTR, section,
    1223               LPCSTR, entry,
    1224               LPCSTR, string,
    1225               LPCSTR, filename)
    1226 {
    1227     BOOL ret = FALSE;
    1228  
    1229     EnterCriticalSection( &PROFILE_CritSect );
    1230  
    1231     if (PROFILE_Open( filename ))
    1232     {
    1233         if (!section && !entry && !string)
    1234             PROFILE_ReleaseFile();  /* always return FALSE in this case */
    1235         else
    1236             ret = PROFILE_SetString( section, entry, string );
    1237     }
    1238  
    1239     LeaveCriticalSection( &PROFILE_CritSect );
    1240     return ret;
    1241 }
    1242  
    1243 /***********************************************************************
    1244  *           WritePrivateProfileString32W   (KERNEL32.583)
    1245  */
    1246 ODINFUNCTION4(BOOL, WritePrivateProfileStringW,
    1247               LPCWSTR, section,
    1248               LPCWSTR, entry,
    1249               LPCWSTR, string,
    1250               LPCWSTR, filename)
    1251 {
    1252     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1253     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
    1254     LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
    1255     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1256     BOOL res = WritePrivateProfileStringA( sectionA, entryA,
    1257                   stringA, filenameA );
    1258     HeapFree( GetProcessHeap(), 0, sectionA );
    1259     HeapFree( GetProcessHeap(), 0, entryA );
    1260     HeapFree( GetProcessHeap(), 0, stringA );
    1261     HeapFree( GetProcessHeap(), 0, filenameA );
    1262     return res;
    1263 }
    1264  
    1265 /***********************************************************************
    1266  *           WritePrivateProfileSection32A   (KERNEL32)
    1267  */
    1268 ODINFUNCTION3(BOOL, WritePrivateProfileSectionA,
    1269               LPCSTR, section,
    1270               LPCSTR, string,
    1271               LPCSTR, filename)
    1272 {
    1273   char *p =(char*)string;
    1274  
    1275   dprintf(("Kernel32:Profile:fixme WritePrivateProfileSection32A empty stub\n"));
    1276   return FALSE;
    1277 }
    1278  
    1279 /***********************************************************************
    1280  *           WritePrivateProfileSection32W   (KERNEL32)
    1281  */
    1282 ODINFUNCTION3(BOOL, WritePrivateProfileSectionW,
    1283               LPCWSTR, section,
    1284               LPCWSTR, string,
     34// -------------------------
     35// WINE compatibility macros
     36// -------------------------
     37
     38#ifndef MAX_PATHNAME_LEN
     39#define MAX_PATHNAME_LEN 260
     40#endif
     41
     42#define SystemHeap               GetProcessHeap()
     43#define strcasecmp               stricmp
     44#define DOSFS_GetFullName(a,b,c) strcpy(c,a)
     45#define CharLowerA(a)            (a)
     46
     47
     48typedef struct tagPROFILEKEY
     49{
     50    char                  *name;
     51    char                  *value;
     52    struct tagPROFILEKEY  *next;
     53} PROFILEKEY;
     54
     55typedef struct tagPROFILESECTION
     56{
     57    char                       *name;
     58    struct tagPROFILEKEY       *key;
     59    struct tagPROFILESECTION   *next;
     60} PROFILESECTION;
     61
     62
     63typedef struct
     64{
     65    BOOL             changed;
     66    PROFILESECTION  *section;
     67    char            *filename; //first open name
     68    char            *fullname; //name with path
     69    time_t           mtime;
     70} PROFILE;
     71
     72
     73#define N_CACHED_PROFILES 10
     74
     75/* Cached profile files */
     76static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
     77
     78#define CurProfile (MRUProfile[0])
     79
     80/* ODIN.INI profile content */
     81BOOL OdinProfileChanged = FALSE;
     82static PROFILESECTION *PROFILE_OdinProfile;
     83
     84#define PROFILE_MAX_LINE_LEN   1024
     85#define WINININAME "WIN.INI"
     86
     87/* Odin profile name in KERNEL32.DLL directory */
     88#define ODINININAME "ODIN.INI"
     89
     90/* Odin profile: the profile file being used */
     91static char PROFILE_OdinIniUsed[MAX_PATHNAME_LEN] = "";
     92
     93/* Check for comments in profile */
     94#define IS_ENTRY_COMMENT(str)  ((str)[0] == ';')
     95
     96static LPCWSTR wininiW = NULL;
     97
     98static CRITICAL_SECTION PROFILE_CritSect;
     99
     100
     101/***********************************************************************
     102 *           PROFILE_CopyEntry
     103 *
     104 * Copy the content of an entry into a buffer, removing quotes, and possibly
     105 * translating environment variables.
     106 */
     107static void PROFILE_CopyEntry( char *buffer,
     108                               const char *value,
     109                               int len,
     110                               int handle_env )
     111{
     112    char quote = '\0';
     113    const char *p;
     114
     115    if ((*value == '\'') || (*value == '\"'))
     116    {
     117        if (value[1] && (value[strlen(value)-1] == *value)) quote = *value++;
     118    }
     119
     120    if (!handle_env)
     121    {
     122        lstrcpynA( buffer, value, len );
     123        if (quote && (len >= strlen(value))) buffer[strlen(buffer)-1] = '\0';
     124        return;
     125    }
     126
     127    for (p = value; (*p && (len > 1)); *buffer++ = *p++, len-- )
     128    {
     129        if ((*p == '$') && (p[1] == '{'))
     130        {
     131            char env_val[1024];
     132            const char *env_p;
     133            const char *p2 = strchr( p, '}' );
     134            if (!p2) continue;  /* ignore it */
     135            lstrcpynA(env_val, p + 2, MIN( sizeof(env_val), (int)(p2-p)-1 ));
     136            if ((env_p = getenv( env_val )) != NULL)
     137            {
     138                lstrcpynA( buffer, env_p, len );
     139                buffer += strlen( buffer );
     140                len -= strlen( buffer );
     141            }
     142            p = p2 + 1;
     143        }
     144    }
     145    *buffer = '\0';
     146}
     147
     148
     149/***********************************************************************
     150 *           PROFILE_Save
     151 *
     152 * Save a profile tree to a file.
     153 */
     154static void PROFILE_Save( FILE *file, PROFILESECTION *section )
     155{
     156    PROFILEKEY *key;
     157
     158    for ( ; section; section = section->next)
     159    {
     160        if (section->name) fprintf( file, "\n[%s]\n", section->name );
     161        for (key = section->key; key; key = key->next)
     162        {
     163            fprintf( file, "%s", key->name );
     164            if (key->value) fprintf( file, "=%s", key->value );
     165            fprintf( file, "\n" );
     166        }
     167    }
     168}
     169
     170
     171/***********************************************************************
     172 *           PROFILE_Free
     173 *
     174 * Free a profile tree.
     175 */
     176static void PROFILE_Free( PROFILESECTION *section )
     177{
     178    PROFILESECTION *next_section;
     179    PROFILEKEY *key, *next_key;
     180
     181    for ( ; section; section = next_section)
     182    {
     183        if (section->name) HeapFree( SystemHeap, 0, section->name );
     184        for (key = section->key; key; key = next_key)
     185        {
     186            next_key = key->next;
     187            if (key->name) HeapFree( SystemHeap, 0, key->name );
     188            if (key->value) HeapFree( SystemHeap, 0, key->value );
     189            HeapFree( SystemHeap, 0, key );
     190        }
     191        next_section = section->next;
     192        HeapFree( SystemHeap, 0, section );
     193    }
     194}
     195
     196static int
     197PROFILE_isspace(char c) {
     198   if (isspace(c)) return 1;
     199   if (c=='\r' || c==0x1a) return 1;
     200   /* CR and ^Z (DOS EOF) are spaces too  (found on CD-ROMs) */
     201   return 0;
     202}
     203
     204
     205/***********************************************************************
     206 *           PROFILE_Load
     207 *
     208 * Load a profile tree from a file.
     209 */
     210static PROFILESECTION *PROFILE_Load( FILE *file )
     211{
     212    char buffer[PROFILE_MAX_LINE_LEN];
     213    char *p, *p2;
     214    int line = 0;
     215    PROFILESECTION *section, *first_section;
     216    PROFILESECTION **next_section;
     217    PROFILEKEY *key, *prev_key, **next_key;
     218
     219    first_section = (PROFILESECTION *)HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
     220    first_section->name = NULL;
     221    first_section->key  = NULL;
     222    first_section->next = NULL;
     223    next_section = &first_section->next;
     224    next_key     = &first_section->key;
     225    prev_key     = NULL;
     226
     227    while (fgets( buffer, PROFILE_MAX_LINE_LEN, file ))
     228    {
     229        line++;
     230        p = buffer;
     231        while (*p && PROFILE_isspace(*p)) p++;
     232        if (*p == '[')  /* section start */
     233        {
     234            if (!(p2 = strrchr( p, ']' )))
     235            {
     236                dprintf(("Kernel32:Profile:Invalid section header at line %d: '%s'\n",
     237           line, p ));
     238            }
     239            else
     240            {
     241                *p2 = '\0';
     242                p++;
     243                section = (PROFILESECTION*)HEAP_xalloc( SystemHeap, 0, sizeof(*section) );
     244                section->name = HEAP_strdupA( SystemHeap, 0, p );
     245                section->key  = NULL;
     246                section->next = NULL;
     247                *next_section = section;
     248                next_section  = &section->next;
     249                next_key      = &section->key;
     250                prev_key      = NULL;
     251
     252                dprintf(("Kernel32:Profile:New section: '%s'\n",section->name));
     253
     254                continue;
     255            }
     256        }
     257
     258        p2=p+strlen(p) - 1;
     259        while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2))) *p2--='\0';
     260
     261        if ((p2 = strchr( p, '=' )) != NULL)
     262        {
     263            char *p3 = p2 - 1;
     264            while ((p3 > p) && PROFILE_isspace(*p3)) *p3-- = '\0';
     265            *p2++ = '\0';
     266            while (*p2 && PROFILE_isspace(*p2)) p2++;
     267        }
     268
     269        if(*p || !prev_key || *prev_key->name)
     270          {
     271           key = (PROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(*key) );
     272           key->name  = HEAP_strdupA( SystemHeap, 0, p );
     273           key->value = p2 ? HEAP_strdupA( SystemHeap, 0, p2 ) : NULL;
     274           key->next  = NULL;
     275           *next_key  = key;
     276           next_key   = &key->next;
     277           prev_key   = key;
     278
     279           dprintf(("Kernel32:Profile:New key: name='%s', value='%s'\n",key->name,key->value?key->value:"(none)"));
     280          }
     281    }
     282    return first_section;
     283}
     284
     285
     286/***********************************************************************
     287 *           PROFILE_DeleteSection
     288 *
     289 * Delete a section from a profile tree.
     290 */
     291static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCSTR name )
     292{
     293    while (*section)
     294    {
     295        if ((*section)->name && !strcasecmp( (*section)->name, name ))
     296        {
     297            PROFILESECTION *to_del = *section;
     298            *section = to_del->next;
     299            to_del->next = NULL;
     300            PROFILE_Free( to_del );
     301            return TRUE;
     302        }
     303        section = &(*section)->next;
     304    }
     305    return FALSE;
     306}
     307
     308
     309/***********************************************************************
     310 *           PROFILE_DeleteKey
     311 *
     312 * Delete a key from a profile tree.
     313 */
     314static BOOL PROFILE_DeleteKey( PROFILESECTION **section,
     315                LPCSTR section_name, LPCSTR key_name )
     316{
     317    while (*section)
     318    {
     319        if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
     320        {
     321            PROFILEKEY **key = &(*section)->key;
     322            while (*key)
     323            {
     324                if (!strcasecmp( (*key)->name, key_name ))
     325                {
     326                    PROFILEKEY *to_del = *key;
     327                    *key = to_del->next;
     328                    if (to_del->name) HeapFree( SystemHeap, 0, to_del->name );
     329                    if (to_del->value) HeapFree( SystemHeap, 0, to_del->value);
     330                    HeapFree( SystemHeap, 0, to_del );
     331                    return TRUE;
     332                }
     333                key = &(*key)->next;
     334            }
     335        }
     336        section = &(*section)->next;
     337    }
     338    return FALSE;
     339}
     340
     341
     342/***********************************************************************
     343 *           PROFILE_Find
     344 *
     345 * Find a key in a profile tree, optionally creating it.
     346 */
     347static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
     348                                 const char *section_name,
     349                                 const char *key_name, int create )
     350{
     351    while (*section)
     352    {
     353        if ((*section)->name && !strcasecmp( (*section)->name, section_name ))
     354        {
     355            PROFILEKEY **key = &(*section)->key;
     356            while (*key)
     357            {
     358                if (!strcasecmp( (*key)->name, key_name )) return *key;
     359                key = &(*key)->next;
     360            }
     361            if (!create) return NULL;
     362            *key = (PROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
     363            (*key)->name  = HEAP_strdupA( SystemHeap, 0, key_name );
     364            (*key)->value = NULL;
     365            (*key)->next  = NULL;
     366            return *key;
     367        }
     368        section = &(*section)->next;
     369    }
     370    if (!create) return NULL;
     371    *section = (PROFILESECTION*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILESECTION) );
     372    (*section)->name = HEAP_strdupA( SystemHeap, 0, section_name );
     373    (*section)->next = NULL;
     374    (*section)->key  = (tagPROFILEKEY*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILEKEY) );
     375    (*section)->key->name  = HEAP_strdupA( SystemHeap, 0, key_name );
     376    (*section)->key->value = NULL;
     377    (*section)->key->next  = NULL;
     378    return (*section)->key;
     379}
     380
     381
     382/***********************************************************************
     383 *           PROFILE_FlushFile
     384 *
     385 * Flush the current profile to disk if changed.
     386 */
     387static BOOL PROFILE_FlushFile(void)
     388{
     389    FILE *file = NULL;
     390    struct stat buf;
     391
     392    if(!CurProfile)
     393    {
     394        dprintf(("Kernel32:Profile:No current profile!\n"));
     395        return FALSE;
     396    }
     397
     398    // not changed, return immediately
     399    if (!CurProfile->changed)
     400      return TRUE;
     401
     402    // try to open file
     403    file = fopen(CurProfile->fullname, "w");
     404    if (!file)
     405    {
     406        dprintf(("Kernel32:Profile:could not save profile file %s\n", CurProfile->fullname));
     407        return FALSE;
     408    }
     409
     410    dprintf(("Kernel32:Profile:Saving %s\n", CurProfile->fullname ));
     411    PROFILE_Save( file, CurProfile->section );
     412    fclose( file );
     413    CurProfile->changed = FALSE;
     414    if(!stat(CurProfile->fullname,&buf))
     415       CurProfile->mtime=buf.st_mtime;
     416    return TRUE;
     417}
     418
     419
     420/***********************************************************************
     421 *           PROFILE_ReleaseFile
     422 *
     423 * Flush the current profile to disk and remove it from the cache.
     424 */
     425static void PROFILE_ReleaseFile(void)
     426{
     427    PROFILE_FlushFile();
     428    PROFILE_Free( CurProfile->section );
     429    if (CurProfile->filename) HeapFree( SystemHeap, 0, CurProfile->filename );
     430    if (CurProfile->fullname) HeapFree(SystemHeap,0,CurProfile->fullname);
     431    CurProfile->changed   = FALSE;
     432    CurProfile->section   = NULL;
     433    CurProfile->filename  = NULL;
     434    CurProfile->fullname  = NULL;
     435    CurProfile->mtime     = 0;
     436}
     437
     438
     439/***********************************************************************
     440 *           PROFILE_Open
     441 *
     442 * Open a profile file, checking the cached file first.
     443 */
     444static BOOL PROFILE_Open( LPCSTR filename )
     445{
     446    FILE *file = NULL;
     447    int i,j;
     448    struct stat buf;
     449    PROFILE *tempProfile;
     450
     451    if (!filename || filename[0] == 0) return FALSE;
     452
     453    /* First time around */
     454
     455    if(!CurProfile)
     456       for(i=0;i<N_CACHED_PROFILES;i++)
     457         {
     458          MRUProfile[i]= (PROFILE*)HEAP_xalloc( SystemHeap, 0, sizeof(PROFILE) );
     459          MRUProfile[i]->changed=FALSE;
     460          MRUProfile[i]->section=NULL;
     461          MRUProfile[i]->filename=NULL;
     462          MRUProfile[i]->fullname=NULL;
     463          MRUProfile[i]->mtime=0;
     464         }
     465
     466    /* Check for a match */
     467
     468    for(i=0;i<N_CACHED_PROFILES;i++)
     469      {
     470       if (MRUProfile[i]->filename && (!stricmp(filename,MRUProfile[i]->filename) || !stricmp(filename,MRUProfile[i]->fullname)))
     471         {
     472          if(i)
     473            {
     474             PROFILE_FlushFile();
     475             tempProfile=MRUProfile[i];
     476             for(j=i;j>0;j--)
     477                MRUProfile[j]=MRUProfile[j-1];
     478             CurProfile=tempProfile;
     479            }
     480          if(!stat(CurProfile->fullname,&buf) && CurProfile->mtime==buf.st_mtime)
     481             dprintf(("Kernel32:Profile:(%s): already opened (mru=%d)\n",
     482                              filename, i ));
     483          else
     484              dprintf(("Kernel32:Profile:(%s): already opened, needs refreshing (mru=%d)\n",
     485                             filename, i ));
     486     return TRUE;
     487         }
     488      }
     489
     490    /* Rotate the oldest to the top to be replaced */
     491
     492    if(i==N_CACHED_PROFILES)
     493      {
     494       tempProfile=MRUProfile[N_CACHED_PROFILES-1];
     495       for(i=N_CACHED_PROFILES-1;i>0;i--)
     496          MRUProfile[i]=MRUProfile[i-1];
     497       CurProfile=tempProfile;
     498      }
     499
     500    /* Flush the profile */
     501
     502    if(CurProfile->filename) PROFILE_ReleaseFile();
     503
     504    CurProfile->filename  = HEAP_strdupA(SystemHeap,0,filename);
     505
     506    /* check for path */
     507
     508    if ((!strchr( filename,'/') &&
     509         !strchr( filename,'\\')) ||
     510        !strchr( filename,':'))
     511    {
     512      char fullname[MAX_PATHNAME_LEN];
     513
     514      GetWindowsDirectoryA(fullname,sizeof(fullname));
     515      strcat(fullname,"\\");
     516      strcat(fullname,filename);
     517      CurProfile->fullname  = HEAP_strdupA(SystemHeap,0,fullname);
     518    } else CurProfile->fullname  = HEAP_strdupA(SystemHeap,0,filename);
     519
     520    file = fopen(CurProfile->fullname,"r");
     521    if (file)
     522    {
     523      dprintf(("Kernel32:Profile:(%s): found it in %s\n",
     524               filename, CurProfile->fullname ));
     525
     526        CurProfile->section = PROFILE_Load( file );
     527        fclose( file );
     528        if(!stat(CurProfile->fullname,&buf))
     529           CurProfile->mtime=buf.st_mtime;
     530    }
     531    else
     532    {
     533        /* Does not exist yet, we will create it in PROFILE_FlushFile */
     534        dprintf(("Kernel32:Profile:profile file %s not found\n", CurProfile->fullname ));
     535    }
     536    return TRUE;
     537}
     538
     539
     540/***********************************************************************
     541 *           PROFILE_GetSection
     542 *
     543 * Returns all keys of a section.
     544 * If return_values is TRUE, also include the corresponding values.
     545 */
     546static INT PROFILE_GetSection( PROFILESECTION *section, LPCSTR section_name,
     547                LPSTR buffer, UINT len, BOOL handle_env,
     548                BOOL return_values )
     549{
     550    PROFILEKEY *key;
     551    while (section)
     552    {
     553        if (section->name && !strcasecmp( section->name, section_name ))
     554        {
     555            UINT oldlen = len;
     556            for (key = section->key; key; key = key->next)
     557            {
     558                if (len <= 2) break;
     559                if (!*key->name) continue;  /* Skip empty lines */
     560                if (IS_ENTRY_COMMENT(key->name)) continue;  /* Skip comments */
     561                PROFILE_CopyEntry( buffer, key->name, len - 1, handle_env );
     562                len -= strlen(buffer) + 1;
     563                buffer += strlen(buffer) + 1;
     564      if (return_values && key->value) {
     565         buffer[-1] = '=';
     566         PROFILE_CopyEntry ( buffer,
     567            key->value, len - 1, handle_env );
     568         len -= strlen(buffer) + 1;
     569         buffer += strlen(buffer) + 1;
     570                }
     571            }
     572            *buffer = '\0';
     573            if (len <= 1)
     574                /*If either lpszSection or lpszKey is NULL and the supplied
     575                  destination buffer is too small to hold all the strings,
     576                  the last string is truncated and followed by two null characters.
     577                  In this case, the return value is equal to cchReturnBuffer
     578                  minus two. */
     579            {
     580      buffer[-1] = '\0';
     581                return oldlen - 2;
     582            }
     583            return oldlen - len;
     584        }
     585        section = section->next;
     586    }
     587    buffer[0] = buffer[1] = '\0';
     588    return 0;
     589}
     590
     591
     592static INT PROFILE_GetSectionNames( LPSTR buffer, UINT len )
     593{
     594    LPSTR buf = buffer;
     595    WORD l, cursize = 0;
     596    PROFILESECTION *section;
     597
     598    for (section = CurProfile->section; section; section = section->next)
     599   if (section->name) {
     600       l = strlen(section->name);
     601       cursize += l+1;
     602       if (cursize > len+1)
     603      return len-2;
     604
     605       strcpy(buf, section->name);
     606       buf += l+1;
     607   }
     608
     609    *buf=0;
     610    buf++;
     611    return buf-buffer;
     612}
     613
     614
     615/***********************************************************************
     616 *           PROFILE_GetString
     617 *
     618 * Get a profile string.
     619 */
     620static INT PROFILE_GetString( LPCSTR section, LPCSTR key_name,
     621               LPCSTR def_val, LPSTR buffer, UINT len )
     622{
     623    PROFILEKEY *key = NULL;
     624
     625    if (!def_val) def_val = "";
     626    if (key_name && key_name[0])
     627    {
     628        key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
     629        PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
     630                           len, FALSE );
     631        dprintf(("Kernel32:Profile:('%s','%s','%s'): returning '%s'\n",
     632                         section, key_name, def_val, buffer ));
     633        return strlen( buffer );
     634    }
     635    if (section && section[0])
     636        return PROFILE_GetSection(CurProfile->section, section, buffer, len,
     637            FALSE, FALSE);
     638    /* undocumented; both section and key_name are NULL */
     639    return PROFILE_GetSectionNames(buffer, len);
     640}
     641
     642
     643/***********************************************************************
     644 *           PROFILE_SetString
     645 *
     646 * Set a profile string.
     647 */
     648static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
     649                LPCSTR value )
     650{
     651    if (!key_name)  /* Delete a whole section */
     652    {
     653        dprintf(("Kernel32:Profile:('%s')\n", section_name));
     654        CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section,
     655                                                      section_name );
     656        return TRUE;         /* Even if PROFILE_DeleteSection() has failed,
     657                                this is not an error on application's level.*/
     658    }
     659    else if (!value)  /* Delete a key */
     660    {
     661        dprintf(("Kernel32:Profile:('%s','%s')\n",
     662                         section_name, key_name ));
     663        CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section,
     664                                                  section_name, key_name );
     665        return TRUE;          /* same error handling as above */
     666    }
     667    else  /* Set the key value */
     668    {
     669        PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
     670                                        key_name, TRUE );
     671        dprintf(("Kernel32:Profile:('%s','%s','%s'): \n",
     672                         section_name, key_name, value ));
     673        if (!key) return FALSE;
     674        if (key->value)
     675        {
     676            if (!strcmp( key->value, value ))
     677            {
     678                dprintf(("Kernel32:Profile:  no change needed\n" ));
     679                return TRUE;  /* No change needed */
     680            }
     681            dprintf(("Kernel32:Profile:  replacing '%s'\n", key->value ));
     682            HeapFree( SystemHeap, 0, key->value );
     683        }
     684        else dprintf(("Kernel32:Profile:  creating key\n" ));
     685        key->value = HEAP_strdupA( SystemHeap, 0, value );
     686        CurProfile->changed = TRUE;
     687    }
     688    return TRUE;
     689}
     690
     691
     692/***********************************************************************
     693 *           PROFILE_GetOdinIniString
     694 *
     695 * Get a config string from the odin.ini file.
     696 */
     697ODINFUNCTION5(int,PROFILE_GetOdinIniString,
     698  LPCSTR,section,
     699  LPCSTR,key_name,
     700  LPCSTR,def,
     701  LPCSTR,buffer,
     702  int,len)
     703{
     704    int  ret;
     705
     706    EnterCriticalSection( &PROFILE_CritSect );
     707
     708    if (key_name)
     709    {
     710        PROFILEKEY *key = PROFILE_Find(&PROFILE_OdinProfile, section, key_name, FALSE);
     711        PROFILE_CopyEntry( (char*)buffer, (key && key->value) ? key->value : def,
     712                           len, TRUE );
     713        dprintf(("Kernel32:Odin profile:('%s','%s','%s'): returning '%s'\n",
     714                         section, key_name, def, buffer ));
     715        ret = strlen( buffer );
     716    }
     717    else
     718    {
     719       ret = PROFILE_GetSection( PROFILE_OdinProfile, section, (char*)buffer, len, TRUE, FALSE );
     720    }
     721    LeaveCriticalSection( &PROFILE_CritSect );
     722
     723    return ret;
     724}
     725
     726ODINFUNCTION3(int,PROFILE_SetOdinIniString,
     727  LPCSTR,section_name,
     728  LPCSTR,key_name,
     729  LPCSTR,value)
     730{
     731    int  ret;
     732
     733    EnterCriticalSection( &PROFILE_CritSect );
     734
     735    if (!key_name)  /* Delete a whole section */
     736    {
     737        dprintf(("Kernel32:Odin profile:('%s')\n", section_name));
     738        OdinProfileChanged |= PROFILE_DeleteSection( &PROFILE_OdinProfile,
     739                                                      section_name );
     740        ret = TRUE;         /* Even if PROFILE_DeleteSection() has failed,
     741                               this is not an error on application's level.*/
     742    }
     743    else if (!value)  /* Delete a key */
     744    {
     745        dprintf(("Kernel32:Odin profile:('%s','%s')\n", section_name, key_name ));
     746        OdinProfileChanged |= PROFILE_DeleteKey( &PROFILE_OdinProfile,
     747                                                  section_name, key_name );
     748        ret = TRUE;          /* same error handling as above */
     749    }
     750    else  /* Set the key value */
     751    {
     752        PROFILEKEY *key = PROFILE_Find( &PROFILE_OdinProfile, section_name,
     753                                        key_name, TRUE );
     754        dprintf(("Kernel32:Odin profile:('%s','%s','%s'): \n",
     755                         section_name, key_name, value ));
     756        if (!key) ret = FALSE; else
     757        {
     758          if (key->value && !strcmp(key->value,value))
     759          {
     760            dprintf(("Kernel32:Odin profile:  no change needed\n" ));
     761            /* No change needed */
     762          } else
     763          {
     764            if (key->value)
     765            {
     766              dprintf(("Kernel32:Odin profile:  replacing '%s'\n", key->value ));
     767              HeapFree( SystemHeap, 0, key->value );
     768            }
     769            else dprintf(("Kernel32:Odin profile:  creating key\n" ));
     770            key->value = HEAP_strdupA( SystemHeap, 0, value );
     771            OdinProfileChanged = TRUE;
     772          }
     773          ret = TRUE;
     774        }
     775    }
     776
     777    LeaveCriticalSection( &PROFILE_CritSect );
     778
     779    return ret;
     780}
     781
     782
     783/***********************************************************************
     784 *           PROFILE_GetOdinIniInt
     785 *
     786 * Get a config integer from the odin.ini file.
     787 */
     788ODINFUNCTION3(int,PROFILE_GetOdinIniInt,
     789  LPCSTR,section,
     790  LPCSTR,key_name,
     791  int,def )
     792{
     793    char buffer[20];
     794    char *p;
     795    long result;
     796    PROFILEKEY *key;
     797    int  ret;
     798
     799    EnterCriticalSection( &PROFILE_CritSect );
     800
     801    key = PROFILE_Find( &PROFILE_OdinProfile, section, key_name, FALSE );
     802    if (!key || !key->value) {
     803       ret = def;
     804    } else {
     805       PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
     806       result = strtol( buffer, &p, 0 );
     807       ret = (p == buffer) ? 0  /* No digits at all */ : (int)result;
     808    }
     809
     810    LeaveCriticalSection( &PROFILE_CritSect );
     811
     812    return ret;
     813}
     814
     815
     816ODINFUNCTION3(int,PROFILE_SetOdinIniInt,
     817  LPCSTR,section,
     818  LPCSTR,key_name,
     819  int,value )
     820{
     821    char buffer[20];
     822
     823    sprintf(buffer,"%d",value);
     824    return PROFILE_SetOdinIniString(section,key_name,buffer);
     825}
     826
     827/******************************************************************************
     828 *
     829 *   int  PROFILE_EnumerateOdinIniSection(
     830 *     char const  *section,  #Name of the section to enumerate
     831 *     void  (*cbfn)(char const *key, char const *value, void *user),
     832 *                            # Address of the callback function
     833 *     void  *user )          # User-specified pointer.
     834 *
     835 *   For each entry in a section in the wine.conf file, this function will
     836 *   call the specified callback function, informing it of each key and
     837 *   value.  An optional user pointer may be passed to it (if this is not
     838 *   needed, pass NULL through it and ignore the value in the callback
     839 *   function).
     840 *
     841 *   The callback function must accept three parameters:
     842 *      The name of the key (char const *)
     843 *      The value of the key (char const *)
     844 *      A user-specified parameter (void *)
     845 *   Note that the first two are char CONST *'s, not char *'s!  The callback
     846 *   MUST not modify these strings!
     847 *
     848 *   The return value indicates the number of times the callback function
     849 *   was called.
     850 */
     851int PROFILE_EnumerateOdinIniSection(LPCSTR section,PVOID (*cbfn)(LPCSTR,LPCSTR,PVOID),PVOID userptr)
     852{
     853    PROFILESECTION  *scansect;
     854    PROFILEKEY  *scankey;
     855    int  calls = 0;
     856
     857    EnterCriticalSection( &PROFILE_CritSect );
     858
     859    /* Search for the correct section */
     860    for(scansect = PROFILE_OdinProfile; scansect; scansect = scansect->next) {
     861   if(scansect->name && !strcasecmp(scansect->name, section)) {
     862
     863       /* Enumerate each key with the callback */
     864       for(scankey = scansect->key; scankey; scankey = scankey->next) {
     865
     866      /* Ignore blank entries -- these shouldn't exist, but let's
     867         be extra careful */
     868      if(scankey->name[0]) {
     869          cbfn(scankey->name, scankey->value, userptr);
     870          ++calls;
     871      }
     872       }
     873
     874       break;
     875   }
     876    }
     877    LeaveCriticalSection( &PROFILE_CritSect );
     878
     879    return calls;
     880}
     881
     882
     883/******************************************************************************
     884 *
     885 *   int  PROFILE_GetOdinIniBool(
     886 *      char const  *section,
     887 *      char const  *key_name,
     888 *      int  def )
     889 *
     890 *   Reads a boolean value from the odin.ini file.  This function attempts to
     891 *   be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
     892 *   (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
     893 *   true.  Anything else results in the return of the default value.
     894 *
     895 *   This function uses 1 to indicate true, and 0 for false.  You can check
     896 *   for existence by setting def to something other than 0 or 1 and
     897 *   examining the return value.
     898 */
     899ODINFUNCTION3(int,PROFILE_GetOdinIniBool,
     900    LPCSTR,section,
     901    LPCSTR,key_name,
     902    int,def)
     903{
     904    char  key_value[2];
     905    int  retval;
     906
     907    PROFILE_GetOdinIniString(section, key_name, "~", key_value, 2);
     908
     909    switch(key_value[0]) {
     910    case 'n':
     911    case 'N':
     912    case 'f':
     913    case 'F':
     914    case '0':
     915   retval = 0;
     916   break;
     917
     918    case 'y':
     919    case 'Y':
     920    case 't':
     921    case 'T':
     922    case '1':
     923   retval = 1;
     924   break;
     925
     926    default:
     927   retval = def;
     928    }
     929
     930    dprintf(("Kernel32:Odin profile:(\"%s\", \"%s\", %s), "
     931          "[%c], ret %s.\n", section, key_name,
     932          def ? "TRUE" : "FALSE", key_value[0],
     933          retval ? "TRUE" : "FALSE"));
     934
     935    return retval;
     936}
     937
     938
     939ODINFUNCTION3(int,PROFILE_SetOdinIniBool,
     940  LPCSTR,section,
     941  LPCSTR,key_name,
     942  int,value )
     943{
     944  return PROFILE_SetOdinIniString(section,key_name,value ? "1":"0");
     945}
     946
     947
     948/***********************************************************************
     949 *           LoadOdinIni
     950 *
     951 * Load the odin.ini file.
     952 */
     953ODINFUNCTION0(int,PROFILE_LoadOdinIni)
     954{
     955    char buffer[MAX_PATHNAME_LEN];
     956    const char *p;
     957    FILE *f;
     958
     959    InitializeCriticalSection( &PROFILE_CritSect );
     960    MakeCriticalSectionGlobal( &PROFILE_CritSect );
     961
     962    if ( (p = getenv( "ODIN_INI" )) && (f = fopen( p, "r" )) )
     963    {
     964      PROFILE_OdinProfile = PROFILE_Load( f );
     965      fclose( f );
     966      strncpy(PROFILE_OdinIniUsed,p,MAX_PATHNAME_LEN-1);
     967    } else
     968    {
     969      HINSTANCE hInstance = LoadLibraryA("KERNEL32.DLL");
     970      GetModuleFileNameA(hInstance,PROFILE_OdinIniUsed,sizeof(PROFILE_OdinIniUsed));
     971      FreeLibrary(hInstance);
     972      strcpy(strrchr(PROFILE_OdinIniUsed,'\\')+1,ODINININAME);
     973      f = fopen(PROFILE_OdinIniUsed,"r");
     974      PROFILE_OdinProfile = PROFILE_Load(f);
     975      fclose(f);
     976    }
     977
     978    dprintf(("Kernel32: Odin ini loaded: %s",PROFILE_OdinIniUsed));
     979
     980    return 1;
     981}
     982
     983ODINFUNCTION0(int,PROFILE_SaveOdinIni)
     984{
     985  int ret;
     986  FILE *file;
     987
     988  EnterCriticalSection( &PROFILE_CritSect );
     989
     990  if (OdinProfileChanged)
     991  {
     992    file = fopen(PROFILE_OdinIniUsed,"w");
     993    if (!file)
     994    {
     995        dprintf(("Kernel32:Odin profile:could not save profile file %s\n", PROFILE_OdinIniUsed));
     996        ret = FALSE;
     997    } else
     998    {
     999      dprintf(("Kernel32:Odin profile:Saving %s\n", PROFILE_OdinIniUsed ));
     1000      PROFILE_Save( file, PROFILE_OdinProfile );
     1001      fclose( file );
     1002      OdinProfileChanged = FALSE;
     1003      ret = TRUE;
     1004    }
     1005  }
     1006
     1007  LeaveCriticalSection( &PROFILE_CritSect );
     1008
     1009  return ret;
     1010}
     1011
     1012#if 0
     1013/***********************************************************************
     1014 *           PROFILE_UsageOdinIni
     1015 *
     1016 * Explain the wine.ini file to those who don't read documentation.
     1017 * Keep below one screenful in length so that error messages above are
     1018 * noticed.
     1019 */
     1020void PROFILE_UsageOdinIni(void)
     1021{
     1022    MESSAGE("Perhaps you have not properly edited or created "
     1023   "your Odin configuration file.\n");
     1024    MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
     1025    MESSAGE("  or it is determined by the -config option or from\n"
     1026        "  the WINE_INI environment variable.\n");
     1027    if (*PROFILE_WineIniUsed)
     1028   MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
     1029    /* RTFM, so to say */
     1030}
     1031#endif
     1032
     1033/***********************************************************************
     1034 *           PROFILE_GetStringItem
     1035 *
     1036 *  Convenience function that turns a string 'xxx, yyy, zzz' into
     1037 *  the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
     1038 */
     1039char* PROFILE_GetStringItem( char* start )
     1040{
     1041    char* lpchX, *lpch;
     1042
     1043    for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
     1044    {
     1045        if( *lpchX == ',' )
     1046        {
     1047            if( lpch ) *lpch = '\0'; else *lpchX = '\0';
     1048            while( *(++lpchX) )
     1049                if( !PROFILE_isspace(*lpchX) ) return lpchX;
     1050        }
     1051   else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
     1052        else lpch = NULL;
     1053    }
     1054    if( lpch ) *lpch = '\0';
     1055    return NULL;
     1056}
     1057
     1058/********************* API functions **********************************/
     1059
     1060/***********************************************************************
     1061 *           GetProfileInt32A   (KERNEL32.264)
     1062 */
     1063ODINFUNCTION3(UINT, GetProfileIntA,
     1064              LPCSTR, section,
     1065              LPCSTR, entry,
     1066              INT, def_val)
     1067{
     1068    return GetPrivateProfileIntA( section, entry, def_val, WINININAME );
     1069}
     1070
     1071/***********************************************************************
     1072 *           GetProfileInt32W   (KERNEL32.264)
     1073 */
     1074ODINFUNCTION3(UINT, GetProfileIntW,
     1075              LPCWSTR, section,
     1076              LPCWSTR, entry,
     1077              INT, def_val)
     1078{
     1079    if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
     1080    return GetPrivateProfileIntW( section, entry, def_val, wininiW );
     1081}
     1082
     1083/***********************************************************************
     1084 *           GetProfileString32A   (KERNEL32.268)
     1085 */
     1086ODINFUNCTION5(INT, GetProfileStringA,
     1087              LPCSTR, section,
     1088              LPCSTR, entry,
     1089              LPCSTR, def_val,
     1090              LPSTR, buffer,
     1091              UINT, len)
     1092{
     1093    return GetPrivateProfileStringA( section, entry, def_val,
     1094                 buffer, len, WINININAME );
     1095}
     1096
     1097/***********************************************************************
     1098 *           GetProfileString32W   (KERNEL32.269)
     1099 */
     1100ODINFUNCTION5(INT, GetProfileStringW,
     1101              LPCWSTR, section,
     1102              LPCWSTR, entry,
     1103              LPCWSTR, def_val,
     1104              LPWSTR, buffer,
     1105              UINT, len)
     1106{
     1107    if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
     1108    return GetPrivateProfileStringW( section, entry, def_val,
     1109                 buffer, len, wininiW );
     1110}
     1111
     1112/***********************************************************************
     1113 *           WriteProfileString32A   (KERNEL32.587)
     1114 */
     1115ODINFUNCTION3(BOOL, WriteProfileStringA,
     1116              LPCSTR, section,
     1117              LPCSTR, entry,
     1118              LPCSTR, string)
     1119{
     1120    return WritePrivateProfileStringA( section, entry, string, WINININAME );
     1121}
     1122
     1123/***********************************************************************
     1124 *           WriteProfileString32W   (KERNEL32.588)
     1125 */
     1126ODINFUNCTION3(BOOL, WriteProfileStringW,
     1127              LPCWSTR, section,
     1128              LPCWSTR, entry,
     1129              LPCWSTR, string)
     1130{
     1131    if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
     1132    return WritePrivateProfileStringW( section, entry, string, wininiW );
     1133}
     1134
     1135/***********************************************************************
     1136 *           GetPrivateProfileInt32A   (KERNEL32.251)
     1137 */
     1138ODINFUNCTION4(UINT, GetPrivateProfileIntA,
     1139              LPCSTR, section,
     1140              LPCSTR, entry,
     1141              INT, def_val,
     1142              LPCSTR, filename)
     1143{
     1144    char buffer[20];
     1145    char *p;
     1146    long result;
     1147
     1148    GetPrivateProfileStringA( section, entry, "",
     1149                                buffer, sizeof(buffer), filename );
     1150    if (!buffer[0]) return (UINT)def_val;
     1151    result = strtol( buffer, &p, 0 );
     1152    if (p == buffer) return 0;  /* No digits at all */
     1153    return (UINT)result;
     1154}
     1155
     1156/***********************************************************************
     1157 *           GetPrivateProfileInt32W   (KERNEL32.252)
     1158 */
     1159ODINFUNCTION4(UINT, GetPrivateProfileIntW,
     1160              LPCWSTR, section,
     1161              LPCWSTR, entry,
     1162              INT, def_val,
    12851163              LPCWSTR, filename)
    1286 {
    1287     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1288     LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
    1289     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1290     BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
    1291     HeapFree( GetProcessHeap(), 0, sectionA );
    1292     HeapFree( GetProcessHeap(), 0, stringA );
    1293     HeapFree( GetProcessHeap(), 0, filenameA );
    1294     return res;
    1295 }
    1296  
    1297 /***********************************************************************
    1298  *           WriteProfileSection32A   (KERNEL32.747)
    1299  */
    1300 ODINFUNCTION2(BOOL, WriteProfileSectionA,
    1301               LPCSTR, section,
     1164{
     1165    LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
     1166    LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
     1167    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
     1168    UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
     1169    HeapFree( GetProcessHeap(), 0, sectionA );
     1170    HeapFree( GetProcessHeap(), 0, filenameA );
     1171    HeapFree( GetProcessHeap(), 0, entryA );
     1172    return res;
     1173}
     1174
     1175/***********************************************************************
     1176 *           GetPrivateProfileString32A   (KERNEL32.255)
     1177 */
     1178ODINFUNCTION6(INT, GetPrivateProfileStringA,
     1179              LPCSTR, section,
     1180              LPCSTR, entry,
     1181              LPCSTR, def_val,
     1182              LPSTR, buffer,
     1183              UINT, len,
     1184              LPCSTR, filename)
     1185{
     1186    int     ret;
     1187
     1188    if (!filename)
     1189    filename = WINININAME;
     1190
     1191    EnterCriticalSection( &PROFILE_CritSect );
     1192
     1193    if (PROFILE_Open( filename )) {
     1194        ret = PROFILE_GetString( section, entry, def_val, buffer, len );
     1195    } else {
     1196       lstrcpynA( buffer, def_val, len );
     1197       ret = strlen( buffer );
     1198    }
     1199
     1200    LeaveCriticalSection( &PROFILE_CritSect );
     1201
     1202    return ret;
     1203}
     1204
     1205/***********************************************************************
     1206 *           GetPrivateProfileString32W   (KERNEL32.256)
     1207 */
     1208ODINFUNCTION6(INT, GetPrivateProfileStringW,
     1209              LPCWSTR, section,
     1210              LPCWSTR, entry,
     1211              LPCWSTR, def_val,
     1212              LPWSTR, buffer,
     1213              UINT, len,
     1214              LPCWSTR, filename)
     1215{
     1216    LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
     1217    LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
     1218    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
     1219    LPSTR def_valA  = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
     1220    LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
     1221    INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
     1222                                            bufferA, len, filenameA );
     1223    lstrcpynAtoW( buffer, bufferA, len );
     1224    HeapFree( GetProcessHeap(), 0, sectionA );
     1225    HeapFree( GetProcessHeap(), 0, entryA );
     1226    HeapFree( GetProcessHeap(), 0, filenameA );
     1227    HeapFree( GetProcessHeap(), 0, def_valA );
     1228    HeapFree( GetProcessHeap(), 0, bufferA);
     1229    return ret;
     1230}
     1231
     1232/***********************************************************************
     1233 *           GetPrivateProfileSection32A   (KERNEL32.255)
     1234 */
     1235ODINFUNCTION4(INT, GetPrivateProfileSectionA,
     1236              LPCSTR, section,
     1237              LPSTR, buffer,
     1238              DWORD, len,
     1239              LPCSTR, filename)
     1240{
     1241    int     ret = 0;
     1242
     1243    EnterCriticalSection( &PROFILE_CritSect );
     1244
     1245    if (PROFILE_Open( filename ))
     1246        ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
     1247             FALSE, TRUE);
     1248
     1249    LeaveCriticalSection( &PROFILE_CritSect );
     1250
     1251    return ret;
     1252}
     1253
     1254/***********************************************************************
     1255 *           GetPrivateProfileSection32W   (KERNEL32.256)
     1256 */
     1257
     1258ODINFUNCTION4(INT, GetPrivateProfileSectionW,
     1259              LPCWSTR, section,
     1260              LPWSTR, buffer,
     1261              DWORD, len,
     1262              LPCWSTR, filename)
     1263
     1264{
     1265    LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
     1266    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
     1267    LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
     1268    INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
     1269                  filenameA );
     1270    MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
     1271    HeapFree( GetProcessHeap(), 0, sectionA );
     1272    HeapFree( GetProcessHeap(), 0, filenameA );
     1273    HeapFree( GetProcessHeap(), 0, bufferA);
     1274    return ret;
     1275}
     1276
     1277/***********************************************************************
     1278 *           GetProfileSection32A   (KERNEL32.268)
     1279 */
     1280ODINFUNCTION3(INT, GetProfileSectionA,
     1281              LPCSTR, section,
     1282              LPSTR, buffer,
     1283              DWORD, len)
     1284{
     1285    return GetPrivateProfileSectionA( section, buffer, len, WINININAME );
     1286}
     1287
     1288/***********************************************************************
     1289 *           GetProfileSection32W   (KERNEL32)
     1290 */
     1291ODINFUNCTION3(INT, GetProfileSectionW,
     1292              LPCWSTR, section,
     1293              LPWSTR, buffer,
     1294              DWORD, len)
     1295{
     1296    if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
     1297    return GetPrivateProfileSectionW( section, buffer, len, wininiW );
     1298}
     1299
     1300/***********************************************************************
     1301 *           WritePrivateProfileString32A   (KERNEL32.582)
     1302 */
     1303ODINFUNCTION4(BOOL, WritePrivateProfileStringA,
     1304              LPCSTR, section,
     1305              LPCSTR, entry,
     1306              LPCSTR, string,
     1307              LPCSTR, filename)
     1308{
     1309    BOOL ret = FALSE;
     1310
     1311    EnterCriticalSection( &PROFILE_CritSect );
     1312
     1313    if (PROFILE_Open( filename ))
     1314    {
     1315        if (!section && !entry && !string)
     1316            PROFILE_ReleaseFile();  /* always return FALSE in this case */
     1317        else
     1318            ret = PROFILE_SetString( section, entry, string );
     1319    }
     1320
     1321    LeaveCriticalSection( &PROFILE_CritSect );
     1322    return ret;
     1323}
     1324
     1325/***********************************************************************
     1326 *           WritePrivateProfileString32W   (KERNEL32.583)
     1327 */
     1328ODINFUNCTION4(BOOL, WritePrivateProfileStringW,
     1329              LPCWSTR, section,
     1330              LPCWSTR, entry,
     1331              LPCWSTR, string,
     1332              LPCWSTR, filename)
     1333{
     1334    LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
     1335    LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
     1336    LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
     1337    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
     1338    BOOL res = WritePrivateProfileStringA( sectionA, entryA,
     1339                  stringA, filenameA );
     1340    HeapFree( GetProcessHeap(), 0, sectionA );
     1341    HeapFree( GetProcessHeap(), 0, entryA );
     1342    HeapFree( GetProcessHeap(), 0, stringA );
     1343    HeapFree( GetProcessHeap(), 0, filenameA );
     1344    return res;
     1345}
     1346
     1347/***********************************************************************
     1348 *           WritePrivateProfileSection32A   (KERNEL32)
     1349 */
     1350ODINFUNCTION3(BOOL, WritePrivateProfileSectionA,
     1351              LPCSTR, section,
     1352              LPCSTR, string,
     1353              LPCSTR, filename)
     1354{
     1355  char *p =(char*)string;
     1356
     1357  dprintf(("Kernel32:Profile:fixme WritePrivateProfileSection32A empty stub\n"));
     1358  return FALSE;
     1359}
     1360
     1361/***********************************************************************
     1362 *           WritePrivateProfileSection32W   (KERNEL32)
     1363 */
     1364ODINFUNCTION3(BOOL, WritePrivateProfileSectionW,
     1365              LPCWSTR, section,
     1366              LPCWSTR, string,
     1367              LPCWSTR, filename)
     1368{
     1369    LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
     1370    LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
     1371    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
     1372    BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
     1373    HeapFree( GetProcessHeap(), 0, sectionA );
     1374    HeapFree( GetProcessHeap(), 0, stringA );
     1375    HeapFree( GetProcessHeap(), 0, filenameA );
     1376    return res;
     1377}
     1378
     1379/***********************************************************************
     1380 *           WriteProfileSection32A   (KERNEL32.747)
     1381 */
     1382ODINFUNCTION2(BOOL, WriteProfileSectionA,
     1383              LPCSTR, section,
    13021384              LPCSTR, keys_n_values)
    1303 { 
    1304     return WritePrivateProfileSectionA( section, keys_n_values, WINININAME); 
    1305 } 
    1306  
    1307 /*********************************************************************** 
    1308  *           WriteProfileSection32W   (KERNEL32.748) 
    1309  */ 
    1310 ODINFUNCTION2(BOOL, WriteProfileSectionW, 
    1311               LPCWSTR, section, 
     1385{
     1386    return WritePrivateProfileSectionA( section, keys_n_values, WINININAME);
     1387}
     1388
     1389/***********************************************************************
     1390 *           WriteProfileSection32W   (KERNEL32.748)
     1391 */
     1392ODINFUNCTION2(BOOL, WriteProfileSectionW,
     1393              LPCWSTR, section,
    13121394              LPCWSTR, keys_n_values)
    1313 {
    1314    if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME);
    1315  
    1316    return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
    1317 }
    1318  
    1319 /***********************************************************************
    1320  *           GetPrivateProfileSectionNames16   (KERNEL.143)
    1321  */
    1322 ODINFUNCTION3(WORD, GetPrivateProfileSectionNames16,
    1323               LPSTR, buffer,
    1324               WORD, size,
    1325               LPCSTR, filename)
    1326 {
    1327     WORD ret = 0;
    1328  
    1329     EnterCriticalSection( &PROFILE_CritSect );
    1330  
    1331     if (PROFILE_Open( filename ))
    1332       ret = PROFILE_GetSectionNames(buffer, size);
    1333  
    1334     LeaveCriticalSection( &PROFILE_CritSect );
    1335  
    1336     return ret;
    1337 }
    1338  
    1339 /***********************************************************************
    1340  *           GetPrivateProfileSectionNames32A  (KERNEL32.365)
    1341  */
    1342 ODINFUNCTION3(DWORD, GetPrivateProfileSectionNamesA,
    1343               LPSTR, buffer,
    1344               DWORD, size,
     1395{
     1396   if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME);
     1397
     1398   return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
     1399}
     1400
     1401/***********************************************************************
     1402 *           GetPrivateProfileSectionNames16   (KERNEL.143)
     1403 */
     1404ODINFUNCTION3(WORD, GetPrivateProfileSectionNames16,
     1405              LPSTR, buffer,
     1406              WORD, size,
    13451407              LPCSTR, filename)
    1346 {
    1347  return (GetPrivateProfileSectionNames16 (buffer,size,filename));
    1348 }
    1349  
    1350 /***********************************************************************
    1351  *           GetPrivateProfileSectionNames32W  (KERNEL32.366)
    1352  */
    1353 ODINFUNCTION3(DWORD, GetPrivateProfileSectionNamesW,
    1354               LPWSTR, buffer,
    1355               DWORD, size,
     1408{
     1409    WORD ret = 0;
     1410
     1411    EnterCriticalSection( &PROFILE_CritSect );
     1412
     1413    if (PROFILE_Open( filename ))
     1414      ret = PROFILE_GetSectionNames(buffer, size);
     1415
     1416    LeaveCriticalSection( &PROFILE_CritSect );
     1417
     1418    return ret;
     1419}
     1420
     1421/***********************************************************************
     1422 *           GetPrivateProfileSectionNames32A  (KERNEL32.365)
     1423 */
     1424ODINFUNCTION3(DWORD, GetPrivateProfileSectionNamesA,
     1425              LPSTR, buffer,
     1426              DWORD, size,
     1427              LPCSTR, filename)
     1428{
     1429 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
     1430}
     1431
     1432/***********************************************************************
     1433 *           GetPrivateProfileSectionNames32W  (KERNEL32.366)
     1434 */
     1435ODINFUNCTION3(DWORD, GetPrivateProfileSectionNamesW,
     1436              LPWSTR, buffer,
     1437              DWORD, size,
    13561438              LPCWSTR, filename)
    1357 { 
    1358    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); 
    1359    LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, size); 
    1360  
    1361    INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA); 
    1362    lstrcpynAtoW( buffer, bufferA, size); 
    1363    HeapFree( GetProcessHeap(), 0, bufferA); 
    1364    HeapFree( GetProcessHeap(), 0, filenameA ); 
    1365  
    1366    return ret; 
    1367 } 
    1368  
    1369 /*********************************************************************** 
    1370  *           GetPrivateProfileStruct32A (KERNEL32.370) 
    1371  */ 
    1372 ODINFUNCTION5(BOOL, GetPrivateProfileStructA, 
    1373               LPCSTR, section, 
    1374               LPCSTR, key, 
    1375               LPVOID, buf, 
    1376               UINT, len, 
     1439{
     1440   LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
     1441   LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, size);
     1442
     1443   INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
     1444   lstrcpynAtoW( buffer, bufferA, size);
     1445   HeapFree( GetProcessHeap(), 0, bufferA);
     1446   HeapFree( GetProcessHeap(), 0, filenameA );
     1447
     1448   return ret;
     1449}
     1450
     1451/***********************************************************************
     1452 *           GetPrivateProfileStruct32A (KERNEL32.370)
     1453 */
     1454ODINFUNCTION5(BOOL, GetPrivateProfileStructA,
     1455              LPCSTR, section,
     1456              LPCSTR, key,
     1457              LPVOID, buf,
     1458              UINT, len,
    13771459              LPCSTR, filename)
    1378 { 
    1379     BOOL ret = FALSE; 
    1380  
    1381     EnterCriticalSection( &PROFILE_CritSect ); 
    1382  
    1383     if (PROFILE_Open( filename )) { 
    1384         PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE); 
    1385    if (k) { 
    1386       lstrcpynA( (LPSTR)buf, k->value, strlen(k->value)); 
    1387       ret = TRUE; 
    1388    } 
    1389     } 
    1390     LeaveCriticalSection( &PROFILE_CritSect ); 
    1391  
    1392     return FALSE; 
    1393 } 
    1394  
    1395 /*********************************************************************** 
    1396  *           GetPrivateProfileStruct32W (KERNEL32.543) 
    1397  */ 
    1398 ODINFUNCTION5(BOOL, GetPrivateProfileStructW, 
    1399               LPCWSTR, section, 
    1400               LPCWSTR, key, 
    1401               LPVOID, buffer, 
    1402               UINT, len, 
     1460{
     1461    BOOL ret = FALSE;
     1462
     1463    EnterCriticalSection( &PROFILE_CritSect );
     1464
     1465    if (PROFILE_Open( filename )) {
     1466        PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
     1467   if (k) {
     1468      lstrcpynA( (LPSTR)buf, k->value, strlen(k->value));
     1469      ret = TRUE;
     1470   }
     1471    }
     1472    LeaveCriticalSection( &PROFILE_CritSect );
     1473
     1474    return FALSE;
     1475}
     1476
     1477/***********************************************************************
     1478 *           GetPrivateProfileStruct32W (KERNEL32.543)
     1479 */
     1480ODINFUNCTION5(BOOL, GetPrivateProfileStructW,
     1481              LPCWSTR, section,
     1482              LPCWSTR, key,
     1483              LPVOID, buffer,
     1484              UINT, len,
    14031485              LPCWSTR, filename)
    1404 { 
    1405     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section ); 
    1406     LPSTR keyA      = HEAP_strdupWtoA( GetProcessHeap(), 0, key); 
    1407     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); 
    1408     LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len ); 
    1409  
    1410     INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA, 
    1411                len, filenameA ); 
    1412     lstrcpynAtoW( (LPWSTR)buffer, bufferA, len ); 
    1413     HeapFree( GetProcessHeap(), 0, bufferA); 
    1414     HeapFree( GetProcessHeap(), 0, sectionA ); 
    1415     HeapFree( GetProcessHeap(), 0, keyA ); 
    1416     HeapFree( GetProcessHeap(), 0, filenameA ); 
    1417  
    1418     return ret; 
    1419 } 
    1420  
    1421  
    1422 /*********************************************************************** 
    1423  *           WritePrivateProfileStruct32A (KERNEL32.744) 
    1424  */ 
    1425 ODINFUNCTION5(BOOL, WritePrivateProfileStructA, 
    1426               LPCSTR, section, 
    1427               LPCSTR, key, 
    1428               LPVOID, buf, 
    1429               UINT, bufsize, 
     1486{
     1487    LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
     1488    LPSTR keyA      = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
     1489    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
     1490    LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
     1491
     1492    INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
     1493               len, filenameA );
     1494    lstrcpynAtoW( (LPWSTR)buffer, bufferA, len );
     1495    HeapFree( GetProcessHeap(), 0, bufferA);
     1496    HeapFree( GetProcessHeap(), 0, sectionA );
     1497    HeapFree( GetProcessHeap(), 0, keyA );
     1498    HeapFree( GetProcessHeap(), 0, filenameA );
     1499
     1500    return ret;
     1501}
     1502
     1503
     1504/***********************************************************************
     1505 *           WritePrivateProfileStruct32A (KERNEL32.744)
     1506 */
     1507ODINFUNCTION5(BOOL, WritePrivateProfileStructA,
     1508              LPCSTR, section,
     1509              LPCSTR, key,
     1510              LPVOID, buf,
     1511              UINT, bufsize,
    14301512              LPCSTR, filename)
    1431 { 
    1432     BOOL ret = FALSE; 
    1433  
    1434     if (!section && !key && !buf)  /* flush the cache */ 
    1435         return WritePrivateProfileStringA( NULL, NULL, NULL, filename ); 
    1436  
    1437     EnterCriticalSection( &PROFILE_CritSect ); 
    1438  
    1439     if (PROFILE_Open( filename )) 
    1440         ret = PROFILE_SetString( section, key, (LPCSTR)buf ); 
    1441  
    1442     LeaveCriticalSection( &PROFILE_CritSect ); 
    1443  
    1444     return ret; 
    1445 } 
    1446  
    1447 /*********************************************************************** 
    1448  *           WritePrivateProfileStruct32W (KERNEL32.544) 
    1449  */ 
    1450 ODINFUNCTION5(BOOL, WritePrivateProfileStructW, 
    1451               LPCWSTR, section, 
    1452               LPCWSTR, key, 
    1453               LPVOID, buf, 
    1454               UINT, bufsize, 
     1513{
     1514    BOOL ret = FALSE;
     1515
     1516    if (!section && !key && !buf)  /* flush the cache */
     1517        return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
     1518
     1519    EnterCriticalSection( &PROFILE_CritSect );
     1520
     1521    if (PROFILE_Open( filename ))
     1522        ret = PROFILE_SetString( section, key, (LPCSTR)buf );
     1523
     1524    LeaveCriticalSection( &PROFILE_CritSect );
     1525
     1526    return ret;
     1527}
     1528
     1529/***********************************************************************
     1530 *           WritePrivateProfileStruct32W (KERNEL32.544)
     1531 */
     1532ODINFUNCTION5(BOOL, WritePrivateProfileStructW,
     1533              LPCWSTR, section,
     1534              LPCWSTR, key,
     1535              LPVOID, buf,
     1536              UINT, bufsize,
    14551537              LPCWSTR, filename)
    1456 { 
    1457     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section ); 
    1458     LPSTR keyA      = HEAP_strdupWtoA( GetProcessHeap(), 0, key); 
    1459     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); 
    1460     INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize, 
    1461                  filenameA ); 
    1462     HeapFree( GetProcessHeap(), 0, sectionA ); 
    1463     HeapFree( GetProcessHeap(), 0, keyA ); 
    1464     HeapFree( GetProcessHeap(), 0, filenameA ); 
    1465  
    1466     return ret; 
    1467 } 
    1468  
    1469 /*********************************************************************** 
    1470  *           WriteOutProfiles   (KERNEL.315) 
    1471  * CB: original: 16 bit function 
    1472  *     here: necessary to save open ini files 
    1473  */ 
     1538{
     1539    LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
     1540    LPSTR keyA      = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
     1541    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
     1542    INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
     1543                 filenameA );
     1544    HeapFree( GetProcessHeap(), 0, sectionA );
     1545    HeapFree( GetProcessHeap(), 0, keyA );
     1546    HeapFree( GetProcessHeap(), 0, filenameA );
     1547
     1548    return ret;
     1549}
     1550
     1551/***********************************************************************
     1552 *           WriteOutProfiles   (KERNEL.315)
     1553 * CB: original: 16 bit function
     1554 *     here: necessary to save open ini files
     1555 */
    14741556ODINPROCEDURE0(WriteOutProfiles)
    14751557{
    1476     PROFILE *lastCurProfile;
    1477     INT x;
    1478  
    1479     EnterCriticalSection(&PROFILE_CritSect);
    1480  
    1481     if (CurProfile && CurProfile->filename)
    1482       PROFILE_FlushFile(); //flash current
    1483  
    1484     if (MRUProfile)
    1485     {
    1486       lastCurProfile = CurProfile;
    1487       for(x = 1;x < N_CACHED_PROFILES;x++)
    1488       {
    1489         if (MRUProfile[x] && MRUProfile[x]->filename)
    1490         {
    1491           CurProfile = MRUProfile[x];
    1492           PROFILE_FlushFile();
    1493         }
    1494       }
    1495       CurProfile = lastCurProfile;
    1496     }
    1497     LeaveCriticalSection(&PROFILE_CritSect);
    1498 }
    1499  
    1500  
    1501 
     1558    PROFILE *lastCurProfile;
     1559    INT x;
     1560
     1561    PROFILE_SaveOdinIni();
     1562
     1563    EnterCriticalSection(&PROFILE_CritSect);
     1564
     1565    if (CurProfile && CurProfile->filename)
     1566      PROFILE_FlushFile(); //flash current
     1567
     1568    if (MRUProfile)
     1569    {
     1570      lastCurProfile = CurProfile;
     1571      for(x = 1;x < N_CACHED_PROFILES;x++)
     1572      {
     1573        if (MRUProfile[x] && MRUProfile[x]->filename)
     1574        {
     1575          CurProfile = MRUProfile[x];
     1576          PROFILE_FlushFile();
     1577        }
     1578      }
     1579      CurProfile = lastCurProfile;
     1580    }
     1581    LeaveCriticalSection(&PROFILE_CritSect);
     1582}
     1583
     1584
     1585
Note: See TracChangeset for help on using the changeset viewer.