\documentclass{article}
\usepackage[latin1]{inputenc}
\usepackage{fullpage}

\title{TD 3 d'Environnement Logiciel}
\date{Mardi 21 septembre 2004}

\begin{document}
\maketitle

\textbf{Entrée sortie, encore, ou le retour du TD 2.}

\begin{itemize}

\item Écrivez une version en \verb+C+ de \verb+cat+ en utilisant
uniquement les fonctions d'entrée sortie de la bibliothèque standard
\verb+fread+ et \verb+fwrite+, et en lisant et écrivant des blocs d'un
caractère.

\item Écrivez une seconde version de \verb+cat+ en utilisant
uniquement les appels systèmes \verb+read+ et \verb+write+.

\item En utilisant la commande \verb+time+ comparez les performances
des deux versions pour une lecture/écriture d'un fichier
raisonnablement volumineux (par exemple \verb+/lib/libc.so.6+ en
n'oubliant pas de rediriger la sortie standard vers \verb+/dev/null+).

\item Interprétez les résultats obtenus. Quels sont les commandes de
plus bas niveau: \verb+read/write+ ou \verb+fread/fwrite+?

\item Essayez le programme suivant:

\begin{verbatim}

#include <stdio.h>
#include <unistd.h>

int main ()
{
	fwrite ("Hello ", sizeof(char), 6, stdout);
	write (STDOUT_FILENO, "World !", 7);

	return 0;
}
\end{verbatim}

Le résultat est-il surprenannt?

\end{itemize}

\textbf{Scripts shell}

\begin{itemize}

\item Dans un script \verb+bash+, écrivez une fonction qui affiche le
nombre de lignes du fichier donné en premier argument. Vous avez le
droit d'utiliser \verb+wc+ (en nettoyant la sortie, \verb+wc+ affiche
généralement le nom du fichier passé en argument, ce que nous ne voulons
pas).

\item Modifiez votre fonction pour pouvoir afficher au choix le nombre
de lignes, de mots ou de caractères. On indiquera ce choix par
\verb+L+, \verb+M+ et \verb+C+, respectivement. Les courageux ont le
droit d'essayer un \verb+case+ pour laisser plus de liberté à
l'utilisateur (par exemple permettre "un mot qui commence par
\verb+L+" plutôt que d'imposer simplement \verb+L+).

\item Utilisez cette fonction dans le script pour qu'il affiche le
nombre total de lignes dans les fichiers sources C (y compris les
headers) du répertoire courant.

\item Modifiez votre script pour inclure les fichiers C des
sous-répertoires, de façon récursive.

\item Modifiez votre script pour n'inclure que les fichiers contenant
le mot 'copyright' sans tenir compte de la casse.

\item Modifiez votre script pour remplacer dans la foulée dans
tous les fichiers visités les lignes contenant 'copyright' par une
ligne de copyright de votre choix. (\emph{exercice à tester sur une
copie de travail des sources de GMP par exemple.})

\end{itemize}

\textbf{Un peu d'awk}

\begin{itemize}

\item Écrivez un script awk qui simule \verb+wc+. Il devra lire
l'entrée standard et n'afficher qu'une ligne de sortie contenant
respectivement le nombre de lignes, de mots, et de caractères lus.

\item Écrivez un script awk qui renverse l'entrée standard: les champs
de chaque ligne doivent être affichés sur la sortie standard dans
l'ordre inverse dans lequel ils sont lus. On ne fait pas d'hypothèse
\emph{a priori} sur le nombre de champs sur une ligne, qui peut varier
d'une ligne à l'autre.

\end{itemize}

\textbf{Un peu de sed}

\begin{itemize}

\item Rotation $13$. La rotation $13$ est un codage par substitution
qui n'offre aucune sécurité mais permet de masquer temporairement du
texte dans un message, par exemple la solution d'une énigme envoyée
par mail. On fait correspondre à chaque lettre la lettre décalée de
$13$ positions dans l'alphabet (\verb+a+ devient \verb+n+). À l'aide
de \verb+sed+ écrivez une fonction shell \verb+rot13+ que vous
chargerez automatiquement dans votre \verb+.bashrc+ (les fonctions
s'exportent avec \verb+export -f+). Votre fonction devra traduire
correctement les majuscules. Votre fonction devra se comporter comme
un filtre entre l'entrée standard et la sortie standard (on ne demande
pas d'accepter des fichiers en argument sur la ligne de commande, mais
c'est une amélioration possible si vous avez le temps).

\item Et la fonction inverse? Vérifiez que \verb+rot13 | rot13+
produit bien le résultat attendu.

\item Petit raffinement: ajoutez une rotation $5$ sur les chiffres.

\item Les fichiers sources de \verb+GMP+ commencent tous ou presque
par un commentaire donnant des informations sur le fichier. Écrivez un
script \verb+sed+ qui enlève ces quelques lignes.

\end{itemize}

\textbf{Du perl?}

\begin{itemize}

\item Codage en base64. Pour des raisons remontant à la nuit des
temps, les fichiers binaires inclus en attachement dans les emails ne
sont pas inclus tels quels, mais codés en base64. Le problème est que
les caractères non affichables (comme le \verb+0x07+, voir
\verb+man ascii+) ne passent pas. On remplace donc 3 octets (3 * 8
bits) du flux d'entrée par 4 octets en sortie en ne choissant les
octets de sortie que parmi 64 octets "imprimables" (lettres majuscules
et minuscules, chiffres, \verb-+- et \verb+/+) avec le \verb+=+ comme
symbole de remplissage. Voir la RFC 3548 pour plus d'informations. Un
alphabet de 64 caractères permet de représenter $6$ bits d'information
($2^6 = 64$) et $6 * 4 = 24$ donc le compte est bon.

Le script perl suivant est un filtre qui code l'entrée en base64:

\begin{verbatim}

use MIME::Base64;

while (<>) {
	print encode_base64($_);
}

\end{verbatim}

et celui-ci fait le décodage:

\begin{verbatim}

use MIME::Base64;

while (<>) {
	print decode_base64($_);
}

\end{verbatim}

\item Écrivez ces deux scripts perl dans des fichiers que vous rendrez
exécutables. N'oubliez pas d'indiquer en première ligne le chemin vers
l'interprète perl.

\item Un codage révolutionnaire: un code base64 valide reste valide
après passage par rot13. Écrivez un filtre qui fait la transformation
suivante:

$$\mathrm{clair} \rightarrow \mathrm{base64}(\mathrm{clair})
\rightarrow \mathrm{rot13}(\mathrm{base64}(\mathrm{clair})) 
\rightarrow
\mathrm{base64}^{-1}(\mathrm{rot13}(\mathrm{base64}(\mathrm{clair})))$$

\item Écrivez un script un demande à l'utilisateur un nom de fichier
et effectue le codage décrit ci-dessus en ajoutant \verb+.sec+ au
fichier produit (essayez de ne pas planter salement en cas d'entrée
incorrecte...).

\item Et pour le décodage? \verb+:-)+

\item Le codage par rot13 n'étant pas d'une sûreté exceptionnelle, on
va utiliser mieux. On suppose qu'une clef est une permutation (avec
éventuellement des points fixes) de l'alphabet des 64 caractères
définis pour la base64, et cette permutation va remplacer la fonction
rot13 dans le diagramme ci-dessus.. La clef est donnée dans un fichier
comme une suite de lignes contenant deux champs: un caractère et son
image.  Écrivez un script shell permettant à l'utilisateur d'indiquer
un fichier clef, un fichier à coder et si l'opération à effectuer est
le codage ou le décodage.

Comparez vos résultats avec le script perl solution suivant:
\newpage
\begin{verbatim}

use MIME::Base64;

use strict;
use warnings;

my $clef = shift || die "Veuillez entrer une clef.";
my $sens = shift || die "Veuillez entrer un sens (1 ou 2).";
my %perm;

open KEY, $clef;
while (<KEY>) {
    if (/\s*(\w)\s*(\w)/) { $perm{$1} = $2; }
}

sub permute {
	my ($in) = (@_);
	if (defined($perm{$in})) {
		return $perm{$in};
	}
	return $in;
}

close KEY;
%perm = reverse(%perm )if ($sens eq "1");
my $ligne;
while ($ligne = <STDIN>) {
    print decode_base64(join('', map { permute($_) } 
	split(/ */, encode_base64($ligne))));
}

\end{verbatim}

aussi disponible sur \verb+http://nowwhat.fousse.info/tmp/code+.

\end{itemize}

\end{document}
