Modifier un fichier C à l'aide d'un script

a marqué ce sujet comme résolu.

Bonjour tout le monde,

J'aimerais tester une bibliothèque de fonctions que j'ai écrite en C. Il y a un fichier par fonction. J'ai écrit un fichier MAIN.c qui contient les tests pour toutes ces fonctions.

Ce dont j'ai besoin, c'est d'un script qui ajoute un appel aux tests dans MAIN.c pour chaque fichier trouvé dans le dossier courant. Autrement dit, si j'ai fct1.c et fct2.c, je veux ajouter test_fct1() et test_fct2() dans le main de MAIN.c

Je n'arrive pas à écrire ce script en Bash. La partie qui me pose problème c'est vider le contenu du main et le remplacer par l'appel aux fonctions. Je suis aussi entrain de regarder du côté de Python (que je n'ai encore jamais vu).

Si vous aviez des pistes à me donner, ça serait cool. Également, comment vous organisez votre code pour pouvoir facilement lancer les tests ?

Merci d'avance.

+0 -0

Le main fait plus de 1000 lignes donc j'ai réduit un peu, mais l'essentiel doit être là.

somme.c

1
2
3
4
5
6
#include "libbiblio.h"

int somme(int a, int b)
{
    return a + b;
}

main.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include "libbiblio.h"

#define OK(test) { printf("%s: \033[32mSUCCESS\033[0m\n", #test); return ; }
#define KO(test) { printf("%s: \033[31mFAIL: file %s, line %i\033[0m\n", \
    #test, __FILE__, __LINE__); return ; }

void    test_somme(void)
{
    if (somme(1, 2) != 3)
        KO(somme)
    else
        OK(somme)
}

int main(void)
{
    test_somme();  /* mettre cette ligne en commentaire si il n'y a pas de fichier somme.c */
                   /* dans le dossier courant                                              */
    return 0; 
}
+0 -0

Tu as deux méthodes, soit tu compiles tes .c en .o. Puis ensuite, tu les charges depuis ton main de manière dynamique.

Soit tu fais un vieux hack comme ça :

1
gcc main.c -DFUNCTION="`ls | grep "\.c" | sed 's/\.c/();/'`"
1
2
3
4
5
6
7
8
9
#include<stdio.h>


int main(void) {
  #ifdef FUNCTION
    FUNCTION
  #endif
  return 0;
}

Faudra penser à rajouter un grev -v main.c pour éviter d'appeler la fonction main en boucle …

+0 -0

Pour rester sur du bash pur, de quoi démarrer (c'est loin d'être parfait, je te laisse découvrir tous les défauts de la méthode :p ) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
    is_test=0
    for f in *.c; do
        # On enlève l'extension du fichier
        name="${f%.*}"
        # On matche innocemment tout ce qui ressemble à un appel de test_$name
        regex="^\s*test_$name\s*(\s*)\s*"
        if [[ "$line" =~ $regex ]]; then
            is_test=1
        fi
    done
    # On commente tout ce qu'on a considéré comme test...
    if [ $is_test -eq 1 ]; then
        echo "//$line"
    else
        echo "$line"
    fi
done < main.c

Sinon, il y a le bon vieux ed(1).

1
2
3
4
5
6
7
8
9
$ ed main.c
P
*r !ls -1 *.c
*g/^main.c$/d
*g/.c$/m/main(/+1
*g/.c$/s/^/test_/
*g/.c$/s//()/
*w
*q

Pour l'explication :

  1. La commande P demande à ed(1) d'afficher un invite de commande (par défaut *) quand il attends une commande ;
  2. La commande r !ls -1 *.c insère à la fin du fichier le résultat de la commande ls -1 *.c (qui liste donc tous les fichiers sources C du répertoire courant sur une seule colonne) ;
  3. La commande g/^main.c$/d supprime du fichier toutes les lignes comportant exclusivement main.c ;
  4. La commande g/.c$/m/main(/+1 déplace chaque ligne se terminant par les caractères .c une ligne après la première comportant les caractères main( ;
  5. La commande g/.c$/s/^/test_/ ajoute les caractères test_ au début des lignes se terminant par .c ;
  6. La commande g/.c$/s//()/ substitue la suite .c par () dans toutes les lignes se terminant par .c ;
  7. La commande w sauvegarde les modifications et la commande q quitte l'éditeur.

Édit : ajout de l'insertion des caractères test_.

+0 -0

Chacun sa solution :) Merci à vous tous en tout cas.

J'ai toujours regretté de ne pas maîtriser ed et sed ou awk, que je trouve assez difficiles à apprendre. Par contre j'ai essayé de faire echo 'script' | ed main.c mais ça ne fonctionne pas.

Je vais regarder du côté des frameworks de tests, apparemment il y a du choix.

+0 -0

@Taurre: :lol: Tu m'as tué … :')

@matthieuj: La "maîtrise" de ces outils s'apprend au fils du temps. J'ai jamais vraiment appris à utiliser sed mais comme j'utilise vim tous les jours et que ça ressemble un peu … Pour ed, c'est un peu la même chose …

+0 -0

J'ai toujours regretté de ne pas maîtriser ed et sed ou awk, que je trouve assez difficiles à apprendre.

matthieuj

ed(1) reste foncièrement assez simple, c'est juste qu'il est quelque peu austère et, surtout, qu'il n'affiche pas le texte couramment édité ce qui rebute assez logiquement de nos jours.

Par contre j'ai essayé de faire echo 'script' | ed main.c mais ça ne fonctionne pas.

matthieuj

ed(1) edite le fichier fourni en argument. Si tu lui fourni une entrée, celle-ci est considérée comme une suite de commandes à appliquer. ;)

@Taurre: :lol: Tu m'as tué … :')

ache

Ne jamais oublier le bon vieux ed. :p

+0 -0

Par contre j'ai essayé de faire echo 'script' | ed main.c mais ça ne fonctionne pas.

matthieuj

ed(1) edite le fichier fourni en argument. Si tu lui fourni une entrée, celle-ci est considérée comme une suite de commandes à appliquer. ;)

Je ne sais pas pourquoi je me suis obstiné à faire un echo :P

+0 -0

Tout fonctionne correctement en utilisant un script ed et un script sh.

Par contre le script ed supprime toutes les lignes commençant par test_, je voudrais supprimer les lignes suivant le motif test_name(); Pour l'instant ça me donne: g/^ *test_.*\(\);$/d, mais ça ne fonctionne pas. Ma conclusion: je ne sais pas écrire une regex.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte