| 6219 | /////////////////////////////// |
| 6220 | |
| 6221 | ResultType Line::FormatTime(char *aYYYYMMDD, char *aFormat) |
| 6222 | // The compressed code size of this function is about 1 KB (2 KB uncompressed), which compares |
| 6223 | // favorably to using setlocale()+strftime(), which together are about 8 KB of compressed code |
| 6224 | // (setlocale() seems to be needed to put the user's or system's locale into effect for strftime()). |
| 6225 | // setlocale() weighs in at about 6.5 KB compressed (14 KB uncompressed). |
| 6226 | { |
| 6227 | Var *output_var = ResolveVarOfArg(0); |
| 6228 | if (!output_var) |
| 6229 | return FAIL; |
| 6230 | |
| 6231 | #define FT_MAX_INPUT_CHARS 2000 // In preparation for future use of TCHARs, since GetDateFormat() uses char-count not size. |
| 6232 | // Input/format length is restricted since it must be translated and expanded into a new format |
| 6233 | // string that uses single quotes around non-alphanumeric characters such as punctuation: |
| 6234 | if (strlen(aFormat) > FT_MAX_INPUT_CHARS) |
| 6235 | return output_var->Assign(); |
| 6236 | |
| 6237 | // Worst case expansion: .d.d.d.d. (9 chars) --> '.'d'.'d'.'d'.'d'.' (19 chars) |
| 6238 | // Buffer below is sized to a little more than twice as big as the largest allowed format, |
| 6239 | // which avoids having to constantly check for buffer overflow while translating aFormat |
| 6240 | // into format_buf: |
| 6241 | #define FT_MAX_OUTPUT_CHARS (2*FT_MAX_INPUT_CHARS + 10) |
| 6242 | char format_buf[FT_MAX_OUTPUT_CHARS + 1]; |
| 6243 | char output_buf[FT_MAX_OUTPUT_CHARS + 1]; // The size of this is somewhat arbitrary, but buffer overflow is checked so it's safe. |
| 6244 | |
| 6245 | char yyyymmdd[256] = ""; // Large enough to hold date/time and any options that follow it (note that D and T options can appear multiple times). |
| 6246 | |
| 6247 | SYSTEMTIME st; |
| 6248 | char *options = NULL; |
| 6249 | |
| 6250 | if (!*aYYYYMMDD) // Use current local time by default. |
| 6251 | GetLocalTime(&st); |
| 6252 | else |
| 6253 | { |
| 6254 | strlcpy(yyyymmdd, omit_leading_whitespace(aYYYYMMDD), sizeof(yyyymmdd)); // Make a modifiable copy. |
| 6255 | if (*yyyymmdd < '0' || *yyyymmdd > '9') // First character isn't a digit, therefore... |
| 6256 | { |
| 6257 | // ... options are present without date (since yyyymmdd [if present] must come before options). |
| 6258 | options = yyyymmdd; |
| 6259 | GetLocalTime(&st); // Use current local time by default. |
| 6260 | } |
| 6261 | else // Since the string starts with a digit, rules say it must be a YYYYMMDD string, possibly followed by options. |
| 6262 | { |
| 6263 | // Find first space or tab because YYYYMMDD portion might contain only the leading part of date/timestamp. |
| 6264 | if (options = StrChrAny(yyyymmdd, " \t")) // Find space or tab. |
| 6265 | { |
| 6266 | *options = '\0'; // Terminate yyyymmdd at the end of the YYYYMMDDHH24MISS string. |
| 6267 | options = omit_leading_whitespace(++options); // Point options to the right place (can be empty string). |
| 6268 | } |
| 6269 | //else leave options set to NULL to indicate that there are none. |
| 6270 | |
| 6271 | // Pass "false" for validatation so that times can still be reported even if the year |
| 6272 | // is prior to 1601. If the time and/or date is invalid, GetTimeFormat() and GetDateFormat() |
| 6273 | // will refuse to produce anything, which is documented behavior: |
| 6274 | YYYYMMDDToSystemTime(yyyymmdd, st, false); |
| 6275 | } |
| 6276 | } |
| 6277 | |
| 6278 | // Set defaults. Some can be overridden by options (if there are any options). |
nothing calls this directly
no test coverage detected