Ignore:
Timestamp:
Aug 19, 1999, 12:48:49 PM (26 years ago)
Author:
sandervl
Message:

Odin wrappers for profile apis

File:
1 edited

Legend:

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

    r565 r573  
    1 /* $Id: profile.cpp,v 1.17 1999-08-18 23:44:48 phaller Exp $ */
     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>
     21#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 
     33ODINDEBUGCHANNEL(PROFILE)
    234
    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  */
     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 
     50typedef struct tagPROFILEKEY
     51{
     52    char                  *name;
     53    char                  *value;
     54    struct tagPROFILEKEY  *next;
     55} PROFILEKEY;
     56 
     57typedef struct tagPROFILESECTION
     58{
     59    char                       *name;
     60    struct tagPROFILEKEY       *key;
     61    struct tagPROFILESECTION   *next;
     62} PROFILESECTION;
     63 
     64 
     65typedef 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 */
     78static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
     79 
     80#define CurProfile (MRUProfile[0])
     81 
     82/* wine.ini profile content */
     83static 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 */
     89static const char PROFILE_WineIniName[] = "/.winerc";
     90 
     91/* Wine profile: the profile file being used */
     92static 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 
     99static LPCWSTR wininiW = NULL; //CB: never freed
     100 
     101static 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 */
     110static 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 */
     157static 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 */
     179static 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 
     199static int
     200PROFILE_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 */
     213static 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 */
     294static 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 */
     317static 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 */
     350static 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 */
     390static 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 */
     428static 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 */
     447static 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 */
     549static 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 
     595static 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 */
     623static 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 */
     651static 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 */
     700int 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 */
     731int 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 */
     780int  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 */
     831int  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 */
     877int 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 */
     938void 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 */
     957char* 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 */
     981ODINFUNCTION3(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 */
     992ODINFUNCTION3(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 */
     1004ODINFUNCTION5(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 */
     1018ODINFUNCTION5(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 */
     1033ODINFUNCTION3(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 */
     1044ODINFUNCTION3(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 */
     1056ODINFUNCTION4(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 */
     1077ODINFUNCTION4(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 */
     1096ODINFUNCTION6(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 */
     1126ODINFUNCTION6(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 */
     1153ODINFUNCTION4(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 
     1176ODINFUNCTION4(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 */
     1198ODINFUNCTION3(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 */
     1209ODINFUNCTION3(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 */
     1221ODINFUNCTION4(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 */
     1246ODINFUNCTION4(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 */
     1268ODINFUNCTION3(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 */
     1282ODINFUNCTION3(BOOL, WritePrivateProfileSectionW,
     1283              LPCWSTR, section,
     1284              LPCWSTR, string,
     1285              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 */
     1300ODINFUNCTION2(BOOL, WriteProfileSectionA,
     1301              LPCSTR, section,
     1302              LPCSTR, keys_n_values)
     1303{
     1304    return WritePrivateProfileSectionA( section, keys_n_values, WINININAME);
     1305}
     1306 
     1307/***********************************************************************
     1308 *           WriteProfileSection32W   (KERNEL32.748)
     1309 */
     1310ODINFUNCTION2(BOOL, WriteProfileSectionW,
     1311              LPCWSTR, section,
     1312              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 */
     1322ODINFUNCTION3(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 */
     1342ODINFUNCTION3(DWORD, GetPrivateProfileSectionNamesA,
     1343              LPSTR, buffer,
     1344              DWORD, size,
     1345              LPCSTR, filename)
     1346{
     1347 return (GetPrivateProfileSectionNames16 (buffer,size,filename));
     1348}
     1349 
     1350/***********************************************************************
     1351 *           GetPrivateProfileSectionNames32W  (KERNEL32.366)
     1352 */
     1353ODINFUNCTION3(DWORD, GetPrivateProfileSectionNamesW,
     1354              LPWSTR, buffer,
     1355              DWORD, size,
     1356              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 */
     1372ODINFUNCTION5(BOOL, GetPrivateProfileStructA,
     1373              LPCSTR, section,
     1374              LPCSTR, key,
     1375              LPVOID, buf,
     1376              UINT, len,
     1377              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 */
     1398ODINFUNCTION5(BOOL, GetPrivateProfileStructW,
     1399              LPCWSTR, section,
     1400              LPCWSTR, key,
     1401              LPVOID, buffer,
     1402              UINT, len,
     1403              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 */
     1425ODINFUNCTION5(BOOL, WritePrivateProfileStructA,
     1426              LPCSTR, section,
     1427              LPCSTR, key,
     1428              LPVOID, buf,
     1429              UINT, bufsize,
     1430              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 */
     1450ODINFUNCTION5(BOOL, WritePrivateProfileStructW,
     1451              LPCWSTR, section,
     1452              LPCWSTR, key,
     1453              LPVOID, buf,
     1454              UINT, bufsize,
     1455              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 */
     1474ODINPROCEDURE0(WriteOutProfiles)
     1475{
     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 
    141501
    15 #include <os2win.h>
    16 #include <ctype.h>
    17 #include <stdlib.h>
    18 #include <string.h>
    19 #include <stdio.h>
    20 #include <unicode.h>
    21 #include "heap.h"
    22 #include "heapstring.h"
    23 
    24 #include <sys/stat.h>
    25 
    26 #include "winbase.h"
    27 //#include "wine/winbase16.h"
    28 #include "winuser.h"
    29 #include "winnls.h"
    30 
    31 
    32 // -------------------------
    33 // WINE compatibility macros
    34 // -------------------------
    35 
    36 #ifndef MAX_PATHNAME_LEN
    37 #define MAX_PATHNAME_LEN 260
    38 #endif
    39 
    40 #define SystemHeap               GetProcessHeap()
    41 #define strcasecmp               strcmp
    42 #define DOSFS_GetFullName(a,b,c) strcpy(c,a)
    43 //#define lstrcpynA(a,b,c)         strncpy((char*)a,(char*)b,(int)c)
    44 #define CharLowerA(a)            (a)
    45 
    46 
    47 typedef struct tagPROFILEKEY
    48 {
    49     char                  *name;
    50     char                  *value;
    51     struct tagPROFILEKEY  *next;
    52 } PROFILEKEY;
    53 
    54 typedef struct tagPROFILESECTION
    55 {
    56     char                       *name;
    57     struct tagPROFILEKEY       *key;
    58     struct tagPROFILESECTION   *next;
    59 } PROFILESECTION;
    60 
    61 
    62 typedef struct
    63 {
    64     BOOL             changed;
    65     PROFILESECTION  *section;
    66     char            *filename; //first open name
    67     char            *fullname; //name with path
    68     time_t           mtime;
    69 } PROFILE;
    70 
    71 
    72 #define N_CACHED_PROFILES 10
    73 
    74 /* Cached profile files */
    75 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
    76 
    77 #define CurProfile (MRUProfile[0])
    78 
    79 /* wine.ini profile content */
    80 static PROFILESECTION *PROFILE_WineProfile;
    81 
    82 #define PROFILE_MAX_LINE_LEN   1024
    83 #define WINININAME "WIN.INI"
    84 
    85 /* Wine profile name in $HOME directory; must begin with slash */
    86 static const char PROFILE_WineIniName[] = "/.winerc";
    87 
    88 /* Wine profile: the profile file being used */
    89 static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
    90 
    91 /* Check for comments in profile */
    92 #define IS_ENTRY_COMMENT(str)  ((str)[0] == ';')
    93 
    94 #define WINE_INI_GLOBAL ETCDIR "/wine.conf"
    95 
    96 static LPCWSTR wininiW = NULL; //CB: never freed
    97 
    98 static 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  */
    107 static 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  */
    154 static 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  */
    176 static 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 
    196 static int
    197 PROFILE_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  */
    210 static 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  */
    291 static 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  */
    314 static 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  */
    347 static 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  */
    387 static 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  */
    425 static 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  */
    444 static 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 && (!strcmp(filename,MRUProfile[i]->filename) || !strcmp(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  */
    546 static 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 
    592 static 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  */
    620 static 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  */
    648 static 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_GetWineIniString
    694  *
    695  * Get a config string from the wine.ini file.
    696  */
    697 int PROFILE_GetWineIniString( const char *section, const char *key_name,
    698                               const char *def, char *buffer, int len )
    699 {
    700     int  ret;
    701 
    702     EnterCriticalSection( &PROFILE_CritSect );
    703 
    704     if (key_name)
    705     {
    706         PROFILEKEY *key = PROFILE_Find(&PROFILE_WineProfile, section, key_name, FALSE);
    707         PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def,
    708                            len, TRUE );
    709         dprintf(("Kernel32:Profile:('%s','%s','%s'): returning '%s'\n",
    710                          section, key_name, def, buffer ));
    711         ret = strlen( buffer );
    712     }
    713     else
    714     {
    715        ret = PROFILE_GetSection( PROFILE_WineProfile, section, buffer, len, TRUE, FALSE );
    716     }
    717     LeaveCriticalSection( &PROFILE_CritSect );
    718 
    719     return ret;
    720 }
    721 
    722 
    723 /***********************************************************************
    724  *           PROFILE_GetWineIniInt
    725  *
    726  * Get a config integer from the wine.ini file.
    727  */
    728 int PROFILE_GetWineIniInt( const char *section, const char *key_name, int def )
    729 {
    730     char buffer[20];
    731     char *p;
    732     long result;
    733     PROFILEKEY *key;
    734     int  ret;
    735 
    736     EnterCriticalSection( &PROFILE_CritSect );
    737 
    738     key = PROFILE_Find( &PROFILE_WineProfile, section, key_name, FALSE );
    739     if (!key || !key->value) {
    740        ret = def;
    741     } else {
    742        PROFILE_CopyEntry( buffer, key->value, sizeof(buffer), TRUE );
    743        result = strtol( buffer, &p, 0 );
    744        ret = (p == buffer) ? 0  /* No digits at all */ : (int)result;
    745     }
    746 
    747     LeaveCriticalSection( &PROFILE_CritSect );
    748 
    749     return ret;
    750 }
    751 
    752 
    753 /******************************************************************************
    754  *
    755  *   int  PROFILE_EnumerateWineIniSection(
    756  *     char const  *section,  #Name of the section to enumerate
    757  *     void  (*cbfn)(char const *key, char const *value, void *user),
    758  *                            # Address of the callback function
    759  *     void  *user )          # User-specified pointer.
    760  *
    761  *   For each entry in a section in the wine.conf file, this function will
    762  *   call the specified callback function, informing it of each key and
    763  *   value.  An optional user pointer may be passed to it (if this is not
    764  *   needed, pass NULL through it and ignore the value in the callback
    765  *   function).
    766  *
    767  *   The callback function must accept three parameters:
    768  *      The name of the key (char const *)
    769  *      The value of the key (char const *)
    770  *      A user-specified parameter (void *)
    771  *   Note that the first two are char CONST *'s, not char *'s!  The callback
    772  *   MUST not modify these strings!
    773  *
    774  *   The return value indicates the number of times the callback function
    775  *   was called.
    776  */
    777 int  PROFILE_EnumerateWineIniSection(
    778     char const  *section,
    779     void  (*cbfn)(char const *, char const *, void *),
    780     void  *userptr )
    781 {
    782     PROFILESECTION  *scansect;
    783     PROFILEKEY  *scankey;
    784     int  calls = 0;
    785 
    786     EnterCriticalSection( &PROFILE_CritSect );
    787 
    788     /* Search for the correct section */
    789     for(scansect = PROFILE_WineProfile; scansect; scansect = scansect->next) {
    790    if(scansect->name && !strcasecmp(scansect->name, section)) {
    791 
    792        /* Enumerate each key with the callback */
    793        for(scankey = scansect->key; scankey; scankey = scankey->next) {
    794 
    795       /* Ignore blank entries -- these shouldn't exist, but let's
    796          be extra careful */
    797       if(scankey->name[0]) {
    798           cbfn(scankey->name, scankey->value, userptr);
    799           ++calls;
    800       }
    801        }
    802 
    803        break;
    804    }
    805     }
    806     LeaveCriticalSection( &PROFILE_CritSect );
    807 
    808     return calls;
    809 }
    810 
    811 
    812 /******************************************************************************
    813  *
    814  *   int  PROFILE_GetWineIniBool(
    815  *      char const  *section,
    816  *      char const  *key_name,
    817  *      int  def )
    818  *
    819  *   Reads a boolean value from the wine.ini file.  This function attempts to
    820  *   be user-friendly by accepting 'n', 'N' (no), 'f', 'F' (false), or '0'
    821  *   (zero) for false, 'y', 'Y' (yes), 't', 'T' (true), or '1' (one) for
    822  *   true.  Anything else results in the return of the default value.
    823  *
    824  *   This function uses 1 to indicate true, and 0 for false.  You can check
    825  *   for existence by setting def to something other than 0 or 1 and
    826  *   examining the return value.
    827  */
    828 int  PROFILE_GetWineIniBool(
    829     char const  *section,
    830     char const  *key_name,
    831     int  def )
    832 {
    833     char  key_value[2];
    834     int  retval;
    835 
    836     PROFILE_GetWineIniString(section, key_name, "~", key_value, 2);
    837 
    838     switch(key_value[0]) {
    839     case 'n':
    840     case 'N':
    841     case 'f':
    842     case 'F':
    843     case '0':
    844    retval = 0;
    845    break;
    846 
    847     case 'y':
    848     case 'Y':
    849     case 't':
    850     case 'T':
    851     case '1':
    852    retval = 1;
    853    break;
    854 
    855     default:
    856    retval = def;
    857     }
    858 
    859     dprintf(("Kernel32:Profile:(\"%s\", \"%s\", %s), "
    860           "[%c], ret %s.\n", section, key_name,
    861           def ? "TRUE" : "FALSE", key_value[0],
    862           retval ? "TRUE" : "FALSE"));
    863 
    864     return retval;
    865 }
    866 
    867 
    868 #if 0
    869 /***********************************************************************
    870  *           PROFILE_LoadWineIni
    871  *
    872  * Load the wine.ini file.
    873  */
    874 int PROFILE_LoadWineIni(void)
    875 {
    876     char buffer[MAX_PATHNAME_LEN];
    877     const char *p;
    878     FILE *f;
    879 
    880     InitializeCriticalSection( &PROFILE_CritSect );
    881     MakeCriticalSectionGlobal( &PROFILE_CritSect );
    882 
    883     if ( (Options.configFileName!=NULL) && (f = fopen(Options.configFileName, "r")) )
    884     {
    885       /* Open -config specified file */
    886       PROFILE_WineProfile = PROFILE_Load ( f);
    887       fclose ( f );
    888       strncpy(PROFILE_WineIniUsed,Options.configFileName,MAX_PATHNAME_LEN-1);
    889       return 1;
    890     }
    891 
    892     if ( (p = getenv( "WINE_INI" )) && (f = fopen( p, "r" )) )
    893     {
    894    PROFILE_WineProfile = PROFILE_Load( f );
    895    fclose( f );
    896    strncpy(PROFILE_WineIniUsed,p,MAX_PATHNAME_LEN-1);
    897    return 1;
    898     }
    899     if ((p = getenv( "HOME" )) != NULL)
    900     {
    901         lstrcpynA(buffer, p, MAX_PATHNAME_LEN - sizeof(PROFILE_WineIniName));
    902         strcat( buffer, PROFILE_WineIniName );
    903         if ((f = fopen( buffer, "r" )) != NULL)
    904         {
    905             PROFILE_WineProfile = PROFILE_Load( f );
    906             fclose( f );
    907        strncpy(PROFILE_WineIniUsed,buffer,MAX_PATHNAME_LEN-1);
    908             return 1;
    909         }
    910     }
    911     else dprintf(("Kernel32:Profile:could not get $HOME value for config file.\n" ));
    912 
    913     /* Try global file */
    914 
    915     if ((f = fopen( WINE_INI_GLOBAL, "r" )) != NULL)
    916     {
    917         PROFILE_WineProfile = PROFILE_Load( f );
    918         fclose( f );
    919    strncpy(PROFILE_WineIniUsed,WINE_INI_GLOBAL,MAX_PATHNAME_LEN-1);
    920         return 1;
    921     }
    922     MESSAGE( "Can't open configuration file %s or $HOME%s\n",
    923     WINE_INI_GLOBAL, PROFILE_WineIniName );
    924     return 0;
    925 }
    926 
    927 
    928 /***********************************************************************
    929  *           PROFILE_UsageWineIni
    930  *
    931  * Explain the wine.ini file to those who don't read documentation.
    932  * Keep below one screenful in length so that error messages above are
    933  * noticed.
    934  */
    935 void PROFILE_UsageWineIni(void)
    936 {
    937     MESSAGE("Perhaps you have not properly edited or created "
    938    "your Wine configuration file.\n");
    939     MESSAGE("This is either %s or $HOME%s\n",WINE_INI_GLOBAL,PROFILE_WineIniName);
    940     MESSAGE("  or it is determined by the -config option or from\n"
    941         "  the WINE_INI environment variable.\n");
    942     if (*PROFILE_WineIniUsed)
    943    MESSAGE("Wine has used %s as configuration file.\n", PROFILE_WineIniUsed);
    944     /* RTFM, so to say */
    945 }
    946 #endif
    947 
    948 /***********************************************************************
    949  *           PROFILE_GetStringItem
    950  *
    951  *  Convenience function that turns a string 'xxx, yyy, zzz' into
    952  *  the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
    953  */
    954 char* PROFILE_GetStringItem( char* start )
    955 {
    956     char* lpchX, *lpch;
    957 
    958     for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++ )
    959     {
    960         if( *lpchX == ',' )
    961         {
    962             if( lpch ) *lpch = '\0'; else *lpchX = '\0';
    963             while( *(++lpchX) )
    964                 if( !PROFILE_isspace(*lpchX) ) return lpchX;
    965         }
    966    else if( PROFILE_isspace( *lpchX ) && !lpch ) lpch = lpchX;
    967         else lpch = NULL;
    968     }
    969     if( lpch ) *lpch = '\0';
    970     return NULL;
    971 }
    972 
    973 /********************* API functions **********************************/
    974 
    975 /***********************************************************************
    976  *           GetProfileInt32A   (KERNEL32.264)
    977  */
    978 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val )
    979 {
    980     return GetPrivateProfileIntA( section, entry, def_val, WINININAME );
    981 }
    982 
    983 /***********************************************************************
    984  *           GetProfileInt32W   (KERNEL32.264)
    985  */
    986 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val )
    987 {
    988     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
    989     return GetPrivateProfileIntW( section, entry, def_val, wininiW );
    990 }
    991 
    992 /***********************************************************************
    993  *           GetProfileString32A   (KERNEL32.268)
    994  */
    995 INT WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val,
    996                LPSTR buffer, UINT len )
    997 {
    998     return GetPrivateProfileStringA( section, entry, def_val,
    999                  buffer, len, WINININAME );
    1000 }
    1001 
    1002 /***********************************************************************
    1003  *           GetProfileString32W   (KERNEL32.269)
    1004  */
    1005 INT WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry,
    1006                LPCWSTR def_val, LPWSTR buffer, UINT len )
    1007 {
    1008     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
    1009     return GetPrivateProfileStringW( section, entry, def_val,
    1010                  buffer, len, wininiW );
    1011 }
    1012 
    1013 /***********************************************************************
    1014  *           WriteProfileString32A   (KERNEL32.587)
    1015  */
    1016 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry,
    1017              LPCSTR string )
    1018 {
    1019     return WritePrivateProfileStringA( section, entry, string, WINININAME );
    1020 }
    1021 
    1022 /***********************************************************************
    1023  *           WriteProfileString32W   (KERNEL32.588)
    1024  */
    1025 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry,
    1026                                      LPCWSTR string )
    1027 {
    1028     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
    1029     return WritePrivateProfileStringW( section, entry, string, wininiW );
    1030 }
    1031 
    1032 /***********************************************************************
    1033  *           GetPrivateProfileInt32A   (KERNEL32.251)
    1034  */
    1035 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry,
    1036                INT def_val, LPCSTR filename )
    1037 {
    1038     char buffer[20];
    1039     char *p;
    1040     long result;
    1041 
    1042     GetPrivateProfileStringA( section, entry, "",
    1043                                 buffer, sizeof(buffer), filename );
    1044     if (!buffer[0]) return (UINT)def_val;
    1045     result = strtol( buffer, &p, 0 );
    1046     if (p == buffer) return 0;  /* No digits at all */
    1047     return (UINT)result;
    1048 }
    1049 
    1050 /***********************************************************************
    1051  *           GetPrivateProfileInt32W   (KERNEL32.252)
    1052  */
    1053 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry,
    1054                INT def_val, LPCWSTR filename )
    1055 {
    1056     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1057     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
    1058     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1059     UINT res = GetPrivateProfileIntA(sectionA, entryA, def_val, filenameA);
    1060     HeapFree( GetProcessHeap(), 0, sectionA );
    1061     HeapFree( GetProcessHeap(), 0, filenameA );
    1062     HeapFree( GetProcessHeap(), 0, entryA );
    1063     return res;
    1064 }
    1065 
    1066 /***********************************************************************
    1067  *           GetPrivateProfileString32A   (KERNEL32.255)
    1068  */
    1069 INT WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry,
    1070                  LPCSTR def_val, LPSTR buffer,
    1071                  UINT len, LPCSTR filename )
    1072 {
    1073     int     ret;
    1074 
    1075     if (!filename)
    1076    filename = WINININAME;
    1077 
    1078     EnterCriticalSection( &PROFILE_CritSect );
    1079 
    1080     if (PROFILE_Open( filename )) {
    1081         ret = PROFILE_GetString( section, entry, def_val, buffer, len );
    1082     } else {
    1083        lstrcpynA( buffer, def_val, len );
    1084        ret = strlen( buffer );
    1085     }
    1086 
    1087     LeaveCriticalSection( &PROFILE_CritSect );
    1088 
    1089     return ret;
    1090 }
    1091 
    1092 /***********************************************************************
    1093  *           GetPrivateProfileString32W   (KERNEL32.256)
    1094  */
    1095 INT WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
    1096                  LPCWSTR def_val, LPWSTR buffer,
    1097                  UINT len, LPCWSTR filename )
    1098 {
    1099     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1100     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
    1101     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1102     LPSTR def_valA  = HEAP_strdupWtoA( GetProcessHeap(), 0, def_val );
    1103     LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
    1104     INT ret = GetPrivateProfileStringA( sectionA, entryA, def_valA,
    1105                                             bufferA, len, filenameA );
    1106     lstrcpynAtoW( buffer, bufferA, len );
    1107     HeapFree( GetProcessHeap(), 0, sectionA );
    1108     HeapFree( GetProcessHeap(), 0, entryA );
    1109     HeapFree( GetProcessHeap(), 0, filenameA );
    1110     HeapFree( GetProcessHeap(), 0, def_valA );
    1111     HeapFree( GetProcessHeap(), 0, bufferA);
    1112     return ret;
    1113 }
    1114 
    1115 /***********************************************************************
    1116  *           GetPrivateProfileSection32A   (KERNEL32.255)
    1117  */
    1118 INT WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer,
    1119                   DWORD len, LPCSTR filename )
    1120 {
    1121     int     ret = 0;
    1122 
    1123     EnterCriticalSection( &PROFILE_CritSect );
    1124 
    1125     if (PROFILE_Open( filename ))
    1126         ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
    1127              FALSE, TRUE);
    1128 
    1129     LeaveCriticalSection( &PROFILE_CritSect );
    1130 
    1131     return ret;
    1132 }
    1133 
    1134 /***********************************************************************
    1135  *           GetPrivateProfileSection32W   (KERNEL32.256)
    1136  */
    1137 
    1138 INT WINAPI GetPrivateProfileSectionW (LPCWSTR section, LPWSTR buffer,
    1139                   DWORD len, LPCWSTR filename )
    1140 
    1141 {
    1142     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1143     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1144     LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
    1145     INT ret = GetPrivateProfileSectionA( sectionA, bufferA, len,
    1146                   filenameA );
    1147     MultiByteToWideChar(CP_ACP,0,bufferA,ret,buffer,len);
    1148     HeapFree( GetProcessHeap(), 0, sectionA );
    1149     HeapFree( GetProcessHeap(), 0, filenameA );
    1150     HeapFree( GetProcessHeap(), 0, bufferA);
    1151     return ret;
    1152 }
    1153 
    1154 /***********************************************************************
    1155  *           GetProfileSection32A   (KERNEL32.268)
    1156  */
    1157 INT WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len )
    1158 {
    1159     return GetPrivateProfileSectionA( section, buffer, len, WINININAME );
    1160 }
    1161 
    1162 /***********************************************************************
    1163  *           GetProfileSection32W   (KERNEL32)
    1164  */
    1165 INT WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len )
    1166 {
    1167     if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME );
    1168     return GetPrivateProfileSectionW( section, buffer, len, wininiW );
    1169 }
    1170 
    1171 /***********************************************************************
    1172  *           WritePrivateProfileString32A   (KERNEL32.582)
    1173  */
    1174 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry,
    1175                LPCSTR string, LPCSTR filename )
    1176 {
    1177     BOOL ret = FALSE;
    1178 
    1179     EnterCriticalSection( &PROFILE_CritSect );
    1180 
    1181     if (PROFILE_Open( filename ))
    1182     {
    1183         if (!section && !entry && !string)
    1184             PROFILE_ReleaseFile();  /* always return FALSE in this case */
    1185         else
    1186             ret = PROFILE_SetString( section, entry, string );
    1187     }
    1188 
    1189     LeaveCriticalSection( &PROFILE_CritSect );
    1190     return ret;
    1191 }
    1192 
    1193 /***********************************************************************
    1194  *           WritePrivateProfileString32W   (KERNEL32.583)
    1195  */
    1196 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry,
    1197                LPCWSTR string, LPCWSTR filename )
    1198 {
    1199     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1200     LPSTR entryA    = HEAP_strdupWtoA( GetProcessHeap(), 0, entry );
    1201     LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
    1202     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1203     BOOL res = WritePrivateProfileStringA( sectionA, entryA,
    1204                   stringA, filenameA );
    1205     HeapFree( GetProcessHeap(), 0, sectionA );
    1206     HeapFree( GetProcessHeap(), 0, entryA );
    1207     HeapFree( GetProcessHeap(), 0, stringA );
    1208     HeapFree( GetProcessHeap(), 0, filenameA );
    1209     return res;
    1210 }
    1211 
    1212 /***********************************************************************
    1213  *           WritePrivateProfileSection32A   (KERNEL32)
    1214  */
    1215 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section,
    1216                 LPCSTR string, LPCSTR filename )
    1217 {
    1218   char *p =(char*)string;
    1219 
    1220   dprintf(("Kernel32:Profile:fixme WritePrivateProfileSection32A empty stub\n"));
    1221   return FALSE;
    1222 }
    1223 
    1224 /***********************************************************************
    1225  *           WritePrivateProfileSection32W   (KERNEL32)
    1226  */
    1227 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section,
    1228                 LPCWSTR string, LPCWSTR filename)
    1229 
    1230 {
    1231     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1232     LPSTR stringA   = HEAP_strdupWtoA( GetProcessHeap(), 0, string );
    1233     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1234     BOOL res = WritePrivateProfileSectionA( sectionA, stringA, filenameA );
    1235     HeapFree( GetProcessHeap(), 0, sectionA );
    1236     HeapFree( GetProcessHeap(), 0, stringA );
    1237     HeapFree( GetProcessHeap(), 0, filenameA );
    1238     return res;
    1239 }
    1240 
    1241 /***********************************************************************
    1242  *           WriteProfileSection32A   (KERNEL32.747)
    1243  */
    1244 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values)
    1245 
    1246 {
    1247     return WritePrivateProfileSectionA( section, keys_n_values, WINININAME);
    1248 }
    1249 
    1250 /***********************************************************************
    1251  *           WriteProfileSection32W   (KERNEL32.748)
    1252  */
    1253 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values)
    1254 {
    1255    if (!wininiW) wininiW = HEAP_strdupAtoW( SystemHeap, 0, WINININAME);
    1256 
    1257    return (WritePrivateProfileSectionW (section,keys_n_values, wininiW));
    1258 }
    1259 
    1260 /***********************************************************************
    1261  *           GetPrivateProfileSectionNames16   (KERNEL.143)
    1262  */
    1263 WORD WINAPI GetPrivateProfileSectionNames16( LPSTR buffer, WORD size,
    1264                                              LPCSTR filename )
    1265 {
    1266     WORD ret = 0;
    1267 
    1268     EnterCriticalSection( &PROFILE_CritSect );
    1269 
    1270     if (PROFILE_Open( filename ))
    1271       ret = PROFILE_GetSectionNames(buffer, size);
    1272 
    1273     LeaveCriticalSection( &PROFILE_CritSect );
    1274 
    1275     return ret;
    1276 }
    1277 
    1278 /***********************************************************************
    1279  *           GetPrivateProfileSectionNames32A  (KERNEL32.365)
    1280  */
    1281 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size,
    1282                     LPCSTR filename)
    1283 
    1284 {
    1285  return (GetPrivateProfileSectionNames16 (buffer,size,filename));
    1286 }
    1287 
    1288 /***********************************************************************
    1289  *           GetPrivateProfileSectionNames32W  (KERNEL32.366)
    1290  */
    1291 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size,
    1292                     LPCWSTR filename)
    1293 
    1294 {
    1295    LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1296    LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, size);
    1297 
    1298    INT ret = GetPrivateProfileSectionNames16 (bufferA, size, filenameA);
    1299    lstrcpynAtoW( buffer, bufferA, size);
    1300    HeapFree( GetProcessHeap(), 0, bufferA);
    1301    HeapFree( GetProcessHeap(), 0, filenameA );
    1302 
    1303    return ret;
    1304 }
    1305 
    1306 /***********************************************************************
    1307  *           GetPrivateProfileStruct32A (KERNEL32.370)
    1308  */
    1309 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key,
    1310                   LPVOID buf, UINT len, LPCSTR filename)
    1311 {
    1312     BOOL ret = FALSE;
    1313 
    1314     EnterCriticalSection( &PROFILE_CritSect );
    1315 
    1316     if (PROFILE_Open( filename )) {
    1317         PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
    1318    if (k) {
    1319       lstrcpynA( (LPSTR)buf, k->value, strlen(k->value));
    1320       ret = TRUE;
    1321    }
    1322     }
    1323     LeaveCriticalSection( &PROFILE_CritSect );
    1324 
    1325     return FALSE;
    1326 }
    1327 
    1328 /***********************************************************************
    1329  *           GetPrivateProfileStruct32W (KERNEL32.543)
    1330  */
    1331 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key,
    1332                   LPVOID buffer, UINT len, LPCWSTR filename)
    1333 {
    1334     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1335     LPSTR keyA      = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
    1336     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1337     LPSTR bufferA   = (LPSTR)HeapAlloc( GetProcessHeap(), 0, len );
    1338 
    1339     INT ret = GetPrivateProfileStructA( sectionA, keyA, bufferA,
    1340                len, filenameA );
    1341     lstrcpynAtoW( (LPWSTR)buffer, bufferA, len );
    1342     HeapFree( GetProcessHeap(), 0, bufferA);
    1343     HeapFree( GetProcessHeap(), 0, sectionA );
    1344     HeapFree( GetProcessHeap(), 0, keyA );
    1345     HeapFree( GetProcessHeap(), 0, filenameA );
    1346 
    1347     return ret;
    1348 }
    1349 
    1350 
    1351 /***********************************************************************
    1352  *           WritePrivateProfileStruct32A (KERNEL32.744)
    1353  */
    1354 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key,
    1355                                         LPVOID buf, UINT bufsize, LPCSTR filename)
    1356 {
    1357     BOOL ret = FALSE;
    1358 
    1359     if (!section && !key && !buf)  /* flush the cache */
    1360         return WritePrivateProfileStringA( NULL, NULL, NULL, filename );
    1361 
    1362     EnterCriticalSection( &PROFILE_CritSect );
    1363 
    1364     if (PROFILE_Open( filename ))
    1365         ret = PROFILE_SetString( section, key, (LPCSTR)buf );
    1366 
    1367     LeaveCriticalSection( &PROFILE_CritSect );
    1368 
    1369     return ret;
    1370 }
    1371 
    1372 /***********************************************************************
    1373  *           WritePrivateProfileStruct32W (KERNEL32.544)
    1374  */
    1375 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key,
    1376                LPVOID buf, UINT bufsize, LPCWSTR filename)
    1377 {
    1378     LPSTR sectionA  = HEAP_strdupWtoA( GetProcessHeap(), 0, section );
    1379     LPSTR keyA      = HEAP_strdupWtoA( GetProcessHeap(), 0, key);
    1380     LPSTR filenameA = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
    1381     INT ret = WritePrivateProfileStructA( sectionA, keyA, buf, bufsize,
    1382                  filenameA );
    1383     HeapFree( GetProcessHeap(), 0, sectionA );
    1384     HeapFree( GetProcessHeap(), 0, keyA );
    1385     HeapFree( GetProcessHeap(), 0, filenameA );
    1386 
    1387     return ret;
    1388 }
    1389 
    1390 /***********************************************************************
    1391  *           WriteOutProfiles   (KERNEL.315)
    1392  * CB: original: 16 bit function
    1393  *     here: necessary to save open ini files
    1394  */
    1395 void WINAPI WriteOutProfiles(void)
    1396 {
    1397     PROFILE *lastCurProfile;
    1398     INT x;
    1399 
    1400     EnterCriticalSection(&PROFILE_CritSect);
    1401 
    1402     if (CurProfile && CurProfile->filename)
    1403       PROFILE_FlushFile(); //flash current
    1404 
    1405     if (MRUProfile)
    1406     {
    1407       lastCurProfile = CurProfile;
    1408       for(x = 1;x < N_CACHED_PROFILES;x++)
    1409       {
    1410         if (MRUProfile[x] && MRUProfile[x]->filename)
    1411         {
    1412           CurProfile = MRUProfile[x];
    1413           PROFILE_FlushFile();
    1414         }
    1415       }
    1416       CurProfile = lastCurProfile;
    1417     }
    1418     LeaveCriticalSection(&PROFILE_CritSect);
    1419 }
    1420 
    1421 
Note: See TracChangeset for help on using the changeset viewer.