#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS

function display_help() {
    uecho "$scriptname: Afficher le résultat d'une recherche par regexp et compter
éventuellement leurs occurences

USAGE
    $scriptname [options] [regexp]

Chaque ligne *entière* de stdin est mise en correspondance avec l'expression
regulière qui doit avoir la syntaxe de awk. S'il y a correspondance, afficher
soit toute l'expression matchée, soit chaque groupe s'il y a des expressions
parenthésées, chacun des groupes étant séparé par le caractère sep.

Si l'expression régulière n'est pas spécifiée, elle vaut par défaut '.*' ce qui
fait que toutes les lignes correspondent. Ceci peut être utile avec les options
-s et -c.

Certaines expressions régulières sont prédéfinies. regexp peut avoir l'une des
valeurs prédéfinies suivantes:

    ip --> "'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'"

OPTIONS
    -F sep
        Spécifier le caractère séparateur en sortie s'il faut afficher des
        champs multiples. Par défaut, utiliser le caractère ':'
        Si un séparateur vide est spécifié, le séparateur standard de awk est
        utilisé.
    -s  Trier le résultat
    -C FIELDNUM
    -c, --count
        Compter les occurences successives de la valeur du champ FIELDNUM, et
        afficher une ligne de la forme 'count<sep>last_line' pour chaque groupe,
        last_line étant la dernière occurence du groupe. L'option -c correspond
        à '-C 0', c'est à dire compter les occurences successives de toute les
        lignes.
        Le séparateur utilisé pour calculer le numéro de champ est sep, spécifié
        avec l'option -F.
    -a, --all-lines
        Avec les options -c/-C, afficher toutes les lignes des occurences
        successives au lieu de seulement la ligne de la dernière occurence. Ceci
        est utile surtout avec l'option -C, pour voir les différences avec les
        différentes lignes.
    -m, --multiple
        Avec les options -c/-C, n'afficher que les lignes dont le compte est
        supérieur à 1. Avec l'option -a, les groupes contigus sont séparés par
        une ligne '--'"
}

function match() {
    local regexp="$1" sep="$2"
    awkrun ${sep:+FS="$sep"} '{
      pos = match($0, /'"${regexp//\//\\/}"'/, out)
      if (pos != 0) {
        max = length(out) / 3
        if (max == 1) {
          print out[0]
        } else {
          line = ""
          for (i = 1; i < max; i++) {
            if (i > 1) line = line FS
            line = line out[i]
          }
          print line
        }
      }
    }'
}
function count() {
    local field="$1" sep="$2" all_lines="$3"
    awkrun field="$field" ${sep:+FS="$sep"} all_lines="$all_lines" '
      BEGIN {
        first = 1
        lastfield = ""
        lastline = ""
        count = 0
        if (all_lines == "") all_lines = 0
        else all_lines = 1
      }
      !first && $field != lastfield {
        if (!all_lines) print count FS lastline
        count = 0
      }
      {
        count = count + 1
        lastfield = $field
        lastline = $0
        first = 0
        if (all_lines) print count FS lastline
      }
      END {
        print count FS lastline
      }
    '
}

sep=:
sort=
count=
all_lines=
multiple=
parse_opts "${PRETTYOPTS[@]}" \
    --help '$exit_with display_help' \
    -F: sep= \
    -s sort=1 \
    -c,--count count=0 \
    -C: count= \
    -a,--all-lines all_lines=1 \
    -m,--multiple multiple=1 \
    @ args -- "$@" && set -- "${args[@]}" || die "$args"

regexp="$1"
[ -n "$regexp" ] || regexp=".*"

case "$regexp" in
ip) regexp='[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+';;
esac

cmd="$(quoted_args match "$regexp" "$sep")"
[ -n "$sort" ] && cmd="$cmd | sort"
[ -n "$count" ] && cmd="$cmd | $(quoted_args count "$count" "$sep" "$all_lines")"
if [ -n "$multiple" ]; then
    if [ -n "$all_lines" ]; then
        cmd="$cmd | $(quoted_args grep -v -B 1 "^1$sep")"
    else
        cmd="$cmd | $(quoted_args grep -v "^1$sep")"
    fi
fi

eval "$cmd"