ps: Add configurable date format for lstart field
The lstart field has been converted to use the strftime() function so that it uses the locale. A new option -D allows the user to define the format that would want this field to show. This may mean the field will be longer than it should be, especially for French locales and the user defined field, but the field length can be specified too. --- This commit started off making all the relevant fields use the locale correctly so it could solve #226 as well. The issue is there an implied restriction (or not) around strftime("%b") and probably strftime("%a") for abbrievated month and day names respectively. English, and some/most other languages put an additional restriction that all abbreviations are 3 characters long. The problem is, not all languages do this. French is a good example: janv. févr. mars avril mai juin juil. août sept. oct. nov. déc. Maybe strip the . at the end? That helps for some months, not all Maybe take the first three characters? Several wide languages will have big issues Maybe convert wide, get wcslen then use that. Even after that June "juin" and July "juil" are both "jui". So, anything that uses the month (bsdstart,start) use ctime which doesn't use locale. That solves the length issue. stime does, which means it has this issue but its been like that for years. You get stuff like this: janv.13 482261 00:00 1151918 2022 1458628 06:12 1957584 The only way to fix that would be to a)Make the field two characters longer b)Convert it back to ctime() which means everyone else loses. This could have be oh-so easy if everyone made %b and %a three (wide) characters everywhere. References: procps-ng/procps#228 procps-ng/procps#226 Signed-off-by: Craig Small <csmall@dropbear.xyz>
This commit is contained in:
parent
bfe65a2cce
commit
2532b5d2dd
39
man/ps.1
39
man/ps.1
@ -1,10 +1,15 @@
|
|||||||
'\" t
|
|
||||||
.\" (The preceding line is a note to broken versions of man to tell
|
|
||||||
.\" Man page for ps.
|
|
||||||
.\" Quick hack conversion by Albert Cahalan, 1998.
|
|
||||||
.\" Licensed under version 2 of the Gnu General Public License.
|
|
||||||
.\"
|
.\"
|
||||||
.TH PS "1" "2023-01-16" "procps-ng" "User Commands"
|
.\" Copyright 1998 Albert Cahalan
|
||||||
|
.\" 2011-2023 Jim Warner <james.warner@comcast.net>
|
||||||
|
.\" 2011-2023 Craig Small <csmall@dropbear.xyz>
|
||||||
|
.\"
|
||||||
|
.\" This program is free software; you can redistribute it and/or modify
|
||||||
|
.\" it under the terms of the GNU General Public License as published by
|
||||||
|
.\" the Free Software Foundation; either version 2 of the License, or
|
||||||
|
.\" (at your option) any later version.
|
||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.TH PS "1" "2023-01-18" "procps-ng" "User Commands"
|
||||||
.\"
|
.\"
|
||||||
.\" To render this page:
|
.\" To render this page:
|
||||||
.\" groff -t -b -man -X -P-resolution -P100 -Tps ps.1 &
|
.\" groff -t -b -man -X -P-resolution -P100 -Tps ps.1 &
|
||||||
@ -598,6 +603,16 @@ Set screen width.
|
|||||||
.B \-\-cumulative
|
.B \-\-cumulative
|
||||||
Include some dead child process data (as a sum with the parent).
|
Include some dead child process data (as a sum with the parent).
|
||||||
.TP
|
.TP
|
||||||
|
.TP
|
||||||
|
.BI \-D \ format
|
||||||
|
Set the date format of the \fBlstart\fR field to \fIformat\fR. This format is parsed
|
||||||
|
by
|
||||||
|
.BR strftime (3)
|
||||||
|
and should be a maximum of 24 characters to not mis-align columns.
|
||||||
|
.TP
|
||||||
|
.BI \-\-date-format \ format
|
||||||
|
Identical to \fB\-D\fR.
|
||||||
|
.TP
|
||||||
.B e
|
.B e
|
||||||
Show the environment after the command.
|
Show the environment after the command.
|
||||||
.TP
|
.TP
|
||||||
@ -1385,8 +1400,8 @@ the
|
|||||||
T}
|
T}
|
||||||
|
|
||||||
lstart STARTED T{
|
lstart STARTED T{
|
||||||
time the command started. See also
|
time the command started. This will be in the form "DDD mmm HH:MM:SS YYY"
|
||||||
.BR bsdstart , \ start , \ start_time ", and" \ stime .
|
unless changed by the \fB\-D\fR option.
|
||||||
T}
|
T}
|
||||||
|
|
||||||
lsession SESSION T{
|
lsession SESSION T{
|
||||||
@ -2064,10 +2079,18 @@ unix98 standard
|
|||||||
.TE
|
.TE
|
||||||
.PP
|
.PP
|
||||||
.PP
|
.PP
|
||||||
|
.SH BUGS
|
||||||
|
The fields \fBbsdstart\fR and \fBstart\fR will only show the abbreviated
|
||||||
|
month name in English. The fields \fBlstart\fR and \fBstime\fR will show
|
||||||
|
the abbreviated month name in the configured locale but may exceed the
|
||||||
|
column width due to the different lengths for abbreviated month and day
|
||||||
|
names across languages.
|
||||||
|
.PP
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR pgrep (1),
|
.BR pgrep (1),
|
||||||
.BR pstree (1),
|
.BR pstree (1),
|
||||||
.BR top (1),
|
.BR top (1),
|
||||||
|
.BR strftime (3),
|
||||||
.BR proc (5).
|
.BR proc (5).
|
||||||
.PP
|
.PP
|
||||||
.PP
|
.PP
|
||||||
|
@ -451,6 +451,7 @@ extern int header_gap;
|
|||||||
extern int header_type; /* none, single, multi... */
|
extern int header_type; /* none, single, multi... */
|
||||||
extern int include_dead_children;
|
extern int include_dead_children;
|
||||||
extern int lines_to_next_header;
|
extern int lines_to_next_header;
|
||||||
|
extern char *lstart_format;
|
||||||
extern int max_line_width;
|
extern int max_line_width;
|
||||||
extern int negate_selection;
|
extern int negate_selection;
|
||||||
extern int page_size; // "int" for math reasons?
|
extern int page_size; // "int" for math reasons?
|
||||||
|
@ -183,6 +183,7 @@ int header_gap = -1;
|
|||||||
int header_type = -1;
|
int header_type = -1;
|
||||||
int include_dead_children = -1;
|
int include_dead_children = -1;
|
||||||
int lines_to_next_header = -1;
|
int lines_to_next_header = -1;
|
||||||
|
char *lstart_format = NULL;
|
||||||
int negate_selection = -1;
|
int negate_selection = -1;
|
||||||
int running_only = -1;
|
int running_only = -1;
|
||||||
int page_size = -1; // "int" for math reasons?
|
int page_size = -1; // "int" for math reasons?
|
||||||
|
@ -126,6 +126,7 @@ void do_help (const char *opt, int rc) {
|
|||||||
}
|
}
|
||||||
if (section == HELP_OUT || section == HELP_ALL) {
|
if (section == HELP_OUT || section == HELP_ALL) {
|
||||||
fputs(_("\nOutput formats:\n"), out);
|
fputs(_("\nOutput formats:\n"), out);
|
||||||
|
fputs(_(" -D <format> date format for lstart\n"), out);
|
||||||
fputs(_(" -F extra full\n"), out);
|
fputs(_(" -F extra full\n"), out);
|
||||||
fputs(_(" -f full-format, including command lines\n"), out);
|
fputs(_(" -f full-format, including command lines\n"), out);
|
||||||
fputs(_(" f, --forest ascii art process tree\n"), out);
|
fputs(_(" f, --forest ascii art process tree\n"), out);
|
||||||
|
@ -1044,11 +1044,21 @@ setREL1(VM_RSS)
|
|||||||
return snprintf(outbuf, COLWID, "%2u.%u", (unsigned)(pmem/10), (unsigned)(pmem%10));
|
return snprintf(outbuf, COLWID, "%2u.%u", (unsigned)(pmem/10), (unsigned)(pmem%10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format cannot be %c as the length changes depending on locale
|
||||||
|
#define DEFAULT_LSTART_FORMAT "%a %b %e %H:%M:%S %Y"
|
||||||
static int pr_lstart(char *restrict const outbuf, const proc_t *restrict const pp){
|
static int pr_lstart(char *restrict const outbuf, const proc_t *restrict const pp){
|
||||||
time_t t;
|
time_t t;
|
||||||
|
struct tm start_time;
|
||||||
|
size_t len;
|
||||||
setREL1(TICS_BEGAN)
|
setREL1(TICS_BEGAN)
|
||||||
t = boot_time() + rSv(TICS_BEGAN, ull_int, pp) / Hertz;
|
t = boot_time() + rSv(TICS_BEGAN, ull_int, pp) / Hertz;
|
||||||
return snprintf(outbuf, COLWID, "%24.24s", ctime(&t));
|
if (localtime_r(&t, &start_time) == NULL)
|
||||||
|
return 0;
|
||||||
|
len = strftime(outbuf, COLWID,
|
||||||
|
(lstart_format?lstart_format:DEFAULT_LSTART_FORMAT), &start_time);
|
||||||
|
if (len <= 0 || len >= COLWID)
|
||||||
|
outbuf[len = 0] = '\0';
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unix98 specifies a STIME header for a column that shows the start
|
/* Unix98 specifies a STIME header for a column that shows the start
|
||||||
|
@ -244,6 +244,13 @@ static const char *parse_sysv_option(void){
|
|||||||
if(err) return err;
|
if(err) return err;
|
||||||
selection_list->typecode = SEL_COMM;
|
selection_list->typecode = SEL_COMM;
|
||||||
return NULL; /* can't have any more options */
|
return NULL; /* can't have any more options */
|
||||||
|
case 'D':
|
||||||
|
trace("-D sets lstart date format\n");
|
||||||
|
arg = get_opt_arg();
|
||||||
|
if (!arg) return _("date format must follow -D");
|
||||||
|
if (lstart_format) free(lstart_format);
|
||||||
|
lstart_format = strdup(arg);
|
||||||
|
break;
|
||||||
case 'F': /* DYNIX/ptx -f plus sz,rss,psr=ENG between c and stime */
|
case 'F': /* DYNIX/ptx -f plus sz,rss,psr=ENG between c and stime */
|
||||||
trace("-F does fuller listing\n");
|
trace("-F does fuller listing\n");
|
||||||
format_modifiers |= FM_F;
|
format_modifiers |= FM_F;
|
||||||
@ -794,6 +801,7 @@ static const char *parse_gnu_option(void){
|
|||||||
{"columns", &&case_columns},
|
{"columns", &&case_columns},
|
||||||
{"context", &&case_context},
|
{"context", &&case_context},
|
||||||
{"cumulative", &&case_cumulative},
|
{"cumulative", &&case_cumulative},
|
||||||
|
{"date-format", &&case_dateformat},
|
||||||
{"deselect", &&case_deselect}, /* -N */
|
{"deselect", &&case_deselect}, /* -N */
|
||||||
{"forest", &&case_forest}, /* f -H */
|
{"forest", &&case_forest}, /* f -H */
|
||||||
{"format", &&case_format},
|
{"format", &&case_format},
|
||||||
@ -881,6 +889,12 @@ static const char *parse_gnu_option(void){
|
|||||||
if(s[sl]) return _("option --cumulative does not take an argument");
|
if(s[sl]) return _("option --cumulative does not take an argument");
|
||||||
include_dead_children = 1;
|
include_dead_children = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
case_dateformat:
|
||||||
|
arg=grab_gnu_arg();
|
||||||
|
if (!arg) return _("date format must follow --date-format");
|
||||||
|
if (lstart_format) free(lstart_format);
|
||||||
|
lstart_format = strdup(arg);
|
||||||
|
return NULL;
|
||||||
case_deselect:
|
case_deselect:
|
||||||
trace("--deselect\n");
|
trace("--deselect\n");
|
||||||
if(s[sl]) return _("option --deselect does not take an argument");
|
if(s[sl]) return _("option --deselect does not take an argument");
|
||||||
|
Loading…
Reference in New Issue
Block a user