From dcd8cf0b4b133de71848f1f4e233a9e5f1f03ba6 Mon Sep 17 00:00:00 2001 From: Jaromir Capik Date: Wed, 20 Jun 2012 22:19:14 +1000 Subject: [PATCH] Rework of the -i feature This version detects IPv6 address in the host field and also IPv6 link interface separated by % sign. It also handles unprintable characters and spaces better than the previous one. Signed-off-by: Craig Small --- w.c | 76 +++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/w.c b/w.c index 43e941a5..2e79980d 100644 --- a/w.c +++ b/w.c @@ -103,35 +103,67 @@ static void print_host(const char *restrict host, int len, const int fromlen) } -/* This routine prints the display part of the host */ -static void print_display(const char *restrict host, int len, int restlen) +/* This routine prints the display part of the host or IPv6 link address interface */ +static void print_display_or_interface(const char *restrict host, int len, int restlen) { - char *disp; + char *disp,*tmp; - if (restlen <= 0) return; /* not enough space for the display */ + if (restlen <= 0) return; /* not enough space for printing anything */ - /* search for the display (collon) */ + /* search for a collon (might be a display) */ disp = (char *)host; - while ( (disp < (host + len)) && (*disp != ':') && (*disp != '\0') ) disp++; + while ( (disp < (host + len)) && (*disp != ':') && isprint(*disp) ) disp++; - /* number of chars till the end of the input field */ - len -= (disp - host); - - /* if it is still longer than the rest of the output field, then cut it */ - if (len > restlen) len = restlen; - - /* display found, print it */ + /* colon found */ if (*disp == ':') { - while ((len > 0) && (*disp != '\0')) { - len--; restlen--; - /* print only if printable and non-space */ - if (isprint(*host) && *host != ' ') { + /* detect multiple colons -> IPv6 in the host (not a display) */ + tmp = disp+1; + while ( (tmp < (host + len)) && (*tmp != ':') && isprint(*tmp) ) tmp++; + + if (*tmp != ':') { /* multiple colons not found - it's a display */ + + /* number of chars till the end of the input field */ + len -= (disp - host); + + /* if it is still longer than the rest of the output field, then cut it */ + if (len > restlen) len = restlen; + + /* print the display */ + while ((len > 0) && isprint(*disp) && (*disp != ' ')) { + len--; restlen--; fputc(*disp, stdout); disp++; - } else { /* space or nonprintable - replace with dash and stop printing */ - fputc('-', stdout); - break; } + + if ((len > 0) && (*disp != '\0')) { /* space or nonprintable found - replace with dash and stop printing */ + restlen--; + fputc('-', stdout); + } + } else { /* multiple colons found - it's an IPv6 address */ + + /* search for % (interface separator in case of IPv6 link address) */ + while ( (tmp < (host + len)) && (*tmp != '%') && isprint(*tmp) ) tmp++; + + if (*tmp == '%') { /* interface separator found */ + + /* number of chars till the end of the input field */ + len -= (tmp - host); + + /* if it is still longer than the rest of the output field, then cut it */ + if (len > restlen) len = restlen; + + /* print the interface */ + while ((len > 0) && isprint(*tmp) && (*tmp != ' ')) { + len--; restlen--; + fputc(*tmp, stdout); + tmp++; + } + if ((len > 0) && (*tmp != '\0')) { /* space or nonprintable found - replace with dash and stop printing */ + restlen--; + fputc('-', stdout); + } + } + } } @@ -177,8 +209,8 @@ static void print_from(const utmp_t *restrict const u, const int ip_addresses, c len = strlen(buf); if (len) { /* IP address is non-empty, print it (and concatenate with display, if present) */ fputs(buf, stdout); - /* show the display part of the host, if present */ - print_display(u->ut_host, UT_HOSTSIZE, fromlen - len); + /* show the display part of the host or IPv6 link addr. interface, if present */ + print_display_or_interface(u->ut_host, UT_HOSTSIZE, fromlen - len); } else { /* IP address is empty, print the host instead */ print_host(u->ut_host, UT_HOSTSIZE, fromlen); }