bug-coreutils
[Top][All Lists]
Advanced

[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;






reply via email to

[Prev in Thread] Current Thread [Next in Thread]