int android_log_addFilterRule(AndroidLogFormat *p_format, const char *filterExpression) { size_t i=0; size_t tagNameLength; android_LogPriority pri = ANDROID_LOG_DEFAULT; tagNameLength = strcspn(filterExpression, ":"); if (tagNameLength == 0) { goto error; } if(filterExpression[tagNameLength] == ':') { pri = filterCharToPri(filterExpression[tagNameLength+1]); if (pri == ANDROID_LOG_UNKNOWN) { goto error; } } 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 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 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 #ifdef HAVE_STRNDUP tagName = strndup(filterExpression, tagNameLength); #else //a few extra bytes copied... tagName = strdup(filterExpression); tagName[tagNameLength] = '\0'; #endif /*HAVE_STRNDUP*/ FilterInfo *p_fi = filterinfo_new(tagName, pri); free(tagName); p_fi->p_next = p_format->filters; p_format->filters = p_fi; } return 0; error: return -1; }
char *alog_formatLogLine ( AndroidLogFormat *p_format, char *defaultBuffer, size_t defaultBufferSize, const AndroidLogEntry *entry, size_t *p_outLength) { #if defined(HAVE_LOCALTIME_R) //struct tm tmBuf; #endif //struct tm* ptm; char timeBuf[32]; char prefixBuf[128], suffixBuf[128]; char priChar; int prefixSuffixIsHeaderFooter = 0; char * ret = NULL; size_t prefixLen, suffixLen; size_t numLines; char *p; size_t bufferSize; const char *pm; priChar = filterPriToChar(filterCharToPri(entry->priority)); #if defined(HAVE_LOCALTIME_R) //ptm = localtime_r(&(entry->tv_sec), &tmBuf); #else //ptm = localtime(&(entry->tv_sec)); #endif // strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm); snprintf(timeBuf, sizeof(prefixBuf),"%d-%d %d:%d:%d", (unsigned int)entry->tv_sec%13, (unsigned int)entry->tv_sec%32, (unsigned int)entry->tv_sec%25, (unsigned int)entry->tv_sec%60, (unsigned int)entry->tv_sec%60); /* * Construct a buffer containing the log header and log message. */ switch (p_format->format) { case FORMAT_TAG: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c/%-8s: ", priChar, entry->tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_PROCESS: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c(%5d) ", priChar, entry->pid); suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), " (%s)\n", entry->tag); break; case FORMAT_THREAD: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c(%5d:%p) ", priChar, entry->pid, (void*)entry->tid); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_RAW: prefixBuf[0] = 0; prefixLen = 0; strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_TIME: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000, priChar, entry->tag, entry->pid); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_THREADTIME: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000, (int)entry->pid, (int)entry->tid, priChar, entry->tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_LONG: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "[ %s.%03ld %5d:%p %c/%-8s ]\n", timeBuf, entry->tv_nsec / 1000000, entry->pid, (void*)entry->tid, priChar, entry->tag); strcpy(suffixBuf, "\n\n"); suffixLen = 2; prefixSuffixIsHeaderFooter = 1; break; case FORMAT_BRIEF: default: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid); strcpy(suffixBuf, "\n"); suffixLen = 1; break; } /* the following code is tragically unreadable */ if (prefixSuffixIsHeaderFooter) { // 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 while (pm < (entry->message + entry->messageLen)) { if (*pm++ == '\n') numLines++; } // 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; if (defaultBufferSize >= bufferSize) { ret = defaultBuffer; } else { ret = (char *)kmalloc(bufferSize,GFP_KERNEL); if (ret == NULL) { return ret; } } ret[0] = '\0'; /* to start strcat off */ p = ret; pm = entry->message; if (prefixSuffixIsHeaderFooter) { strcat(p, prefixBuf); p += prefixLen; strncat(p, entry->message, entry->messageLen); p += entry->messageLen; strcat(p, suffixBuf); p += suffixLen; } else { while(pm < (entry->message + entry->messageLen)) { const char *lineStart; size_t lineLen; lineStart = pm; // 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; strncat(p, lineStart, lineLen); p += lineLen; strcat(p, suffixBuf); p += suffixLen; if (*pm == '\n') pm++; } } if (p_outLength != NULL) { *p_outLength = p - ret; } return ret; }