Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ae69bbe authored by Mark Salyzyn's avatar Mark Salyzyn Committed by Android Git Automerger
Browse files

am 79ae578e: Merge "liblog: logcat: Add printable format modifier"

* commit '79ae578e':
  liblog: logcat: Add printable format modifier
parents f360bed8 79ae578e
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -36,9 +36,10 @@ typedef enum {
    FORMAT_TIME,
    FORMAT_THREADTIME,
    FORMAT_LONG,
    /* The following two are modifiers to above formats */
    /* The following three are modifiers to above formats */
    FORMAT_MODIFIER_COLOR,     /* converts priority to color */
    FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
    FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
} AndroidLogPrintFormat;

typedef struct AndroidLogFormat_t AndroidLogFormat;
+182 −31
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@
#include <log/logd.h>
#include <log/logprint.h>

/* open coded fragment, prevent circular dependencies */
#define WEAK static

typedef struct FilterInfo_t {
    char *mTag;
    android_LogPriority mPri;
@@ -44,6 +47,7 @@ struct AndroidLogFormat_t {
    AndroidLogPrintFormat format;
    bool colored_output;
    bool usec_time_output;
    bool printable_output;
};

/*
@@ -187,6 +191,7 @@ AndroidLogFormat *android_log_format_new()
    p_ret->format = FORMAT_BRIEF;
    p_ret->colored_output = false;
    p_ret->usec_time_output = false;
    p_ret->printable_output = false;

    return p_ret;
}
@@ -212,13 +217,18 @@ void android_log_format_free(AndroidLogFormat *p_format)
int android_log_setPrintFormat(AndroidLogFormat *p_format,
        AndroidLogPrintFormat format)
{
    if (format == FORMAT_MODIFIER_COLOR) {
    switch (format) {
    case FORMAT_MODIFIER_COLOR:
        p_format->colored_output = true;
        return 0;
    }
    if (format == FORMAT_MODIFIER_TIME_USEC) {
    case FORMAT_MODIFIER_TIME_USEC:
        p_format->usec_time_output = true;
        return 0;
    case FORMAT_MODIFIER_PRINTABLE:
        p_format->printable_output = true;
        return 0;
    default:
        break;
    }
    p_format->format = format;
    return 1;
@@ -241,6 +251,7 @@ AndroidLogPrintFormat android_log_formatFromString(const char * formatString)
    else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
    else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
    else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
    else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
    else format = FORMAT_OFF;

    return format;
@@ -276,29 +287,35 @@ int android_log_addFilterRule(AndroidLogFormat *p_format,
    }

    if(0 == strncmp("*", filterExpression, tagNameLength)) {
        // This filter expression refers to the global filter
        // The default level for this is DEBUG if the priority
        // is unspecified
        /*
         * This filter expression refers to the global filter
         * The default level for this is DEBUG if the priority
         * is unspecified
         */
        if (pri == ANDROID_LOG_DEFAULT) {
            pri = ANDROID_LOG_DEBUG;
        }

        p_format->global_pri = pri;
    } else {
        // for filter expressions that don't refer to the global
        // filter, the default is verbose if the priority is unspecified
        /*
         * for filter expressions that don't refer to the global
         * filter, the default is verbose if the priority is unspecified
         */
        if (pri == ANDROID_LOG_DEFAULT) {
            pri = ANDROID_LOG_VERBOSE;
        }

        char *tagName;

// Presently HAVE_STRNDUP is never defined, so the second case is always taken
// Darwin doesn't have strnup, everything else does
/*
 * Presently HAVE_STRNDUP is never defined, so the second case is always taken
 * Darwin doesn't have strnup, everything else does
 */
#ifdef HAVE_STRNDUP
        tagName = strndup(filterExpression, tagNameLength);
#else
        //a few extra bytes copied...
        /* a few extra bytes copied... */
        tagName = strdup(filterExpression);
        tagName[tagNameLength] = '\0';
#endif /*HAVE_STRNDUP*/
@@ -335,9 +352,9 @@ int android_log_addFilterString(AndroidLogFormat *p_format,
    char *p_ret;
    int err;

    // Yes, I'm using strsep
    /* Yes, I'm using strsep */
    while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
        // ignore whitespace-only entries
        /* ignore whitespace-only entries */
        if(p_ret[0] != '\0') {
            err = android_log_addFilterRule(p_format, p_ret);

@@ -381,8 +398,10 @@ int android_log_processLogBuffer(struct logger_entry *buf,
     * When that happens, we must null-terminate the message ourselves.
     */
    if (buf->len < 3) {
        // An well-formed entry must consist of at least a priority
        // and two null characters
        /*
         * An well-formed entry must consist of at least a priority
         * and two null characters
         */
        fprintf(stderr, "+++ LOG: entry too small\n");
        return -1;
    }
@@ -412,7 +431,7 @@ int android_log_processLogBuffer(struct logger_entry *buf,
        return -1;
    }
    if (msgEnd == -1) {
        // incoming message not null-terminated; force it
        /* incoming message not null-terminated; force it */
        msgEnd = buf->len - 1;
        msg[msgEnd] = '\0';
    }
@@ -473,8 +492,6 @@ static int android_log_printBinaryEvent(const unsigned char** pEventData,
    type = *eventData++;
    eventDataLen--;

    //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);

    switch (type) {
    case EVENT_TYPE_INT:
        /* 32-bit signed int */
@@ -735,6 +752,122 @@ int android_log_processBinaryLogBuffer(struct logger_entry *buf,
    return 0;
}

/*
 * One utf8 character at a time
 *
 * Returns the length of the utf8 character in the buffer,
 * or -1 if illegal or truncated
 *
 * Open coded from libutils/Unicode.cpp, borrowed from utf8_length(),
 * can not remove from here because of library circular dependencies.
 * Expect one-day utf8_character_length with the same signature could
 * _also_ be part of libutils/Unicode.cpp if its usefullness needs to
 * propagate globally.
 */
WEAK ssize_t utf8_character_length(const char *src, size_t len)
{
    const char *cur = src;
    const char first_char = *cur++;
    static const uint32_t kUnicodeMaxCodepoint = 0x0010FFFF;
    int32_t mask, to_ignore_mask;
    size_t num_to_read;
    uint32_t utf32;

    if ((first_char & 0x80) == 0) { /* ASCII */
        return 1;
    }

    /*
     * (UTF-8's character must not be like 10xxxxxx,
     *  but 110xxxxx, 1110xxxx, ... or 1111110x)
     */
    if ((first_char & 0x40) == 0) {
        return -1;
    }

    for (utf32 = 1, num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
         num_to_read < 5 && (first_char & mask);
         num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
        if (num_to_read > len) {
            return -1;
        }
        if ((*cur & 0xC0) != 0x80) { /* can not be 10xxxxxx? */
            return -1;
        }
        utf32 = (utf32 << 6) + (*cur++ & 0b00111111);
    }
    /* "first_char" must be (110xxxxx - 11110xxx) */
    if (num_to_read >= 5) {
        return -1;
    }
    to_ignore_mask |= mask;
    utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
    if (utf32 > kUnicodeMaxCodepoint) {
        return -1;
    }
    return num_to_read;
}

/*
 * Convert to printable from message to p buffer, return string length. If p is
 * NULL, do not copy, but still return the expected string length.
 */
static size_t convertPrintable(char *p, const char *message, size_t messageLen)
{
    char *begin = p;
    bool print = p != NULL;

    while (messageLen) {
        char buf[6];
        ssize_t len = sizeof(buf) - 1;
        if ((size_t)len > messageLen) {
            len = messageLen;
        }
        len = utf8_character_length(message, len);

        if (len < 0) {
            snprintf(buf, sizeof(buf),
                     ((messageLen > 1) && isdigit(message[1]))
                         ? "\\%03o"
                         : "\\%o",
                     *message & 0377);
            len = 1;
        } else {
            buf[0] = '\0';
            if (len == 1) {
                if (*message == '\a') {
                    strcpy(buf, "\\a");
                } else if (*message == '\b') {
                    strcpy(buf, "\\b");
                } else if (*message == '\t') {
                    strcpy(buf, "\\t");
                } else if (*message == '\v') {
                    strcpy(buf, "\\v");
                } else if (*message == '\f') {
                    strcpy(buf, "\\f");
                } else if (*message == '\r') {
                    strcpy(buf, "\\r");
                } else if (*message == '\\') {
                    strcpy(buf, "\\\\");
                } else if ((*message < ' ') || (*message & 0x80)) {
                    snprintf(buf, sizeof(buf), "\\%o", *message & 0377);
                }
            }
            if (!buf[0]) {
                strncpy(buf, message, len);
                buf[len] = '\0';
            }
        }
        if (print) {
            strcpy(p, buf);
        }
        p += strlen(buf);
        message += len;
        messageLen -= len;
    }
    return p - begin;
}

/**
 * Formats a log message into a buffer
 *
@@ -778,7 +911,7 @@ char *android_log_formatLogLine (
#else
    ptm = localtime(&(entry->tv_sec));
#endif
    //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
    /* strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm); */
    strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
    len = strlen(timeBuf);
    if (p_format->usec_time_output) {
@@ -873,24 +1006,34 @@ char *android_log_formatLogLine (
    const char *pm;

    if (prefixSuffixIsHeaderFooter) {
        // we're just wrapping message with a header/footer
        /* we're just wrapping message with a header/footer */
        numLines = 1;
    } else {
        pm = entry->message;
        numLines = 0;

        // The line-end finding here must match the line-end finding
        // in for ( ... numLines...) loop below
        /*
         * The line-end finding here must match the line-end finding
         * in for ( ... numLines...) loop below
         */
        while (pm < (entry->message + entry->messageLen)) {
            if (*pm++ == '\n') numLines++;
        }
        // plus one line for anything not newline-terminated at the end
        /* plus one line for anything not newline-terminated at the end */
        if (pm > entry->message && *(pm-1) != '\n') numLines++;
    }

    // this is an upper bound--newlines in message may be counted
    // extraneously
    bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
    /*
     * this is an upper bound--newlines in message may be counted
     * extraneously
     */
    bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
    if (p_format->printable_output) {
        /* Calculate extra length to convert non-printable to printable */
        bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
    } else {
        bufferSize += entry->messageLen;
    }

    if (defaultBufferSize >= bufferSize) {
        ret = defaultBuffer;
@@ -910,8 +1053,12 @@ char *android_log_formatLogLine (
    if (prefixSuffixIsHeaderFooter) {
        strcat(p, prefixBuf);
        p += prefixLen;
        if (p_format->printable_output) {
            p += convertPrintable(p, entry->message, entry->messageLen);
        } else {
            strncat(p, entry->message, entry->messageLen);
            p += entry->messageLen;
        }
        strcat(p, suffixBuf);
        p += suffixLen;
    } else {
@@ -920,15 +1067,19 @@ char *android_log_formatLogLine (
            size_t lineLen;
            lineStart = pm;

            // Find the next end-of-line in message
            /* Find the next end-of-line in message */
            while (pm < (entry->message + entry->messageLen)
                    && *pm != '\n') pm++;
            lineLen = pm - lineStart;

            strcat(p, prefixBuf);
            p += prefixLen;
            if (p_format->printable_output) {
                p += convertPrintable(p, lineStart, lineLen);
            } else {
                strncat(p, lineStart, lineLen);
                p += lineLen;
            }
            strcat(p, suffixBuf);
            p += suffixLen;

+2 −1
Original line number Diff line number Diff line
@@ -253,7 +253,8 @@ static void show_help(const char *cmd)
                    "  -r <kbytes>     Rotate log every kbytes. Requires -f\n"
                    "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
                    "  -v <format>     Sets the log print format, where <format> is:\n\n"
                    "                  brief color long process raw tag thread threadtime time usec\n\n"
                    "                      brief color long printable process raw tag thread\n"
                    "                      threadtime time usec\n\n"
                    "  -D              print dividers between each log buffer\n"
                    "  -c              clear (flush) the entire log and exit\n"
                    "  -d              dump the log and then exit (don't block)\n"