On Tue, Nov 27, 2018 at 11:28:31AM -0600, Scott Cheloha wrote: > On Sat, Nov 24, 2018 at 04:06:34PM +0100, Klemens Nanni wrote: > > Sometimes I want to see certain programs with least amount of memory, > > so this diff implements `o -field' to sort in reverse order. > > > > The logic is straight forward: > > > > 1. merge common code from argument and command loops into new setorder() > > 2. introduce global state `rev_order' (set in the helper) > > 3. move identical code to set up process objects from compare_*() > > functions into SETORDER macro using global boolean > > > > compare_*() are used by qsort(3). To sort in reverse, the macro simply > > swaps the objects used by the ORDERKEY_* macros. That is it inverts the > > comparison from `p1 > p2' into `p2 > p1' respectively `p1 < p2'. > > > > Works fine for all available fields on amd64, no behaviour change for > > "normal" order. > > > > Feedback? Objections? > > [...]
After lingering on this I missed a bug in my initial review. See inline. > > Index: display.c > > =================================================================== > > RCS file: /cvs/src/usr.bin/top/display.c,v > > retrieving revision 1.57 > > diff -u -p -r1.57 display.c > > --- display.c 17 Nov 2018 23:10:08 -0000 1.57 > > +++ display.c 24 Nov 2018 14:09:38 -0000 > > @@ -817,7 +817,8 @@ show_help(void) > > "I | i - toggle the display of idle processes\n" > > "k [-sig] pid - send signal `-sig' to process `pid'\n" > > "n|# count - show `count' processes\n" > > - "o field - specify sort order (size, res, cpu, time, pri, pid, > > command)\n" > > + "o [-]field - specify sort order (size, res, cpu, time, pri, pid, > > command)\n" > > + " (o -field sorts in reverse)\n" > > "o" isn't needed, as contextually you're talking about the 'o' shortcut. > Maybe "-field reverses order" or "'-' prefix reverses sort order"? > > > "P pid - highlight process `pid' (P+ switches highlighting > > off)\n" > > "p pid - display process by `pid' (p+ selects all > > processes)\n" > > "q - quit\n" > > Index: machine.c > > =================================================================== > > RCS file: /cvs/src/usr.bin/top/machine.c,v > > retrieving revision 1.95 > > diff -u -p -r1.95 machine.c > > --- machine.c 17 Nov 2018 23:10:08 -0000 1.95 > > +++ machine.c 24 Nov 2018 14:47:32 -0000 > > @@ -602,6 +602,8 @@ static unsigned char sorted_state[] = > > 1 /* zombie */ > > }; > > > > +extern int rev_order; > > + > > /* > > * proc_compares - comparison functions for "qsort" > > */ > > @@ -631,6 +633,17 @@ static unsigned char sorted_state[] = > > #define ORDERKEY_CMD \ > > if ((result = strcmp(p1->p_comm, p2->p_comm)) == 0) > > > > +/* remove one level of indirection and set sort order */ > > +#define SETORDER do { \ > > + if (rev_order) { \ > > + p1 = *(struct kinfo_proc **) pp2; \ > > + p2 = *(struct kinfo_proc **) pp1; \ > > + } else { \ > > + p1 = *(struct kinfo_proc **) pp1; \ > > + p2 = *(struct kinfo_proc **) pp2; \ > > + } \ > > + } while (0) > > + > > /* compare_cpu - the comparison function for sorting by cpu percentage */ > > static int > > compare_cpu(const void *v1, const void *v2) > > @@ -640,9 +653,7 @@ compare_cpu(const void *v1, const void * > > struct kinfo_proc *p1, *p2; > > int result; > > > > - /* remove one level of indirection */ > > - p1 = *(struct kinfo_proc **) pp1; > > - p2 = *(struct kinfo_proc **) pp2; > > + SETORDER; > > > > ORDERKEY_PCTCPU > > ORDERKEY_CPUTIME > > @@ -663,9 +674,7 @@ compare_size(const void *v1, const void > > struct kinfo_proc *p1, *p2; > > int result; > > > > - /* remove one level of indirection */ > > - p1 = *(struct kinfo_proc **) pp1; > > - p2 = *(struct kinfo_proc **) pp2; > > + SETORDER; > > > > ORDERKEY_MEM > > ORDERKEY_RSSIZE > > @@ -686,9 +695,7 @@ compare_res(const void *v1, const void * > > struct kinfo_proc *p1, *p2; > > int result; > > > > - /* remove one level of indirection */ > > - p1 = *(struct kinfo_proc **) pp1; > > - p2 = *(struct kinfo_proc **) pp2; > > + SETORDER; > > > > ORDERKEY_RSSIZE > > ORDERKEY_MEM > > @@ -709,9 +716,7 @@ compare_time(const void *v1, const void > > struct kinfo_proc *p1, *p2; > > int result; > > > > - /* remove one level of indirection */ > > - p1 = *(struct kinfo_proc **) pp1; > > - p2 = *(struct kinfo_proc **) pp2; > > + SETORDER; > > > > ORDERKEY_CPUTIME > > ORDERKEY_PCTCPU > > @@ -732,9 +737,7 @@ compare_prio(const void *v1, const void > > struct kinfo_proc *p1, *p2; > > int result; > > > > - /* remove one level of indirection */ > > - p1 = *(struct kinfo_proc **) pp1; > > - p2 = *(struct kinfo_proc **) pp2; > > + SETORDER; > > > > ORDERKEY_PRIO > > ORDERKEY_PCTCPU > > @@ -754,9 +757,7 @@ compare_pid(const void *v1, const void * > > struct kinfo_proc *p1, *p2; > > int result; > > > > - /* remove one level of indirection */ > > - p1 = *(struct kinfo_proc **) pp1; > > - p2 = *(struct kinfo_proc **) pp2; > > + SETORDER; > > > > ORDERKEY_PID > > ORDERKEY_PCTCPU > > @@ -777,9 +778,7 @@ compare_cmd(const void *v1, const void * > > struct kinfo_proc *p1, *p2; > > int result; > > > > - /* remove one level of indirection */ > > - p1 = *(struct kinfo_proc **) pp1; > > - p2 = *(struct kinfo_proc **) pp2; > > + SETORDER; > > > > ORDERKEY_CMD > > ORDERKEY_PCTCPU > > Index: top.1 > > =================================================================== > > RCS file: /cvs/src/usr.bin/top/top.1,v > > retrieving revision 1.70 > > diff -u -p -r1.70 top.1 > > --- top.1 2 Nov 2018 12:46:10 -0000 1.70 > > +++ top.1 23 Nov 2018 21:50:39 -0000 > > @@ -35,7 +35,7 @@ > > .Op Fl 1bCHIinqSu > > .Op Fl d Ar count > > .Op Fl g Ar string > > -.Op Fl o Ar field > > +.Op Fl o Oo - Oc Ns Ar field > > .Op Fl p Ar pid > > .Op Fl s Ar time > > .Op Fl U Oo - Oc Ns Ar user > > @@ -137,13 +137,16 @@ mode. > > This is identical to > > .Em batch > > mode. > > -.It Fl o Ar field > > +.It Fl o Oo - Oc Ns Ar field > > Sort the process display area using the specified > > .Ar field > > as the primary key. > > The field name is the name of the column as seen in the output, > > but in lower case. > > The > > +.Sq - > > +prefix reverses the order. > > My understanding is that an "order" is the actual progression of > a sequence, while an "ordering" refers to the underlying function > or rule that gives rise to a given "order" when applied to a set. > > So, I *think* you want > > "reverses the ordering for the field" > > or something similar, but I'm not positive. > > > +The > > .Ox > > version of > > .Nm > > @@ -327,10 +330,13 @@ This acts similarly to the command > > Show > > .Ar count > > processes. > > -.It o Ar field > > +.It o Oo - Oc Ns Ar field > > Sort the process display area using the specified > > .Ar field > > as the primary key. > > +The > > +.Sq - > > +prefix reverses the order. > > Same thing here. > > "reverses the ordering for the field" > > > Values are the same as for the > > .Fl o > > flag, as detailed above. > > Index: top.c > > =================================================================== > > RCS file: /cvs/src/usr.bin/top/top.c,v > > retrieving revision 1.97 > > diff -u -p -r1.97 top.c > > --- top.c 17 Nov 2018 23:10:08 -0000 1.97 > > +++ top.c 24 Nov 2018 15:04:04 -0000 > > @@ -74,6 +74,7 @@ extern int ncpuonline; > > > > extern int (*proc_compares[])(const void *, const void *); > > int order_index; > > +int rev_order; > > > > int displays = 0; /* indicates unspecified */ > > char do_unames = Yes; > > @@ -93,6 +94,9 @@ int combine_cpus = 0; > > char topn_specified = No; > > #endif > > > > +struct system_info system_info; > > +struct statics statics; > > + > > /* > > * these defines enumerate the "strchr"s of the commands in > > * command_chars > > @@ -129,12 +133,20 @@ usage(void) > > extern char *__progname; > > > > fprintf(stderr, > > - "usage: %s [-1bCHIinqSu] [-d count] [-g string] [-o field] " > > + "usage: %s [-1bCHIinqSu] [-d count] [-g string] [-o [-]field] " > > "[-p pid] [-s time]\n\t[-U [-]user] [number]\n", > > __progname); > > } > > > > static int > > +getorder(char *field) > > +{ > > + rev_order = field[0] == '-'; > > + > > + return string_index(rev_order ? field + 1 : field, statics.order_names); > > +} > > + You need to check that the field has an ordering before potentially modifying rev_order, otherwise a bogus input will have a side effect. For example, with the current code the input "o -notafield" reverses the ordering. > > +static int > > filteruser(char buf[]) > > { > > const char *errstr; > > @@ -311,9 +323,6 @@ parseargs(int ac, char **av) > > } > > } > > > > -struct system_info system_info; > > -struct statics statics; > > - > > int > > main(int argc, char *argv[]) > > { > > @@ -381,20 +390,9 @@ main(int argc, char *argv[]) > > > > /* determine sorting order index, if necessary */ > > if (order_name != NULL) { > > - if ((order_index = string_index(order_name, > > - statics.order_names)) == -1) { > > - char **pp, msg[512]; > > - > > - snprintf(msg, sizeof(msg), > > - "'%s' is not a recognized sorting order", > > - order_name); > > - strlcat(msg, ". Valid are:", sizeof(msg)); > > - pp = statics.order_names; > > - while (*pp != NULL) { > > - strlcat(msg, " ", sizeof(msg)); > > - strlcat(msg, *pp++, sizeof(msg)); > > - } > > - new_message(MT_delayed, msg); > > + if ((order_index = getorder(order_name)) == -1) { > > + new_message(MT_delayed, > > + " %s: unrecognized sorting order", order_name); > > And again. Maybe: > > "unrecognized sort ordering" > > > order_index = 0; > > } > > } > > @@ -879,10 +877,10 @@ rundisplay(void) > > new_message(MT_standout, > > "Order to sort: "); > > if (readline(tempbuf, sizeof(tempbuf)) > 0) { > > - if ((i = string_index(tempbuf, > > - statics.order_names)) == -1) { > > + if ((i = getorder(tempbuf)) == -1) { > > new_message(MT_standout, > > " %s: unrecognized sorting order", > > + tempbuf[0] == '-' ? tempbuf + 1 : > > tempbuf); > > You aren't ducking the '-' during init so I don't think you should hide it > here. > You could even refactor the two into something like > > void setorder(const char *); > > to keep the messages in sync, but that should be done in a subsequent diff. > > Also, the "order" vs. "ordering" thing here. > > > no_command = Yes; > > } else > > =================================================================== > > Stats: --- 45 lines 1516 chars > > Stats: +++ 49 lines 1189 chars > > Stats: 4 lines > > Stats: -327 chars > >