* Generate a more efficient internal representation describing how to process * the compressed arguments of a NANO_LOG statement given its static * log information. * * The output representation would look something like a FormatMetadata with * nested PrintFragments. This representation can then be interpreted by the * state machine in decompressNextLogStatement to decompress the log stateme
| 813 | * true indicates success; false indicates malformed printf format string |
| 814 | */ |
| 815 | bool |
| 816 | Log::Decoder::createMicroCode(char **microCode, |
| 817 | const char *formatString, |
| 818 | const char *filename, |
| 819 | uint32_t linenum, |
| 820 | uint8_t severity) |
| 821 | { |
| 822 | using namespace NanoLogInternal::Log; |
| 823 | |
| 824 | size_t formatStringLength = strlen(formatString) + 1; // +1 for NULL |
| 825 | char *microCodeStartingPos = *microCode; |
| 826 | FormatMetadata *fm = reinterpret_cast<FormatMetadata*>(*microCode); |
| 827 | *microCode += sizeof(FormatMetadata); |
| 828 | |
| 829 | fm->logLevel = severity; |
| 830 | fm->lineNumber = linenum; |
| 831 | fm->filenameLength = static_cast<uint16_t>(strlen(filename) + 1); |
| 832 | *microCode = stpcpy(*microCode, filename) + 1; |
| 833 | |
| 834 | fm->numNibbles = 0; |
| 835 | fm->numPrintFragments = 0; |
| 836 | |
| 837 | std::regex regex("^%" |
| 838 | "([-+ #0]+)?" // Flags (Position 1) |
| 839 | "([\\d]+|\\*)?" // Width (Position 2) |
| 840 | "(\\.(\\d+|\\*))?"// Precision (Position 4; 3 includes '.') |
| 841 | "(hh|h|l|ll|j|z|Z|t|L)?" // Length (Position 5) |
| 842 | "([diuoxXfFeEgGaAcspn])"// Specifier (Position 6) |
| 843 | ); |
| 844 | |
| 845 | size_t i = 0; |
| 846 | std::cmatch match; |
| 847 | int consecutivePercents = 0; |
| 848 | size_t startOfNextFragment = 0; |
| 849 | PrintFragment *pf = nullptr; |
| 850 | |
| 851 | // The key idea here is to split up the format string in to fragments (i.e. |
| 852 | // PrintFragments) such that there is at most one specifier per fragment. |
| 853 | // This then allows the decompressor later to consume one argument at a |
| 854 | // time and print the fragment (vs. buffering all the arguments first). |
| 855 | |
| 856 | while (i < formatStringLength) { |
| 857 | char c = formatString[i]; |
| 858 | |
| 859 | // Skip the next character if there's an escape |
| 860 | if (c == '\\') { |
| 861 | i += 2; |
| 862 | continue; |
| 863 | } |
| 864 | |
| 865 | if (c != '%') { |
| 866 | ++i; |
| 867 | consecutivePercents = 0; |
| 868 | continue; |
| 869 | } |
| 870 | |
| 871 | // If there's an even number of '%'s, then it's a comment |
| 872 | if (++consecutivePercents % 2 == 0 |
nothing calls this directly
no test coverage detected