michael@0: #include michael@0: michael@0: namespace base { michael@0: michael@0: bool IsWprintfFormatPortable(const wchar_t* format) { michael@0: for (const wchar_t* position = format; *position != '\0'; ++position) { michael@0: if (*position == '%') { michael@0: bool in_specification = true; michael@0: bool modifier_l = false; michael@0: while (in_specification) { michael@0: // Eat up characters until reaching a known specifier. michael@0: if (*++position == '\0') { michael@0: // The format string ended in the middle of a specification. Call michael@0: // it portable because no unportable specifications were found. The michael@0: // string is equally broken on all platforms. michael@0: return true; michael@0: } michael@0: michael@0: if (*position == 'l') { michael@0: // 'l' is the only thing that can save the 's' and 'c' specifiers. michael@0: modifier_l = true; michael@0: } else if (((*position == 's' || *position == 'c') && !modifier_l) || michael@0: *position == 'S' || *position == 'C' || *position == 'F' || michael@0: *position == 'D' || *position == 'O' || *position == 'U') { michael@0: // Not portable. michael@0: return false; michael@0: } michael@0: michael@0: if (wcschr(L"diouxXeEfgGaAcspn%", *position)) { michael@0: // Portable, keep scanning the rest of the format string. michael@0: in_specification = false; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: } // namespace base michael@0: