#!/usr/local/bin/perl

# Script qui ne sert a rien si on a la version GNU de grep (RTFM tu devras).
# Mais bon, on a le droit de s'amuser.
# J'en profite pour le surcommenter, des fois que ca serve a quelqu'un.
# Et en exercice:
#   + Utiliser GetOpt pour gerer proprement un paquet d'options
#   + Donner la possibilite de faire le grep sur plusieurs fichiers
#     (Indice: utiliser le caractere "magique" de l'operateur <>)
#   + Ne pas se limiter a la premiere occurence de la chaine
#   + etc...

# This script is distributed under the GNU General Public License
# version 2.1 or later. See http://www.fsf.org/

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2.1, or (at your option)
# any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# A copy of the GNU General Public License can be obtained from this
# program's author (send electronic mail to the above address) or from
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# or from the Free Software Foundation website: http://www.fsf.org/


# Nombre de lignes a extraire de chaque cote de la ligne correspondante
$maxlines = 20;

# Tableau ou seront stockees les $maxlines lignes precedant la ligne recherchee
@before = ();

# Syntaxe
$usage = "Syntaxe: cgrep [regexp] [fichier]\n";

# Recuperation des arguments en ligne de commande
$terme = shift(@ARGV) || die $usage;
$fichier = shift(@ARGV) || die $usage;

open(F, $fichier) || die "Cannot read $fichier: $!\n";

# On remplit le tableau @before jusqu'a $maxlines elements
while (($_ = <F>) && (scalar(@before) < $maxlines))
{
  # Le //o est la pour indiquer que la variable $terme ne changera pas au
  # cours du prg, donc qu'on peut ne compiler la regexp qu'une seule fois
  # (le gain de temps est appreciable)
  if (/$terme/o)
  {
    # On a trouve la ligne, donc on affiche celles qui la precedaient, puis
    # les $maxlines suivantes
    print @before;
    print $_;
    &print_next_lines;
  }
  # On empile la ligne dans @before
  push(@before, $_);
}

# Le tableau @before contient la bonne quantite d'elements, donc on
# passe maintenant dans une partie ou on lui garde une taille constante
while (<F>)
{
  # Memes remarques que plus haut
  if (/$terme/o)
  {
    print @before;
    print $_;
    &print_next_lines;
  }

  # On empile a  la fin de la liste...
  push(@before, $_);
  # ... et on depile l'element de tete
  shift(@before);
}

close(F);
# Si on arrive ici, c'est qu'on n'a pas trouve la ligne, donc on renvoie un
# code d'erreur non-nul
exit 1;

# Affiche les $maxlines lignes suivantes (on profite du fait que le filehandle
# F et $maxlines sont globaux. C'est pas propre, mais ca marche bien).
sub print_next_lines
{
  my $i;
  
  for ($i = 0; $i < $maxlines; $i++)
  {
    # le scalar() sert ici a donner un contexte scalaire a l'operateur <F>
    # Sinon mettre uniquement "print <F>" lui aurait donne un contexte de
    # liste, donc on aurait lu tout le reste du fichier
    print scalar(<F>);
  }
  exit 0; 
}
