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