Champ Valeur
Auteur·e Élise
Édition 2023-12-12
Durée 1,5 semaine
Taille des équipes 1 personne
Rendu via git, dépôt $YEAR_tr, droits en lecture à delivery_collector

Barème

Critères Points
Fonctionnalité : remplacement CHAINE_1 CHAINE_2 4
Fonctionnalité : suppression -d CHARS 3
Fonctionnalité : suppression inversée -c -d CHARS 3
Fonctionnalité : helper -h 2
Allocation juste de la mémoire 3
Libération de la mémoire 2
Absence d’erreurs mémoires (valgrind/memcheck) 3
Points accessibles 20
Malus par ligne contenant une faute de norme -0,5
Malus dépôt sale -5
Note maximale 20

Règlement de projet

La réalisation de cet exercice est assujettie aux règles en vigueur dans l’école en matière de triche et de normalisation. Tricher vous expose à de graves sanctions.

Vous devez respecter les règles de normalisation suivantes : https://git.ecole-89.com/eriizu/coding_style/src/branch/main/norm.md

Le non-respect de la norme vous fera perdre une partie ou la totalité des points qui auraient pu être acquis, sur l’ensemble du rendu.

Fichiers à rendre

La structure de votre dépôt doit être la suivante :

  • fichiers *.c dans src/
  • fichiers *.h dans include/

Comme vous devez rendre un programme, vous devez rendre une fonction main. Son fichier, devra s’appeler main.c, être dans le dossier src/ et respecter les règles de normalisation (il ne s’agit pas d’un fichier de test.)

Votre projet sera compilé avec la commande suivante :

gcc -Wall -Wextra -Werror -Iinclude ./src/*.c -o tr

Fonctions autorisées et interdites

Pour tout le sujet, les fonctions autorisées sont :

  • write
  • read
  • malloc
  • free

Tests

Vous pouvez inclure des main de test dans votre rendu. Ces main doivent être rendus dans un dossier test/. Vous pouvez organiser ce dépôt comme vous le souhaitez.

Préambule

Contexte : systèmes UNIX

Sur un système Linux et sur les systèmes UNIX en général, il y a tout plein de petits outils sous forme de programmes qui nous permettent de faire des opérations quotidiennes depuis un terminal. Vous avez implémenté cat qui est l’un d’entre eux, et probablement l’un des plus utilisés. Vous en avez manipulé plein d’autres comme head, tail, echo, ls, rm, etc. notamment lors de gameshell.

Ces commandes sont requises par une norme qui s’appelle POSIX (et une autre qui s’appelle SUS et qui aujourd’hui est fonctionnellement identique à POSIX) que GNU/Linux respecte en grande partie.

POSIX décrit également comment doivent se comporter les appels systèmes (comme read, write, open et close). Si vous allez sur le man de read.2, vous pouvez constater qu’il y a une section “STANDARDS” avec la norme à laquelle cette fonction se conforme. Il existe même une page read.3p qui correspond au manuel de la fonction telle que POSIX l’imagine.

Ces standards ont plusieurs intérêts.

  1. Si vous devez utiliser une machine qui tourne sur NetBSD, FreeBSD, OpenBDS ou sur MacOS, vous ne serez pas complètements perdus. Les commandes de base sont les mêmes. Elles peuvent avoir des variations mineures comme majeures mais elles ne vous seront pas complètement étrangères.
  2. Un programme écrit pour Linux (faisant usage d’appels systèmes directement), peut être porté facilement sur un autre système UNIX. Parfois sans avoir à changer une seule ligne de code.

Ces choses là étant possible sans que MacOS et Linux (par exemple) n’aient d’ancêtres communs.

A diagram showing the key Unix and Unix-like operating systems.

Introduction

Dans le cadre de ce sujet, vous allez implémenter un clone partiel de la commande tr. Il s’agit d’un utilitaire qui peut remplacer ou supprimer des caractères lus sur son entrée standard. Il affiche le résultat sur sa sortie standard.

tr est un outil nécessaire pour qu’un système soit considéré POSIX. Il a fait sa première apparition sur la version 4 d’UNIX en 1973, avant même la première version de Windows (1985) ou de MS-DOS (1981). Il a donc fêté ses 50 ans cette année.

Consignes

Implémentez un clone de tr avec ces trois modes de fonctionnement :

  • remplacement de caractères ;
  • suppression de caractères faisant partie d’un ensemble ; et
  • suppression de caractères ne faisant pas partie d’un ensemble.

Il peut y avoir n’importe quelle quantité d’octets sur l’entrée standard, vous devez donc lire en boucle.

Après avoir lu des caractères depuis l’entrée standard, vous devez les traiter et les afficher immédiatement. Vous êtes autorisés à appeler read seulement après avoir affiché le résultat de la dernière lecture.

Fonctionnalité : traduction simple

Le comportement de TR est différent en fonction des arguments reçus. Sans options, TR est en mode traduction. Il admet deux chaînes en argument appelons-les to_replace et substitutes.

TR restitue ce qu’il lit depuis l’entrée standard sur la sortie standard sauf pour les caractères qui sont présents dans to_replace. Chacun de ces caractères doit être remplacé par un caractère tiré de substitutes à la même position.

Exemple :

[sh] $ echo "tata" | ./tr a i
titi
[sh] $ echo "tata" | ./tr at if
fifi

Dans le premier exemple les “a” sont remplacés par des “i”.

Dans le second exemple :

  • les “a” sont remplacés par des “i” ; et
  • les “t” sont remplacés par des “f”.

Et ce peut importe le nombre de caractères dans to_replace et substitutes.

Erreurs possibles :

  • to_replace et substitutes ne font pas la même taille ; et
  • il n’y a pas assez d’arguments.

Fonctionnalité : suppression

Avec l’option d TR admet une chaîne en argument que l’on va appeler to_delete.

TR va restituer les caractères lus depuis l’entrée standard sauf ceux qui apparaissent dans to_delete.

[sh] $ echo zabcdef | ./tr -d zcdb
aef

Erreur possible :

  • s’il n’y a pas assez d’arguments.

Fonctionnalité : conservation

Avec les options d et c TR admet une chaîne en argument que l’on va appeler to_keep.

TR va restituer les caractères lus depuis l’entrée standard SEULEMENT SI ils figurent dans la chaîne to_keep.

Cela concerne aussi les retours à la ligne, ce qui signifie que TR risque de ne rien afficher jusqu’à ce qu’il reçoive EOF s’il n’y a pas de \n dans to_keep.

[sh] $ echo lmqskdjfqmssldtakjfqmslkdmf | ./tr -cd ta
ta[sh] $ echo lmqskdjfqmssldtakjfqmslkdmf | ./tr -cd ta\\n
ta
[sh] $

Le \n sera reçu comme deux caractères séparés par votre programme. Il faudra le considérer comme un retour à la ligne quand même.

Fonctionnalité : helper

Lorsque vous recevez l’option h, affichez l’aide de votre programme. Elle doit avoir le même style que tr --help et elle doit inclure seulement les fonctionnalités que vous avec implémenté.

Elle doit aussi être en anglais.