# mq-select-list.awk
# ------------------------------------------------------------------------------
#
# Helper script, to compile a sorted list of all guards which are specified
# in the patch queue series file; the formatted listing is produced by use of
# an embedded awk script.
#
# ------------------------------------------------------------------------------
#
# $Id$
#
# Written by Keith Marshall <keith@users.osdn.me>
# Copyright (C) 2019, Keith Marshall
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ------------------------------------------------------------------------------
#
# While parsing the series file, ignore the first field of each record,
# (which represents the patch name), and tally unique instances of each
# additional field, compiling an ordered list of defined guards, with a
# running count of patches to which each applies.
#
  { if( NF > 1 )
    { for( idx = 2; NF >= idx; ++idx ) count[$idx] = 0;
      for( idx = 2; NF >= idx; ++idx )
      { if( !( $idx in guarded ) ) keys[++ordered] = $idx;
	if( (count[$idx]++ == 0) && (++guarded[$idx] > width) )
	  width = guarded[$idx];
      }
    }
    else if( verbose && (NF == 1) )
      if( guarded[verbose]++ == 0 ) keys[++ordered] = verbose;
  }

# It may be tempting to use GNU awk's "asorti()" function to sort the
# guards list, but that isn't portable ... not even among versions of
# GNU awk itself!  (In particular, we require a specialized comparison
# function, which isn't supported prior to GNU awk-4.x).  Thus, we use
# our own quick-sort function, which should be supported regardless of
# the particular awk implementation which is available.
#
  function qsort( array, first, last, scan, pivot )
  { if( last > first )
    { scan = pivot = first;
      while( last >= ++scan ) if( key_compare( array[scan], array[first] ) )
	swap( array, scan, pivot );
      if( pivot > first ) swap( array, first, pivot );
      qsort( array, first, pivot - 1 );
      qsort( array, pivot + 1, last );
    }
  }

# When sorting guard references, ignore the "#+" or "#-" prefix to the
# guard name, except when required to discriminate between +ve and -ve
# guards with the same name.
#
  function key_compare( idx1, idx2, val1, val2 )
  { val1 = (substr( idx1, 1, 1 ) == "#") ? substr( idx1, 3 ) : idx1;
    val2 = (substr( idx2, 1, 1 ) == "#") ? substr( idx2, 3 ) : idx2;
    return (val1 == val2) ? (idx1 < idx2 ) : (val1 < val2);
  }

# The following "swap()" function is called by the "qsort()" function,
# to reorder the entries within the guards listing array.
#
  function swap( array, idx1, idx2, tmp )
  { tmp = array[idx1]; array[idx1] = array[idx2]; array[idx2] = tmp;
  }

# When printing a verbose guards listing, we want to use a minimum of
# to digit positions for the width of the count field; we may use this
# "max()" function, to ensure that at least this "width" is provided.
#
  function max( a, b ) { return (a > b) ? a : b; }

# The "END" action handles the additional output for "verbose" mode,
# (which is categorized by inclusion of a "##NONE" pseudo-guard count
# of unguarded patches), followed by the sorted list of all guards
# which are named within the series file.
#
  END {
    if( verbose )
    { if( guarded[verbose] == 0 ) keys[++ordered] = verbose;
      print facility ": directory of guards specified in series file";
    }
    qsort( keys, 1, ordered );
    width = max( (1 + int( log( width ) / log( 10 ) )), 2 );
    for( idx = 1; ordered >= idx; idx++ )
    { tag = keys[idx]; sub( "^#*", "", tag );
      if( verbose ) printf "%*d  %s\n", width, guarded[keys[idx]], tag;
      else print tag;
    }
  }
#
# ------------------------------------------------------------------------------
# $RCSfile$: end of file
