Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shorten CWD path #854

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions CwdUtils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#include "CwdUtils.h"

#include <stdbool.h>
#include <stdlib.h>
#include <wchar.h>

#include "XUtils.h"

typedef struct ShortenCwdContext {
size_t maxLength;
size_t len;
wchar_t **parts;
size_t partsLen;
size_t *partLengths;
} ShortenCwdContext;

static void shortenCwdParts(ShortenCwdContext *ctx) {
for (int i = ctx->partsLen - 2; i >= 0 && ctx->len > ctx->maxLength; i--) {
if (ctx->partLengths[i] < 3)
continue;

size_t extraChars = ctx->len - ctx->maxLength;
size_t maxRemovableChars = ctx->partLengths[i] - 2;
size_t charsToRemove = extraChars < maxRemovableChars ? extraChars : maxRemovableChars;

ctx->partLengths[i] -= charsToRemove;
ctx->len -= charsToRemove;

Wstring_safeWcsncpy(ctx->parts[i] + (ctx->partLengths[i] - 1), L"~", 2);
}
}

static size_t collapseCwdParts(ShortenCwdContext *ctx, bool doActualWork) {
if (ctx->len <= ctx->maxLength || ctx->partsLen <= 3)
return 0;

size_t len = ctx->len;

size_t i;
for (i = ctx->partsLen - 2; i > 1; i--) {
if (len + (3 - ctx->partLengths[i]) <= ctx->maxLength)
break;

len -= ctx->partLengths[i] + 1;

if (doActualWork) {
ctx->partLengths[i] = 0;
free(ctx->parts[i]);
ctx->parts[i] = NULL;
}
}

len += 3 - ctx->partLengths[i];
size_t diff = ctx->len - len;

if (doActualWork) {
wchar_t newPart[] = L"~~~";
newPart[0] = ctx->parts[i][0];
free(ctx->parts[i]);
ctx->parts[i] = xWcsdup(newPart);
ctx->partLengths[i] = 3;
ctx->len = len;
}

return diff;
}

static size_t shortenCwdLastPart(ShortenCwdContext *ctx, bool doActualWork) {
if (ctx->len <= ctx->maxLength)
return 0;

size_t lastPartLen = ctx->partLengths[ctx->partsLen - 1];
if (lastPartLen <= 3)
return 0;

wchar_t *lastPart = ctx->parts[ctx->partsLen - 1];
size_t extraChars = ctx->len - ctx->maxLength + 1;
size_t maxRemovableChars = lastPartLen - 2;
size_t charsToRemove = extraChars < maxRemovableChars ? extraChars : maxRemovableChars;

if (doActualWork) {
size_t charsAtBeginning = (lastPartLen - charsToRemove + 1) / 2;
size_t charsAtEnd = lastPartLen - charsToRemove - charsAtBeginning;
lastPart[charsAtBeginning] = '~';
wmemmove(lastPart + charsAtBeginning + 1, lastPart + lastPartLen - charsAtEnd, charsAtEnd);
lastPart[charsAtBeginning + charsAtEnd + 1] = '\0';
ctx->partLengths[ctx->partsLen - 1] = lastPartLen - charsToRemove + 1;
ctx->len -= charsToRemove - 1;
}

return charsToRemove - 1;
}

static wchar_t* buildCwdFromParts(ShortenCwdContext *ctx) {
size_t len = ctx->partsLen - 1;
for (size_t i = 0; i < ctx->partsLen; i++)
len += ctx->partLengths[i];

wchar_t *newCwd = xCalloc(len + 1, sizeof(wchar_t));

newCwd[0] = '\0';
for (size_t i = 0, writeIndex = 0; i < ctx->partsLen; i++) {
if (!ctx->parts[i])
continue;

Wstring_safeWcsncpy(newCwd + writeIndex, ctx->parts[i], ctx->partLengths[i] + 1);
writeIndex += ctx->partLengths[i];
if (i < ctx->partsLen - 1)
newCwd[writeIndex++] = L'/';
}

return newCwd;
}

char* CwdUtils_shortenCwd(char *cwd, const size_t maxLength) {
wchar_t *wcwd = xMbstowcs(cwd);
size_t len = wcslen(wcwd);
if (len <= maxLength) {
free(wcwd);
return xStrdup(cwd);
}

ShortenCwdContext ctx = {
.maxLength = maxLength,
.len = len,
};
ctx.parts = Wstring_split(wcwd, L'/', &ctx.partsLen);
free(wcwd);
wcwd = NULL;
ctx.partLengths = xCalloc(ctx.partsLen, sizeof(size_t));
for (size_t i = 0; i < ctx.partsLen; i++)
ctx.partLengths[i] = wcslen(ctx.parts[i]);

shortenCwdParts(&ctx);
if (shortenCwdLastPart(&ctx, false) > collapseCwdParts(&ctx, false)) {
shortenCwdLastPart(&ctx, true);
collapseCwdParts(&ctx, true);
} else {
collapseCwdParts(&ctx, true);
shortenCwdLastPart(&ctx, true);
}

wchar_t *newWcwd = buildCwdFromParts(&ctx);
char *newCwd = xWcstombs(newWcwd);
free(newWcwd);

free(ctx.partLengths);
for (size_t i = 0; i < ctx.partsLen; i++)
free(ctx.parts[i]);
free(ctx.parts);

return newCwd;
}
8 changes: 8 additions & 0 deletions CwdUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef HEADER_CwdUtils
#define HEADER_CwdUtils

#include <stddef.h>

char* CwdUtils_shortenCwd(char* cwd, size_t maxLength);

#endif
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ myhtopsources = \
Compat.c \
CPUMeter.c \
CRT.c \
CwdUtils.c \
DateMeter.c \
DateTimeMeter.c \
DiskIOMeter.c \
Expand Down Expand Up @@ -101,6 +102,7 @@ myhtopheaders = \
CommandLine.h \
CommandScreen.h \
Compat.h \
CwdUtils.h \
DateMeter.h \
DateTimeMeter.h \
DiskIOMeter.h \
Expand Down
9 changes: 8 additions & 1 deletion Process.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ in the source distribution for its full text.
#include "RichString.h"
#include "Settings.h"
#include "XUtils.h"
#include "CwdUtils.h"

#if defined(MAJOR_IN_MKDEV)
#include <sys/mkdev.h>
Expand Down Expand Up @@ -825,7 +826,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
attr = CRT_colors[PROCESS_SHADOW];
cwd = "main thread terminated";
} else {
cwd = this->procCwd;
cwd = this->procCwdShort;
}
Process_printLeftAlignedField(str, attr, cwd, 25);
return;
Expand Down Expand Up @@ -955,6 +956,7 @@ void Process_done(Process* this) {
free(this->procComm);
free(this->procExe);
free(this->procCwd);
free(this->procCwdShort);
free(this->mergedCommand.str);
free(this->tty_name);
}
Expand Down Expand Up @@ -1238,3 +1240,8 @@ void Process_updateExe(Process* this, const char* exe) {
}
this->mergedCommand.exeChanged = true;
}

onlined marked this conversation as resolved.
Show resolved Hide resolved
void Process_updateShortCwd(Process* this) {
free(this->procCwdShort);
this->procCwdShort = this->procCwd ? CwdUtils_shortenCwd(this->procCwd, 25) : NULL;
}
4 changes: 4 additions & 0 deletions Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ typedef struct Process_ {
/* The process/thread working directory */
char* procCwd;

/* Shortened process/thread working directory */
char* procCwdShort;

/* Offset in procExe of the process basename */
int procExeBasenameOffset;

Expand Down Expand Up @@ -388,6 +391,7 @@ const char* Process_getCommandStr(const Process* this);
void Process_updateComm(Process* this, const char* comm);
void Process_updateCmdline(Process* this, const char* cmdline, int basenameStart, int basenameEnd);
void Process_updateExe(Process* this, const char* exe);
void Process_updateShortCwd(Process* this);

/* This function constructs the string that is displayed by
* Process_writeCommand and also returned by Process_getCommandStr */
Expand Down
2 changes: 2 additions & 0 deletions ProcessList.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,8 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
Process* p = (Process*) Vector_get(this->processes, i);
Process_makeCommandStr(p);
if (p->settings->flags & PROCESS_FLAG_CWD)
Process_updateShortCwd(p);

if (p->tombStampMs > 0) {
// remove tombed process
Expand Down
80 changes: 80 additions & 0 deletions XUtils.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,83 @@ ssize_t xReadfileat(openat_arg_t dirfd, const char* pathname, void* buffer, size

return readfd_internal(fd, buffer, count);
}

wchar_t* xMbstowcs(const char *mbs) {
size_t len = strlen(mbs);
wchar_t *wcs = xCalloc(len + 1, sizeof(wchar_t));
mbstate_t mbstate = {0};
mbsrtowcs(wcs, &mbs, len + 1, &mbstate);
if (mbs)
fail();
return wcs;
}

char* xWcstombs(const wchar_t *wcs) {
size_t len = wcslen(wcs);
size_t mbsSize = len * sizeof(wchar_t) + 1;
char *mbs = xMalloc(mbsSize);
mbstate_t mbstate = {0};
wcsrtombs(mbs, &wcs, mbsSize, &mbstate);
if (wcs)
fail();
return mbs;
}

wchar_t* xWcsdup(const wchar_t* str) {
wchar_t* data = wcsdup(str);
if (!data)
fail();
return data;
}

wchar_t* xWcsndup(const wchar_t* str, size_t len) {
wchar_t* data = xCalloc(len + 1, sizeof(wchar_t));
if (!data)
fail();

for (size_t i = 0; i < len && str[i]; i++)
data[i] = str[i];

return data;
}

wchar_t** Wstring_split(const wchar_t* s, wchar_t sep, size_t* n) {
const unsigned int rate = 10;
wchar_t** out = xCalloc(rate, sizeof(wchar_t*));
size_t ctr = 0;
unsigned int blocks = rate;
const wchar_t* where;
while ((where = wcschr(s, sep)) != NULL) {
size_t size = (size_t)(where - s);
out[ctr] = xWcsndup(s, size);
ctr++;
if (ctr == blocks) {
blocks += rate;
out = (wchar_t**) xRealloc(out, sizeof(wchar_t*) * blocks);
}
s += size + 1;
}
if (s[0] != L'\0') {
out[ctr] = xWcsdup(s);
ctr++;
}
out = xRealloc(out, sizeof(wchar_t*) * (ctr + 1));
out[ctr] = NULL;

if (n)
*n = ctr;

return out;
}

size_t Wstring_safeWcsncpy(wchar_t* restrict dest, const wchar_t* restrict src, size_t size) {
assert(size > 0);

size_t i = 0;
for (; i < size - 1 && src[i]; i++)
dest[i] = src[i];

dest[i] = L'\0';

return i;
}
7 changes: 7 additions & 0 deletions XUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,11 @@ char* xStrndup(const char* str, size_t len) ATTR_NONNULL ATTR_MALLOC;
ssize_t xReadfile(const char* pathname, void* buffer, size_t count);
ssize_t xReadfileat(openat_arg_t dirfd, const char* pathname, void* buffer, size_t count);

wchar_t* xMbstowcs(const char *mbs);
char* xWcstombs(const wchar_t *wcs);
wchar_t* xWcsdup(const wchar_t* str);
wchar_t* xWcsndup(const wchar_t* str, size_t len);
wchar_t** Wstring_split(const wchar_t* s, wchar_t sep, size_t* n);
size_t Wstring_safeWcsncpy(wchar_t* restrict dest, const wchar_t* restrict src, size_t size);

#endif