[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[patch] add sort option for IP addresses
From: |
Norbert Kiesel |
Subject: |
[patch] add sort option for IP addresses |
Date: |
Mon, 27 Nov 2006 00:36:20 +0100 |
Hi,
I needed to sort some text by IP addresses, and there does not seem to
be a good way to do it. They only trick I found was "-n -t. -k1,1 -k2,2
-k3,3 -k4.4" or so, but that is kind of ugly. So I hacked together a
patch that adds -I,--ipaddess-sort to sort. It's still incomplete (no
IPv6, no manual, possibly configure.in checks needed), but I would work
on this if there is a chance that the patch will get added.
The patch below is against 5.97 (actually against 5.97 + Debian unstable
patches that make up 5.97-5.2, but I think sort.c is not affected by
this).
Comments?
Best,
Norbert
P.S.: Please CC, I'm not subscribed. --nk
--- src/sort.c~ 2006-11-26 03:57:00.000000000 -0800
+++ src/sort.c 2006-11-26 10:37:04.000000000 -0800
@@ -25,6 +25,8 @@
#include <getopt.h>
#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
#include <signal.h>
#include "system.h"
#include "error.h"
@@ -150,6 +152,7 @@
bool general_numeric; /* Flag for general, numeric comparison.
Handle numbers in exponential notation. */
bool month; /* Flag for comparison by month name. */
+ bool ipaddress; /* Flag for comparison as ip address. */
bool reverse; /* Reverse the sense of comparison. */
struct keyfield *next; /* Next keyfield to try. */
};
@@ -302,6 +305,7 @@
-g, --general-numeric-sort compare according to general numerical value\n\
-i, --ignore-nonprinting consider only printable characters\n\
-M, --month-sort compare (unknown) < `JAN' < ... < `DEC'\n\
+ -I, --ipaddress-sort compare according to IP address value\n\
-n, --numeric-sort compare according to string numerical value\n\
-r, --reverse reverse the result of comparisons\n\
\n\
@@ -353,7 +357,7 @@
exit (status);
}
-static char const short_options[] = "-bcdfgik:mMno:rsS:t:T:uy:z";
+static char const short_options[] = "-bcdfgik:mMIno:rsS:t:T:uy:z";
static struct option const long_options[] =
{
@@ -366,6 +370,7 @@
{"key", required_argument, NULL, 'k'},
{"merge", no_argument, NULL, 'm'},
{"month-sort", no_argument, NULL, 'M'},
+ {"ipaddress-sort", no_argument, NULL, 'I'},
{"numeric-sort", no_argument, NULL, 'n'},
{"output", required_argument, NULL, 'o'},
{"reverse", no_argument, NULL, 'r'},
@@ -1106,6 +1111,31 @@
: memcmp ((char *) &a, (char *) &b, sizeof a));
}
+static int
+ipaddresscompare (const char *a, const char *b)
+{
+ struct in_addr ia;
+ struct in_addr ib;
+
+ int is_a;
+ int is_b;
+
+ while (blanks[to_uchar (*a)])
+ a++;
+ while (blanks[to_uchar (*b)])
+ b++;
+
+ is_a = inet_pton (AF_INET, a, &ia);
+ is_b = inet_pton (AF_INET, b, &ib);
+ if (is_a > 0 && is_b > 0)
+ {
+ uint32_t sa = ntohl (ia.s_addr);
+ uint32_t sb = ntohl (ib.s_addr);
+ return sa == sb ? 0 : sa < sb ? -1 : 1;
+ }
+ return is_a > 0 ? -1 : is_b > 0 ? 1 : 0;
+}
+
/* Return an integer in 1..12 of the month name MONTH with length LEN.
Return 0 if the name in S is not recognized. */
@@ -1192,6 +1222,14 @@
diff = getmonth (texta, lena) - getmonth (textb, lenb);
/* Sorting like this may become slow, so in a simple locale the user
can select a faster sort that is similar to ascii sort. */
+ else if (key->ipaddress)
+ {
+ char savea = *lima, saveb = *limb;
+
+ *lima = *limb = '\0';
+ diff = ipaddresscompare (texta, textb);
+ *lima = savea, *limb = saveb;
+ }
else if (hard_LC_COLLATE)
{
if (ignore || translate)
@@ -2078,6 +2116,9 @@
case 'M':
key->month = true;
break;
+ case 'I':
+ key->ipaddress = true;
+ break;
case 'n':
key->numeric = true;
break;
@@ -2187,7 +2228,7 @@
gkey.sword = gkey.eword = SIZE_MAX;
gkey.ignore = NULL;
gkey.translate = NULL;
- gkey.numeric = gkey.general_numeric = gkey.month = gkey.reverse = false;
+ gkey.numeric = gkey.general_numeric = gkey.month = gkey.ipaddress =
gkey.reverse = false;
gkey.skipsblanks = gkey.skipeblanks = false;
files = xnmalloc (argc, sizeof *files);
@@ -2263,6 +2304,7 @@
case 'g':
case 'i':
case 'M':
+ case 'I':
case 'n':
case 'r':
{
@@ -2419,7 +2461,7 @@
for (key = keylist; key; key = key->next)
if (! (key->ignore || key->translate
|| (key->skipsblanks | key->reverse
- | key->skipeblanks | key->month | key->numeric
+ | key->skipeblanks | key->month | key->ipaddress | key->numeric
| key->general_numeric)))
{
key->ignore = gkey.ignore;
@@ -2427,13 +2469,14 @@
key->skipsblanks = gkey.skipsblanks;
key->skipeblanks = gkey.skipeblanks;
key->month = gkey.month;
+ key->ipaddress = gkey.ipaddress;
key->numeric = gkey.numeric;
key->general_numeric = gkey.general_numeric;
key->reverse = gkey.reverse;
}
if (!keylist && (gkey.ignore || gkey.translate
- || (gkey.skipsblanks | gkey.skipeblanks | gkey.month
+ || (gkey.skipsblanks | gkey.skipeblanks | gkey.month |
gkey.ipaddress
| gkey.numeric | gkey.general_numeric)))
insertkey (&gkey);
reverse = gkey.reverse;