ps(1): Remove not-explicitly-requested columns with duplicate data
Before this change, when stacking up more columns in the display through
command-line options, if user requested to add some "canned" display
(through options '-j', '-l', '-u' or '-v'), columns in it that were
"duplicates" of already requested ones (meaning that they share the same
keyword, regardless of whether their headers have been customized) were
in the end omitted.
However, this mechanism did not work the other way around, i.e.,
requesting some canned display(s) first and then adding some columns
that are duplicates (through '-o' or '-O') would not remove them from
the canned display. Additionally, it did not take into account keyword
aliases (which also lead to displaying the same information).
This whole mechanism of removing columns from requested canned displays
when there are duplicates is useful in a number of scenarios:
- When one wants the columns of a canned display, but with some of them in a different order and at the edges of the bulk. This needs the change here to move columns after the bulk (previously, only moving them before the bulk would work).
- To combine multiple canned displays to get more information without repeating common columns. This part has been working before and this behavior is unchanged.
- In combination with requesting a canned display and additional columns after it, ensure that a single COMMAND column appears at the end of the display (to benefit from the fact that a last COMMAND column can extend further to the right).
Point 2 above implies that, when multiple canned displays are requested,
we should keep the leftmost column with same keyword. However, columns
requested explicitly by '-o' have priority (as the natural extension of
point 1's behavior before this change), and in this case all matching
columns in canned displays must be suppressed.
To this end, when adding requested options to the display's list, we
stop trying to find an earlier matching column (which is incidentally
a O(n²) algorithm). Instead, we do a first pass over all requested
options once they have all been added to the display's list (in
scan_vars()). For each keyword, we note if it was requested at least
once explicitly (through '-o' or '-O'), in addition to setting
'needuser' and 'needcomm' (as before). Then, a second pass decides
whether to keep each column. A column is removed if it should not be
kept absolutely (i.e., it wasn't specified via '-o' or '-O') and there
is either a matching column that must be kept (determined during the
first pass), or we have seen one already (earlier canned displays take
precedence).
Matching columns are in fact not only those that have same keywords, but
also those that have keywords determined to be aliases to each other.
Some previous commits ensured that this determination is O(1) and in
practice just a few assembly instructions.
find_varentry() has been kept although its last caller has been removed
as next commit will reintroduce a call to it.
MFC after: 3 days
Relnotes: yes
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D49612
Differential Revision: https://reviews.freebsd.org/D49613 (manual page)
(cherry picked from commit cd768a840644ad55029ce9c3d41fc52b5045e0cc)