top: introduce relational operators with other filters

When I originally entertained thoughts of maybe adding
relational operators to the new 'Other Filter' feature
the programming challenges seemed just too great. Yet,
when Jaromir suggests its desirability it now suddenly
becomes a reality. Another of life's little mysteries!

At any rate what was already an extremely powerful new
feature is even better by several orders of magnitude!

(everything is perfectly justified plus right margins)
(are completely filled, but of course it must be luck)

References:
http://www.freelists.org/post/procps/top-beyond-infinity,1

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2013-03-05 00:00:00 -06:00 committed by Jaromir Capik
parent f9a208b273
commit 2c2c5f5cd2
2 changed files with 44 additions and 22 deletions

View File

@ -1299,19 +1299,21 @@ static inline const char *hex_make (KLONG num, int noz) {
/* /*
* The sructure hung from a WIN_t when 'other' filtering is active. */ * This sructure is hung from a WIN_t when other filtering is active */
struct osel_s { struct osel_s {
int flg; // include == 1, exclude == 0
FLG_t enu; // field (procflag) to filter
char *val; // value included or excluded
char *(*cmp)(const char *, const char *); // string comparison function
char *raw; // raw user input (dup check)
struct osel_s *nxt; // the next criteria or NULL. struct osel_s *nxt; // the next criteria or NULL.
int (*rel)(const char *, const char *); // relational strings compare
char *(*sel)(const char *, const char *); // for selection str compares
char *raw; // raw user input (dup check)
char *val; // value included or excluded
int ops; // filter delimiter/operation
int flg; // include == 1, exclude == 0
int enu; // field (procflag) to filter
}; };
/* /*
* A function to turn off any 'other' filtering in the given window */ * A function to turn off entire other filtering in the given window */
static void osel_clear (WIN_t *q) { static void osel_clear (WIN_t *q) {
struct osel_s *osel = q->osel_1st; struct osel_s *osel = q->osel_1st;
@ -1333,17 +1335,30 @@ static void osel_clear (WIN_t *q) {
/* /*
* Determine if there's a matching value among the 'other' criteria * Determine if there is a matching value or releationship among the
* in a given window -- it's called from only one place, and likely * other criteria in the passed window -- it's called from only one
* inlined even without the directive */ * place, and likely inlined even without the directive */
static inline int osel_matched (const WIN_t *q, FLG_t enu, const char *str) { static inline int osel_matched (const WIN_t *q, FLG_t enu, const char *str) {
struct osel_s *osel = q->osel_1st; struct osel_s *osel = q->osel_1st;
while (osel) { while (osel) {
if (osel->enu == enu) { if (osel->enu == enu) {
char *p = osel->cmp(str, osel->val); int r;
if (p && !osel->flg) return 0; switch (osel->ops) {
if (!p && osel->flg) return 0; case '<': // '<' needs the r < 0 unless
r = osel->rel(str, osel->val); // '!' which needs an inverse
if ((0 <= r && osel->flg) || (0 >= r && !osel->flg)) return 0;
break;
case '>': // '>' needs the r > 0 unless
r = osel->rel(str, osel->val); // '!' which needs an inverse
if ((0 >= r && osel->flg) || (0 <= r && !osel->flg)) return 0;
break;
default:
{ char *p = osel->sel(str, osel->val);
if ((!p && osel->flg) || (p && !osel->flg)) return 0;
}
break;
}
} }
osel = osel->nxt; osel = osel->nxt;
} }
@ -4051,18 +4066,21 @@ signify_that:
static void other_selection (int ch) { static void other_selection (int ch) {
char *(*cmp)(const char *, const char *); int (*rel)(const char *, const char *);
char raw[MEDBUFSIZ], *glob, *pval; char *(*sel)(const char *, const char *);
char raw[MEDBUFSIZ], ops, *glob, *pval;
struct osel_s *osel; struct osel_s *osel;
const char *typ; const char *typ;
int flg, enu; int flg, enu;
if (ch == 'o') { if (ch == 'o') {
typ = N_txt(OSEL_casenot_txt); typ = N_txt(OSEL_casenot_txt);
cmp = strcasestr; rel = strcasecmp;
sel = strcasestr;
} else { } else {
typ = N_txt(OSEL_caseyes_txt); typ = N_txt(OSEL_caseyes_txt);
cmp = strstr; rel = strcmp;
sel = strstr;
} }
glob = ioline(fmtmk(N_fmt(OSEL_prompts_fmt), Curwin->osel_tot + 1, typ)); glob = ioline(fmtmk(N_fmt(OSEL_prompts_fmt), Curwin->osel_tot + 1, typ));
if (!snprintf(raw, sizeof(raw), "%s", glob)) return; if (!snprintf(raw, sizeof(raw), "%s", glob)) return;
@ -4075,11 +4093,12 @@ static void other_selection (int ch) {
} }
if (*glob != '!') flg = 1; // #2: is it include/exclude? if (*glob != '!') flg = 1; // #2: is it include/exclude?
else { ++glob; flg = 0; } else { ++glob; flg = 0; }
if (!(pval = strchr(glob, ':'))) { // #3: do we see a delimiter? if (!(pval = strpbrk(glob, "<=>"))) { // #3: do we see a delimiter?
show_msg(fmtmk(N_fmt(OSEL_errdelm_fmt) show_msg(fmtmk(N_fmt(OSEL_errdelm_fmt)
, flg ? N_txt(WORD_include_txt) : N_txt(WORD_exclude_txt))); , flg ? N_txt(WORD_include_txt) : N_txt(WORD_exclude_txt)));
return; return;
} }
ops = *(pval);
*(pval++) = '\0'; *(pval++) = '\0';
for (enu = 0; enu < P_MAXPFLGS; enu++) // #4: is this a valid field? for (enu = 0; enu < P_MAXPFLGS; enu++) // #4: is this a valid field?
if (!STRCMP(N_col(enu), glob)) break; if (!STRCMP(N_col(enu), glob)) break;
@ -4095,8 +4114,11 @@ static void other_selection (int ch) {
osel = alloc_c(sizeof(struct osel_s)); osel = alloc_c(sizeof(struct osel_s));
osel->flg = flg; osel->flg = flg;
osel->enu = enu; osel->enu = enu;
osel->val = alloc_s(pval); osel->ops = ops;
osel->cmp = cmp; if (ops == '=') osel->val = alloc_s(pval);
else osel->val = alloc_s(justify_pad(pval, Fieldstab[enu].width, Fieldstab[enu].align));
osel->rel = rel;
osel->sel = sel;
osel->raw = alloc_s(raw); osel->raw = alloc_s(raw);
osel->nxt = Curwin->osel_1st; osel->nxt = Curwin->osel_1st;
Curwin->osel_1st = osel; Curwin->osel_1st = osel;

View File

@ -431,7 +431,7 @@ static void build_norm_nlstab (void) {
Norm_nlstab[YINSP_workin_txt] = _("patience please, working..."); Norm_nlstab[YINSP_workin_txt] = _("patience please, working...");
/* Translation Hint: Below are 2 abbreviations which can be as long as needed: /* Translation Hint: Below are 2 abbreviations which can be as long as needed:
. FLD = FIELD, VAL = VALUE */ . FLD = FIELD, VAL = VALUE */
Norm_nlstab[OSEL_prompts_fmt] = _("add filter #%d (%s) as: [!]FLD:VAL"); Norm_nlstab[OSEL_prompts_fmt] = _("add filter #%d (%s) as: [!]FLD?VAL");
Norm_nlstab[OSEL_casenot_txt] = _("ignoring case"); Norm_nlstab[OSEL_casenot_txt] = _("ignoring case");
Norm_nlstab[OSEL_caseyes_txt] = _("case sensitive"); Norm_nlstab[OSEL_caseyes_txt] = _("case sensitive");
Norm_nlstab[OSEL_errdups_txt] = _("duplicate filter was ignored"); Norm_nlstab[OSEL_errdups_txt] = _("duplicate filter was ignored");
@ -439,7 +439,7 @@ static void build_norm_nlstab (void) {
Norm_nlstab[OSEL_errvalu_fmt] = _("'%s' filter value is missing"); Norm_nlstab[OSEL_errvalu_fmt] = _("'%s' filter value is missing");
Norm_nlstab[WORD_include_txt] = _("include"); Norm_nlstab[WORD_include_txt] = _("include");
Norm_nlstab[WORD_exclude_txt] = _("exclude"); Norm_nlstab[WORD_exclude_txt] = _("exclude");
Norm_nlstab[OSEL_statlin_fmt] = _("<Enter> to resume, filters = %s"); Norm_nlstab[OSEL_statlin_fmt] = _("<Enter> to resume, filters: %s");
Norm_nlstab[WORD_noneone_txt] = _("none"); Norm_nlstab[WORD_noneone_txt] = _("none");
} }