BSD 4_3_Net_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Thu, 28 Dec 1989 23:16:00 +0000 (15:16 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Thu, 28 Dec 1989 23:16:00 +0000 (15:16 -0800)
Work on file usr/src/lib/libg++/grot/etc/lf/directory-handler.cc
Work on file usr/src/lib/libg++/grot/etc/lf/directory-handler.h
Work on file usr/src/lib/libg++/grot/etc/lf/lf.cc
Work on file usr/src/lib/libg++/grot/etc/lf/entry-handler.h
Work on file usr/src/lib/libg++/grot/etc/lf/entry-handler.cc
Work on file usr/src/lib/libg++/grot/etc/lf/option-handler.cc
Work on file usr/src/lib/libg++/grot/etc/lf/option-handler.h
Work on file usr/src/lib/libg++/grot/etc/lf/screen-handler.cc
Work on file usr/src/lib/libg++/grot/etc/lf/screen-handler.h
Work on file usr/src/lib/libg++/grot/etc/lf/sort.cc

Synthesized-from: CSRG/cd2/net.2

usr/src/lib/libg++/grot/etc/lf/directory-handler.cc [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/directory-handler.h [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/entry-handler.cc [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/entry-handler.h [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/lf.cc [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/option-handler.cc [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/option-handler.h [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/screen-handler.cc [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/screen-handler.h [new file with mode: 0644]
usr/src/lib/libg++/grot/etc/lf/sort.cc [new file with mode: 0644]

diff --git a/usr/src/lib/libg++/grot/etc/lf/directory-handler.cc b/usr/src/lib/libg++/grot/etc/lf/directory-handler.cc
new file mode 100644 (file)
index 0000000..7ec7bec
--- /dev/null
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <std.h>
+#include "Dirent.h"
+#include "option-handler.h"
+#include "entry-handler.h"
+#include "directory-handler.h"
+
+/* Provided in the main driver program. */
+extern Option_Handler option;
+
+/* Names used to print out various file classes. */
+char *Directory_Handler::class_name[Directory_Handler::MAX_TYPES] =
+{
+  "Directory", "Regular", "Executable", "Directory Link", "File Link", "Symbolic Link",
+};
+
+/* Read each file in the current directory, and enter it into
+   the correct file class according to its file type. 
+   Then, for each file class, sort the class entries by 
+   name and print them to the standard output. */
+
+Directory_Handler::Directory_Handler (void)
+{
+  Dirent directory (".");
+  file_types     file_type;
+  
+  /* "." always works, since a chdir is performed earlier if a 
+     user-specified directory was supplied on the command-line. */
+  
+  if (!option[HIDDEN])
+    {
+      /* Skip the first two directory entries ("." and "..").  This
+         is fast, but potentially non-portable.  Does this fail
+         on anyone's system?  If so, I'll change it (barf). */
+      directory.readdir ();
+      directory.readdir ();
+    }
+  
+  /* Main loop in program.  Read each directory entry, classify it
+    according to its type, then enter it into the appropriate table slot. */
+  
+  for (struct direct *dir_buf; dir_buf = directory.readdir (); )
+    {
+      if (!option[HIDDEN] && *dir_buf->d_name == '.')
+        continue;
+      
+      struct stat stat_buf;
+      
+      lstat (dir_buf->d_name, &stat_buf);
+      switch (stat_buf.st_mode & S_IFMT)
+        {
+        case S_IFREG:           /* Either a regular file or an executable. */
+          file_type = (stat_buf.st_mode & S_IEXEC) ? EXECS : FILES;
+          break;
+        case S_IFLNK:           
+          if (option[LINK]) /* Either a file or directory link, let's find out... */
+            {
+              stat (dir_buf->d_name, &stat_buf);
+              file_type = (stat_buf.st_mode & S_IFMT) != S_IFDIR ? FLINKS : DLINKS;
+            }
+          else
+            file_type = LINKS;
+          break;
+        default:                /* Must be a directory. */
+          file_type = DIRS;    
+          break;
+        }
+      
+      file_class[file_type].add_entry (dir_buf->d_name, dir_buf->d_namlen);
+    }
+}
+
+/* Sort file class entries and print them to stdout. */
+
+void 
+Directory_Handler::print (void)
+{
+  for (file_types i = (file_types) 0; i < MAX_TYPES; i++)
+    if (file_class[i].entry_number () > 0)
+      {
+        file_class[i].sort_entries ();
+        file_class[i].print_entries (class_name[i]);
+      }
+}  
diff --git a/usr/src/lib/libg++/grot/etc/lf/directory-handler.h b/usr/src/lib/libg++/grot/etc/lf/directory-handler.h
new file mode 100644 (file)
index 0000000..fade096
--- /dev/null
@@ -0,0 +1,33 @@
+// This may look like C code, but it is really -*- C++ -*-
+
+/* Manipulate all directory entries for all file classes. */
+#pragma once
+#include "entry-handler.h"
+
+class Directory_Handler
+{
+public:
+  /* There are five major types of files in the UNIX system. */
+  enum file_types
+    {
+      DIRS,                     /* Subdirectories. */
+      FILES,                    /* Regular files. */
+      EXECS,                    /* Executable files. */
+      DLINKS,                   /* Directory links (if -l option is enabled). */
+      FLINKS,                   /* File links (if -l option is enabled). */
+      LINKS,                    /* File *and* directory links (if -l option is *not* enabled). */
+      MAX_TYPES,
+    };
+
+       Directory_Handler (void); /* Formats the current directory files. */
+  void print (void);             /* Lists the current directory files. */
+
+ private:
+
+/* static */ Entry_Handler file_class[MAX_TYPES]; /* File class array. */
+  static char          *class_name[MAX_TYPES]; /* String naem for each file class. */
+  
+};
+
+
+
diff --git a/usr/src/lib/libg++/grot/etc/lf/entry-handler.cc b/usr/src/lib/libg++/grot/etc/lf/entry-handler.cc
new file mode 100644 (file)
index 0000000..deb6b00
--- /dev/null
@@ -0,0 +1,84 @@
+/* Manipulate directory entries of a particular file class. */
+#include <std.h>
+#include "entry-handler.h"
+
+/* Initially provide a medium-sized file entry size. */
+static int Entry_Handler::default_entries = 50;
+
+/* Print entries to standard output.  The algorithm used to format the files
+   in columns is subtle, and worth studying in some detail. */
+
+void
+Entry_Handler::print_entries (char *class_name) 
+{
+  const int  width = Screen_Handler::screen_width ();
+  const int  ncols = width / (max_entry_length + 1);
+  const int  nrows = (entries + ncols - 1) / ncols;
+  const int  max   = nrows * (entries - (nrows - 1) * ncols);
+  char buffer[width];
+
+  /* Print out the file class name, nicely centered and in inverse video. */
+  sprintf (buffer, "[ %d %s File%s ]", entries, class_name, entries == 1 ? "" : "s");
+  Screen_Handler::print_inverse_centered (buffer);
+  
+  /* Take care of everything but the (possibly non-existent) final row. */
+  
+  for (int row = 0; row < nrows - 1; row++)
+    {
+      /* This loop is subtle, since we don't want to process too many entries.... */
+      
+      for (int col = row; col < entries; col += col < max ? nrows : nrows - 1)
+        printf ("%-*s", max_entry_length + 1, buf[col]);
+      
+      putchar ('\n');
+    }
+  /* Treat the final row specially, if it exists. */
+  
+  for (; row < max; row += nrows) 
+    printf ("%-*s", max_entry_length + 1, buf[row]);
+  
+  putchar ('\n');
+}
+
+/* Only compile these functions if -O is *not* enabled. */
+
+#ifndef __OPTIMIZE__
+
+/* Initialize a new file class. */
+
+Entry_Handler::Entry_Handler (void)
+{
+  entries = max_entry_length = 0;
+  total_entries = default_entries;
+  buf = new char *[default_entries];
+}
+
+/* Current number of file entries. */
+
+int 
+Entry_Handler::entry_number (void)
+{
+  return entries;
+}
+
+/* Add an entry to the file class. */
+
+void 
+Entry_Handler::add_entry (char *entry_name, int length)
+{
+  /* Grow the buffer on overflow. */
+  if (entries >= total_entries)
+    buf = new {buf, total_entries *= 2} char *;
+  max_entry_length >?= length;
+  buf[entries++] = strcpy (new char[length + 1], entry_name);
+}
+
+/* Sort entries by filename. */
+
+void 
+Entry_Handler::sort_entries (void)
+{
+  sort (buf, entries);
+}
+
+#endif                          // __OPTIMIZE__
diff --git a/usr/src/lib/libg++/grot/etc/lf/entry-handler.h b/usr/src/lib/libg++/grot/etc/lf/entry-handler.h
new file mode 100644 (file)
index 0000000..5a4b20c
--- /dev/null
@@ -0,0 +1,63 @@
+// This may look like C code, but it is really -*- C++ -*-
+
+/* Manipulate directory entries of a particular file class. */
+#pragma once
+#include <std.h>
+#include <new.h>
+#include "screen-handler.h"
+
+/* Defined in sort.cc. */
+void sort (char **base_ptr, int total_elems);
+
+class Entry_Handler
+{
+  
+private:
+  static const int    default_entries;  /* Initial number of file entries per class. */
+               int    max_entry_length; /* Size of largest filename. */
+               int    total_entries;    /* Total number of filenames. */
+               int    entries;          /* Current number of filenames. */
+               char **buf;              /* Buffer containing filenames for this file class. */
+  
+public:
+                      Entry_Handler (void);                     /* Initialize a new file class. */
+  int                 entry_number (void);                      /* Current number of entries. */
+  void                add_entry (char *entry_name, int length); /* Add an entry to the class. */
+  void                sort_entries (void);                      /* Sort entries by filename. */
+  void                print_entries (char *class_name);         /* Print file entries. */
+};
+
+/* See comments in the .cc file for the following inline functions */
+
+#ifdef __OPTIMIZE__
+inline 
+Entry_Handler::Entry_Handler (void)
+{
+  entries = max_entry_length = 0;
+  total_entries = default_entries;
+  buf = new char *[default_entries];
+}
+
+inline int 
+Entry_Handler::entry_number (void)
+{
+  return entries;
+}
+
+inline void 
+Entry_Handler::add_entry (char *entry_name, int length)
+{
+  if (entries >= total_entries)
+    buf = new {buf, total_entries *= 2} char *;
+  max_entry_length >?= length;
+  buf[entries++] = strcpy (new char[length + 1], entry_name);
+}
+
+inline void 
+Entry_Handler::sort_entries (void)
+{
+  sort (buf, entries);
+}
+
+#endif // __OPTIMIZE__
+
diff --git a/usr/src/lib/libg++/grot/etc/lf/lf.cc b/usr/src/lib/libg++/grot/etc/lf/lf.cc
new file mode 100644 (file)
index 0000000..0d08425
--- /dev/null
@@ -0,0 +1,23 @@
+/* Driver program for directory listing facility. */
+/* Type the -h option for program usage information. */
+#include "option-handler.h"
+#include "screen-handler.h"
+#include "directory-handler.h"
+
+/* Manages program options, globally visible to other modules. */
+Option_Handler option;
+
+/* Initializes the screen object. */
+Screen_Handler screen;
+
+/* Set the program options and turn over the dirty work
+   to the main directory handling module. */
+
+int
+main (int argc, char *argv[])
+{
+  option (argc, argv);
+  Directory_Handler files;
+  files.print ();
+  return 0;
+}
diff --git a/usr/src/lib/libg++/grot/etc/lf/option-handler.cc b/usr/src/lib/libg++/grot/etc/lf/option-handler.cc
new file mode 100644 (file)
index 0000000..a67930c
--- /dev/null
@@ -0,0 +1,62 @@
+/* Process directory listing program options. */
+#include <stdio.h>
+#include <std.h>
+#include <GetOpt.h>
+#include "option-handler.h"
+
+/* Initialize the program options. */
+
+Option_Handler::Option_Handler (void)
+{     
+  option_word = 0;
+}
+
+/* Prints program usage to standard error stream, then exits. */
+
+void 
+Option_Handler::usage (void)
+{ 
+  fprintf (stderr, "usage: %s [-ahl] [directory]\n", program_name);
+  exit (1);
+}
+
+/* Sets the program options. */
+
+void 
+Option_Handler::operator () (int argc, char *argv[])
+{
+  GetOpt getopt (argc, argv, "ahl");
+  int option_char;
+
+  program_name = argv[0];
+
+  while ((option_char = getopt ()) != EOF)
+    switch (option_char)
+      {
+      case 'a':                 /* Print out hidden files (those starting with '.'). */
+        option_word |= HIDDEN;
+        break;
+      case 'l':
+        option_word |= LINK;
+        break;
+      case 'h': /* Print help message and exit. */
+      default:
+        usage ();
+      }
+
+  /* Change the working directory if default is not ".". This saves
+     time during the directory entry decoding phase. */
+
+  if (argv[getopt.optind])
+    chdir (argv[getopt.optind]);
+}
+
+#ifndef __OPTIMIZE__
+/* TRUE if OPTION enable, else FALSE. */
+
+int
+Option_Handler::operator[] (option_type option) 
+{ 
+  return option_word & option;
+}
+#endif // __OPTIMIZE__
diff --git a/usr/src/lib/libg++/grot/etc/lf/option-handler.h b/usr/src/lib/libg++/grot/etc/lf/option-handler.h
new file mode 100644 (file)
index 0000000..0114c4e
--- /dev/null
@@ -0,0 +1,33 @@
+// This may look like C code, but it is really -*- C++ -*-
+#pragma once
+
+/* Process directory listing program options. */
+
+/* Enumeration of all directory listing options. */
+enum option_type
+{
+  HIDDEN = 01, /* Print hidden files (those beginning with '.') */
+  LINK   = 02, /* Distinguish between directory and file links. */
+};
+
+class Option_Handler
+{
+private:
+  static unsigned option_word;  /* Compact bitwise-storage for program options. */
+  static char    *program_name; /* Name of listing program. */
+  static void     usage (void); /* Prints usage then exits. */
+  
+public:
+                  Option_Handler (void);                /* Initialize options. */
+  void            operator() (int argc, char *argv[]);  /* Process command-line options. */
+  int             operator[] (option_type option);      /* Check if option is enabled. */
+};
+
+/* Speed things up a bit if we're optimizing. */
+#ifdef __OPTIMIZE__
+inline int
+Option_Handler::operator[] (option_type option) 
+{ 
+  return option_word & option;
+}
+#endif // __OPTIMIZE__
diff --git a/usr/src/lib/libg++/grot/etc/lf/screen-handler.cc b/usr/src/lib/libg++/grot/etc/lf/screen-handler.cc
new file mode 100644 (file)
index 0000000..a2a1eb8
--- /dev/null
@@ -0,0 +1,64 @@
+/* Handles screen manipulations for screen width and inverse mode. */
+#include "screen-handler.h"
+
+/* Initializes the current screen width via
+   the terminal independent operation routines. */
+
+Screen_Handler::Screen_Handler (void)
+{
+  if (tgetent (term_entry, getenv ("TERM")) != 1)
+    {
+      perror ("main");
+      exit (1);
+    }
+  else
+    {
+      width         = tgetnum ("co") - 1;
+      current_ptr   = temp_buf;
+      inverse_start = tgetstr("so", &current_ptr);
+      inverse_end   = tgetstr("se", &current_ptr);
+    }
+}
+
+/* Returns current screen width. */
+
+#ifndef __OPTIMIZE__
+int 
+Screen_Handler::screen_width (void)
+{
+  return width;
+}
+
+int 
+Screen_Handler::fputchar (int i)
+{
+  return putchar (i);
+}
+
+/* Prints out leading blanks so as to center buf 
+   assuming a screen width of width. */
+
+void 
+Screen_Handler::center (char *buf)
+{
+  int offset;
+  int len = strlen (buf);
+
+  offset = width - len >> 1;
+
+  for (int i = 0; i < offset; i++)
+    putchar (' ');
+}
+
+/* Centers, ``inverse-videos'' and prints buf. */
+
+void 
+Screen_Handler::print_inverse_centered (char *buf)
+{
+  putchar ('\n');
+  center (buf);
+  tputs (inverse_start, 1, fputchar);
+  printf ("%s\n\n", buf);
+  tputs (inverse_end, 1, fputchar);
+}
+#endif // __optimize__
diff --git a/usr/src/lib/libg++/grot/etc/lf/screen-handler.h b/usr/src/lib/libg++/grot/etc/lf/screen-handler.h
new file mode 100644 (file)
index 0000000..7309b80
--- /dev/null
@@ -0,0 +1,64 @@
+// This may look like C code, but it is really -*- C++ -*-
+#pragma once
+#include <stdio.h>
+#include <std.h>
+
+/* Handles necessary screen-manipultations. */
+class Screen_Handler
+{
+ private:
+  static char  term_entry[1024];   /* Holds termcap entry for current terminal. */
+  static char  temp_buf[100];      /* Holds inverse screen attributes. */
+  static int   width;              /* Current screen width, needed to format output. */
+  static char *current_ptr;        /* Pointer to current position in temp_buf. */
+  static char *inverse_start;      /* Control sequence beginning inverse mode. */
+  static char *inverse_end;        /* Control sequence ending inverse mode. */
+  
+  static void  center (char *buf); /* Prints out leading spaces to center BUF. */
+  static int   fputchar (int i);   /* Prints a character to standard output. */
+
+public:
+              Screen_Handler (void);              /* Initialize the screen width. */
+  static int  screen_width (void);                /* Return current screen width. */
+  static void print_inverse_centered (char *buf); /* Centers, inverts, and prints BUF. */
+};
+
+/* See comments in .cc file for inline functions. */
+
+#ifdef __OPTIMIZE__
+inline int 
+Screen_Handler::screen_width (void)
+{
+  return width;
+}
+
+inline int 
+Screen_Handler::fputchar (int i)
+{
+  putchar (i);
+}
+
+inline void 
+Screen_Handler::center (char *buf)
+{
+  int offset;
+  int len = strlen (buf);
+  
+  offset = width - len >> 1;
+  
+  for (int i = 0; i < offset; i++)
+    putchar (' ');
+}
+
+inline void 
+Screen_Handler::print_inverse_centered (char *buf)
+{
+  putchar ('\n');
+  center (buf);
+  tputs (inverse_start, 1, fputchar);
+  printf ("%s\n\n", buf);
+  tputs (inverse_end, 1, fputchar);
+}
+
+#endif // __OPTIMIZE__
+
diff --git a/usr/src/lib/libg++/grot/etc/lf/sort.cc b/usr/src/lib/libg++/grot/etc/lf/sort.cc
new file mode 100644 (file)
index 0000000..b47bd9a
--- /dev/null
@@ -0,0 +1,175 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <std.h>
+
+/* the next 6 #defines implement a very fast in-line stack abstraction       */
+
+#define MAX_STACK_SIZE 32
+#define DISPOSE_STACK(S) (free(S))
+#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
+#define POP(LOW,HIGH)  do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
+#define STACK_NOT_EMPTY (stack < top)                
+#define SWAP(A,B) do {char *_temp = (A);(A) = (B);(B) = _temp;} while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+   This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 30
+
+/* Data structure for stack of unfulfilled obligations. */
+typedef struct 
+{
+  char **lo;
+  char **hi;
+} stack_node;
+
+/* Once main array is partially sorted by quicksort the remainder is 
+   completely sorted using insertion sort, since this is efficient 
+   for partitions below MAX_THRESH size. BASE points to the beginning 
+   of the array to sort, and END_PTR points at the very last element in
+   the array (*not* one beyond it!). */
+
+inline static void
+insert_sort (char **base_ptr, char **end_ptr)
+{
+  char **run_ptr;
+  char **tmp_ptr = base_ptr;
+  char **thresh  = end_ptr <? base_ptr + MAX_THRESH;
+
+  /* Find the smallest element in the first threshold and put it at the 
+     end of the array.  This is guaranteed to be the smallest element in 
+     the array, and it speeds up the inner loop of insertion sort. */
+
+  for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++)
+    if (strcmp (*run_ptr, *tmp_ptr) < 0)
+      tmp_ptr = run_ptr;
+
+  SWAP (*tmp_ptr, *base_ptr);
+
+  /* Typical insertion sort, but we run from the `right-hand-side'
+     downto the `left-hand-side.' */
+
+  for (run_ptr = base_ptr + 1; run_ptr < end_ptr; run_ptr++)
+    {
+      char *temp = *(tmp_ptr = run_ptr + 1);
+
+      /* Select the correct location for the new element, 
+         by sliding everyone down by 1 to make room! */
+
+      while (strcmp (temp, *--tmp_ptr) < 0)
+        tmp_ptr[1] = *tmp_ptr;
+
+      tmp_ptr[1] = temp; 
+    }
+}
+
+/* Return the median value selected from among the 
+   LOW, MIDDLE, and HIGH.  Rearrange LOW and HIGH so
+   the three values are sorted amongst themselves. 
+   This speeds up later work... */
+
+inline static char *
+find_pivot (char **low, char **high)
+{
+  char **middle = low + ((high - low ) >> 1);
+
+  if (strcmp (*middle, *low) < 0)
+    SWAP (*middle, *low);
+  if (strcmp (*high, *middle) < 0)
+    SWAP (*middle, *high);
+  else 
+    return *middle;
+
+  if (strcmp (*middle, *low) < 0)
+    SWAP (*middle, *low);
+
+  return *middle;
+}
+
+/* Order elements using quicksort.  This implementation incorporates
+   4 optimizations discussed in Sedgewick:
+   
+   1. Non-recursive, using an explicit stack of log (n) pointers that 
+      indicate the next array partition to sort.
+
+   2. Choses the pivot element to be the median-of-three, reducing
+      the probability of selecting a bad pivot value.
+
+   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+      insertion sort to sort within the partitions.  This is a
+      big win, since insertion sort is faster for small, mostly
+      sorted array segements.
+   
+   4. The larger of the 2 sub-partitions are always pushed onto the
+      stack first, with the algorithm then concentrating on the
+      smaller partition.  This *guarantees* no more than log (n)
+      stack size is needed! */
+      
+void
+sort (char **base_ptr, int total_elems)
+{
+  if (total_elems > MAX_THRESH)
+    {
+      char       **lo = base_ptr;
+      char       **hi = lo + (total_elems - 1);
+      char       **left_ptr;
+      char       **right_ptr;
+      stack_node   stack[MAX_STACK_SIZE];
+      stack_node  *top = stack + 1;
+
+      while (STACK_NOT_EMPTY)
+        {
+          /* Select the median-of-three here. This allows us to
+            skip forward for the LEFT_PTR and RIGHT_PTR. */
+          char *pivot = find_pivot (lo, hi);
+          left_ptr  = lo + 1;
+          right_ptr = hi - 1; 
+
+          /* Here's the famous ``collapse the walls'' section of
+            quicksort.  Gotta like those tight inner loops! */
+          do 
+            {
+              while (strcmp (*left_ptr, pivot) < 0)
+                left_ptr++;
+
+              while (strcmp (pivot, *right_ptr) < 0)
+                right_ptr--;
+
+              if (left_ptr < right_ptr) 
+                {
+                  SWAP (*left_ptr, *right_ptr);
+                  left_ptr++;
+                  right_ptr--;
+                }
+              else if (left_ptr == right_ptr) 
+                {
+                  left_ptr++;
+                  right_ptr--;
+                  break;
+                }
+            } 
+          while (left_ptr <= right_ptr);
+
+          if ((right_ptr - lo) <= MAX_THRESH) 
+            {
+              if ((hi - left_ptr) <= MAX_THRESH) /* ignore both small tables */
+                POP (lo, hi);
+              else              /* ignore small left table */
+                lo = left_ptr;
+            }
+          else if ((hi - left_ptr) <= MAX_THRESH) /* ignore small right table */
+            hi = right_ptr;
+          else if ((right_ptr - lo) > (hi - left_ptr)) 
+            {                   /* push larger left table */
+              PUSH (lo, right_ptr);
+              lo = left_ptr;
+            }
+          else 
+            {                   /* push larger right table */
+              PUSH (left_ptr, hi);
+              hi = right_ptr;
+            }
+        }
+    }
+
+  insert_sort (base_ptr, base_ptr + (total_elems - 1));
+}