[dlls/shell32/shell.c] Strncpy elimnation :-) Rewrite of DoEnvironmentSubst16

Peter Berg Larsen pebl at math.ku.dk
Fri Apr 15 17:57:26 CDT 2005


http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/doenvironmentsubst.asp

The old code did not leave str intact if the keyword was not found, as it
returned false before rewriting the '%'.  Secondly it seems that it is
perfectly valid to miss a keyword, the %keyword% should be left intact. Do
test this rewrite some more.

Changelog:
         Rewritten DoEnvironmentSubst16.


Index: dlls/shell32/shell.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/shell.c,v
retrieving revision 1.62
diff -u -r1.62 shell.c
--- dlls/shell32/shell.c        21 Mar 2005 11:25:13 -0000      1.62
+++ dlls/shell32/shell.c        15 Apr 2005 20:14:43 -0000
@@ -363,74 +363,82 @@
  *                             DoEnvironmentSubst      [SHELL.37]
  *
  * Replace %KEYWORD% in the str with the value of variable KEYWORD
- * from "DOS" environment.
+ * from "DOS" environment. If it is not found the %KEYWORD% is left
+ * intact. If the buffer is too small, str is not modified.
+ *
+ * str         [I] '\0' terminated string with %keyword%.
+ *             [O] '\0' terminated string with %keyword% substituted.
+ * length      [I] size of str.
+ *
+ * Return
+ *     str length in the LOWORD and 1 in HIWORD if subst was successful.
  */
 DWORD WINAPI DoEnvironmentSubst16(LPSTR str,WORD length)
 {
   LPSTR   lpEnv = MapSL(GetDOSEnvironment16());
-  LPSTR   lpBuffer = HeapAlloc( GetProcessHeap(), 0, length);
   LPSTR   lpstr = str;
-  LPSTR   lpbstr = lpBuffer;
+  LPSTR   lpend;
+  LPSTR   lpBuffer = HeapAlloc( GetProcessHeap(), 0, length);
+  WORD    bufCnt = 0;
+  WORD    envKeyLen;
+  LPSTR   lpKey;
+  WORD    retStatus = 0;
+  WORD    retLength = length;

   CharToOemA(str,str);

   TRACE("accept %s\n", str);

-  while( *lpstr && lpbstr - lpBuffer < length )
-   {
-     LPSTR lpend = lpstr;
-
-     if( *lpstr == '%' )
-       {
-         do { lpend++; } while( *lpend && *lpend != '%' );
-         if( *lpend == '%' && lpend - lpstr > 1 )      /* found key */
-           {
-              LPSTR lpKey;
-             *lpend = '\0';
-              lpKey = SHELL_FindString(lpEnv, lpstr+1);
-              if( lpKey )                              /* found key value */
-                {
-                  int l = strlen(lpKey);
-
-                  if( l > length - (lpbstr - lpBuffer) - 1 )
-                    {
-           WARN("-- Env subst aborted - string too short\n");
-                     *lpend = '%';
-                      break;
-                    }
-                  strcpy(lpbstr, lpKey);
-                  lpbstr += l;
-                }
-              else break;
-             *lpend = '%';
-              lpstr = lpend + 1;
-           }
-         else break;                                   /* back off and whine */
-
-         continue;
-       }
-
-     *lpbstr++ = *lpstr++;
-   }
-
- *lpbstr = '\0';
-  if( lpstr - str == strlen(str) )
-    {
-      strncpy(str, lpBuffer, length);
-      length = 1;
-    }
-  else
-      length = 0;
-
+  while( *lpstr && bufCnt <= length - 1 ) {
+     if ( *lpstr != '%' ) {
+        lpBuffer[bufCnt++] = *lpstr++;
+        continue;
+     }
+
+     for( lpend = lpstr + 1; *lpend && *lpend != '%'; lpend++) /**/;
+
+     envKeyLen = lpend - lpstr - 1;
+     if( *lpend != '%' || envKeyLen == 0)
+        goto err; /* "%\0" or "%%" found; back off and whine */
+
+     *lpend = '\0';
+     lpKey = SHELL_FindString(lpEnv, lpstr+1);
+     *lpend = '%';
+     if( lpKey ) {
+         int l = strlen(lpKey);
+
+         if( bufCnt + l > length - 1 )
+                goto err;
+
+        memcpy(lpBuffer + bufCnt, lpKey, l);
+        bufCnt += l;
+     } else { /* Keyword not found; Leave the %KEYWORD% intact */
+        if( bufCnt + envKeyLen + 2 > length - 1 )
+            goto err;
+
+         memcpy(lpBuffer + bufCnt, lpstr, envKeyLen + 2);
+        bufCnt += envKeyLen + 2;
+     }
+
+     lpstr = lpend + 1;
+  }
+
+  if (!*lpstr && bufCnt <= length - 1) {
+      memcpy(str,lpBuffer, bufCnt);
+      str[bufCnt] = '\0';
+      retLength = bufCnt + 1;
+      retStatus = 1;
+  }
+
+  err:
+  if (!retStatus)
+      WARN("-- Env subst aborted - string too short or invalid input\n");
   TRACE("-- return %s\n", str);

   OemToCharA(str,str);
   HeapFree( GetProcessHeap(), 0, lpBuffer);

-  /*  Return str length in the LOWORD
-   *  and 1 in HIWORD if subst was successful.
-   */
- return (DWORD)MAKELONG(strlen(str), length);
+  return (DWORD)MAKELONG(retLength, retStatus);
 }


/*************************************************************************





More information about the wine-patches mailing list