get GetDateFormatW somewhat working...

Arthur L. Jones aljones at lbl.gov
Thu Sep 19 16:25:48 CDT 2002


Changelog:
     re-did OLE_GetFormatW so that dates are
         formatted correctly for the XP app i am using

    caveats: it just does what i needed, i attempted to
        follow the docs on msdn but i have not tested anything
        but a few basic dates.  also, rather than figure out the
        old OLE_GetFormatW i just reimplemented it, as
        i figured it would take less time to do it this way, but i'm
        sure it would be a better patch if i just fixed what didn't
        work in OLE_GetFormatW.

    notes:  it seems like, if this ever worked correctly, that
        OLE_GetFormatA could be implemented by just copying
        the ascii buffer and sending it along to OLE_GetFormatW?


-------------- next part --------------
Index: ole/ole2nls.c
===================================================================
RCS file: /home/wine/wine/ole/ole2nls.c,v
retrieving revision 1.104
diff -r1.104 ole2nls.c
1573a1574,1583
>  * OLE_GetRepW [INTERNAL]
>  * 
>  * get count of repetitions of c...
>  */
> static INT OLE_GetRepW(LPCWSTR s, WCHAR c) 
> { 
>    int i = 0; while (s[i] == c) i++; return i; 
> }
> 
> /******************************************************************************
1574a1585,1633
>  *
>  *
>  * dwFlags[in]:
>  *   LOCALE_NOUSEROVERRIDE    : format the struct using system default date format
>  *   LOCALE_USE_CP_ACP        :
>  *   DATE_SHORTDATE
>  *   DATE_LONGDATE
>  *   DATE_YEARMONTH
>  *   DATE_USE_ALT_CALENDAR
>  *   DATE_LTRREADING
>  *   DATE_RTLREADING
>  *
>  * xtime: pointer to SYSTEMTIME. if null, use current local system date
>  * 
>  * format: if null, use date format of locale
>  *   d    day as digits with no leading zero
>  *   dd   day as digits with leading zero
>  *   ddd  day as 3 char abbrev.  uses LOCALE_SABBREVDAYNAME
>  *   dddd day as full name.  uses LOCALE_SDAYNAME
>  *   M    month as digits, no leading zero
>  *   MM   month as digits, leading zero
>  *   MMM  month as 3 char abbrev.  uses LOCALE_SABBREVMONTHNAME
>  *   MMMM month as full name.  uses LOCALE_SMONTHNAME
>  *   y    year as last two digits, no leading zero
>  *   yy   year as last two digits, leading zero
>  *   yyyy year as four digits
>  *   gg   period, or era string.  uses CAL_SERASTRING, not
>  *        used if date does not have an era or period string
>  *   h    hours, no leading zero, 12hr clock
>  *   hh   hours, leading zero, 12hr clock
>  *   H    hours, no leading zero, 24hr clock
>  *   HH   hours, leading zero, 24hr clock
>  *   m    minutes, no leading zero
>  *   mm   minutes, leading zero
>  *   s    seconds, no leading zero
>  *   ss   seconds, leading zero
>  *   t    A or P
>  *   tt   AM or PM
>  *
>  * output: zero terminated buffer
>  * 
>  * outlen: specifies len of output.  if
>  * zero, the function returns the number of chars required
>  * to format the date...
>  *
>  * FIXME: 
>  *   verify xtime!
>  *   flags: DATE_USE_ALT_CALENDAR, DATE_LTREADING, DATE_RTREADING
>  *
1577,1579c1636,1638
< 			    const SYSTEMTIME* xtime,
< 			    LPCWSTR format,
< 			    LPWSTR output, INT outlen)
---
> 			 const SYSTEMTIME* xtime,
> 			 LPCWSTR format,
> 			 LPWSTR output, INT outlen)
1581,1595c1640
<    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     inpos = 0, outpos = 0;
1602,1624c1647,1669
< 
<    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;
---
>    
>    /* outlen must make sense 
>     */
>    if (outlen<0) outlen = 0;
>    if (outlen==0) output=NULL;
> 
>    while (format[inpos]) {
>       WCHAR tmp[256];
>       int tl = 0;
>       char b[256];
>       
>       /* printf("format[%d]: %02x [%c] -> %d\n", inpos, format[inpos], format[inpos], outpos); */
>       
>       if (format[inpos] == (WCHAR) '\'') {
> 	 inpos++;
> 	 while (format[inpos]) {
> 	    if (format[inpos]==(WCHAR)'\'') {
> 	       /* ''' -> ' otherwise exit...
> 		*/
> 	       if (OLE_GetRepW(format+inpos, (WCHAR) '\'')>=3) {
> 		  inpos+=2;
> 	       }
> 	       else break;
1626,1635c1671,1679
< 	 } 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;
---
> 	    if (output!=NULL) {
> 	       if (outpos<outlen) {
> 		  output[outpos] = format[inpos];
> 	       }
> 	       else {
> 		  SetLastError(ERROR_INSUFFICIENT_BUFFER);
> 		  if (outpos>0) output[outpos-1] = 0;
> 		  return 0;
> 	       }
1636a1681,1682
> 	    outpos++;
> 	    inpos++;
1638,1724c1684,1759
<       } 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)
<           {
<           case 'd':
< 	    if        (count == 4) {
< 	       GetLocaleInfoW(locale,
< 			     LOCALE_SDAYNAME1 + (xtime->wDayOfWeek +6)%7,
< 			     buf, sizeof(buf)/sizeof(WCHAR) );
< 	    } else if (count == 3) {
< 	       GetLocaleInfoW(locale,
< 				LOCALE_SABBREVDAYNAME1 +
< 				(xtime->wDayOfWeek +6)%7,
< 				buf, sizeof(buf)/sizeof(WCHAR) );
< 	    } else {
<                 sprintf( tmp, "%.*d", count, xtime->wDay );
<                 MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
< 	    }
<             break;
< 
<           case 'M':
< 	    if        (count == 4) {
< 	       GetLocaleInfoW(locale,  LOCALE_SMONTHNAME1 +
< 				xtime->wMonth -1, buf,
< 				sizeof(buf)/sizeof(WCHAR) );
< 	    } else if (count == 3) {
< 	       GetLocaleInfoW(locale,  LOCALE_SABBREVMONTHNAME1 +
< 				xtime->wMonth -1, buf,
< 				sizeof(buf)/sizeof(WCHAR) );
< 	    } else {
<                 sprintf( tmp, "%.*d", count, xtime->wMonth );
<                 MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
< 	    }
<             break;
<           case 'y':
< 	    if        (count == 4) {
<                 sprintf( tmp, "%d", xtime->wYear );
< 	    } else if (count == 3) {
<                 strcpy( tmp, "yyy" );
< 	    } else {
<                 sprintf( tmp, "%.*d", count, xtime->wYear % 100 );
< 	    }
<             MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
<             break;
< 
<           case 'g':
< 	    if        (count == 2) {
< 	       FIXME("LOCALE_ICALENDARTYPE unimplemented\n");
<                strcpy( tmp, "AD" );
< 	    } else {
< 	       /* Win API sez we copy it verbatim */
<                 strcpy( tmp, "g" );
< 	    }
<             MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
<             break;
< 
<           case 'h':
<               /* hours 1:00-12:00 --- is this right? */
<               sprintf( tmp, "%.*d", 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 );
<               MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
<               break;
< 
<           case 'm':
<               sprintf( tmp, "%.*d", count, xtime->wMinute );
<               MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
<               break;
< 
<           case 's':
<               sprintf( tmp, "%.*d", count, xtime->wSecond );
<               MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
<               break;
< 
<           case 't':
< 	    GetLocaleInfoW(locale, (xtime->wHour < 12) ?
---
> 	 if (format[inpos]) inpos++;
>       }
>       else if (format[inpos] == (WCHAR) 'd') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'd');
> 	 inpos += cnt;
> 	 if (cnt==1 || cnt==2) {
> 	    sprintf(b, (cnt==1) ? "%d" : "%02d", xtime->wDay);
> 	    tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0]));
> 	 }
> 	 else {
> 	    const int dow = (xtime->wDayOfWeek+6)%7;
> 	    tl = GetLocaleInfoW(locale, 
> 				((cnt==3) ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1) + dow,
> 				tmp, sizeof(tmp)/sizeof(tmp[0]));
> 	 }
>       }
>       else if (format[inpos] == (WCHAR) 'M') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'M');
> 	 const int mn = xtime->wMonth;
> 	 inpos += cnt;
> 	 if (cnt==1 || cnt==2) {
> 	    sprintf(b, (cnt==1) ? "%d" : "%02d", mn);
> 	    tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0]));
> 	 }
> 	 else {
> 	    tl = GetLocaleInfoW(locale, 
> 				((cnt==3) ? LOCALE_SABBREVMONTHNAME1 : LOCALE_SMONTHNAME1) + mn,
> 				tmp, sizeof(tmp)/sizeof(tmp[0]));
> 	 }
>       }
>       else if (format[inpos] == (WCHAR) 'y') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'y');
> 	 const int yr = xtime->wYear;
> 	 inpos += cnt;
> 	 if (cnt==1 || cnt==2) {
> 	    sprintf(b, (cnt==1) ? "%d" : "%02d", yr%100);
> 	 }
> 	 else sprintf(b, "%d", yr);
> 	 tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0]));
>       }
>       else if (format[inpos] == (WCHAR) 'g') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'g');
> 	 inpos += cnt;
> 	 /* FIXME: which calendar id?  we use 0...
> 	  */
> 	 tl = GetCalendarInfoW(locale, 0, CAL_SERASTRING,
> 			       tmp, sizeof(tmp)/sizeof(tmp[0]), NULL);
>       }
>       else if (format[inpos] == (WCHAR) 'h') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'h');
> 	 inpos += cnt;
> 	 sprintf(b, (cnt==1) ? "%d" : "%02d", (xtime->wHour-1)%12+1);
> 	 tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0]));
>       }
>       else if (format[inpos] == (WCHAR) 'H') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'H');
> 	 inpos += cnt;
> 	 sprintf(b, (cnt==1) ? "%d" : "%02d", xtime->wHour);
> 	 tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0]));
>       }
>       else if (format[inpos] == (WCHAR) 'm') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'm');
> 	 inpos += cnt;
> 	 sprintf(b, (cnt==1) ? "%d" : "%02d", xtime->wMinute);
> 	 tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0]));
>       }
>       else if (format[inpos] == (WCHAR) 's') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 's');
> 	 inpos += cnt;
> 	 sprintf(b, (cnt==1) ? "%d" : "%02d", xtime->wSecond);
> 	 tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0]));
>       }
>       else if (format[inpos] == (WCHAR) 't') {
> 	 const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 't');
> 	 inpos += cnt;
> 	 tl = GetLocaleInfoW(locale, (xtime->wHour < 12) ?
1726,1731c1761,1771
< 			     buf, sizeof(buf) );
< 	    if        (count == 1) {
< 	       buf[1] = 0;
< 	    }
<             break;
<           }
---
> 			     tmp, sizeof(tmp)/sizeof(tmp[0]));
> 	 if (cnt==1 && tl>1) { tmp[1] = 0;  tl = 2; }
>       }
>       /* default case, just copy output char...
>        */
>       else {
> 	 tl = 2;
> 	 tmp[0] = format[inpos];
> 	 tmp[1] = 0;
> 	 inpos++;
>       }
1733,1745c1773,1787
< 	 /* 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) {
<             strcpyW( output + outpos, buf );
< 	    outpos += buflen;
< 	 } else {
<             lstrcpynW( output + outpos, buf, outlen - outpos );
< 	    Overflow = 1;
< 	    break; /* Abnormal exit */
---
>       /* some characters buffered -- put them in output...
>        */
>       if (tl>0) {
> 	 if (output!=NULL) {
> 	    int j;
> 	    for (j=0; j<tl-1; j++) {
> 	       if (outpos+j<outlen) {
> 		  output[outpos+j] = tmp[j];
> 	       }
> 	       else {
> 		  if (outpos+j>0 && outlen>0) output[outpos+j-1] = 0;
> 		  SetLastError(ERROR_INSUFFICIENT_BUFFER);
> 		  return 0;
> 	       }
> 	    }
1746a1789,1791
> 	 outpos+=tl-1;
>       }
>    }
1748,1754c1793,1794
< 	 /* 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 */
---
>    if (output!=NULL) {
>       if (outpos<outlen) {
1756,1778c1796,1799
< 	 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;
<       } else {
< 	 /* unquoted literals */
< 	 output[outpos++] = format[inpos];
---
> 	 outpos++;
>       }
>       else {
> 	 output[outpos-1]=0;
1782,1795c1803
<    if (Overflow) {
<       SetLastError(ERROR_INSUFFICIENT_BUFFER);
<       WARN(" buffer overflow\n");
<    };
< 
<    /* final string terminator and sanity check */
<    outpos++;
<    if (outpos > outlen-1) outpos = outlen-1;
<    output[outpos] = '0';
< 
<    TRACE(" returning %s\n", debugstr_w(output));
< 
<    return (!Overflow) ? outlen : 0;
< 
---
>    return outpos;
1798d1805
< 
1901c1908,1915
<    unsigned short datearr[] = {'1','9','9','4','-','1','-','1',0};
---
>   WCHAR format_buf[40];
>   LPCWSTR thisformat;
>   SYSTEMTIME t;
>   LPSYSTEMTIME thistime;
>   LCID thislocale;
>   INT ret;
>   FILETIME ft;
>   BOOL res;
1903,1905c1917,1918
<    FIXME("STUB (should call OLE_GetFormatW)\n");
<    lstrcpynW(date, datearr, datelen);
<    return (  datelen < 9) ? datelen : 9;
---
>   TRACE("(0x%04lx,0x%08lx,%p,%p,%p,%d)\n",
> 	      locale,flags,xtime,format,date,datelen);
1906a1920,1922
>   if (!locale) {
>      locale = LOCALE_SYSTEM_DEFAULT;
>      };
1907a1924,1967
>   if (locale == LOCALE_SYSTEM_DEFAULT) {
>      thislocale = GetSystemDefaultLCID();
>   } else if (locale == LOCALE_USER_DEFAULT) {
>      thislocale = GetUserDefaultLCID();
>   } else {
>      thislocale = locale;
>   };
>   
> 
>   if (xtime == NULL) {
>      GetSystemTime(&t);
>   } else {
>       /* Silently correct wDayOfWeek by transforming to FileTime and back again */
>       res=SystemTimeToFileTime(xtime,&ft);
>       /* Check year(?)/month and date for range and set ERROR_INVALID_PARAMETER  on error */
>       /*FIXME: SystemTimeToFileTime doesn't yet do that check */
>       if(!res)
> 	{
> 	  SetLastError(ERROR_INVALID_PARAMETER);
> 	  return 0;
> 	}
>       FileTimeToSystemTime(&ft,&t);
> 
>   };
>   thistime = &t;
> 
>   if (format == NULL) {
>      GetLocaleInfoW(thislocale, ((flags&DATE_LONGDATE)
> 				   ? LOCALE_SLONGDATE
> 				   : LOCALE_SSHORTDATE),
> 		      format_buf, sizeof(format_buf));
>      thisformat = format_buf;
>   } else {
>      thisformat = format;
>   };
> 
> 
>   ret = OLE_GetFormatW(thislocale, flags, 0, thistime, thisformat,
> 		       date, datelen);
> 
>    TRACE(
> 	       "GetDateFormatW() returning %d, with data=%p\n",
> 	       ret, date);
>   return ret;


More information about the wine-patches mailing list