Refactor command string creation

Hopefully this patch makes it a bit more approachable how it's done.
This commit is contained in:
Benny Baumann 2020-11-20 19:55:48 +01:00 committed by BenBE
parent 27b36dab1a
commit 46ee28e897
2 changed files with 118 additions and 76 deletions

View File

@ -335,17 +335,24 @@ returned by LinuxProcess_getCommandStr() for searching, sorting and filtering.
*/ */
void LinuxProcess_makeCommandStr(Process* this) { void LinuxProcess_makeCommandStr(Process* this) {
LinuxProcess *lp = (LinuxProcess *)this; LinuxProcess *lp = (LinuxProcess *)this;
LinuxProcessMergedCommand *mc = &lp->mergedCommand;
bool showMergedCommand = this->settings->showMergedCommand; bool showMergedCommand = this->settings->showMergedCommand;
bool showProgramPath = this->settings->showProgramPath; bool showProgramPath = this->settings->showProgramPath;
bool searchCommInCmdline = this->settings->findCommInCmdline; bool searchCommInCmdline = this->settings->findCommInCmdline;
bool stripExeFromCmdline = this->settings->stripExeFromCmdline; bool stripExeFromCmdline = this->settings->stripExeFromCmdline;
/* lp->mergedCommand.str needs to be remade only if there is a change in its /* lp->mergedCommand.str needs updating only if its state or contents changed.
* state consisting of the relevant settings and the three fields cmdline, * Its content is based on the fields cmdline, comm, and exe. */
* comm and exe */ if (
if (showMergedCommand == lp->mergedCommand.prevMergeSet && showProgramPath == lp->mergedCommand.prevPathSet && mc->prevMergeSet == showMergedCommand &&
searchCommInCmdline == lp->mergedCommand.prevCommSet && stripExeFromCmdline == lp->mergedCommand.prevCmdlineSet && mc->prevPathSet == showProgramPath &&
!lp->mergedCommand.cmdlineChanged && !lp->mergedCommand.commChanged && !lp->mergedCommand.exeChanged) { mc->prevCommSet == searchCommInCmdline &&
mc->prevCmdlineSet == stripExeFromCmdline &&
!mc->cmdlineChanged &&
!mc->commChanged &&
!mc->exeChanged
) {
return; return;
} }
@ -354,107 +361,138 @@ void LinuxProcess_makeCommandStr(Process* this) {
const char *SEPARATOR = CRT_treeStr[TREE_STR_VERT]; const char *SEPARATOR = CRT_treeStr[TREE_STR_VERT];
const int SEPARATOR_LEN = strlen(SEPARATOR); const int SEPARATOR_LEN = strlen(SEPARATOR);
if (lp->mergedCommand.cmdlineChanged || lp->mergedCommand.commChanged || lp->mergedCommand.exeChanged) { /* Check for any changed fields since we last built this string */
free(lp->mergedCommand.str); if (mc->cmdlineChanged || mc->commChanged || mc->exeChanged) {
/* Also accomodate two field separators and a NUL */ free(mc->str);
lp->mergedCommand.str = xMalloc(lp->mergedCommand.maxLen + 2*SEPARATOR_LEN + 1); /* Accomodate the column text, two field separators and terminating NUL */
mc->str = xCalloc(1, mc->maxLen + 2*SEPARATOR_LEN + 1);
} }
lp->mergedCommand.prevMergeSet = showMergedCommand; /* Preserve the settings used in this run */
lp->mergedCommand.prevPathSet = showProgramPath; mc->prevMergeSet = showMergedCommand;
lp->mergedCommand.prevCommSet = searchCommInCmdline; mc->prevPathSet = showProgramPath;
lp->mergedCommand.prevCmdlineSet = stripExeFromCmdline; mc->prevCommSet = searchCommInCmdline;
lp->mergedCommand.cmdlineChanged = false; mc->prevCmdlineSet = stripExeFromCmdline;
lp->mergedCommand.commChanged = false;
lp->mergedCommand.exeChanged = false; /* Mark everything as unchanged */
mc->cmdlineChanged = false;
mc->commChanged = false;
mc->exeChanged = false;
/* Clear any separators */
mc->sep1 = 0;
mc->sep2 = 0;
/* Clear any highlighting locations */
mc->baseStart = 0;
mc->baseEnd = 0;
mc->commStart = 0;
mc->commEnd = 0;
char *str;
char *strStart = lp->mergedCommand.str;
const char *cmdline = this->comm; const char *cmdline = this->comm;
const char *procExe = lp->procExe; const char *procExe = lp->procExe;
const char *procComm = lp->procComm; const char *procComm = lp->procComm;
char *strStart = mc->str;
char *str = strStart;
int cmdlineBasenameOffset = lp->procCmdlineBasenameOffset; int cmdlineBasenameOffset = lp->procCmdlineBasenameOffset;
if (!showMergedCommand || !procExe || !procComm) { /* fall back to cmdline */ if (!showMergedCommand || !procExe || !procComm) { /* fall back to cmdline */
if (showProgramPath) { if (showProgramPath) {
(void) stpcpyWithNewlineConversion(strStart, cmdline); (void) stpcpyWithNewlineConversion(strStart, cmdline);
lp->mergedCommand.baseStart = cmdlineBasenameOffset; mc->baseStart = cmdlineBasenameOffset;
lp->mergedCommand.baseEnd = lp->procCmdlineBasenameEnd; mc->baseEnd = lp->procCmdlineBasenameEnd;
} else { } else {
(void) stpcpyWithNewlineConversion(strStart, cmdline + cmdlineBasenameOffset); (void) stpcpyWithNewlineConversion(strStart, cmdline + cmdlineBasenameOffset);
lp->mergedCommand.baseStart = 0; mc->baseStart = 0;
lp->mergedCommand.baseEnd = lp->procCmdlineBasenameEnd - cmdlineBasenameOffset; mc->baseEnd = lp->procCmdlineBasenameEnd - cmdlineBasenameOffset;
} }
lp->mergedCommand.commEnd = 0;
return; return;
} }
int commStart = 0;
int commEnd = 0;
int exeBasenameOffset = lp->procExeBasenameOffset;
int exeLen = lp->procExeLen; int exeLen = lp->procExeLen;
int exeBaseLen = exeLen - exeBasenameOffset; int exeBasenameOffset = lp->procExeBasenameOffset;
bool commInCmdline = false; int exeBasenameLen = exeLen - exeBasenameOffset;
/* Start with copying exe */ /* Start with copying exe */
if (showProgramPath) { if (showProgramPath) {
str = stpcpy(strStart, procExe); str = stpcpy(str, procExe);
lp->mergedCommand.baseStart = exeBasenameOffset; mc->baseStart = exeBasenameOffset;
lp->mergedCommand.baseEnd = exeLen; mc->baseEnd = exeLen;
} else { } else {
str = stpcpy(strStart, procExe + exeBasenameOffset); str = stpcpy(str, procExe + exeBasenameOffset);
lp->mergedCommand.baseStart = 0; mc->baseStart = 0;
lp->mergedCommand.baseEnd = exeBaseLen; mc->baseEnd = exeBasenameLen;
} }
mc->sep1 = 0;
mc->sep2 = 0;
int commStart = 0;
int commEnd = 0;
bool commInCmdline = false;
/* Try to match procComm with procExe's basename: This is reliable (predictable) */ /* Try to match procComm with procExe's basename: This is reliable (predictable) */
if (strncmp(procExe + exeBasenameOffset, procComm, TASK_COMM_LEN - 1) == 0) { if (strncmp(procExe + exeBasenameOffset, procComm, TASK_COMM_LEN - 1) == 0) {
commStart = lp->mergedCommand.baseStart; commStart = mc->baseStart;
commEnd = lp->mergedCommand.baseEnd; commEnd = mc->baseEnd;
} else if (searchCommInCmdline) { } else if (searchCommInCmdline) {
/* commStart/commEnd will be adjusted later along with cmdline */ /* commStart/commEnd will be adjusted later along with cmdline */
commInCmdline = findCommInCmdline(procComm, cmdline, cmdlineBasenameOffset, &commStart, &commEnd); commInCmdline = findCommInCmdline(procComm, cmdline, cmdlineBasenameOffset, &commStart, &commEnd);
} }
int matchLen = matchCmdlinePrefixWithExeSuffix(cmdline, cmdlineBasenameOffset, int matchLen = matchCmdlinePrefixWithExeSuffix(cmdline, cmdlineBasenameOffset, procExe, exeBasenameOffset, exeBasenameLen);
procExe, exeBasenameOffset, exeBaseLen);
/* Note: commStart, commEnd are offsets into RichString. But the multibyte /* Note: commStart, commEnd are offsets into RichString. But the multibyte
* separator (with size SEPARATOR_LEN) has size 1 in RichString. The offset * separator (with size SEPARATOR_LEN) has size 1 in RichString. The offset
* adjustments below reflect this. */ * adjustments below reflect this. */
if (commEnd) { if (commEnd) {
if (matchLen) { /* strip the matched exe prefix */ mc->unmatchedExe = !matchLen;
lp->mergedCommand.unmatchedExe = false;
if (matchLen) {
/* strip the matched exe prefix */
cmdline += matchLen; cmdline += matchLen;
if (commInCmdline) { if (commInCmdline) {
commStart += str - strStart - matchLen; commStart += str - strStart - matchLen;
commEnd += str - strStart - matchLen; commEnd += str - strStart - matchLen;
} }
} else { /* cmdline will be a separate field */ } else {
lp->mergedCommand.unmatchedExe = true; /* cmdline will be a separate field */
mc->sep1 = str - strStart;
str = stpcpy(str, SEPARATOR); str = stpcpy(str, SEPARATOR);
if (commInCmdline) { if (commInCmdline) {
commStart += str - strStart - SEPARATOR_LEN + 1; commStart += str - strStart - SEPARATOR_LEN + 1;
commEnd += str - strStart - SEPARATOR_LEN + 1; commEnd += str - strStart - SEPARATOR_LEN + 1;
} }
} }
lp->mergedCommand.separateComm = false; /* procComm merged */
mc->separateComm = false; /* procComm merged */
} else { } else {
mc->sep1 = str - strStart;
str = stpcpy(str, SEPARATOR); str = stpcpy(str, SEPARATOR);
commStart = str - strStart - SEPARATOR_LEN + 1;
commStart = str - strStart - SEPARATOR_LEN + 1;
str = stpcpy(str, procComm); str = stpcpy(str, procComm);
commEnd = str - strStart - SEPARATOR_LEN + 1; /* or commStart + strlen(procComm) */ commEnd = str - strStart - SEPARATOR_LEN + 1; /* or commStart + strlen(procComm) */
mc->unmatchedExe = !matchLen;
if (matchLen) { if (matchLen) {
lp->mergedCommand.unmatchedExe = false;
if (stripExeFromCmdline) { if (stripExeFromCmdline) {
cmdline += matchLen; cmdline += matchLen;
} }
} else {
lp->mergedCommand.unmatchedExe = true;
} }
if (*cmdline) { if (*cmdline) {
mc->sep2 = str - strStart - SEPARATOR_LEN + 1;
str = stpcpy(str, SEPARATOR); str = stpcpy(str, SEPARATOR);
} }
lp->mergedCommand.separateComm = true; /* procComm a separate field */
mc->separateComm = true; /* procComm a separate field */
} }
/* Display cmdline if it hasn't been consumed by procExe */ /* Display cmdline if it hasn't been consumed by procExe */
@ -462,56 +500,58 @@ void LinuxProcess_makeCommandStr(Process* this) {
(void) stpcpyWithNewlineConversion(str, cmdline); (void) stpcpyWithNewlineConversion(str, cmdline);
} }
lp->mergedCommand.commStart = commStart; mc->commStart = commStart;
lp->mergedCommand.commEnd = commEnd; mc->commEnd = commEnd;
return; return;
} }
static void LinuxProcess_writeCommand(const Process* this, int attr, int baseAttr, RichString* str) { static void LinuxProcess_writeCommand(const Process* this, int attr, int baseAttr, RichString* str) {
const LinuxProcess *lp = (const LinuxProcess *)this; const LinuxProcess *lp = (const LinuxProcess *)this;
const LinuxProcessMergedCommand *mc = &lp->mergedCommand;
int strStart = RichString_size(str); int strStart = RichString_size(str);
int baseStart = strStart + lp->mergedCommand.baseStart; int baseStart = strStart + lp->mergedCommand.baseStart;
int baseEnd = strStart + lp->mergedCommand.baseEnd; int baseEnd = strStart + lp->mergedCommand.baseEnd;
int commStart = strStart + lp->mergedCommand.commStart;
int commEnd = strStart + lp->mergedCommand.commEnd;
int commAttr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
bool highlightBaseName = this->settings->highlightBaseName; bool highlightBaseName = this->settings->highlightBaseName;
RichString_append(str, attr, lp->mergedCommand.str); RichString_append(str, attr, lp->mergedCommand.str);
if (lp->mergedCommand.commEnd) { if (lp->mergedCommand.commEnd) {
int commStart = strStart + lp->mergedCommand.commStart;
int commEnd = strStart + lp->mergedCommand.commEnd;
int commAttr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
if (lp->mergedCommand.separateComm) { if (lp->mergedCommand.separateComm) {
RichString_setAttrn(str, commAttr, commStart, commEnd - 1); RichString_setAttrn(str, commAttr, commStart, commEnd - 1);
if (lp->mergedCommand.unmatchedExe) { } else if (commStart == baseStart && highlightBaseName) {
RichString_setAttrn(str, CRT_colors[FAILED_READ], commEnd, commEnd);
}
} else {
/* If it was matched with procExe's basename, make it bold if needed */ /* If it was matched with procExe's basename, make it bold if needed */
if (commStart == baseStart && highlightBaseName) { if (commEnd > baseEnd) {
if (commEnd > baseEnd) { RichString_setAttrn(str, A_BOLD | baseAttr, baseStart, baseEnd - 1);
RichString_setAttrn(str, A_BOLD | baseAttr, commStart, baseEnd - 1); RichString_setAttrn(str, A_BOLD | commAttr, baseEnd, commEnd - 1);
baseStart = baseEnd; } else if (commEnd < baseEnd) {
RichString_setAttrn(str, commAttr, baseStart, commEnd - 1); RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - 1);
} else if (commEnd < baseEnd) { RichString_setAttrn(str, A_BOLD | baseAttr, commEnd, baseEnd - 1);
RichString_setAttrn(str, A_BOLD | commAttr, commStart, commEnd - 1);
baseStart = commEnd;
// Remainder marked baseAttr at end of function
} else {
// Actually should be highlighted commAttr, but marked baseAttr to reduce visual noise
RichString_setAttrn(str, A_BOLD | baseAttr, commStart, commEnd - 1);
baseStart = commEnd;
}
} else { } else {
RichString_setAttrn(str, commAttr, commStart, commEnd - 1); // Actually should be highlighted commAttr, but marked baseAttr to reduce visual noise
} RichString_setAttrn(str, A_BOLD | baseAttr, commStart, commEnd - 1);
if (lp->mergedCommand.unmatchedExe) {
RichString_setAttrn(str, CRT_colors[FAILED_READ], baseEnd, baseEnd);
} }
baseStart = baseEnd;
} else {
RichString_setAttrn(str, commAttr, commStart, commEnd - 1);
} }
} }
if (baseStart < baseEnd && highlightBaseName) { if (baseStart < baseEnd && highlightBaseName) {
RichString_setAttrn(str, baseAttr, baseStart, baseEnd - 1); RichString_setAttrn(str, baseAttr, baseStart, baseEnd - 1);
} }
if (mc->sep1)
RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep1, strStart + mc->sep1);
if (mc->sep2)
RichString_setAttrn(str, CRT_colors[FAILED_READ], strStart + mc->sep2, strStart + mc->sep2);
} }
static void LinuxProcess_writeCommandField(const Process *this, RichString *str, char *buffer, int n, int attr) { static void LinuxProcess_writeCommandField(const Process *this, RichString *str, char *buffer, int n, int attr) {

View File

@ -111,6 +111,8 @@ typedef struct LinuxProcessMergedCommand_ {
int baseEnd; /* basename's end offset */ int baseEnd; /* basename's end offset */
int commStart; /* comm's start offset */ int commStart; /* comm's start offset */
int commEnd; /* comm's end offset */ int commEnd; /* comm's end offset */
int sep1; /* first field separator, used if non-zero */
int sep2; /* second field separator, used if non-zero */
bool separateComm; /* whether comm is a separate field */ bool separateComm; /* whether comm is a separate field */
bool unmatchedExe; /* whether exe matched with cmdline */ bool unmatchedExe; /* whether exe matched with cmdline */
bool cmdlineChanged; /* whether cmdline changed */ bool cmdlineChanged; /* whether cmdline changed */