Wrong behaviour in WritePrivateProfileSection

Gerhard Gruber sparhawk at gmx.at
Sat Feb 2 10:51:42 CST 2002


WritePrivateProfileSection should allow to create duplicate keys because
it takes the buffer as it is without any modifications. The earlier
implementation exhibited the same behaviour as WritePrivateProfileString
which doesn't allow for duplicate keys. This is now fixed.
-------------- next part --------------
Index: profile.c
===================================================================
RCS file: /home/wine/wine/files/profile.c,v
retrieving revision 1.63
diff -u -r1.63 profile.c
--- profile.c	21 Jan 2002 23:36:53 -0000	1.63
+++ profile.c	2 Feb 2002 16:45:00 -0000
@@ -84,6 +84,122 @@
 static const char hex[16] = "0123456789ABCDEF";
 
 /***********************************************************************
+ *           PROFILE_GetPrivateProfileSection
+ *
+ * Allocates a buffer and reads the given section into it.
+ * The returnvalue is the pointer to the buffer holding all keys for the
+ * specified section according to the MS docsumentation. BufSize returns
+ * the size of the allocated buffer or 0 if no buffer is available.
+ * The buffer has to be freed by the caller.
+ */
+char *PROFILE_GetPrivateProfileSection(const char *section, 
+									 const char *filename, DWORD *BufSize)
+{
+   char *rc = NULL;
+   char *Buffer = NULL;
+   DWORD bsz, retval;
+
+   // FIXME:? (<Gerhard W. Gruber>sparhawk at gmx.at)
+   // Since there is no function to enumerate the entries in a section, nor
+   // is it possible to determine how many bytes are needed for the buffer
+   // we set up a loop that allocates a larger buffer until the function
+   // returns that all bytes could be copied to the buffer.
+   // If there is a better to way to do this, then fix it.
+   *BufSize = bsz = retval = 0;
+   while(retval >= bsz)
+   {
+		bsz += 4096;
+		if((Buffer = (char *)malloc(bsz)) == NULL)
+		{
+			 TRACE("Error allocating %ld bytes", bsz);
+			 goto Quit;
+		}
+		memset(Buffer, 0, bsz);
+		retval = GetPrivateProfileSectionA(section, Buffer, bsz, filename);
+
+		// According to the MS docs GetPrivateProfileSection returns buffersize - 2,
+		// if the buffer was to small to hold all the bytes in the section.
+		// In that case we have to allocate a larger buffer and try again.
+		// In most cases I guess that 4096 is sufficient and this function is called
+		// once at startup, so this is not really time critical.
+		if(retval == (bsz-2))
+        {
+		   retval = bsz;
+		   free(Buffer);
+		   Buffer = NULL;
+		}
+   }
+
+   rc = Buffer;
+
+Quit:
+   if(rc == NULL)
+		*BufSize = 0;
+   else
+		*BufSize = bsz;
+
+   return(rc);
+}
+
+/***********************************************************************
+ *           PROFILE_AddPrivateProfileString
+ *
+ * Adds a string to a .INI section. This function adds the string
+ * regardless wether the key already exists so you can add the same
+ * key more than once with different values. This is needed in case
+ * of wininit.ini because all files that should be deleted have NUL as
+ * keyname which can't be set with the normal functions.
+ */
+BOOL PROFILE_AddPrivateProfileString(const char *section, 
+									 const char *entry,
+									 const char *value,
+									 const char *filename)
+{
+	 BOOL rc = FALSE;
+	 char *Buffer = NULL, *p;
+	 DWORD BufSize = 0, len, index;
+
+	 if((Buffer = PROFILE_GetPrivateProfileSection(section, filename, &BufSize)) == NULL)
+	 {
+		  TRACE("Couldn't allocate get the profile section for [%s] from [%s]\n", section, filename);
+		  goto Quit;
+	 }
+
+	 // when we have to add the new key we need to add the null byte
+	 // and the '=' character as well.
+	 len = strlen(entry) + strlen(value) + 2;
+
+	 // The buffer contains each key/value pair as a single string with a 0 byte. The
+	 // last pair is followed by two 0 bytes to indicate the end of the buffer.
+	 index = 0;
+	 while(Buffer[index] != 0)
+		  index += strlen(&Buffer[index])+1;
+
+	 // If the allocated buffer is larger than our current section plus the
+	 // space we need for the new pair we don't need to allocate a new buffer;
+	 if(BufSize < (index + len))
+	 {
+		  BufSize += index + len;
+		  if((p = realloc(Buffer, BufSize)) == NULL)
+			   goto Quit;
+
+		  memset(&Buffer[index], 0, len);
+		  Buffer = p;
+	 }
+
+	 sprintf(&Buffer[index], "%s=%s", entry, value);
+	 WritePrivateProfileSectionA(section, Buffer, filename);
+	 rc = TRUE;
+
+Quit:
+	 if(Buffer)
+		  free(Buffer);
+
+	 return(rc);
+}
+
+
+/***********************************************************************
  *           PROFILE_CopyEntry
  *
  * Copy the content of an entry into a buffer, removing quotes, and possibly
@@ -444,7 +560,7 @@
  */
 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section,
                                  const char *section_name,
-                                 const char *key_name, int create )
+                                 const char *key_name, int create, BOOL CreateDup)
 {
     const char *p;
     int seclen, keylen;
@@ -454,26 +570,33 @@
     while ((p > section_name) && PROFILE_isspace(*p)) p--;
     seclen = p - section_name + 1;
     
-    while (PROFILE_isspace(*key_name)) key_name++;
-    p = key_name + strlen(key_name) - 1;
-    while ((p > key_name) && PROFILE_isspace(*p)) p--;
-    keylen = p - key_name + 1;
+	while (PROFILE_isspace(*key_name)) key_name++;
+	p = key_name + strlen(key_name) - 1;
+	while ((p > key_name) && PROFILE_isspace(*p)) p--;
+	keylen = p - key_name + 1;
 
     while (*section)
     {
         if ( ((*section)->name[0])
-	  && (!(strncasecmp( (*section)->name, section_name, seclen )))
-	  && (((*section)->name)[seclen] == '\0') )
+			 && (!(strncasecmp( (*section)->name, section_name, seclen )))
+			 && (((*section)->name)[seclen] == '\0') )
         {
             PROFILEKEY **key = &(*section)->key;
-            while (*key)
-            {
-                if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
-		  && (((*key)->name)[keylen] == '\0') )
-		    return *key;
-                key = &(*key)->next;
-            }
-            if (!create) return NULL;
+
+			while (*key)
+			{
+				 // If CreateDup is FALSE then we check if the keyname already exists.
+				 // Otherwise we add it regardless of its existence, to allow
+				 // keys to be added more then once in some cases.
+				 if(CreateDup == FALSE)
+				 {
+					  if ( (!(strncasecmp( (*key)->name, key_name, keylen )))
+						   && (((*key)->name)[keylen] == '\0') )
+						   return *key;
+				 }
+				 key = &(*key)->next;
+			}
+			if (!create) return NULL;
             if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlen(key_name) )))
                 return NULL;
             strcpy( (*key)->name, key_name );
@@ -827,7 +950,7 @@
     if (!def_val) def_val = "";
     if (key_name && key_name[0])
     {
-        key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE );
+        key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE);
         PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val,
                            len, FALSE );
         TRACE("('%s','%s','%s'): returning '%s'\n",
@@ -851,7 +974,7 @@
  * Set a profile string.
  */
 static BOOL PROFILE_SetString( LPCSTR section_name, LPCSTR key_name,
-			       LPCSTR value )
+			       LPCSTR value, BOOL CreateDup)
 {
     if (!key_name)  /* Delete a whole section */
     {
@@ -871,8 +994,8 @@
     }
     else  /* Set the key value */
     {
-        PROFILEKEY *key = PROFILE_Find( &CurProfile->section, section_name,
-                                        key_name, TRUE );
+        PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
+                                        key_name, TRUE, CreateDup);
         TRACE("('%s','%s','%s'): \n",
                          section_name, key_name, value );
         if (!key) return FALSE;
@@ -1484,7 +1607,7 @@
 	    if (!section) {
 		FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename);
 	    } else {
-		ret = PROFILE_SetString( section, entry, string );
+		ret = PROFILE_SetString( section, entry, string, FALSE);
 	    }
 	}
     }
@@ -1536,7 +1659,7 @@
         if (!section && !string)
             PROFILE_ReleaseFile();  /* always return FALSE in this case */
         else if (!string) /* delete the named section*/
-	    ret = PROFILE_SetString(section,NULL,NULL);
+	    ret = PROFILE_SetString(section,NULL,NULL, FALSE);
         else {
 	    PROFILE_DeleteAllKeys(section);
 	    ret = TRUE;
@@ -1545,13 +1668,11 @@
                 strcpy( buf, string );
                 if((p=strchr( buf, '='))){
                     *p='\0';
-                    ret = PROFILE_SetString( section, buf, p+1 );
-                    
+                    ret = PROFILE_SetString( section, buf, p+1, TRUE);
                 }
                 HeapFree( GetProcessHeap(), 0, buf );
                 string += strlen(string)+1;
             }
-            
         }
     }
 
@@ -1716,7 +1837,7 @@
     EnterCriticalSection( &PROFILE_CritSect );
 
     if (PROFILE_Open( filename )) {
-        PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE);
+        PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE);
 	if (k) {
 	    TRACE("value (at %p): '%s'\n", k->value, k->value);
 	    if (((strlen(k->value) - 2) / 2) == len)
@@ -1842,7 +1963,7 @@
     EnterCriticalSection( &PROFILE_CritSect );
 
     if (PROFILE_Open( filename )) 
-        ret = PROFILE_SetString( section, key, outstring );
+        ret = PROFILE_SetString( section, key, outstring, FALSE);
 
     LeaveCriticalSection( &PROFILE_CritSect );
 


More information about the wine-patches mailing list