top: provide an unlimited capacity for field additions

With each of those references shown below, the maximum
number of fields was increased. However, with a 'char'
based implementation we're nearing the upper limits of
total displayable fields. We currently use 76 of a max
of 86 fields. With extra effort, 94 might be possible.

But 94 is the absolute upper limit of possible fields!

Moreover, the current implementation yields characters
that were unprintable in the rcfile. This could become
an issue with that 'inspect' feature when/if an rcfile
is edited to add entries (as opposed to using 'echo').

So, with this commit the internals of field management
has been completely reimagined. It is now based on the
integer type, not a character. And whereas that former
design used the high order bit to show the 'on' state,
thus yielding an unprintable character, the new design
uses the low order bit for the state. As such, numbers
will be kept small and an even number will be an 'off'
field whereas an odd number will become an 'on' state.

The bottom line is that this new design will afford an
unlimited number of new fields while keeping an rcfile
completely free of that potential unprintable garbage.

And it is embarrassingly easy to extend the maximum of
supportable fields from the currently implemented 100.
Who knows, maybe a future patch will prove this point.

[ unless a subsequent commit proves otherwise, given ]
[ the dramatic differences in rcfile contents, i had ]
[ to abandon the practice of supporting old rcfiles. ]

Reference(s):
. Nov, 2013 - RCF_PLUS_H introduced
commit af4e6533ba
. Jul, 2016 - RCF_PLUS_J introduced
commit d5c5051fb3

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2022-03-13 00:00:00 -06:00 committed by Craig Small
parent c493fca892
commit 46aa96e438
2 changed files with 101 additions and 146 deletions

164
top/top.c
View File

@ -311,6 +311,28 @@ static const char *fmtmk (const char *fmts, ...) {
} // end: fmtmk
/*
* Interger based fieldscur version of 'strlen' */
static inline int mlen (const int *mem) {
int i;
for (i = 0; mem[i]; i++)
;
return i;
} // end: mlen
/*
* Interger based fieldscur version of 'strchr' */
static inline int *msch (const int *mem, int obj, int max) {
int i;
for (i = 0; i < max; i++)
if (*(mem + i) == obj) return (int *)mem + i;
return NULL;
} // end: msch
/*
* This guy is just our way of avoiding the overhead of the standard
* strcat function (should the caller choose to participate) */
@ -439,7 +461,7 @@ static void bye_bye (const char *str) {
, Curwin->rc.sortindx, Curwin->rc.maxtasks
, Curwin->varcolsz, Curwin->winlines
, (int)strlen(Curwin->columnhdr)
, EU_MAXPFLGS, (int)strlen(Curwin->rc.fieldscur)
, EU_MAXPFLGS, mlen(Curwin->rc.fieldscur)
);
}
}
@ -2244,7 +2266,6 @@ static void display_fields (int focus, int extend) {
/* prep sacrificial suffix (allowing for beginning '= ')
note: width passed to 'utf8_embody' may go negative, but he'll be just fine */
snprintf(sbuf, sizeof(sbuf), "= %.*s", utf8_embody(N_fld(f), smax - xEQUS), N_fld(f));
// obtain translated deltas (if any) ...
xcol = utf8_delta(fmtmk("%.*s", utf8_embody(N_col(f), 7), N_col(f)));
xfld = utf8_delta(sbuf + xEQUS); // ignore beginning '= '
@ -2284,14 +2305,14 @@ static void fields_utility (void) {
#else
#define unSCRL { w->begpflg = 0; OFFw(w, Show_HICOLS); }
#endif
#define swapEM { char c; unSCRL; c = w->rc.fieldscur[i]; \
#define swapEM { int c; unSCRL; c = w->rc.fieldscur[i]; \
w->rc.fieldscur[i] = *p; *p = c; p = &w->rc.fieldscur[i]; }
#define spewFI { char *t; f = w->rc.sortindx; t = strchr(w->rc.fieldscur, f + FLD_OFFSET); \
if (!t) t = strchr(w->rc.fieldscur, (f + FLD_OFFSET) | 0x80); \
#define spewFI { int *t; f = w->rc.sortindx; t = msch(w->rc.fieldscur, f + FLD_OFFSET, EU_MAXPFLGS); \
if (!t) t = msch(w->rc.fieldscur, (f + FLD_OFFSET) | 0x01, EU_MAXPFLGS); \
i = (t) ? (int)(t - w->rc.fieldscur) : 0; }
WIN_t *w = Curwin; // avoid gcc bloat with a local copy
const char *h = NULL;
char *p = NULL;
int *p = NULL;
int i, key;
FLG_t f;
@ -2349,7 +2370,8 @@ signify_that:
case 'w':
Curwin = w = ('a' == key) ? w->next : w->prev;
spewFI
h = p = NULL;
h = NULL;
p = NULL;
break;
default: // keep gcc happy
break;
@ -3560,79 +3582,6 @@ static void before (char *me) {
} // end: before
/*
* A configs_file *Helper* function responsible for converting
* a single window's old rc stuff into a new style rcfile entry */
static int config_cvt (WIN_t *q) {
static struct {
int old, new;
} flags_tab[] = {
#define old_View_NOBOLD 0x000001
#define old_VISIBLE_tsk 0x000008
#define old_Qsrt_NORMAL 0x000010
#define old_Show_HICOLS 0x000200
#define old_Show_THREAD 0x010000
{ old_View_NOBOLD, View_NOBOLD },
{ old_VISIBLE_tsk, Show_TASKON },
{ old_Qsrt_NORMAL, Qsrt_NORMAL },
{ old_Show_HICOLS, Show_HICOLS },
{ old_Show_THREAD, 0 }
#undef old_View_NOBOLD
#undef old_VISIBLE_tsk
#undef old_Qsrt_NORMAL
#undef old_Show_HICOLS
#undef old_Show_THREAD
};
static const char fields_src[] = CVT_FIELDS;
char fields_dst[PFLAGSSIZ], *p1, *p2;
int i, j, x;
// first we'll touch up this window's winflags...
x = q->rc.winflags;
q->rc.winflags = 0;
for (i = 0; i < MAXTBL(flags_tab); i++) {
if (x & flags_tab[i].old) {
x &= ~flags_tab[i].old;
q->rc.winflags |= flags_tab[i].new;
}
}
q->rc.winflags |= x;
// now let's convert old top's more limited fields...
j = strlen(q->rc.fieldscur);
if (j > CVT_FLDMAX)
return 1;
strcpy(fields_dst, fields_src);
/* all other fields represent the 'on' state with a capitalized version
of a particular qwerty key. for the 2 additional suse out-of-memory
fields it makes perfect sense to do the exact opposite, doesn't it?
in any case, we must turn them 'off' temporarily... */
if ((p1 = strchr(q->rc.fieldscur, '['))) *p1 = '{';
if ((p2 = strchr(q->rc.fieldscur, '\\'))) *p2 = '|';
for (i = 0; i < j; i++) {
int c = q->rc.fieldscur[i];
x = tolower(c) - 'a';
if (x < 0 || x >= CVT_FLDMAX)
return 1;
fields_dst[i] = fields_src[x];
if (isupper(c))
FLDon(fields_dst[i]);
}
// if we turned any suse only fields off, turn 'em back on OUR way...
if (p1) FLDon(fields_dst[p1 - q->rc.fieldscur]);
if (p2) FLDon(fields_dst[p2 - q->rc.fieldscur]);
strcpy(q->rc.fieldscur, fields_dst);
// lastly, we must adjust the old sort field enum...
x = q->rc.sortindx;
q->rc.sortindx = fields_src[x] - FLD_OFFSET;
if (q->rc.sortindx < 0 || q->rc.sortindx >= EU_MAXPFLGS)
return 1;
return 0;
} // end: config_cvt
/*
* A configs_file *Helper* function responsible for reading
* and validating a configuration file's 'Inspection' entries */
@ -3780,7 +3729,7 @@ static const char *configs_file (FILE *fp, const char *name, float *delay) {
, &Rc.id, &Rc.mode_altscr, &Rc.mode_irixps, &tmp_whole, &tmp_fract, &i)) {
return p;
}
if (Rc.id < 'a' || Rc.id > RCF_VERSION_ID)
if (Rc.id != RCF_VERSION_ID)
return p;
if (Rc.mode_altscr < 0 || Rc.mode_altscr > 1)
return p;
@ -3796,18 +3745,17 @@ static const char *configs_file (FILE *fp, const char *name, float *delay) {
*delay = (float)tmp_whole + (float)tmp_fract / 1000;
for (i = 0 ; i < GROUPSMAX; i++) {
int n, x;
int j, n, x;
WIN_t *w = &Winstk[i];
p = fmtmk(N_fmt(RC_bad_entry_fmt), i+1, name);
// note: "fieldscur=%__s" on next line should equal (PFLAGSSIZ -1) !
if (2 != fscanf(fp, "%3s\tfieldscur=%99s\n"
, w->rc.winname, w->rc.fieldscur))
if (1 != fscanf(fp, "%3s\tfieldscur=", w->rc.winname))
return p;
for (j = 0; j < mlen(w->rc.fieldscur); j++) {
if (1 != fscanf(fp, "%d ", &w->rc.fieldscur[j]))
return p;
#if PFLAGSSIZ != 100
// too bad fscanf is not as flexible with his format string as snprintf
#error Hey, fix the above fscanf 'PFLAGSSIZ' dependency !
#endif
}
// be tolerant of missing release 3.3.10 graph modes additions
if (3 > fscanf(fp, "\twinflags=%d, sortindx=%d, maxtasks=%d, graph_cpus=%d, graph_mems=%d"
", double_up=%d, combine_cpus=%d\n"
@ -3839,38 +3787,26 @@ static const char *configs_file (FILE *fp, const char *name, float *delay) {
switch (Rc.id) {
case 'a': // 3.2.8 (former procps)
if (config_cvt(w))
return p;
// fall through
case 'f': // 3.3.0 thru 3.3.3 (ng)
SETw(w, Show_JRNUMS);
// fall through
case 'g': // from 3.3.4 thru 3.3.8
scat(w->rc.fieldscur, RCF_PLUS_H);
// fall through
case 'h': // this is release 3.3.9
w->rc.graph_cpus = w->rc.graph_mems = 0;
// these next 2 are really global, but best documented here
Rc.summ_mscale = Rc.task_mscale = SK_Kb;
// fall through
case 'i': // from 3.3.10 thru 3.3.16
scat(w->rc.fieldscur, RCF_PLUS_J);
w->rc.double_up = w->rc.combine_cpus = 0;
// fall through
case 'j': // this is release 3.3.17
Rc.tics_scaled = 0;
return p;
case 'k': // current RCF_VERSION_ID
default:
if (strlen(w->rc.fieldscur) != sizeof(DEF_FIELDS) - 1)
if (mlen(w->rc.fieldscur) < EU_MAXPFLGS)
return p;
for (x = 0; x < EU_MAXPFLGS; ++x)
if (EU_MAXPFLGS <= FLDget(w, x))
for (x = 0; x < EU_MAXPFLGS; x++) {
FLG_t f = FLDget(w, x);
if (f >= EU_MAXPFLGS || f < 0)
return p;
}
break;
}
// ensure there's been no manual alteration of fieldscur
for (n = 0 ; n < EU_MAXPFLGS; n++) {
if (&w->rc.fieldscur[n] != strrchr(w->rc.fieldscur, w->rc.fieldscur[n]))
if (&w->rc.fieldscur[n] != msch(w->rc.fieldscur, w->rc.fieldscur[n], EU_MAXPFLGS))
return p;
}
#ifndef USE_X_COLHDR
@ -4964,7 +4900,7 @@ static void other_filters (int ch) {
static void write_rcfile (void) {
FILE *fp;
int i;
int i, j, n;
if (Rc_questions) {
show_pmt(N_txt(XTRA_warncfg_txt));
@ -4991,8 +4927,14 @@ static void write_rcfile (void) {
, (int)(Curwin - Winstk));
for (i = 0 ; i < GROUPSMAX; i++) {
fprintf(fp, "%s\tfieldscur=%s\n"
, Winstk[i].rc.winname, Winstk[i].rc.fieldscur);
n = mlen(Winstk[i].rc.fieldscur);
fprintf(fp, "%s\tfieldscur=", Winstk[i].rc.winname);
for (j = 0; j < n; j++) {
if (j && !(j % FLD_ROWMAX) && j < n)
fprintf(fp, "\n\t\t ");
fprintf(fp, "%4d ", (int)Winstk[i].rc.fieldscur[j]);
}
fprintf(fp, "\n");
fprintf(fp, "\twinflags=%d, sortindx=%d, maxtasks=%d, graph_cpus=%d, graph_mems=%d"
", double_up=%d, combine_cpus=%d\n"
, Winstk[i].rc.winflags, Winstk[i].rc.sortindx, Winstk[i].rc.maxtasks

View File

@ -226,7 +226,7 @@ enum resize_states {
};
/* This typedef just ensures consistent 'process flags' handling */
typedef unsigned char FLG_t;
typedef int FLG_t;
/* These typedefs attempt to ensure consistent 'ticks' handling */
typedef unsigned long long TIC_t;
@ -316,8 +316,8 @@ typedef struct RCW_t { // the 'window' portion of an rcfile
msgsclr, // " in msgs/pmts
headclr, // " in cols head
taskclr; // " in task rows
char winname [WINNAMSIZ], // name for the window, user changeable
fieldscur [PFLAGSSIZ]; // the fields for display & their order
char winname [WINNAMSIZ]; // name for the window, user changeable
FLG_t fieldscur [PFLAGSSIZ]; // the fields for display & their order
} RCW_t;
/* This represents the complete rcfile */
@ -399,12 +399,11 @@ typedef struct WIN_t {
#define VIZTOGw(q,f) (VIZISw(q)) ? TOGw(q,(f)) : win_warn(Warn_VIZ)
// Used to test/manipulte fieldscur values
#define FLDon(c) ((c) |= 0x80)
#define FLDget(q,i) ((FLG_t)((q)->rc.fieldscur[i] & 0x7f) - FLD_OFFSET)
#define FLDtog(q,i) ((q)->rc.fieldscur[i] ^= 0x80)
#define FLDviz(q,i) ((q)->rc.fieldscur[i] & 0x80)
#define ENUviz(w,E) (NULL != memchr((w)->procflgs, E, (w)->maxpflgs))
#define ENUpos(w,E) ((int)((FLG_t*)memchr((w)->pflgsall, E, (w)->totpflgs) - (w)->pflgsall))
#define FLDget(q,i) ( (((q)->rc.fieldscur[i]) >> 1) - FLD_OFFSET )
#define FLDtog(q,i) ( (q)->rc.fieldscur[i] ^= 0x01 )
#define FLDviz(q,i) ( (q)->rc.fieldscur[i] & 0x01 )
#define ENUviz(w,E) ( NULL != msch((w)->procflgs, E, w->maxpflgs) )
#define ENUpos(w,E) ( (int)(msch((w)->pflgsall, E, (w)->totpflgs) - (w)->pflgsall) )
// Support for variable width columns (and potentially scrolling too)
#define VARcol(E) (-1 == Fieldstab[E].width)
@ -507,33 +506,47 @@ typedef struct WIN_t {
#define SYS_RCRESTRICT "/etc/toprc"
#define SYS_RCDEFAULTS "/etc/topdefaultrc"
#define RCF_EYECATCHER "Config File (Linux processes with windows)\n"
#define RCF_PLUS_H "\\]^_`abcdefghij"
#define RCF_PLUS_J "klmnopqrstuvwxyz"
#define RCF_VERSION_ID 'k'
/* The default fields displayed and their order, if nothing is
specified by the loser, oops user.
note: any *contiguous* ascii sequence can serve as fieldscur
characters as long as the initial value is coordinated
with that specified for FLD_OFFSET
( we're providing for up to 86 fields currently, )
( with just one escaped value, the '\' character ) */
#define FLD_OFFSET '%'
// seq_fields "%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz"
#ifdef ORIG_TOPDEFS
#define DEF_FIELDS "¥¨³´»½ÀÄ·º¹Å&')*+,-./012568<>?ABCFGHIJKLMNOPQRSTUVWXYZ[" RCF_PLUS_H RCF_PLUS_J
#else
#define DEF_FIELDS "¥&K¨³´»½@·º¹56ÄFÅ')*+,-./0128<>?ABCGHIJLMNOPQRSTUVWXYZ[" RCF_PLUS_H RCF_PLUS_J
#endif
/* Pre-configured windows/field groups */
#define JOB_FIELDS "¥¦¹·º(³´Ä»½@<§Å)*+,-./012568>?ABCFGHIJKLMNOPQRSTUVWXYZ[" RCF_PLUS_H RCF_PLUS_J
#define MEM_FIELDS "¥º»<½¾¿ÀÁMBNÃD34·Å&'()*+,-./0125689FGHIJKLOPQRSTUVWXYZ[" RCF_PLUS_H RCF_PLUS_J
#define USR_FIELDS "¥¦§¨ª°¹·ºÄÅ)+,-./1234568;<=>?@ABCFGHIJKLMNOPQRSTUVWXYZ[" RCF_PLUS_H RCF_PLUS_J
// old top fields ( 'a'-'z' ) in positions 0-25
// other suse old top fields ( '{|' ) in positions 26-27
#define CVT_FIELDS "%&*'(-0346789:;<=>?@ACDEFGML)+,./125BHIJKNOPQRSTUVWXYZ["
#define CVT_FLDMAX 28
#define FLD_OFFSET ( (int)'%' )
#define FLD_ROWMAX 20
/* The default fields displayed and their order,
if nothing is specified by the loser, oops user. */
#define OLD_FIELDS { \
75, 81, 103, 105, 119, 123, 129, 137, 111, 117, 115, 139, 76, 78, 82, 84, 86, 88, 90, 92, \
94, 96, 98, 100, 106, 108, 112, 120, 124, 126, 130, 132, 134, 140, 142, 144, 146, 148, 150, 152, \
154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, \
194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, \
234, 236, 238, 240, 242, 244, }
#ifdef ORIG_TOPDEFS
#define DEF_FIELDS OLD_FIELDS
#else
#define DEF_FIELDS { \
75, 76, 150, 81, 103, 105, 119, 123, 128, 111, 117, 115, 106, 108, 137, 140, 139, 78, 82, 84, \
86, 88, 90, 92, 94, 96, 98, 100, 112, 120, 124, 126, 130, 132, 134, 142, 144, 146, 148, 152, \
154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, \
194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, \
234, 236, 238, 240, 242, 244 }
#endif
#define JOB_FIELDS { \
75, 77, 115, 111, 117, 80, 103, 105, 137, 119, 123, 128, 120, 79, 139, 82, 84, 86, 88, 90, \
92, 94, 96, 98, 100, 106, 108, 112, 124, 126, 130, 132, 134, 140, 142, 144, 146, 148, 150, 152, \
154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, \
194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, \
234, 236, 238, 240, 242, 244 }
#define MEM_FIELDS { \
75, 117, 119, 120, 123, 125, 127, 129, 131, 154, 132, 156, 135, 136, 102, 104, 111, 139, 76, 78, \
80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 106, 108, 112, 114, 140, 142, 144, 146, 148, \
150, 152, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, \
194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, \
234, 236, 238, 240, 242, 244 }
#define USR_FIELDS { \
75, 77, 79, 81, 85, 97, 115, 111, 117, 137, 139, 82, 86, 88, 90, 92, 94, 98, 100, 102, \
104, 106, 108, 112, 118, 120, 122, 124, 126, 128, 130, 132, 134, 140, 142, 144, 146, 148, 150, 152, \
154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, \
194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, \
234, 236, 238, 240, 242, 244 }
/* The default values for the local config file */
#define DEF_RCFILE { \
@ -557,7 +570,6 @@ typedef struct WIN_t {
#define LOADAV_line "%s -%s\n"
#define LOADAV_line_alt "%s~6 -%s\n"
/*###### For Piece of mind #############################################*/
/* just sanity check(s)... */
@ -586,6 +598,8 @@ typedef struct WIN_t {
/* ( see the find_string function for the one true required protoype ) */
/*------ Tiny useful routine(s) ----------------------------------------*/
//atic const char *fmtmk (const char *fmts, ...);
//atic inline int mlen (const int *mem);
//atic inline int *msch (const int *mem, int obj, int max);
//atic inline char *scat (char *dst, const char *src);
//atic const char *tg2 (int x, int y);
/*------ Exit/Interrput routines ---------------------------------------*/
@ -667,7 +681,6 @@ typedef struct WIN_t {
//atic inline int osel_matched (const WIN_t *q, FLG_t enu, const char *str);
/*------ Startup routines ----------------------------------------------*/
//atic void before (char *me);
//atic int config_cvt (WIN_t *q);
//atic int config_insp (FILE *fp, char *buf, size_t size);
//atic int config_osel (FILE *fp, char *buf, size_t size);
//atic const char *configs_file (FILE *fp, const char *name, float *delay);