preferable GetDateFormatW fix

Medland, Bill Bill.Medland at accpac.com
Wed Oct 23 22:52:27 CDT 2002


Bill Medland (medbi01 at accpac.com)
Fix OLE_GetFormatW so that GetDateFormatW works
Rearranged for simplicity

Index: wine/ole/ole2nls.c
===================================================================
RCS file: /home/wine/wine/ole/ole2nls.c,v
retrieving revision 1.105
diff -u -r1.105 ole2nls.c
--- wine/ole/ole2nls.c	3 Oct 2002 22:57:55 -0000	1.105
+++ wine/ole/ole2nls.c	24 Oct 2002 03:34:12 -0000
@@ -1572,26 +1572,15 @@
 
 
/***************************************************************************
***
  * OLE_GetFormatW [INTERNAL]
+ *
+ * dateformat is set TRUE if being called for a date, false for a time
  */
 static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags,
 			    const SYSTEMTIME* xtime,
 			    LPCWSTR format,
-			    LPWSTR output, INT outlen)
+			    LPWSTR output, INT outlen, int dateformat)
 {
-   INT   inpos, outpos;
-   int     count, type=0, inquote;
-   int     Overflow; /* loop check */
-   char    tmp[16];
-   WCHAR   buf[40];
-   int     buflen=0;
-   WCHAR   arg0[] = {0}, arg1[] = {'%','d',0};
-   WCHAR   arg2[] = {'%','0','2','d',0};
-   WCHAR  *argarr[3];
-   int     datevars=0, timevars=0;
-
-   argarr[0] = arg0;
-   argarr[1] = arg1;
-   argarr[2] = arg2;
+   INT     outpos;
 
    /* make a debug report */
    TRACE("args: 0x%lx, 0x%lx, 0x%lx, time(d=%d,h=%d,m=%d,s=%d), fmt:%s (at
%p), "
@@ -1600,55 +1589,50 @@
 	 xtime->wDay, xtime->wHour, xtime->wMinute, xtime->wSecond,
 	 debugstr_w(format), format, output, outlen);
 
-   if(outlen == 0) {
-     FIXME("outlen = 0, returning 255\n");
-     return 255;
-   }
-
    /* initialize state variables */
-   inpos = outpos = 0;
-   count = 0;
-   inquote = Overflow = 0;
-   /* this is really just a sanity check */
-   output[0] = buf[0] = 0;
-
-   /* this loop is the core of the function */
-   for (inpos = 0; /* we have several break points */ ; inpos++) {
-      if (inquote) {
-	 if (format[inpos] == (WCHAR) '\'') {
-	    if (format[inpos+1] == '\'') {
-	       inpos++;
-	       output[outpos++] = '\'';
-	    } else {
-	       inquote = 0;
-	       continue;
-	    }
-	 } else if (format[inpos] == 0) {
-	    output[outpos++] = 0;
-	    if (outpos > outlen) Overflow = 1;
-	    break;  /*  normal exit (within a quote) */
-	 } else {
-	    output[outpos++] = format[inpos]; /* copy input */
-	    if (outpos > outlen) {
-	       Overflow = 1;
-	       output[outpos-1] = 0;
-	       break;
-	    }
-	 }
-      } else if (  (count && (format[inpos] != type))
-		   || ( (count==4 && type =='y') ||
-			(count==4 && type =='M') ||
-			(count==4 && type =='d') ||
-			(count==2 && type =='g') ||
-			(count==2 && type =='h') ||
-			(count==2 && type =='H') ||
-			(count==2 && type =='m') ||
-			(count==2 && type =='s') ||
-			(count==2 && type =='t') )  ) {
-          switch(type)
-          {
+   outpos = 0;
+
+   while (*format) {
+      /* Literal string: Maybe terminated early by a \0 */
+      if (*format == (WCHAR) '\'') {
+         format++;
+         while (*format) {
+            if (*format == (WCHAR) '\'') {
+               format++;
+               if (*format != '\'') {
+                  break; /* It was a terminating quote */
+               }
+            }
+            if (!outlen)
+               /* We are counting */;
+            else if (outpos >= outlen)
+               goto too_short;
+            else
+               output[outpos] = *format;
+            outpos++;
+            format++;
+         }
+      } else if ( (dateformat &&  (*format=='d' ||
+				   *format=='M' ||
+				   *format=='y' ||
+				   *format=='g')  ) ||
+		  (!dateformat && (*format=='H' ||
+				   *format=='h' ||
+				   *format=='m' ||
+				   *format=='s' ||
+				   *format=='t') )    ) {
+         int type, count;
+         char    tmp[16];
+         WCHAR   buf[40];
+         int     buflen=0;
+         type = *format;
+         format++;
+         for (count = 1; *format == type; format++)
+            count++;
+         switch(type)
+         {
           case 'd':
-	    if        (count == 4) {
+	    if        (count >= 4) {
 	       GetLocaleInfoW(locale,
 			     LOCALE_SDAYNAME1 + (xtime->wDayOfWeek +6)%7,
 			     buf, sizeof(buf)/sizeof(WCHAR) );
@@ -1664,7 +1648,7 @@
             break;
 
           case 'M':
-	    if        (count == 4) {
+	    if        (count >= 4) {
 	       GetLocaleInfoW(locale,  LOCALE_SMONTHNAME1 +
 				xtime->wMonth -1, buf,
 				sizeof(buf)/sizeof(WCHAR) );
@@ -1678,12 +1662,10 @@
 	    }
             break;
           case 'y':
-	    if        (count == 4) {
+	    if        (count >= 4) {
                 sprintf( tmp, "%d", xtime->wYear );
-	    } else if (count == 3) {
-                strcpy( tmp, "yyy" );
 	    } else {
-                sprintf( tmp, "%.*d", count, xtime->wYear % 100 );
+                sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wYear %
100 );
 	    }
             MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf,
sizeof(buf)/sizeof(WCHAR) );
             break;
@@ -1701,22 +1683,22 @@
 
           case 'h':
               /* hours 1:00-12:00 --- is this right? */
-              sprintf( tmp, "%.*d", count, (xtime->wHour-1)%12 +1);
+              sprintf( tmp, "%.*d", count > 2 ? 2 : count,
(xtime->wHour-1)%12 +1);
               MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf,
sizeof(buf)/sizeof(WCHAR) );
               break;
 
           case 'H':
-              sprintf( tmp, "%.*d", count, xtime->wHour );
+              sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wHour );
               MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf,
sizeof(buf)/sizeof(WCHAR) );
               break;
 
           case 'm':
-              sprintf( tmp, "%.*d", count, xtime->wMinute );
+              sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wMinute
);
               MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf,
sizeof(buf)/sizeof(WCHAR) );
               break;
 
           case 's':
-              sprintf( tmp, "%.*d", count, xtime->wSecond );
+              sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wSecond
);
               MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf,
sizeof(buf)/sizeof(WCHAR) );
               break;
 
@@ -1728,71 +1710,49 @@
 	       buf[1] = 0;
 	    }
             break;
-          }
-
-	 /* no matter what happened,  we need to check this next
-	    character the next time we loop through */
-	 inpos--;
+         }
 
 	 /* cat buf onto the output */
-	 outlen = strlenW(buf);
-	 if (outpos + buflen < outlen) {
+	 buflen = strlenW(buf);
+         if (!outlen)
+            /* We are counting */;
+         else if (outpos + buflen < outlen) {
             strcpyW( output + outpos, buf );
-	    outpos += buflen;
 	 } else {
             lstrcpynW( output + outpos, buf, outlen - outpos );
-	    Overflow = 1;
-	    break; /* Abnormal exit */
+            /* Is this an undocumented feature we are supporting? */
+            goto too_short;
 	 }
-
-	 /* reset the variables we used this time */
-	 count = 0;
-	 type = '\0';
-      } else if (format[inpos] == 0) {
-	 /* we can't check for this at the beginning,  because that
-	 would keep us from printing a format spec that ended the
-	 string */
-	 output[outpos] = 0;
-	 break;  /*  NORMAL EXIT  */
-      } else if (count) {
-	 /* how we keep track of the middle of a format spec */
-	 count++;
-	 continue;
-      } else if ( (datevars && (format[inpos]=='d' ||
-				format[inpos]=='M' ||
-				format[inpos]=='y' ||
-				format[inpos]=='g')  ) ||
-		  (timevars && (format[inpos]=='H' ||
-				format[inpos]=='h' ||
-				format[inpos]=='m' ||
-				format[inpos]=='s' ||
-				format[inpos]=='t') )    ) {
-	 type = format[inpos];
-	 count = 1;
-	 continue;
-      } else if (format[inpos] == '\'') {
-	 inquote = 1;
-	 continue;
+	 outpos += buflen;
       } else {
-	 /* unquoted literals */
-	 output[outpos++] = format[inpos];
+         /* a literal character */
+         if (!outlen)
+            /* We are counting */;
+         else if (outpos >= outlen)
+            goto too_short;
+         else
+            output[outpos] = *format;
+         outpos++;
+         format++;
       }
    }
 
-   if (Overflow) {
-      SetLastError(ERROR_INSUFFICIENT_BUFFER);
-      WARN(" buffer overflow\n");
-   };
-
    /* final string terminator and sanity check */
+   if (!outlen)
+      /* We are counting */;
+   else if (outpos >= outlen)
+      goto too_short;
+   else
+      output[outpos] = '\0';
    outpos++;
-   if (outpos > outlen-1) outpos = outlen-1;
-   output[outpos] = '0';
 
-   TRACE(" returning %s\n", debugstr_w(output));
-
-   return (!Overflow) ? outlen : 0;
+   TRACE(" returning %d %s\n", outpos, debugstr_w(output));
+   return outpos;
 
+too_short:
+   SetLastError(ERROR_INSUFFICIENT_BUFFER);
+   WARN(" buffer overflow\n");
+   return 0;
 }
 
 
@@ -1910,6 +1870,17 @@
     TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",
 	  locale,flags,xtime,debugstr_w(format),date,datelen);
     
+    /* Tests (could be left until OLE_GetFormatW) */
+    if (flags && format)
+    {
+        SetLastError (ERROR_INVALID_FLAGS);
+	return 0;
+    }
+    if (datelen && !date)
+    {
+        SetLastError (ERROR_INVALID_PARAMETER);
+	return 0;
+    }
     if (!locale) {
 	locale = LOCALE_SYSTEM_DEFAULT;
     };
@@ -1950,7 +1921,7 @@
     
     
     ret = OLE_GetFormatW(thislocale, flags, 0, thistime, thisformat,
-			 date, datelen);
+			 date, datelen, 1);
     
     
     TRACE("GetDateFormatW() returning %d, with data=%s\n",
@@ -3067,7 +3038,7 @@
 	}
 
 	ret = OLE_GetFormatW(thislocale, thisflags, flags, thistime,
thisformat,
-  			 timestr, timelen);
+  			 timestr, timelen, 0);
 	return ret;
 }
 
Index: wine/dlls/kernel/tests/locale.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/tests/locale.c,v
retrieving revision 1.4
diff -u -r1.4 locale.c
--- wine/dlls/kernel/tests/locale.c	4 Jun 2002 22:12:50 -0000	1.4
+++ wine/dlls/kernel/tests/locale.c	24 Oct 2002 03:34:12 -0000
@@ -30,6 +30,7 @@
 #define BUFFER_SIZE		50
 /* Buffer used by callback function */
 char GlobalBuffer[BUFFER_SIZE];
+#define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
 
 /* TODO :
  * Unicode versions
@@ -183,6 +184,58 @@
 	eq (ret, 0, "GetDateFormat with len=2", "%d");
 }
 
+void TestGetDateFormatW()
+{
+    int ret, error, cmp;
+    SYSTEMTIME  curtime;
+    WCHAR buffer[BUFFER_SIZE], format[BUFFER_SIZE], Expected[BUFFER_SIZE];
+    LCID lcid;
+
+    lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
SORT_DEFAULT );
+
+    /* 1. Error cases */
+
+    /* 1a If flags is not zero then format must be null. */
+    ret = GetDateFormatW (LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
format, buffer, sizeof(buffer)/sizeof(buffer[0]));
+    error = ret ? 0 : GetLastError();
+    ok (ret == 0 && error == ERROR_INVALID_FLAGS, "GetDateFormatW allowed
flags and format");
+
+    /* 1b The buffer can only be null if the count is zero */
+    /* For the record other bad pointers result in a page fault (Win98) */
+    ret = GetDateFormatW (LOCALE_SYSTEM_DEFAULT, 0, NULL, format, NULL,
sizeof(buffer)/sizeof(buffer[0]));
+    error = ret ? 0 : GetLastError();
+    ok (ret == 0 && error == ERROR_INVALID_PARAMETER, "GetDateFormatW did
not detect null buffer pointer.");
+    ret = GetDateFormatW (LOCALE_SYSTEM_DEFAULT, 0, NULL, format, NULL, 0);
+    error = ret ? 0 : GetLastError();
+    ok (ret != 0 && error == 0, "GetDateFormatW did not permit null buffer
pointer when counting.");
+
+    /* 1c An incorrect day of week is corrected. */
+    curtime.wYear = 2002;
+    curtime.wMonth = 10;
+    curtime.wDay = 23;
+    curtime.wDayOfWeek = 5; /* should be 3 - Wednesday */
+    curtime.wHour = 0;
+    curtime.wMinute = 0;
+    curtime.wSecond = 0;
+    curtime.wMilliseconds = 234;
+    MultiByteToWideChar (CP_ACP, 0, "dddd d MMMM yyyy", -1, format,
COUNTOF(format));
+    ret = GetDateFormatW (lcid, 0, &curtime, format, buffer,
COUNTOF(buffer));
+    error = ret ? 0 : GetLastError();
+    MultiByteToWideChar (CP_ACP, 0, "Wednesday 23 October 2002", -1,
Expected, COUNTOF(Expected));
+    cmp = ret ? lstrcmpW (buffer, Expected) : 2;
+    ok (ret == lstrlenW(Expected)+1 && error == 0 && cmp == 0, "Day of week
correction failed\n");
+
+    /* 1d Invalid year, month or day results in error */
+
+    /* 1e Insufficient space results in error */
+
+    /* 2. Standard behaviour */
+    /* 1c is a reasonable test */
+
+    /* 3. Replicated undocumented behaviour */
+    /* e.g. unexepected characters are retained. */
+}
+
 
 void TestGetCurrencyFormat()
 {
@@ -343,6 +396,7 @@
 	TestGetLocaleInfoA();
 	TestGetTimeFormatA();
 	TestGetDateFormatA();
+	TestGetDateFormatW();
 	TestGetNumberFormat();
 	TestGetCurrencyFormat();
 	TestCompareStringA();



More information about the wine-patches mailing list