I should have responded earlier to this thread, but for what it's 
worth, here's the scoop (note that I'm referring to 3.5 headers in 
all notes below)...

1. The APIs for DateToAscii and DateToDOWDMFormat both assume that 
you pass them big enough string buffers. The documentation for "how 
big is big enough" has been wrong since the beginning of time, and is 
still slightly in error with the current 3.5 PDFs, but that will be 
corrected in the near future.

2. For DateToAscii, the string buffer (including the terminating null 
byte) needs to be dateStringLength (==9) if the format passed to the 
routine is one of the "short" date formats, and 
longDateStrLength(==15) if you pass it one of the "long" date formats.

The short date formats are dfMDYWithSlashes through dfYMDWithSlashes, 
while the long date formats are dfMDYLongWithComma through 
dfYMDLongWithSpace.

Note that no max buffer size constants have ever been defined for the 
medium length date formats (dfMYMed and dfMYMedNoPost), but older 
versions of the ROM would fill longDateStrLength bytes with 0xFE, so 
use the long limit.

2. DateToDOWDMFormat also needs a buffer for the resulting formatted 
string, but this buffer will obviously need to be bigger than what's 
required for just the date (since the day of week name gets added). 
Before 3.5, no limits were defined for this routine. Most apps were 
written using a size of dateStringLength + 4 for short formats, and 
longDateStrLength + 4 for long formats.

Unfortunately this assumes that the day of week name will only 
require an additional four bytes. While this is true for English and 
most European languages, it isn't the case world-wide.

For this reason, when the new dowDateStringLength and 
dowLongDateStrLength constants were defined, they were expanded to be 
19 and 25 bytes respectively.

3. Starting with the debugging 2.0 ROMs, code was added to 
DateToAscii and DateToDOWDMFormat to flush out problems with 
undersized buffers. This code fills the string buffer with 0xFE, up 
to the appropriate limit, based on the requested date format.

Unfortunately what's missing are better ways of catching when a 
buffer is too small. One particularly difficult problem to debug is 
when you've got a form label which isn't long enough. For example, 
you've got a label in your form set to "XXXXXXXXXXXXXXXXXXX", which 
is 19 bytes, or something that you thought was long enough to handle 
a long date format with the day of week name. Then you do something 
in your code like:

        FormType* frmP = FrmGetActiveForm();
        DateToDOWDMFormat(month, day, year, format, FrmGetLabel(frmP, 
labelIndex));

What happens is that the debug ROM code will write past the end of 
the space in the form data that's been reserved for the label text, 
and tromp over the following form object's data. Sometimes this 
corrupts the following object's id, or its location, or its 
attributes, etc. The problem doesn't show up until later, when 
redrawing or tapping or whatever doesn't work properly.

For these type of embedded form text fields, we can (and will) do a 
better job of detecting over-writes in the future, probably via an 
extra guard byte inserted at the end of each text block. For now, it 
would be wise to examine any form objects which are dynamically 
formatted with dates, and ensure that they have enough space reserved.

4. To summarize the main points:

a. Previous documentation regarding date format buffer sizes was wrong.
b. The buffer size limits for DateToAscii haven't changed.
c. The buffer size limits for DateToDOWDMFormat have increased.

5. So does the change mentioned in 4c above create a backwards 
compatibility problem? No, as Jim Schram pointed out this is a 
forwards compatibility problem which only exists on the debug ROMs. 
Older apps that call DateToDOWDMFormat with smaller string buffers 
will encounter errors when run on 3.5 debug ROMs.

The two areas where we didn't do a good job w/3.5 were publicizing 
this change, and providing more help in detecting problems caused by 
under-sized buffers.

Note that calling DateToDOWDMFormat with a buffer of size 
longDateStrLength (==15) bytes would have failed on older ROMs, if 
the format was something like dfDMYLongWithComma, since the resulting 
string (even in the US) would look like "Mon 31 Jan, 2000", which 
needs 17 total bytes in the buffer.

5. There's a new routine in 3.5, called DateTemplateToAscii, that 
addresses most of the shortcomings of the DateToAscii and 
DateToDOWDMFormat routines. If we're lucky, it will get documented 
soon. A rough description of the routine follows:

UInt16 DateTemplateToAscii(const Char *templateP, UInt8 months,
        UInt8 days, UInt16 years, Char *stringP, Int16 stringLen);

This routine uses the template text contained in <templateP>, and 
creates a properly formatted date string in <stringP> for the values 
passed in <months>, <days>, and <years>.

Parameters:
templateP - pointer to the template string. Max length is 
maxDateTemplateLen bytes, excluding the terminating null.

months - month number (1..12)
days - day number (1..31)
years - e.g. 1995

stringP - if not NULL, then the formatted string is written to it, up 
to <stringLen> bytes (excluding the terminating null byte).

stringLen - size of buffer pointed to by stringP, excluding the 
terminating null byte.

Result:
The length of the formatted string (without the terminating null 
byte) is always returned, even if the stringP parameter is null. This 
then lets you allocate a buffer at run time, without having to 
previously fix it to some max size.

Template strings:
A template string contains a mixture of regular text and formatting 
substrings. Each formatting substring has the format 
"^<number><modifier>". The possible values for <number> are:

        dateTemplateDayNum = '0',       // Day number (1..31)
        dateTemplateDOWName,            // Day name (e.g. Tue)
        dateTemplateMonthName,          // Month name (e.g. Aug)
        dateTemplateMonthNum,           // Month number (1..12)
        dateTemplateYearNum             // Year (e.g. 1995)

The possible values for <modifier> are:

        #define dateTemplateShortModifier       's'
        #define dateTemplateRegularModifier     'r'
        #define dateTemplateLongModifier        'l'
        #define dateTemplateLeadZeroModifier    'z'

The meaning of each modifier depends on what type of formatting 
string it's part of. An example of each is as follows:

Format          Short   Regular Long    Zero
DayNum          5       5       5       05
DOWName         T       Tue     Tuesday n/a
MonthName       A       Aug     August  n/a
MonthNum        8       8       8       08
YearNum         00      2000    2000    n/a

So, for example, the formatting string to get "02 February 2000" would be:

"^0z ^2l ^4r" (intuitive, isn't it?)

-- Ken
Ken Krugler
TransPac Software, Inc.
<http://www.transpac.com>
+1 530-470-9200

-- 
For information on using the Palm Developer Forums, or to unsubscribe, please see 
http://www.palm.com/devzone/mailinglists.html

Reply via email to