Simon Gerraty
2014-07-25 04:49:21 UTC
Hi,
At a vendor summit a few years ago I asked about whether anyone but us
(Juniper) would be interested in the ablity to have standard BSD apps
output XML.
I was actually surprised by the amount of interest expressed.
I've occasionally nagged our UI team ever since for a clean and simple
API that we could contribute to address this.
We now have a what I think is a viable candidate
and we'd like to take the next steps towards contributing it and
converting at least a few apps.
Not only does it handle TXT and XML output but JSON and HTML as well,
and very rich HTML at that.
With some slick javascript - you can do amazing things with the level of
detail you can get out of this sort of thing.
The API is of necessity a bit more complex than just printf(3).
Considering the level of functionality available though it is a good
tradeoff.
The main open issue (assuming this functionality is still desired) is
support of wide charachters.
We figure the worst case solution is a sed(1) script to generate the wide
version of the API from the normal one, but perhaps simply always using
UTF8 would be a better solution?
Thanks
--sjg
The following from Phil provides some idea of the functionality
available and the API.
The one shown here uses the default output handle (stdout), but there
are variants that allow multiple output handles.
At a vendor summit a few years ago I asked about whether anyone but us
(Juniper) would be interested in the ablity to have standard BSD apps
output XML.
I was actually surprised by the amount of interest expressed.
I've occasionally nagged our UI team ever since for a clean and simple
API that we could contribute to address this.
We now have a what I think is a viable candidate
and we'd like to take the next steps towards contributing it and
converting at least a few apps.
Not only does it handle TXT and XML output but JSON and HTML as well,
and very rich HTML at that.
With some slick javascript - you can do amazing things with the level of
detail you can get out of this sort of thing.
The API is of necessity a bit more complex than just printf(3).
Considering the level of functionality available though it is a good
tradeoff.
The main open issue (assuming this functionality is still desired) is
support of wide charachters.
We figure the worst case solution is a sed(1) script to generate the wide
version of the API from the normal one, but perhaps simply always using
UTF8 would be a better solution?
Thanks
--sjg
The following from Phil provides some idea of the functionality
available and the API.
The one shown here uses the default output handle (stdout), but there
are variants that allow multiple output handles.
T X J and H are the modes (text, xml, json, html);
P means pretty print (indent, newlines)
I means print help (datatype, description), if provided (there aren't for "w")
x means print xpath to the data)
% foreach i ( T XP JP HP HPIx )
echo === $i ===
env LIBXO_OPTIONS=$i ./xtest -n | head -10
end
=== T ===
6:47PM up 18 days, 2:01, 9 user%s, load averages: 0.00, 0.00, 0.00
phil pts/0 76.182.32.73 5:09PM 33 /bin/sh
phil pts/1 76.182.32.73 05Jul14 2 /usr/bin/perl /u/phil/bin/plum (
phil pts/2 76.182.32.73 05Jul14 1 /bin/tcsh
phil pts/3 76.182.32.73 05Jul14 2days ssh dent
phil pts/4 76.182.32.73 Tue02PM 2days ssh svl-junos-d026.juniper.net
phil pts/5 76.182.32.73 Wed01AM 2days telnet man-o-war 2006
phil pts/6 76.182.32.73 Fri10PM 2days ssh 198.85.229.65
phil pts/7 76.182.32.73 Fri10PM 2days ssh zap
=== XP ===
<uptime-information>
<time-of-day> 6:47PM</time-of-day>
<uptime seconds="1562436">18 days</uptime>
<uptime> 2:01</uptime>
<users>9</users>
<load-average-1>0.00</load-average-1>
<load-average-5>0.00</load-average-5>
<load-average-15>0.00</load-average-15>
<user-table>
<user-entry>
=== JP ===
"uptime-information": {
"time-of-day": " 6:47PM",
"uptime": "18 days",
"uptime": 2:01,
"users": 9,
"load-average-1": 0.00,
"load-average-5": 0.00,
"load-average-15": 0.00,
"user-table": {
"user-entry": [
=== HP ===
<div class="line">
<div class="data" data-tag="time-of-day"> 6:47PM</div>
<div class="text"> </div>
<div class="text"> up</div>
<div class="text"> </div>
<div class="data" data-tag="uptime">18 days</div>
<div class="text">,</div>
<div class="text"> </div>
<div class="data" data-tag="uptime"> 2:01</div>
<div class="text">,</div>
=== HPIx ===
<div class="line">
<div class="data" data-tag="time-of-day" data-xpath="/uptime-information/time-of-day"> 6:47PM</div>
<div class="text"> </div>
<div class="text"> up</div>
<div class="text"> </div>
<div class="data" data-tag="uptime" data-xpath="/uptime-information/uptime">18 days</div>
<div class="text">,</div>
<div class="text"> </div>
<div class="data" data-tag="uptime" data-xpath="/uptime-information/uptime"> 2:01</div>
<div class="text">,</div>
Thanks,
Phil
-----
FWIW: here's the diff for "w". I don't have "wchar_t" support
yet, so I just undid it for now.
diff -rbu /usr/src/usr.bin/w/pr_time.c ./pr_time.c
--- /usr/src/usr.bin/w/pr_time.c 2010-12-21 12:09:25.000000000 -0500
+++ ./pr_time.c 2014-07-21 17:12:19.000000000 -0400
@@ -55,10 +55,10 @@
int
pr_attime(time_t *started, time_t *now)
{
- static wchar_t buf[256];
+ static char buf[256];
struct tm tp, tm;
time_t diff;
- wchar_t *fmt;
+ char *fmt;
int len, width, offset = 0;
tp = *localtime(started);
@@ -67,7 +67,7 @@
/* If more than a week, use day-month-year. */
if (diff > 86400 * 7)
- fmt = L"%d%b%y";
+ fmt = "%d%b%y";
/* If not today, use day-hour-am/pm. */
else if (tm.tm_mday != tp.tm_mday ||
@@ -75,23 +75,23 @@
tm.tm_year != tp.tm_year) {
/* The line below does not take DST into consideration */
/* else if (*now / 86400 != *started / 86400) { */
- fmt = use_ampm ? L"%a%I%p" : L"%a%H";
+ fmt = use_ampm ? "%a%I%p" : "%a%H";
}
/* Default is hh:mm{am,pm}. */
else {
- fmt = use_ampm ? L"%l:%M%p" : L"%k:%M";
+ fmt = use_ampm ? "%l:%M%p" : "%k:%M";
}
- (void)wcsftime(buf, sizeof(buf), fmt, &tp);
- len = wcslen(buf);
- width = wcswidth(buf, len);
+ (void)strftime(buf, sizeof(buf), fmt, &tp);
+ len = strlen(buf);
+ width = len;
if (len == width)
- (void)wprintf(L"%-7.7ls", buf);
+ xo_emit("{:login-time/%-7.7s}", buf);
else if (width < 7)
- (void)wprintf(L"%ls%.*s", buf, 7 - width, " ");
+ xo_emit("{:login-time/%s}%.*s", buf, 7 - width, " ");
else {
- (void)wprintf(L"%ls", buf);
+ xo_emit("{:login-time/%s}", buf);
offset = width - 7;
}
return (offset);
@@ -108,7 +108,7 @@
/* If idle more than 36 hours, print as a number of days. */
if (idle >= 36 * 3600) {
int days = idle / 86400;
- (void)printf(" %dday%s ", days, days > 1 ? "s" : " " );
+ xo_emit(" {:idle/%dday%s} ", days, days > 1 ? "s" : " " );
if (days >= 100)
return (2);
if (days >= 10)
@@ -117,15 +117,15 @@
/* If idle more than an hour, print as HH:MM. */
else if (idle >= 3600)
- (void)printf(" %2d:%02d ",
+ xo_emit(" {:idle/%2d:%02d/} ",
(int)(idle / 3600), (int)((idle % 3600) / 60));
else if (idle / 60 == 0)
- (void)printf(" - ");
+ xo_emit(" - ");
/* Else print the minutes idle. */
else
- (void)printf(" %2d ", (int)(idle / 60));
+ xo_emit(" {:idle/%2d} ", (int)(idle / 60));
return (0); /* not idle longer than 9 days */
}
diff -rbu /usr/src/usr.bin/w/w.c ./w.c
--- /usr/src/usr.bin/w/w.c 2010-12-21 12:09:25.000000000 -0500
+++ ./w.c 2014-07-21 18:13:50.000000000 -0400
@@ -86,6 +86,7 @@
#include <unistd.h>
#include <utmp.h>
#include <vis.h>
+#include <libxo/libxo.h>
#include "extern.h"
@@ -260,9 +261,12 @@
}
(void)fclose(ut);
+ xo_open_container("uptime-information");
+
if (header || wcmd == 0) {
pr_header(&now, nusers);
if (wcmd == 0) {
+ xo_close_container("uptime-information");
(void)kvm_close(kd);
exit(0);
}
@@ -274,11 +278,11 @@
#define HEADER_WHAT "WHAT\n"
#define WUSED (UT_NAMESIZE + UT_LINESIZE + W_DISPHOSTSIZE + \
sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */
- (void)printf("%-*.*s %-*.*s %-*.*s %s",
+ xo_emit("{T:/%-*.*s} {T:/%-*.*s} "
UT_NAMESIZE, UT_NAMESIZE, HEADER_USER,
UT_LINESIZE, UT_LINESIZE, HEADER_TTY,
- W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM,
- HEADER_LOGIN_IDLE HEADER_WHAT);
+ W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM);
}
if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
@@ -347,6 +351,9 @@
}
}
+ xo_open_container("user-table");
+ xo_open_list("user-entry");
+
for (ep = ehead; ep != NULL; ep = ep->next) {
char host_buf[UT_HOSTSIZE + 1];
struct sockaddr_storage ss;
@@ -356,6 +363,8 @@
time_t t;
int isaddr;
+ xo_open_instance("user-entry");
+
host_buf[UT_HOSTSIZE] = '\0';
strncpy(host_buf, ep->utmp.ut_host, UT_HOSTSIZE);
p = *host_buf ? host_buf : "-";
@@ -388,6 +397,9 @@
p = buf;
}
if (dflag) {
+ xo_open_container("process-table");
+ xo_open_list("process-entry");
+
for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) {
const char *ptr;
@@ -395,23 +407,37 @@
dkp->ki_comm, MAXCOMLEN);
if (ptr == NULL)
ptr = "-";
- (void)printf("\t\t%-9d %s\n",
+ xo_open_instance("process-entry");
+ xo_emit("\t\t{:process-id/%-9d/%d} "
+ "{:command/%s}\n",
dkp->ki_pid, ptr);
+ xo_close_instance("process-entry");
}
+ xo_close_list("process-entry");
+ xo_close_container("process-table");
}
- (void)printf("%-*.*s %-*.*s %-*.*s ",
UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
UT_LINESIZE, UT_LINESIZE,
strncmp(ep->utmp.ut_line, "tty", 3) &&
strncmp(ep->utmp.ut_line, "cua", 3) ?
ep->utmp.ut_line : ep->utmp.ut_line + 3,
W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-");
+
t = _time_to_time32(ep->utmp.ut_time);
longattime = pr_attime(&t, &now);
longidle = pr_idle(ep->idle);
- (void)printf("%.*s\n", argwidth - longidle - longattime,
- ep->args);
+ argwidth - longidle - longattime, ep->args);
+
+ xo_close_instance("user-entry");
}
+
+ xo_close_list("user-entry");
+ xo_close_container("user-table");
+ xo_close_container("uptime-information");
+
(void)kvm_close(kd);
exit(0);
}
@@ -430,7 +456,7 @@
*/
if (strftime(buf, sizeof(buf),
use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp)) != 0)
- (void)printf("%s ", buf);
+ xo_emit("{:time-of-day/%s} ", buf);
/*
* Print how long system has been up.
*/
@@ -444,35 +470,45 @@
uptime %= 3600;
mins = uptime / 60;
secs = uptime % 60;
- (void)printf(" up");
+ xo_emit(" up");
+ xo_attr("seconds", "%lu", (unsigned long) tp.tv_sec);
if (days > 0)
- (void)printf(" %d day%s,", days, days > 1 ? "s" : "");
+ xo_emit(" {:uptime/%d day%s},",
+ days, days > 1 ? "s" : "");
if (hrs > 0 && mins > 0)
- (void)printf(" %2d:%02d,", hrs, mins);
+ xo_emit(" {:uptime/%2d:%02d},", hrs, mins);
else if (hrs > 0)
- (void)printf(" %d hr%s,", hrs, hrs > 1 ? "s" : "");
+ xo_emit(" {:uptime/%d hr%s},",
+ hrs, hrs > 1 ? "s" : "");
else if (mins > 0)
- (void)printf(" %d min%s,", mins, mins > 1 ? "s" : "");
+ xo_emit(" {:uptime/%d min%s},",
+ mins, mins > 1 ? "s" : "");
else
- (void)printf(" %d sec%s,", secs, secs > 1 ? "s" : "");
+ xo_emit(" {:uptime/%d sec%s},",
+ secs, secs > 1 ? "s" : "");
}
/* Print number of users logged in to system */
- (void)printf(" %d user%s", nusers, nusers == 1 ? "" : "s");
+ xo_emit(" {:users/%d} user%s", nusers, nusers == 1 ? "" : "s");
/*
* Print 1, 5, and 15 minute load averages.
*/
if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1)
- (void)printf(", no load average information available\n");
+ xo_emit(", no load average information available\n");
else {
- (void)printf(", load averages:");
+ static const char *format[] = {
+ " {:load-average-1/%.2f}",
+ " {:load-average-5/%.2f}",
+ " {:load-average-15/%.2f}",
+ };
+ xo_emit(", load averages:");
for (i = 0; i < (int)(sizeof(avenrun) / sizeof(avenrun[0])); i++) {
if (use_comma && i > 0)
- (void)printf(",");
- (void)printf(" %.2f", avenrun[i]);
+ xo_emit(",");
+ xo_emit(format[i], avenrun[i]);
}
- (void)printf("\n");
+ xo_emit("\n");
}
}
@@ -493,10 +529,9 @@
usage(int wcmd)
{
if (wcmd)
- (void)fprintf(stderr,
- "usage: w [-dhin] [-M core] [-N system] [user ...]\n");
+ xo_error("usage: w [-dhin] [-M core] [-N system] [user ...]\n");
else
- (void)fprintf(stderr, "usage: uptime\n");
+ xo_error("usage: uptime\n");
exit(1);
}
P means pretty print (indent, newlines)
I means print help (datatype, description), if provided (there aren't for "w")
x means print xpath to the data)
% foreach i ( T XP JP HP HPIx )
echo === $i ===
env LIBXO_OPTIONS=$i ./xtest -n | head -10
end
=== T ===
6:47PM up 18 days, 2:01, 9 user%s, load averages: 0.00, 0.00, 0.00
phil pts/0 76.182.32.73 5:09PM 33 /bin/sh
phil pts/1 76.182.32.73 05Jul14 2 /usr/bin/perl /u/phil/bin/plum (
phil pts/2 76.182.32.73 05Jul14 1 /bin/tcsh
phil pts/3 76.182.32.73 05Jul14 2days ssh dent
phil pts/4 76.182.32.73 Tue02PM 2days ssh svl-junos-d026.juniper.net
phil pts/5 76.182.32.73 Wed01AM 2days telnet man-o-war 2006
phil pts/6 76.182.32.73 Fri10PM 2days ssh 198.85.229.65
phil pts/7 76.182.32.73 Fri10PM 2days ssh zap
=== XP ===
<uptime-information>
<time-of-day> 6:47PM</time-of-day>
<uptime seconds="1562436">18 days</uptime>
<uptime> 2:01</uptime>
<users>9</users>
<load-average-1>0.00</load-average-1>
<load-average-5>0.00</load-average-5>
<load-average-15>0.00</load-average-15>
<user-table>
<user-entry>
=== JP ===
"uptime-information": {
"time-of-day": " 6:47PM",
"uptime": "18 days",
"uptime": 2:01,
"users": 9,
"load-average-1": 0.00,
"load-average-5": 0.00,
"load-average-15": 0.00,
"user-table": {
"user-entry": [
=== HP ===
<div class="line">
<div class="data" data-tag="time-of-day"> 6:47PM</div>
<div class="text"> </div>
<div class="text"> up</div>
<div class="text"> </div>
<div class="data" data-tag="uptime">18 days</div>
<div class="text">,</div>
<div class="text"> </div>
<div class="data" data-tag="uptime"> 2:01</div>
<div class="text">,</div>
=== HPIx ===
<div class="line">
<div class="data" data-tag="time-of-day" data-xpath="/uptime-information/time-of-day"> 6:47PM</div>
<div class="text"> </div>
<div class="text"> up</div>
<div class="text"> </div>
<div class="data" data-tag="uptime" data-xpath="/uptime-information/uptime">18 days</div>
<div class="text">,</div>
<div class="text"> </div>
<div class="data" data-tag="uptime" data-xpath="/uptime-information/uptime"> 2:01</div>
<div class="text">,</div>
Thanks,
Phil
-----
FWIW: here's the diff for "w". I don't have "wchar_t" support
yet, so I just undid it for now.
diff -rbu /usr/src/usr.bin/w/pr_time.c ./pr_time.c
--- /usr/src/usr.bin/w/pr_time.c 2010-12-21 12:09:25.000000000 -0500
+++ ./pr_time.c 2014-07-21 17:12:19.000000000 -0400
@@ -55,10 +55,10 @@
int
pr_attime(time_t *started, time_t *now)
{
- static wchar_t buf[256];
+ static char buf[256];
struct tm tp, tm;
time_t diff;
- wchar_t *fmt;
+ char *fmt;
int len, width, offset = 0;
tp = *localtime(started);
@@ -67,7 +67,7 @@
/* If more than a week, use day-month-year. */
if (diff > 86400 * 7)
- fmt = L"%d%b%y";
+ fmt = "%d%b%y";
/* If not today, use day-hour-am/pm. */
else if (tm.tm_mday != tp.tm_mday ||
@@ -75,23 +75,23 @@
tm.tm_year != tp.tm_year) {
/* The line below does not take DST into consideration */
/* else if (*now / 86400 != *started / 86400) { */
- fmt = use_ampm ? L"%a%I%p" : L"%a%H";
+ fmt = use_ampm ? "%a%I%p" : "%a%H";
}
/* Default is hh:mm{am,pm}. */
else {
- fmt = use_ampm ? L"%l:%M%p" : L"%k:%M";
+ fmt = use_ampm ? "%l:%M%p" : "%k:%M";
}
- (void)wcsftime(buf, sizeof(buf), fmt, &tp);
- len = wcslen(buf);
- width = wcswidth(buf, len);
+ (void)strftime(buf, sizeof(buf), fmt, &tp);
+ len = strlen(buf);
+ width = len;
if (len == width)
- (void)wprintf(L"%-7.7ls", buf);
+ xo_emit("{:login-time/%-7.7s}", buf);
else if (width < 7)
- (void)wprintf(L"%ls%.*s", buf, 7 - width, " ");
+ xo_emit("{:login-time/%s}%.*s", buf, 7 - width, " ");
else {
- (void)wprintf(L"%ls", buf);
+ xo_emit("{:login-time/%s}", buf);
offset = width - 7;
}
return (offset);
@@ -108,7 +108,7 @@
/* If idle more than 36 hours, print as a number of days. */
if (idle >= 36 * 3600) {
int days = idle / 86400;
- (void)printf(" %dday%s ", days, days > 1 ? "s" : " " );
+ xo_emit(" {:idle/%dday%s} ", days, days > 1 ? "s" : " " );
if (days >= 100)
return (2);
if (days >= 10)
@@ -117,15 +117,15 @@
/* If idle more than an hour, print as HH:MM. */
else if (idle >= 3600)
- (void)printf(" %2d:%02d ",
+ xo_emit(" {:idle/%2d:%02d/} ",
(int)(idle / 3600), (int)((idle % 3600) / 60));
else if (idle / 60 == 0)
- (void)printf(" - ");
+ xo_emit(" - ");
/* Else print the minutes idle. */
else
- (void)printf(" %2d ", (int)(idle / 60));
+ xo_emit(" {:idle/%2d} ", (int)(idle / 60));
return (0); /* not idle longer than 9 days */
}
diff -rbu /usr/src/usr.bin/w/w.c ./w.c
--- /usr/src/usr.bin/w/w.c 2010-12-21 12:09:25.000000000 -0500
+++ ./w.c 2014-07-21 18:13:50.000000000 -0400
@@ -86,6 +86,7 @@
#include <unistd.h>
#include <utmp.h>
#include <vis.h>
+#include <libxo/libxo.h>
#include "extern.h"
@@ -260,9 +261,12 @@
}
(void)fclose(ut);
+ xo_open_container("uptime-information");
+
if (header || wcmd == 0) {
pr_header(&now, nusers);
if (wcmd == 0) {
+ xo_close_container("uptime-information");
(void)kvm_close(kd);
exit(0);
}
@@ -274,11 +278,11 @@
#define HEADER_WHAT "WHAT\n"
#define WUSED (UT_NAMESIZE + UT_LINESIZE + W_DISPHOSTSIZE + \
sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */
- (void)printf("%-*.*s %-*.*s %-*.*s %s",
+ xo_emit("{T:/%-*.*s} {T:/%-*.*s} "
UT_NAMESIZE, UT_NAMESIZE, HEADER_USER,
UT_LINESIZE, UT_LINESIZE, HEADER_TTY,
- W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM,
- HEADER_LOGIN_IDLE HEADER_WHAT);
+ W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM);
}
if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
@@ -347,6 +351,9 @@
}
}
+ xo_open_container("user-table");
+ xo_open_list("user-entry");
+
for (ep = ehead; ep != NULL; ep = ep->next) {
char host_buf[UT_HOSTSIZE + 1];
struct sockaddr_storage ss;
@@ -356,6 +363,8 @@
time_t t;
int isaddr;
+ xo_open_instance("user-entry");
+
host_buf[UT_HOSTSIZE] = '\0';
strncpy(host_buf, ep->utmp.ut_host, UT_HOSTSIZE);
p = *host_buf ? host_buf : "-";
@@ -388,6 +397,9 @@
p = buf;
}
if (dflag) {
+ xo_open_container("process-table");
+ xo_open_list("process-entry");
+
for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) {
const char *ptr;
@@ -395,23 +407,37 @@
dkp->ki_comm, MAXCOMLEN);
if (ptr == NULL)
ptr = "-";
- (void)printf("\t\t%-9d %s\n",
+ xo_open_instance("process-entry");
+ xo_emit("\t\t{:process-id/%-9d/%d} "
+ "{:command/%s}\n",
dkp->ki_pid, ptr);
+ xo_close_instance("process-entry");
}
+ xo_close_list("process-entry");
+ xo_close_container("process-table");
}
- (void)printf("%-*.*s %-*.*s %-*.*s ",
UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
UT_LINESIZE, UT_LINESIZE,
strncmp(ep->utmp.ut_line, "tty", 3) &&
strncmp(ep->utmp.ut_line, "cua", 3) ?
ep->utmp.ut_line : ep->utmp.ut_line + 3,
W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-");
+
t = _time_to_time32(ep->utmp.ut_time);
longattime = pr_attime(&t, &now);
longidle = pr_idle(ep->idle);
- (void)printf("%.*s\n", argwidth - longidle - longattime,
- ep->args);
+ argwidth - longidle - longattime, ep->args);
+
+ xo_close_instance("user-entry");
}
+
+ xo_close_list("user-entry");
+ xo_close_container("user-table");
+ xo_close_container("uptime-information");
+
(void)kvm_close(kd);
exit(0);
}
@@ -430,7 +456,7 @@
*/
if (strftime(buf, sizeof(buf),
use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp)) != 0)
- (void)printf("%s ", buf);
+ xo_emit("{:time-of-day/%s} ", buf);
/*
* Print how long system has been up.
*/
@@ -444,35 +470,45 @@
uptime %= 3600;
mins = uptime / 60;
secs = uptime % 60;
- (void)printf(" up");
+ xo_emit(" up");
+ xo_attr("seconds", "%lu", (unsigned long) tp.tv_sec);
if (days > 0)
- (void)printf(" %d day%s,", days, days > 1 ? "s" : "");
+ xo_emit(" {:uptime/%d day%s},",
+ days, days > 1 ? "s" : "");
if (hrs > 0 && mins > 0)
- (void)printf(" %2d:%02d,", hrs, mins);
+ xo_emit(" {:uptime/%2d:%02d},", hrs, mins);
else if (hrs > 0)
- (void)printf(" %d hr%s,", hrs, hrs > 1 ? "s" : "");
+ xo_emit(" {:uptime/%d hr%s},",
+ hrs, hrs > 1 ? "s" : "");
else if (mins > 0)
- (void)printf(" %d min%s,", mins, mins > 1 ? "s" : "");
+ xo_emit(" {:uptime/%d min%s},",
+ mins, mins > 1 ? "s" : "");
else
- (void)printf(" %d sec%s,", secs, secs > 1 ? "s" : "");
+ xo_emit(" {:uptime/%d sec%s},",
+ secs, secs > 1 ? "s" : "");
}
/* Print number of users logged in to system */
- (void)printf(" %d user%s", nusers, nusers == 1 ? "" : "s");
+ xo_emit(" {:users/%d} user%s", nusers, nusers == 1 ? "" : "s");
/*
* Print 1, 5, and 15 minute load averages.
*/
if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1)
- (void)printf(", no load average information available\n");
+ xo_emit(", no load average information available\n");
else {
- (void)printf(", load averages:");
+ static const char *format[] = {
+ " {:load-average-1/%.2f}",
+ " {:load-average-5/%.2f}",
+ " {:load-average-15/%.2f}",
+ };
+ xo_emit(", load averages:");
for (i = 0; i < (int)(sizeof(avenrun) / sizeof(avenrun[0])); i++) {
if (use_comma && i > 0)
- (void)printf(",");
- (void)printf(" %.2f", avenrun[i]);
+ xo_emit(",");
+ xo_emit(format[i], avenrun[i]);
}
- (void)printf("\n");
+ xo_emit("\n");
}
}
@@ -493,10 +529,9 @@
usage(int wcmd)
{
if (wcmd)
- (void)fprintf(stderr,
- "usage: w [-dhin] [-M core] [-N system] [user ...]\n");
+ xo_error("usage: w [-dhin] [-M core] [-N system] [user ...]\n");
else
- (void)fprintf(stderr, "usage: uptime\n");
+ xo_error("usage: uptime\n");
exit(1);
}