Programmer une interface en ligne de commande
Table des matières
- 1. Introduction
- 2. Mise en place du code
- 3. Définition de la grammaire, et introduction de Lex et Yacc
- 4. Ré-usinage du code
- 5. Auto-complétion contextuelle
- 5.1. Invocation de
marchande_complete
- 5.2. Invocation de
marchande_complete
, en anglais - 5.3. Nouvelles règles de grammaire
- 5.4. Adaptation du code
- 5.4.1. Le parseur
- 5.4.2. Le lexeur
- 5.4.3. L'en-tête principal
- 5.4.4. L'implémentation de la bibliothèque
- 5.4.5. L'implémentation de l'en-tête privé
- 5.4.6. L'implémentation du test
- 5.4.7. Le programme principal
- 5.4.8. Le programme d'auto-complétion
- 5.4.9. Le manuel
- 5.4.10. La configuration avec autoconf
- 5.4.11. Le Makefile
- 5.5. Testons !
- 5.1. Invocation de
- 6. Intégration de readline//readline est une bibliothèque qui permet à l'utilisateur d'entrer
- 6.1. Changement de comportement pour charger l'entrée utilisateur
- 6.2. Appel de la fonction d'auto-complétion
- 6.3. Mise en place de la nouvelle version
- 6.3.1. Le parseur
- 6.3.2. Le lexeur
- 6.3.3. L'en-tête principal
- 6.3.4. L'implémentation de la bibliothèque
- 6.3.5. L'implémentation de l'en-tête privé
- 6.3.6. L'implémentation du test
- 6.3.7. Le programme principal
- 6.3.8. Le programme d'auto-complétion
- 6.3.9. Le manuel
- 6.3.10. La configuration avec autoconf
- 6.3.11. Le Makefile
- 6.4. Testons !
- 7. Internationalisation de la grammaire
- 8. Conclusion
1 Introduction
Les logiciels ont pour mission d'accomplir une tâche pour ses utilisatrices et ses utilisateurs. Pour savoir quoi faire, il doit recevoir des commandes et communiquer les résultats. Bien que les standards actuels poussent à utiliser des interfaces graphiques, ce qui est selon moi une bonne chose, de nombreux programmes utiles continuent à utiliser une interface en ligne de commande, où l'utilisateur entre une ligne au clavier, et le résultat s'affiche sous forme de texte. Nous allons examiner plus précisément cette question.
Le programme bash
est l'exemple le plus connu : on entre des lignes
dans un certain langage, et on obtient un résultat. Par exemple, si
je tape :
date
J'obtiens le résultat suivant :
mardi 16 juillet 2019, 07:03:20 (UTC+0000)
La ligne de commande a un gigantesque avantage : cela permet au système d'exploitation d'utiliser le programme comme si c'était un utilisateur, le programme est donc potentiellement plus utile. Elle permet aussi de tout faire avec un clavier, ce qui est souvent plus pratique (sauf sur un téléphone portable, bien sûr). Enfin, dans le futur où l'on s'exprimera vocalement à son assistant virtuel, il n'est pas impossible que l'on revienne à ce fonctionnement.
Elle a bien sûr des inconvénients. Le principal inconvénient, c'est bien sûr qu'il faut tout faire avec du texte. Laissons celui-ci de côté. Il nous reste les problèmes suivants :
- la langue dans laquelle on s'exprime pour donner des commandes est très souvent une forme charcutée de l'anglais, même si les résultats s'affichent généralement dans notre langue. Ceci est inacceptable ;
- la syntaxe est généralement très rigide : si l'on fait une faute, l'opération ne sera pas effectuée.
Pour illustrer cela, voyons comment dire à bash
de compter le nombre
de lignes qui contiennent le mot "bidule" dans ce document1.
grep bidule index.org | wc --lines
2
On peut découper cette commande en plusieurs éléments :
- de la syntaxe, avec le symbole
|
. C'est assez important pour spécifier précisément et de façon concise des commandes complexes ; - des commandes, nommées
grep
etwc
, dont les noms sont peu évocateurs ; - des compléments pour spécifier plus précisément nos entrées. On
retrouve le nom de ce document,
index.org
, ainsi que le texte que l'on recherche ; - des compléments connus du programme, comme
--lines
, dont le nom est complètement en anglais.
Là où bash
fait des efforts, c'est pour le second point. Même si le
résultat échoue toujours à la moindre faute, on peut appuyer sur la
touche de tabulation à peu près n'importe où, et bash
complètera la
commande autant que possible à notre place. En cas de doute, il nous
proposera les différentes options. Il y a donc moins lieu de se
tromper.
Dans la suite, je vais vous montrer comment on peut implémenter une ligne de commande en faisant le moins d'efforts possibles.
2 Mise en place du code
Afin de faire cette démonstration, nous avons besoin d'un cas d'utilisation amusant mais simple qui nous permettra de nous concentrer sur l'implémentation de la ligne de commande.
2.1 Le jeu de la marchande
Vous voici face à une marchande de légumes bio. Devant elle, sur son étal, vous voyez une cagette contenant des pommes de terre et une cagette contenant des bottes de radis. La marchande remercie le client précédent et se tourne vers vous.
- Au suivant ! Qu'est-ce que ce sera ?
Vous avez besoin d'acheter des radis et des pommes de terre. Il va falloir que vous réussissiez à en acheter à la marchande…
2.2 Le jeu de la marchande, en anglais (désolé si c'est mal traduit)
You find yourself facing the organic vegetable seller. In front of her, on her stall, you see a crate containing potatoes and bunches of radishes. The seller thanks the previous customer and turns to you.
- Next! What will it be?
You need to buy a few radishes and potatoes. You're going to have to be able to buy it from the merchant…
2.3 Un petit intermède pénible
Je sais, c'est pénible, mais il faut en passer par là. Nous allons écrire du code, et quand on écrit du code il faut mettre sur chaque fichier source la description de la license utilisée. Dans la suite, on se contentera de recopier le programme 1 automatiquement pour chaque fichier source.
Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> 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 3 of the License, 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. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
2.4 Une bibliothèque pour le jeu
Nous avons plusieurs choses à implémenter :
- la marchande nous salue, et le narrateur nous présente les options ;
- en cas d'erreur, la marchande s'interroge et le narrateur nous explique quoi faire ;
- la marchande peut nous dire qu'elle ne vend pas quelque chose.
- on peut acheter des patates (en précisant le poids) ;
- on peut acheter un certain nombre de bottes de radis ;
- on peut valider la transaction ;
- on peut réfléchir ;
C'est parti !
2.4.1 Ininitialisation de la bibliothèque
Nous allons implémenter la fonction suivante, programme 2.
/** * marchande_init: * * Initializes the library. * * Returns: an error code, 0 on success or 1 if an error happened. */ int marchande_init ();
Pour ce faire, nous allons simplement réinitialiser les compteurs et afficher le salut de la marchande (5). Pour le message d'accueil, on utilise le programme 3.
marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be?
On pourrait le traduire par le programme 4.
marchande Copyright (C) 2019 Vivien Kraus Ce programme n'est accompagné d'ABSOLUMENT AUCUNE GARANTIE. Ce programme est libre, et vous êtes invité à le redistribuer sous certaines conditions. Voir la License Publique Générale de GNU (GNU GPL) pour plus de détails. En essayant de vous rétablir de cette attaque de texte juridique inattendue, vous levez les yeux vers la marchande. Elle a : * quelques bottes de radis ; * quelques patates. - Au suivant ! Bonjour :) Qu'est-ce que ça sera ?
int marchande_init () { n_radishes = 0; weight_potatoes = 0.0; printf (_ ("marchande Copyright (C) 2019 Vivien Kraus\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions.\nSee the GNU General Public License for details.\n\nTrying to recover from this unexpected assault of legalese, you look\nup to the merchant. She has:\n * a few bunches of radishes;\n * some potatoes.\n\n- Next! Hello :) What will it be?\n")); return 0; }
N.B. Afin de transformer le code 3 en littéral textuel C, on a besoin de le modifier légèrement. Pour ce faire, on utilise le programme 6.
(save-excursion (org-babel-goto-named-src-block ref) (let* ((text (org-babel-expand-src-block)) (text (format "%S" text)) (text (replace-regexp-in-string "\n" "\\\\n" text)) (text (replace-regexp-in-string "\t" "\\\\t" text))) text))
2.4.2 Gestion des erreurs
Il y a deux types d'erreurs à gérer :
- Les légumes demandés ne sont pas à vendre, ce qu'on règle dans le programme 7 / 13 ;
- La marchande n'a pas compris ce que l'on voulait dire. C'est une erreur de syntaxe (programme 8 / 14).
/** * marchande_value_error */ void marchande_value_error (const char *what);
/** * marchande_syntax_error */ void marchande_syntax_error ();
Lorsque ce que l'on demande n'est pas disponible, la marchande doit annoncer le programme 9, ou alors 10 en français. Lorsque la commande n'est pas comprise, on affiche le programme 11 en anglais, ou alors 12 en français.
- Sorry, I don't have %s.
- Désolé, je n'ai pas de %s.
- Huh? The merchant did not understand what you were trying to say.
- Hein ? La marchande n'a pas compris ce que vous essayiez de dire.
void marchande_value_error (const char *what) { fprintf (stderr, _ ("- Sorry, I don't have %s.\n"), what); }
void marchande_syntax_error () { fprintf (stderr, _ ("- Huh?\n\nThe merchant did not understand what you were trying to say.\n")); }
2.4.3 Achat de légumes
Si tout se passe bien, la marchande va comprendre que l'on souhaite acheter un certain nombre de bottes de radis, ou une certaine quantité de patates. Il faut donc mettre à jour notre panier.
La fonction marchande_buy_radishes
(19,
21) achète des radis, et la fonction
marchande_buy_potatoes
(20,
22) achète des patates. Le narrateur l'annonce en
anglais avec les programmes respectivement 15 et
16, et en français avec respectivement
17 et 18.
The merchant takes the radishes and put them aside for you. - And with this?
The merchant takes the potatoes and put them aside for you. - And with this?
La marchande prend les radis et vous les met de côté. - Et avec ceci ?
La marchande pèse les pommes de terre et vous les met de côté. - Et avec ceci ?
/** * marchande_buy_radishes: */ void marchande_buy_radishes (int bunches);
/** * marchande_buy_potatoes: */ void marchande_buy_potatoes (double weight);
void marchande_buy_radishes (int bunches) { n_radishes += bunches; printf (_ ("The merchant takes the radishes and put them aside for you.\n- And with this?\n")); }
void marchande_buy_potatoes (double weight) { weight_potatoes += weight; printf (_ ("The merchant takes the potatoes and put them aside for you.\n- And with this?\n")); }
2.4.4 Valider la transaction
Lorsque l'on a fait nos courses, il est temps de payer et de partir. On déclare la fonction pour quitter dans les programmes 25 et 26. Le message du narrateur est 23 et 24 en français.
You pay the merchant, take your belongings, and leave.
Vous payez la marchande, prenez vos affaires et partez.
/** * marchande_exit: */ void marchande_exit ();
void marchande_exit () { printf (_ ("You pay the merchant, take your belongings, and leave.\n")); }
2.4.5 L'invite de commande
Enfin, on doit afficher du texte pour inviter le client à s'exprimer. Il faut faire attention : si l'on est en plein milieu d'une phrase, la marchande doit simplement attendre la fin de notre phrase (avec les programmes 29 et 30). Autrement, on affiche juste un tiret, avec les programmes 27 et 28.
La fonction marchande_main_prompt
(programmes 31 et
33) retourne le tiret simple, et la fonction
marchande_secondary_prompt
(programmes 32 et
34) retourne la version étendue.
-
-
The merchant waits patiently as you try to end your sentence. -
La marchande attent patiemment que vous finissiez votre phrase. -
/** * marchande_main_prompt: */ const char *marchande_main_prompt ();
/** * marchande_secondary_prompt: */ const char *marchande_secondary_prompt ();
const char * marchande_main_prompt () { static const char *ret_c = N_("- "); return _ (ret_c); }
const char * marchande_secondary_prompt () { static const char *ret_c = N_("The merchant waits patiently as you try to end your sentence.\n- "); return _ (ret_c); }
2.4.6 Déclarations et définitions supplémentaires
Il ne vous a pas échappé que nous utilisions des variables globales,
les macros _
et N_
, et des fonctions déclarées dans d'autres
headers. Elles sont déclarées dans le programme 35.
#include <config.h> #include <stdio.h> #include <stdlib.h> #define _(String) (String) #define N_(String) (String) static int n_radishes; static double weight_potatoes;
2.4.7 Résumé du code
Maintenant que nous avons tout défini, nous pouvons tranquillement rassembler les morceaux de code et les écrire dans un seul fichier.
Le programme 36 résume le fichier d'entête. Le programme 37 résume le fichier source principal.
/* * File: src/marchande.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_INCLUDED #define H_MARCHANDE_INCLUDED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * marchande_init: * * Initializes the library. * * Returns: an error code, 0 on success or 1 if an error happened. */ int marchande_init (); /** * marchande_value_error */ void marchande_value_error (const char *what); /** * marchande_syntax_error */ void marchande_syntax_error (); /** * marchande_buy_radishes: */ void marchande_buy_radishes (int bunches); /** * marchande_buy_potatoes: */ void marchande_buy_potatoes (double weight); /** * marchande_exit: */ void marchande_exit (); /** * marchande_main_prompt: */ const char *marchande_main_prompt (); /** * marchande_secondary_prompt: */ const char *marchande_secondary_prompt (); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* not H_MARCHANDE_INCLUDED */
/* * File: src/libmarchande.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdio.h> #include <stdlib.h> #define _(String) (String) #define N_(String) (String) static int n_radishes; static double weight_potatoes; #include <marchande.h> int marchande_init () { n_radishes = 0; weight_potatoes = 0.0; printf (_ ("marchande Copyright (C) 2019 Vivien Kraus\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions.\nSee the GNU General Public License for details.\n\nTrying to recover from this unexpected assault of legalese, you look\nup to the merchant. She has:\n * a few bunches of radishes;\n * some potatoes.\n\n- Next! Hello :) What will it be?\n")); return 0; } void marchande_value_error (const char *what) { fprintf (stderr, _ ("- Sorry, I don't have %s.\n"), what); } void marchande_syntax_error () { fprintf (stderr, _ ("- Huh?\n\nThe merchant did not understand what you were trying to say.\n")); } void marchande_buy_radishes (int bunches) { n_radishes += bunches; printf (_ ("The merchant takes the radishes and put them aside for you.\n- And with this?\n")); } void marchande_buy_potatoes (double weight) { weight_potatoes += weight; printf (_ ("The merchant takes the potatoes and put them aside for you.\n- And with this?\n")); } void marchande_exit () { printf (_ ("You pay the merchant, take your belongings, and leave.\n")); } const char * marchande_main_prompt () { static const char *ret_c = N_("- "); return _ (ret_c); } const char * marchande_secondary_prompt () { static const char *ret_c = N_("The merchant waits patiently as you try to end your sentence.\n- "); return _ (ret_c); }
2.5 Un scénario écrit à l'avance
Pour tester ce code, nous allons écrire un petit scénario et vérifier que tout fonctionne comme prévu. Le programme 38 est un simple test.
/* * File: src/check.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } printf ("%s1 bunch of radishes\n", marchande_main_prompt ()); marchande_buy_radishes (1); printf ("%s1kg of tomatoes\n", marchande_main_prompt ()); fflush (stdout); marchande_value_error ("tomatoes"); fflush (stderr); printf ("%s1kg\n", marchande_main_prompt ()); printf ("%sof potatoes\n", marchande_secondary_prompt ()); marchande_buy_potatoes (1.0); printf ("%sWhat do you think of Free Software?\n", marchande_main_prompt ()); fflush (stdout); marchande_syntax_error (); fflush (stderr); printf ("%sThat will be all.\n", marchande_main_prompt ()); marchande_exit (); return EXIT_SUCCESS; }
On s'attend à la discussion du programme 39.
marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - 1 bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1kg of tomatoes - Sorry, I don't have tomatoes. - 1kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free Software? - Huh? The merchant did not understand what you were trying to say. - That will be all. You pay the merchant, take your belongings, and leave.
Pour remplacer %s
dans le texte du code 9, on
utilise le programme 40.
(save-excursion (org-babel-goto-named-src-block fmt) (let* ((text (org-babel-expand-src-block)) (text (format text arg1))) text))
On peut donc créer le test pour exécuter le programme et comparer les résultats. On obtient le programme 41.
export LANG=C EXPECTED=$( cat <<EOF marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - 1 bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1kg of tomatoes - Sorry, I don't have tomatoes. - 1kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free Software? - Huh? The merchant did not understand what you were trying to say. - That will be all. You pay the merchant, take your belongings, and leave. EOF ) ACTUAL=$(./src/check 2>&1) echo "Expected:" echo "$EXPECTED" echo "Actual:" echo "$ACTUAL" if test "x$EXPECTED" = "x$ACTUAL" then echo "OK" else >&2 echo "Failed." exit 1 fi
2.6 Un manuel d'utilisation
Comme tout bon programme, marchande
dispose d'un manuel au format
Texinfo. Pour l'instant, on va faire simple : on ne va inclure que
la section 2.2. Le programme 42 contient tout ce qu'il faut pour
faire un manuel texinfo.
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+author: Vivien Kraus #+email: vivien@planete-kraus.eu This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction
Le programme 43 convertit le manuel au format texinfo.
ORGFILE=$(mktemp XXXXXXX.org) trap "{ rm -rf $ORGFILE; }" EXIT cat > $ORGFILE <<EOF #+macro: version 0 # Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+subitile: version {{{version}}} of the program #+author: Vivien Kraus #+email: vivien@planete-kraus.eu #+options: ':t toc:t author:t email:t #+language: en #+texinfo_filename: marchande.info #+texinfo_dir_category: Games #+texinfo_dir_title: marchande: (marchande) #+texinfo_dir_desc: Marchande #+texinfo_printed_title: Marchande #+texinfo: @documentencoding UTF-8 This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction #+include: "./index.org::*Le jeu de la marchande, en anglais (désolé si c'est mal traduit)" :only-contents t EOF LANG=C emacs --batch \ --file $ORGFILE \ --eval "(require 'ox-texinfo)" \ -f org-texinfo-export-to-texinfo \ || exit 1 cat "$(basename $ORGFILE .org).texi"
On obtient donc le manuel au format texinfo dans le programme 44.
\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename marchande.info @settitle Play the merchant @documentencoding UTF-8 @documentlanguage en @c %**end of header @copying This manual is for Marchande (version 0), an example about how to make a command-line interface. Copyright @copyright{} 2019 Vivien Kraus @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. @end quotation @end copying @dircategory Games @direntry * marchande: (marchande). Marchande. @end direntry @finalout @titlepage @title Marchande @author Vivien Kraus (@email{vivien@@planete-kraus.eu}) @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top @top Play the merchant @documentencoding UTF-8 This manual is for marchande version 0. @end ifnottex @menu * Introduction:: @end menu @node Introduction @chapter Introduction You find yourself facing the organic vegetable seller. In front of her, on her stall, you see a crate containing @strong{potatoes} and @strong{bunches of radishes}. The seller thanks the previous customer and turns to you. @quotation @itemize @item Next! What will it be? @end itemize @end quotation You need to buy a few radishes and potatoes. You're going to have to be able to buy it from the merchant@dots{} @bye
2.7 Fichiers annexes
Pour exécuter notre code, il nous manque encore quelques fichiers à écrire.
La plus grosse partie du travail consiste à mettre en place un système de compilation. C'est une partie chargée d'histoire et assez délicate, mais fort heureusement les autotools sont là pour nous.
Le système de compilation se divise en deux parties : en premier lieu, on sonde le système pour trouver comment compiler un programme. En second lieu, on applique ce que l'on a trouvé et on s'en sert pour construire le programme. Cette partie n'étant pas très intéressante, on va se contenter de fournir les fichiers sans trop s'y attarder.
On obtient donc les programmes 45 et 46.
dnl Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> dnl dnl This program is free software: you can redistribute it and/or dnl modify it under the terms of the GNU General Public License as dnl published by the Free Software Foundation, either version 3 of the dnl License, or (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see dnl <http://www.gnu.org/licenses/>. AC_PREREQ([2.69]) AC_INIT([marchande], [0.0], [vivien@planete-kraus.eu]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([m4]) AC_PROG_CC AM_INIT_AUTOMAKE([foreign subdir-objects]) LT_INIT AC_CONFIG_FILES([Makefile]) AC_OUTPUT
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. dist_noinst_SCRIPTS = src/run-test noinst_LTLIBRARIES = src/libmarchande.la include_HEADERS = src/marchande.h info_TEXINFOS = doc/marchande.texi check_PROGRAMS = src/check src_check_LDADD = src/libmarchande.la AM_CPPFLAGS = -I $(srcdir)/src -I . TESTS = src/run-test
2.8 Compilation et test
Maintenant que nous avons tout ce qu'il nous faut, il ne nous reste plus qu'à compiler le projet. Le code source complet est disponible ici.
cd v0 autoreconf -vif 2>&1 ./configure 2>&1 make V=0 -j 16 distcheck 2>&1 echo "Built"
autoreconf: Entering directory `.' autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal --force aclocal: warning: couldn't open directory 'm4': No such file or directory autoreconf: configure.ac: tracing autoreconf: running: libtoolize --copy --force libtoolize: putting auxiliary files in '.'. libtoolize: copying file './ltmain.sh' libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'. libtoolize: copying file 'm4/libtool.m4' libtoolize: copying file 'm4/ltoptions.m4' libtoolize: copying file 'm4/ltsugar.m4' libtoolize: copying file 'm4/ltversion.m4' libtoolize: copying file 'm4/lt~obsolete.m4' libtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am. autoreconf: running: /usr/bin/autoconf --force autoreconf: running: /usr/bin/autoheader --force autoreconf: running: automake --add-missing --copy --force-missing configure.ac:20: installing './compile' configure.ac:22: installing './config.guess' configure.ac:22: installing './config.sub' configure.ac:21: installing './install-sh' configure.ac:21: installing './missing' Makefile.am: installing './depcomp' Makefile.am:20: installing './texinfo.tex' parallel-tests: installing './test-driver' autoreconf: Leaving directory `.' checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make dist-gzip am__post_remove_distdir='@:' make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » make distdir-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » if test -d "marchande-0.0"; then find "marchande-0.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-0.0" || { sleep 5 && rm -rf "marchande-0.0"; }; else :; fi test -d "marchande-0.0" || mkdir "marchande-0.0" make \ top_distdir="marchande-0.0" distdir="marchande-0.0" \ dist-info make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » MAKEINFO doc/marchande.info make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » test -n "" \ || find "marchande-0.0" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-0.0" make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » tardir=marchande-0.0 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-0.0.tar.gz make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » if test -d "marchande-0.0"; then find "marchande-0.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-0.0" || { sleep 5 && rm -rf "marchande-0.0"; }; else :; fi case 'marchande-0.0.tar.gz' in \ *.tar.gz*) \ eval GZIP= gzip --best -dc marchande-0.0.tar.gz | ${TAR-tar} xf - ;;\ *.tar.bz2*) \ bzip2 -dc marchande-0.0.tar.bz2 | ${TAR-tar} xf - ;;\ *.tar.lz*) \ lzip -dc marchande-0.0.tar.lz | ${TAR-tar} xf - ;;\ *.tar.xz*) \ xz -dc marchande-0.0.tar.xz | ${TAR-tar} xf - ;;\ *.tar.Z*) \ uncompress -c marchande-0.0.tar.Z | ${TAR-tar} xf - ;;\ *.shar.gz*) \ eval GZIP= gzip --best -dc marchande-0.0.shar.gz | unshar ;;\ *.zip*) \ unzip marchande-0.0.zip ;;\ esac chmod -R a-w marchande-0.0 chmod u+w marchande-0.0 mkdir marchande-0.0/_build marchande-0.0/_build/sub marchande-0.0/_inst chmod a-w marchande-0.0 test -d marchande-0.0/_build || exit 0; \ dc_install_base=`CDPATH="${ZSH_VERSION+.}:" && cd marchande-0.0/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="${TMPDIR-/tmp}/am-dc-$$/" \ && am__cwd=`pwd` \ && CDPATH="${ZSH_VERSION+.}:" && cd marchande-0.0/_build/sub \ && ../../configure \ \ \ --srcdir=../.. --prefix="$dc_install_base" \ && make \ && make dvi \ && make check \ && make install \ && make installcheck \ && make uninstall \ && make distuninstallcheck_dir="$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$dc_destdir") \ && make DESTDIR="$dc_destdir" install \ && make DESTDIR="$dc_destdir" uninstall \ && make DESTDIR="$dc_destdir" \ distuninstallcheck_dir="$dc_destdir" distuninstallcheck; \ } || { rm -rf "$dc_destdir"; exit 1; }) \ && rm -rf "$dc_destdir" \ && make dist \ && rm -rf marchande-0.0.tar.gz \ && make distcleancheck \ && cd "$am__cwd" \ || exit 1 checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make all-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » CC src/libmarchande.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » TEXI2DVI doc/marchande.dvi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make src/check make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » CC src/check.o CCLD src/check make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make check-TESTS make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » PASS: src/run-test ============================================================================ Testsuite summary for marchande 0.0 ============================================================================ # TOTAL: 1 # PASS: 1 # SKIP: 0 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 ============================================================================ make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[2]: rien à faire pour « install-exec-am ». /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/include' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/include' /usr/bin/install -c -m 644 ../../doc/marchande.info '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info/marchande.info' make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1]: rien à faire pour « installcheck ». make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/doc/marchande/marchande.dvi' rm -rf '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/doc/marchande/marchande.html' ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/include' && rm -f marchande.h ) rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/doc/marchande/marchande.pdf' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/doc/marchande/marchande.ps' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' --remove '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info/marchande.info' cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[2]: rien à faire pour « install-exec-am ». /bin/mkdir -p '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/include' /bin/mkdir -p '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/include' /usr/bin/install -c -m 644 ../../doc/marchande.info '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' install-info --info-dir='/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info/marchande.info' make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » rm -f '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/doc/marchande/marchande.dvi' rm -rf '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/doc/marchande/marchande.html' ( cd '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/include' && rm -f marchande.h ) rm -f '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/doc/marchande/marchande.pdf' rm -f '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/doc/marchande/marchande.ps' install-info --info-dir='/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' --remove '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info/marchande.info' cd '/tmp/am-dc-13237//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make dist-gzip am__post_remove_distdir='@:' make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make distdir-am make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » if test -d "marchande-0.0"; then find "marchande-0.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-0.0" || { sleep 5 && rm -rf "marchande-0.0"; }; else :; fi test -d "marchande-0.0" || mkdir "marchande-0.0" make \ top_distdir="marchande-0.0" distdir="marchande-0.0" \ dist-info make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » test -n "" \ || find "marchande-0.0" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-0.0" make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » tardir=marchande-0.0 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-0.0.tar.gz make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » if test -d "marchande-0.0"; then find "marchande-0.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-0.0" || { sleep 5 && rm -rf "marchande-0.0"; }; else :; fi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » test -z "doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html" \ || rm -rf doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html rm -rf .libs _libs test -z "src/libmarchande.la" || rm -f src/libmarchande.la rm -rf doc/marchande.t2d doc/marchande.t2p rm -f *.o test -z "src/run-test.log" || rm -f src/run-test.log rm -f *.lo rm -f src/check rm -rf src/.libs src/_libs rm -f *.tab.c rm -f src/*.o test -z "src/run-test.trs" || rm -f src/run-test.trs test -z "" || rm -f rm -f config.h stamp-h1 rm -f libtool config.lt rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags test . = "../.." || test -z "" || rm -f rm -f src/*.lo test -z "test-suite.log" || rm -f test-suite.log rm -f doc/.dirstamp rm -f cscope.out cscope.in.out cscope.po.out cscope.files rm -f src/so_locations rm -f src/.deps/.dirstamp rm -f src/.dirstamp rm -f config.status config.cache config.log configure.lineno config.status.lineno rm -f src/.deps/check.Po rm -f src/.deps/libmarchande.Plo rm -f Makefile make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0/marchande-0.0/_build/sub » if test -d "marchande-0.0"; then find "marchande-0.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-0.0" || { sleep 5 && rm -rf "marchande-0.0"; }; else :; fi =============================================== marchande-0.0 archives ready for distribution: marchande-0.0.tar.gz =============================================== Built
Si on lance le programme à la main, on obtient :
cd v0
make -j 16 check
./src/check
depbase=`echo src/libmarchande.lo | sed 's|[^/]*$|.deps/&|;s|\.lo$||'`;\ /bin/bash ./libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I ./src -I . -g -O2 -MT src/libmarchande.lo -MD -MP -MF $depbase.Tpo -c -o src/libmarchande.lo src/libmarchande.c &&\ mv -f $depbase.Tpo $depbase.Plo libtool: compile: gcc -DHAVE_CONFIG_H -I. -I ./src -I . -g -O2 -MT src/libmarchande.lo -MD -MP -MF src/.deps/libmarchande.Tpo -c src/libmarchande.c -fPIC -DPIC -o src/.libs/libmarchande.o libtool: compile: gcc -DHAVE_CONFIG_H -I. -I ./src -I . -g -O2 -MT src/libmarchande.lo -MD -MP -MF src/.deps/libmarchande.Tpo -c src/libmarchande.c -o src/libmarchande.o >/dev/null 2>&1 /bin/bash ./libtool --tag=CC --mode=link gcc -g -O2 -o src/libmarchande.la src/libmarchande.lo libtool: link: ar cru src/.libs/libmarchande.a src/.libs/libmarchande.o libtool: link: ranlib src/.libs/libmarchande.a libtool: link: ( cd "src/.libs" && rm -f "libmarchande.la" && ln -s "../libmarchande.la" "libmarchande.la" ) make src/check make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » depbase=`echo src/check.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\ gcc -DHAVE_CONFIG_H -I. -I ./src -I . -g -O2 -MT src/check.o -MD -MP -MF $depbase.Tpo -c -o src/check.o src/check.c &&\ mv -f $depbase.Tpo $depbase.Po /bin/bash ./libtool --tag=CC --mode=link gcc -g -O2 -o src/check src/check.o src/libmarchande.la libtool: link: gcc -g -O2 -o src/check src/check.o src/.libs/libmarchande.a make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » make check-TESTS make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » PASS: src/run-test ============================================================================ Testsuite summary for marchande 0.0 ============================================================================ # TOTAL: 1 # PASS: 1 # SKIP: 0 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 ============================================================================ make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v0 » marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - 1 bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1kg of tomatoes - 1kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free Software? - That will be all. You pay the merchant, take your belongings, and leave.
3 Définition de la grammaire, et introduction de Lex et Yacc
La syntaxe du programme est simple : on demande soit à quitter, soit une commande composée d'une quantité (poids pour les patates, nombre pour les radis) et la marchandise. Pour l'instant, on ne se concentre que sur la grammaire anglaise.
Pour cela, il nous faut un vocabulaire contenant :
- de quoi définir le message de sortie, that will be all ;
- de quoi définir un nombre entier ;
- de quoi définir un poids ;
- les unités ;
- les marchandises.
Il faut aussi penser à ignorer tous les espaces. Ça n'est pas important pour l'instant, mais lorsqu'on voudra faire la complétion contextuelle il faudra toujours fonctionner avec des mots. On va donc éviter de faire un gros agrégat pour that will be all en une seule fois, et à la place on fera 4 mots différents, that, will, be et all.
3.1 La grammaire
Les mots que l'on reconnaît sont d'abord transformés en identifiant entiers. Par exemple, le mot "That" dans l'expression "That will be all" a son propre numéro. Ensuite, on peut définir des constructions à plus haut niveau. Par exemple, un nombre suivi d'une unité de poids désigne tout simplement un poids. On peut ainsi agréger des concepts jusqu'au plus haut niveau : on entre une série de commandes.
Le programme 47 liste les mots-clés.
%token THAT %token WILL %token BE %token ALL %token A %token KG %token BUNCH %token BUNCHES %token OF %token POTATOES %token RADISHES %token END_OF_PHRASE
Il faut savoir qu'un mot peut avoir une valeur sémantique. Par exemple, un entier porte sa valeur. Quand on définit le mot, on spécifie aussi son type. C'est pourquoi on doit aussi prendre en compte le programme 48.
%token <int> INTEGER %token <double> DECIMAL %token <char *> UNKNOWN_WORD
Étant donné que l'on utilise des types différents, il faut dire à
bison d'adapter son code pour briser la compatibilité avec
l'antédiluvien yacc
. C'est l'objet du programme
49.
%define api.value.type union
Une dernière chose pour laquelle il faut faire très attention, c'est la gestion de mémoire. En effet, si l'on croise un mot inconnu, il faut le copier en mémoire. Mais qui va se charger de libérer la mémoire, et quand ? Si le mot fait partie d'une règle, on y aura accès en dernier et donc on pourra le libérer tranquillement. Mais s'il est agrégé dans un gros bloc d'erreur, on ne pourra plus jamais y toucher et c'est à bison de libérer la mémoire. Il faut donc définir un destructeur. C'est ce que fait le code 50.
%destructor { free ($$); } UNKNOWN_WORD
Une fois les mots de plus bas niveau défini, il faut s'intéresser aux valeurs sémantiques des règles elles-mêmes. Par exemple, il faut s'assurer qu'un poids a bien une valeur réelle. Comme un poids n'est pas un mot-clé du plus bas niveau, la syntaxe change légèrement. On obtient le programme 51.
%type <int> bunches %type <double> weight
Si on résume le tout, on obtient le programme 52.
%define api.value.type union %token THAT %token WILL %token BE %token ALL %token A %token KG %token BUNCH %token BUNCHES %token OF %token POTATOES %token RADISHES %token END_OF_PHRASE %token <int> INTEGER %token <double> DECIMAL %token <char *> UNKNOWN_WORD %destructor { free ($$); } UNKNOWN_WORD %type <int> bunches %type <double> weight
Il ne reste plus qu'à aligner ces mots dans le bon ordre. Chaque ligne est définie de la façon suivante : le nom de la règle, deux-points, et un ensemble de couples règle / production, et enfin un point-virgule.
Comme un exemple vaut mieux qu'un long discours, le programme
53 définit la règle de plus haut niveau, le
programme 54 définit la règle de grammaire pour
une commande, et le programme 55 définit les
règles de bas niveau pour le poids et les bottes. On note que $1
désigne la valeur du premier mot du motif, et $$
désigne la valeur
de l'expression totale.
interaction: %empty | interaction command | interaction error END_OF_PHRASE { prompt_type = 1; marchande_syntax_error (); yyerrok; } ;
command: THAT WILL BE ALL { command (_ ("that will be all")); YYACCEPT; } | weight OF POTATOES { marchande_buy_potatoes ($1); command (_ ("%f kg of potatoes"), $1); } | bunches OF RADISHES { marchande_buy_radishes ($1); command (_ ("%d bunches of radishes"), $1); } | weight OF UNKNOWN_WORD { marchande_value_error ($3); command (_ ("%f kg of %s"), $1, $3); free ($3); } | bunches OF UNKNOWN_WORD { marchande_value_error ($3); command (_ ("%d bunches of %s"), $1, $3); free ($3); } ;
weight: DECIMAL KG { $$ = $1; } | INTEGER KG { $$ = (double) $1; } ; bunches: A BUNCH { $$ = 1; } | INTEGER BUNCHES { $$ = $1; } ;
À chaque commande, on la note quelque part. Pour l'instant, on n'en a
rien à faire, donc on utilise le programme 56.
Notons que la variable prompt_type
sert à savoir quel message
d'invitation afficher. Si la valeur est 1, alors on doit afficher le
message principal. Sinon, on doit afficher le message secondaire.
int prompt_type; void command (const char *format, ...) { (void) format; prompt_type = 1; }
3.2 Les expressions régulières
Pour détecter les mots un par un, on utilise des expressions régulières. Le format est assez similaire : à chaque expression régulière, on associe un mot-clé. Cependant, on doit aussi récupérer la valeur des nombres. On obtient le programme 57.
that { return THAT; } will { return WILL; } be { return BE; } all { return ALL; } [0-9]+ { yylval.INTEGER = (unsigned int) strtoul (yytext, NULL, 10); return INTEGER; } [0-9]+\.[0-9]* { yylval.DECIMAL = strtod (yytext, NULL); return DECIMAL; } of { return OF; } kg { return KG; } a { return A; } bunch { return BUNCH; } bunches { return BUNCHES; } potatoes { return POTATOES; } radishes { return RADISHES; } [ \t\n]+ /* do nothing */ [^ \t\n.,?!0-9]+ { yylval.UNKNOWN_WORD = strdup (yytext); return UNKNOWN_WORD; } [.,?!] { return END_OF_PHRASE; }
Il y a simplement un petit problème : lorsqu'on a lu une ligne, il
faut afficher un message d'invitation à entrer du texte. La variable
prompt_type
indique s'il faut afficher le message principal (1) ou
le message secondaire (2). Comme l'analyseur lexical n'affiche rien
en règle générale, il faut modifier son code. Pour cela, on utilise
le programme 58.
int prompt_type = 1; int get_input (char *buf, int max_size) { int c; static int need_prompt = 1; (void) max_size; if (need_prompt) { if (prompt_type == 1) { printf ("%s", marchande_main_prompt ()); } else { printf ("%s", marchande_secondary_prompt ()); } need_prompt = 0; } c = getchar (); if (c == '\n') { need_prompt = 1; } if (c == EOF) { return YY_NULL; } buf[0] = c; return 1; }
3.3 Description de la syntaxe, en anglais
When you run the marchande
program, you have a command-line
interface. There are several options:
- say
that will be all
, and the program exits; - say
a bunch of radishes
, or2 bunches of radishes
, or another number, to add some radishes; - say
1.3kg of potatoes
, to add some potatoes.
3.4 Ajout de code
Pour pouvoir utiliser cette superbe grammaire, nous avons besoin de plusieurs fichiers supplémentaires.
Tout d'abord, nous devons adapter le code existant.
Le code source de la bibliothèque, programmes 59 et 60, ne change pas. Du coup, le test 61 et le pilote 62 non plus.
/* * File: src/marchande.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_INCLUDED #define H_MARCHANDE_INCLUDED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * marchande_init: * * Initializes the library. * * Returns: an error code, 0 on success or 1 if an error happened. */ int marchande_init (); /** * marchande_value_error */ void marchande_value_error (const char *what); /** * marchande_syntax_error */ void marchande_syntax_error (); /** * marchande_buy_radishes: */ void marchande_buy_radishes (int bunches); /** * marchande_buy_potatoes: */ void marchande_buy_potatoes (double weight); /** * marchande_exit: */ void marchande_exit (); /** * marchande_main_prompt: */ const char *marchande_main_prompt (); /** * marchande_secondary_prompt: */ const char *marchande_secondary_prompt (); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* not H_MARCHANDE_INCLUDED */
/* * File: src/libmarchande.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdio.h> #include <stdlib.h> #define _(String) (String) #define N_(String) (String) static int n_radishes; static double weight_potatoes; #include <marchande.h> int marchande_init () { n_radishes = 0; weight_potatoes = 0.0; printf (_ ("marchande Copyright (C) 2019 Vivien Kraus\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions.\nSee the GNU General Public License for details.\n\nTrying to recover from this unexpected assault of legalese, you look\nup to the merchant. She has:\n * a few bunches of radishes;\n * some potatoes.\n\n- Next! Hello :) What will it be?\n")); return 0; } void marchande_value_error (const char *what) { fprintf (stderr, _ ("- Sorry, I don't have %s.\n"), what); } void marchande_syntax_error () { fprintf (stderr, _ ("- Huh?\n\nThe merchant did not understand what you were trying to say.\n")); } void marchande_buy_radishes (int bunches) { n_radishes += bunches; printf (_ ("The merchant takes the radishes and put them aside for you.\n- And with this?\n")); } void marchande_buy_potatoes (double weight) { weight_potatoes += weight; printf (_ ("The merchant takes the potatoes and put them aside for you.\n- And with this?\n")); } void marchande_exit () { printf (_ ("You pay the merchant, take your belongings, and leave.\n")); } const char * marchande_main_prompt () { static const char *ret_c = N_("- "); return _ (ret_c); } const char * marchande_secondary_prompt () { static const char *ret_c = N_("The merchant waits patiently as you try to end your sentence.\n- "); return _ (ret_c); }
/* * File: src/check.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } printf ("%s1 bunch of radishes\n", marchande_main_prompt ()); marchande_buy_radishes (1); printf ("%s1kg of tomatoes\n", marchande_main_prompt ()); fflush (stdout); marchande_value_error ("tomatoes"); fflush (stderr); printf ("%s1kg\n", marchande_main_prompt ()); printf ("%sof potatoes\n", marchande_secondary_prompt ()); marchande_buy_potatoes (1.0); printf ("%sWhat do you think of Free Software?\n", marchande_main_prompt ()); fflush (stdout); marchande_syntax_error (); fflush (stderr); printf ("%sThat will be all.\n", marchande_main_prompt ()); marchande_exit (); return EXIT_SUCCESS; }
export LANG=C EXPECTED=$( cat <<EOF marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - 1 bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1kg of tomatoes - Sorry, I don't have tomatoes. - 1kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free Software? - Huh? The merchant did not understand what you were trying to say. - That will be all. You pay the merchant, take your belongings, and leave. EOF ) ACTUAL=$(./src/check 2>&1) echo "Expected:" echo "$EXPECTED" echo "Actual:" echo "$ACTUAL" if test "x$EXPECTED" = "x$ACTUAL" then echo "OK" else >&2 echo "Failed." exit 1 fi
En revanche, il faut adapter le manuel, en rajoutant la section 3.3. En org-mode, on a le programme 63. Grâce au programme 64, on l'exporte en texinfo, pour obtenir le programme 65.
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+author: Vivien Kraus #+email: vivien@planete-kraus.eu This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction * Invoking =marchande=
ORGFILE=$(mktemp XXXXXXX.org) trap "{ rm -rf $ORGFILE; }" EXIT cat > $ORGFILE <<EOF #+macro: version 1 # Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+subitile: version {{{version}}} of the program #+author: Vivien Kraus #+email: vivien@planete-kraus.eu #+options: ':t toc:t author:t email:t #+language: en #+texinfo_filename: marchande.info #+texinfo_dir_category: Games #+texinfo_dir_title: marchande: (marchande) #+texinfo_dir_desc: Marchande #+texinfo_printed_title: Marchande #+texinfo: @documentencoding UTF-8 This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction #+include: "./index.org::*Le jeu de la marchande, en anglais (désolé si c'est mal traduit)" :only-contents t * Invoking =marchande= #+include: "./index.org::*Description de la syntaxe, en anglais" :only-contents t EOF LANG=C emacs --batch \ --file $ORGFILE \ --eval "(require 'ox-texinfo)" \ -f org-texinfo-export-to-texinfo \ || exit 1 cat "$(basename $ORGFILE .org).texi"
\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename marchande.info @settitle Play the merchant @documentencoding UTF-8 @documentlanguage en @c %**end of header @copying This manual is for Marchande (version 1), an example about how to make a command-line interface. Copyright @copyright{} 2019 Vivien Kraus @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. @end quotation @end copying @dircategory Games @direntry * marchande: (marchande). Marchande. @end direntry @finalout @titlepage @title Marchande @author Vivien Kraus (@email{vivien@@planete-kraus.eu}) @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top @top Play the merchant @documentencoding UTF-8 This manual is for marchande version 1. @end ifnottex @menu * Introduction:: * Invoking @samp{marchande}:: @end menu @node Introduction @chapter Introduction You find yourself facing the organic vegetable seller. In front of her, on her stall, you see a crate containing @strong{potatoes} and @strong{bunches of radishes}. The seller thanks the previous customer and turns to you. @quotation @itemize @item Next! What will it be? @end itemize @end quotation You need to buy a few radishes and potatoes. You're going to have to be able to buy it from the merchant@dots{} @node Invoking @samp{marchande} @chapter Invoking @samp{marchande} When you run the @samp{marchande} program, you have a command-line interface. There are several options: @itemize @item say @samp{that will be all}, and the program exits; @item say @samp{a bunch of radishes}, or @samp{2 bunches of radishes}, or another number, to add some radishes; @item say @samp{1.3kg of potatoes}, to add some potatoes. @end itemize @bye
Pour le script de configuration et de compilation, cela change un peu.
Il faut chercher sur le sytème le programme yacc
(ou bison
) et le
programme lex
(ou flex
). On obtient donc les programmes
respectivement 66 et 68. Comme on veut
utiliser explicitement bison
et pas yacc
, puisqu'on a des valeurs
hétérogènes pour nos types, on doit ré-écrire à la main les règles
pour produire le parseur. C'est un peu complexe, parce que la règle
doit fabriquer deux fichiers en même temps. Heureusement, on peut se
fier à la FAQ Automake :
https://www.gnu.org/software/automake/manual/html_node/Multiple-Outputs.html#Multiple-Outputs,
et définir les règles nécessaires dans le programme
67.
dnl Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> dnl dnl This program is free software: you can redistribute it and/or dnl modify it under the terms of the GNU General Public License as dnl published by the Free Software Foundation, either version 3 of the dnl License, or (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see dnl <http://www.gnu.org/licenses/>. AC_PREREQ([2.69]) AC_INIT([marchande], [1.0], [vivien@planete-kraus.eu]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([m4]) AC_PROG_CC AC_PROG_LEX AM_MISSING_PROG([YACC], [bison]) AM_INIT_AUTOMAKE([foreign subdir-objects]) LT_INIT AC_CONFIG_FILES([Makefile]) AC_OUTPUT
$(srcdir)/src/parser.stamp: src/parser.y $(AM_V_GEN) (cd $(srcdir) && $(YACC) src/parser.y -o src/parser.c --defines=src/parser.h) @touch $(srcdir)/src/parser.stamp $(srcdir)/src/parser.h $(srcdir)/src/parser.c: $(srcdir)/src/parser.stamp @dry=; for f in x $$MAKEFLAGS; do \ case $$f in \ *=*|--*);; \ *n*) dry=:;; \ esac; \ done; \ if test -f $@; then :; else \ $$dry trap 'rm -rf $(srcdir)/src/parser.lock $(srcdir)/src/parser.stamp' 1 2 13 15; \ if $$dry mkdir $(srcdir)/src/parser.lock 2>/dev/null; then \ $$dry rm -f $(srcdir)/src/parser.stamp || exit 1; \ $(MAKE) $(AM_MAKEFLAGS) src/parser.stamp; \ $$dry rmdir $(srcdir)/src/parser.lock; \ else \ while test -d $(srcdir)/src/parser.lock && test -z "$$dry"; do \ sleep 1; \ done; \ $$dry test -f $(srcdir)/src/parser.stamp; exit $$?; \ fi; \ fi
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. dist_noinst_SCRIPTS = src/run-test noinst_LTLIBRARIES = src/libmarchande.la include_HEADERS = src/marchande.h info_TEXINFOS = doc/marchande.texi check_PROGRAMS = src/check src_check_LDADD = src/libmarchande.la AM_CPPFLAGS = -I $(srcdir)/src -I . TESTS = src/run-test bin_PROGRAMS = src/marchande src_marchande_SOURCES = src/parser.c src/lexer.l src_marchande_LDADD = src/libmarchande.la EXTRA_DIST = src/parser.y src/parser.h src/parser.stamp MAINTAINERCLEANFILES = src/parser src/parser.h src/parser.c src/parser.stamp BUILT_SOURCES = src/parser.h $(srcdir)/src/parser.stamp: src/parser.y $(AM_V_GEN) (cd $(srcdir) && $(YACC) src/parser.y -o src/parser.c --defines=src/parser.h) @touch $(srcdir)/src/parser.stamp $(srcdir)/src/parser.h $(srcdir)/src/parser.c: $(srcdir)/src/parser.stamp @dry=; for f in x $$MAKEFLAGS; do \ case $$f in \ *=*|--*);; \ *n*) dry=:;; \ esac; \ done; \ if test -f $@; then :; else \ $$dry trap 'rm -rf $(srcdir)/src/parser.lock $(srcdir)/src/parser.stamp' 1 2 13 15; \ if $$dry mkdir $(srcdir)/src/parser.lock 2>/dev/null; then \ $$dry rm -f $(srcdir)/src/parser.stamp || exit 1; \ $(MAKE) $(AM_MAKEFLAGS) src/parser.stamp; \ $$dry rmdir $(srcdir)/src/parser.lock; \ else \ while test -d $(srcdir)/src/parser.lock && test -z "$$dry"; do \ sleep 1; \ done; \ $$dry test -f $(srcdir)/src/parser.stamp; exit $$?; \ fi; \ fi
Les fichiers v1/src/parser.y et v1/src/lexer.l sont définis par les programmes 69 et 70.
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %{ #include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> #define _(String) String int yylex (void); void yyerror (const char *error); int main (int argc, char *argv[]); void command (const char *format, ...); int prompt_type; int yywrap () { return 1; } %} %define api.value.type union %token THAT %token WILL %token BE %token ALL %token A %token KG %token BUNCH %token BUNCHES %token OF %token POTATOES %token RADISHES %token END_OF_PHRASE %token <int> INTEGER %token <double> DECIMAL %token <char *> UNKNOWN_WORD %destructor { free ($$); } UNKNOWN_WORD %type <int> bunches %type <double> weight %% interaction: %empty | interaction command | interaction error END_OF_PHRASE { prompt_type = 1; marchande_syntax_error (); yyerrok; } ; command: THAT WILL BE ALL { command (_ ("that will be all")); YYACCEPT; } | weight OF POTATOES { marchande_buy_potatoes ($1); command (_ ("%f kg of potatoes"), $1); } | bunches OF RADISHES { marchande_buy_radishes ($1); command (_ ("%d bunches of radishes"), $1); } | weight OF UNKNOWN_WORD { marchande_value_error ($3); command (_ ("%f kg of %s"), $1, $3); free ($3); } | bunches OF UNKNOWN_WORD { marchande_value_error ($3); command (_ ("%d bunches of %s"), $1, $3); free ($3); } ; weight: DECIMAL KG { $$ = $1; } | INTEGER KG { $$ = (double) $1; } ; bunches: A BUNCH { $$ = 1; } | INTEGER BUNCHES { $$ = $1; } ; %% int prompt_type; void yyerror (const char *error) { (void) error; } int main (int argc, char *argv[]) { (void) argc; (void) argv; if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } if (yyparse () == 0) { marchande_exit (); return EXIT_SUCCESS; } return EXIT_FAILURE; } int prompt_type; void command (const char *format, ...) { (void) format; prompt_type = 1; }
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %{ #include <config.h> #include <string.h> #include <marchande.h> #include "parser.h" #define YY_INPUT(buf, result, max_size) { result = get_input (buf, max_size); } #define YY_USER_ACTION { prompt_type = 2; } int prompt_type = 1; int get_input (char *buf, int max_size) { int c; static int need_prompt = 1; (void) max_size; if (need_prompt) { if (prompt_type == 1) { printf ("%s", marchande_main_prompt ()); } else { printf ("%s", marchande_secondary_prompt ()); } need_prompt = 0; } c = getchar (); if (c == '\n') { need_prompt = 1; } if (c == EOF) { return YY_NULL; } buf[0] = c; return 1; } %} %% that { return THAT; } will { return WILL; } be { return BE; } all { return ALL; } [0-9]+ { yylval.INTEGER = (unsigned int) strtoul (yytext, NULL, 10); return INTEGER; } [0-9]+\.[0-9]* { yylval.DECIMAL = strtod (yytext, NULL); return DECIMAL; } of { return OF; } kg { return KG; } a { return A; } bunch { return BUNCH; } bunches { return BUNCHES; } potatoes { return POTATOES; } radishes { return RADISHES; } [ \t\n]+ /* do nothing */ [^ \t\n.,?!0-9]+ { yylval.UNKNOWN_WORD = strdup (yytext); return UNKNOWN_WORD; } [.,?!] { return END_OF_PHRASE; }
Notons que l'on a rajouté deux fonctions : la fonction yyerror
, à
appeler en cas d'erreur, et la fonction main
, pour démarrer le
programme. Ces deux fonctions sont définies respectivement dans les
programmes 71 et 72.
int prompt_type; void yyerror (const char *error) { (void) error; }
int main (int argc, char *argv[]) { (void) argc; (void) argv; if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } if (yyparse () == 0) { marchande_exit (); return EXIT_SUCCESS; } return EXIT_FAILURE; }
3.5 Compilation et prise en main
Après la compilation, on pourra compiler le code source plus simplement à partir de la distribution source. Mais pour l'instant, on doit suivre toute la procédure.
cd v1 autoreconf -vif 2>&1 ./configure 2>&1 make V=0 -j 16 all 2>&1 make V=0 -j 16 distcheck 2>&1 echo "Built"
autoreconf: Entering directory `.' autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal --force aclocal: warning: couldn't open directory 'm4': No such file or directory autoreconf: configure.ac: tracing autoreconf: running: libtoolize --copy --force libtoolize: putting auxiliary files in '.'. libtoolize: copying file './ltmain.sh' libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'. libtoolize: copying file 'm4/libtool.m4' libtoolize: copying file 'm4/ltoptions.m4' libtoolize: copying file 'm4/ltsugar.m4' libtoolize: copying file 'm4/ltversion.m4' libtoolize: copying file 'm4/lt~obsolete.m4' libtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am. autoreconf: running: /usr/bin/autoconf --force autoreconf: running: /usr/bin/autoheader --force autoreconf: running: automake --add-missing --copy --force-missing configure.ac:20: installing './compile' configure.ac:24: installing './config.guess' configure.ac:24: installing './config.sub' configure.ac:23: installing './install-sh' configure.ac:22: installing './missing' Makefile.am: installing './depcomp' configure.ac: installing './ylwrap' Makefile.am:20: installing './texinfo.tex' parallel-tests: installing './test-driver' autoreconf: Leaving directory `.' checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for flex... flex checking lex output file root... lex.yy checking lex library... -lfl checking whether yytext is a pointer... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands GEN src/parser.stamp make all-am make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1 » MAKEINFO doc/marchande.info LEX src/lexer.c CC src/parser.o CC src/libmarchande.lo CC src/lexer.o CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1 » make dist-gzip am__post_remove_distdir='@:' make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1 » make distdir-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1 » if test -d "marchande-1.0"; then find "marchande-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.0" || { sleep 5 && rm -rf "marchande-1.0"; }; else :; fi test -d "marchande-1.0" || mkdir "marchande-1.0" make \ top_distdir="marchande-1.0" distdir="marchande-1.0" \ dist-info make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1 » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1 » test -n "" \ || find "marchande-1.0" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-1.0" make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1 » tardir=marchande-1.0 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-1.0.tar.gz make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1 » if test -d "marchande-1.0"; then find "marchande-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.0" || { sleep 5 && rm -rf "marchande-1.0"; }; else :; fi case 'marchande-1.0.tar.gz' in \ *.tar.gz*) \ eval GZIP= gzip --best -dc marchande-1.0.tar.gz | ${TAR-tar} xf - ;;\ *.tar.bz2*) \ bzip2 -dc marchande-1.0.tar.bz2 | ${TAR-tar} xf - ;;\ *.tar.lz*) \ lzip -dc marchande-1.0.tar.lz | ${TAR-tar} xf - ;;\ *.tar.xz*) \ xz -dc marchande-1.0.tar.xz | ${TAR-tar} xf - ;;\ *.tar.Z*) \ uncompress -c marchande-1.0.tar.Z | ${TAR-tar} xf - ;;\ *.shar.gz*) \ eval GZIP= gzip --best -dc marchande-1.0.shar.gz | unshar ;;\ *.zip*) \ unzip marchande-1.0.zip ;;\ esac chmod -R a-w marchande-1.0 chmod u+w marchande-1.0 mkdir marchande-1.0/_build marchande-1.0/_build/sub marchande-1.0/_inst chmod a-w marchande-1.0 test -d marchande-1.0/_build || exit 0; \ dc_install_base=`CDPATH="${ZSH_VERSION+.}:" && cd marchande-1.0/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="${TMPDIR-/tmp}/am-dc-$$/" \ && am__cwd=`pwd` \ && CDPATH="${ZSH_VERSION+.}:" && cd marchande-1.0/_build/sub \ && ../../configure \ \ \ --srcdir=../.. --prefix="$dc_install_base" \ && make \ && make dvi \ && make check \ && make install \ && make installcheck \ && make uninstall \ && make distuninstallcheck_dir="$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$dc_destdir") \ && make DESTDIR="$dc_destdir" install \ && make DESTDIR="$dc_destdir" uninstall \ && make DESTDIR="$dc_destdir" \ distuninstallcheck_dir="$dc_destdir" distuninstallcheck; \ } || { rm -rf "$dc_destdir"; exit 1; }) \ && rm -rf "$dc_destdir" \ && make dist \ && rm -rf marchande-1.0.tar.gz \ && make distcleancheck \ && cd "$am__cwd" \ || exit 1 checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for flex... flex checking lex output file root... lex.yy checking lex library... -lfl checking whether yytext is a pointer... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make all-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » CC src/parser.o CC src/lexer.o CC src/libmarchande.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » TEXI2DVI doc/marchande.dvi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make check-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make src/check make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » CC src/check.o CCLD src/check make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make check-TESTS make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » PASS: src/run-test ============================================================================ Testsuite summary for marchande 1.0 ============================================================================ # TOTAL: 1 # PASS: 1 # SKIP: 0 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 ============================================================================ make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make install-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/include' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/bin' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/bin/marchande make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1]: rien à faire pour « installcheck ». make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/doc/marchande/marchande.dvi' ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/bin' && rm -f marchande ) rm -rf '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/doc/marchande/marchande.html' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/doc/marchande/marchande.ps' ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/include' && rm -f marchande.h ) rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/doc/marchande/marchande.pdf' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' --remove '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info/marchande.info' cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make install-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » /bin/mkdir -p '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/include' /bin/mkdir -p '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/bin' /bin/mkdir -p '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' install-info --info-dir='/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/bin/marchande make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » rm -f '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/doc/marchande/marchande.dvi' ( cd '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/bin' && rm -f marchande ) rm -rf '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/doc/marchande/marchande.html' ( cd '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/include' && rm -f marchande.h ) rm -f '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/doc/marchande/marchande.pdf' rm -f '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/doc/marchande/marchande.ps' install-info --info-dir='/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' --remove '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info/marchande.info' cd '/tmp/am-dc-18456//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make dist-gzip am__post_remove_distdir='@:' make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make distdir-am make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » if test -d "marchande-1.0"; then find "marchande-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.0" || { sleep 5 && rm -rf "marchande-1.0"; }; else :; fi test -d "marchande-1.0" || mkdir "marchande-1.0" make \ top_distdir="marchande-1.0" distdir="marchande-1.0" \ dist-info make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » test -n "" \ || find "marchande-1.0" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-1.0" make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » tardir=marchande-1.0 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-1.0.tar.gz make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » if test -d "marchande-1.0"; then find "marchande-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.0" || { sleep 5 && rm -rf "marchande-1.0"; }; else :; fi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » test -z "doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html" \ || rm -rf doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html rm -rf .libs _libs test -z "src/libmarchande.la" || rm -f src/libmarchande.la rm -rf doc/marchande.t2d doc/marchande.t2p rm -f *.o rm -f src/marchande rm -f src/check test -z "src/run-test.log" || rm -f src/run-test.log rm -f *.lo rm -f *.tab.c rm -rf src/.libs src/_libs test -z "" || rm -f rm -f src/*.o rm -f config.h stamp-h1 test -z "src/run-test.trs" || rm -f src/run-test.trs test . = "../.." || test -z "" || rm -f rm -f libtool config.lt rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags rm -f src/*.lo rm -f src/so_locations rm -f doc/.dirstamp test -z "test-suite.log" || rm -f test-suite.log rm -f cscope.out cscope.in.out cscope.po.out cscope.files rm -f src/.deps/.dirstamp rm -f src/.dirstamp rm -f config.status config.cache config.log configure.lineno config.status.lineno rm -f src/.deps/check.Po rm -f src/.deps/lexer.Po rm -f src/.deps/libmarchande.Plo rm -f src/.deps/parser.Po rm -f Makefile make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1/marchande-1.0/_build/sub » if test -d "marchande-1.0"; then find "marchande-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.0" || { sleep 5 && rm -rf "marchande-1.0"; }; else :; fi =============================================== marchande-1.0 archives ready for distribution: marchande-1.0.tar.gz =============================================== Built
Et maintenant, le test ! Essayez par vous-mêmes :)
cp v1/marchande-1.0.tar.gz /tmp cd /tmp tar xf marchande-1.0.tar.gz mkdir -p build cd build ../marchande-1.0/configure --prefix=/tmp/v1 2>&1 make V=0 -j 2>&1 make V=0 -j install 2>&1 /tmp/v1/bin/marchande 2>&1 <<EOF a bunch of radishes 1 kg of tomatoes 1.3 kg of potatoes What do you think of Free software? that will be all EOF
checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for flex... flex checking lex output file root... lex.yy checking lex library... -lfl checking whether yytext is a pointer... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make all-am make[1] : on entre dans le répertoire « /tmp/build » CC src/parser.o CC src/lexer.o CC src/libmarchande.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande make[1] : on quitte le répertoire « /tmp/build » make install-am make[1] : on entre dans le répertoire « /tmp/build » make[2] : on entre dans le répertoire « /tmp/build » /bin/mkdir -p '/tmp/v1/include' /bin/mkdir -p '/tmp/v1/bin' /bin/mkdir -p '/tmp/v1/share/info' /usr/bin/install -c -m 644 ../marchande-1.0/src/marchande.h '/tmp/v1/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande '/tmp/v1/bin' /usr/bin/install -c -m 644 ../marchande-1.0/doc/marchande.info '/tmp/v1/share/info' install-info --info-dir='/tmp/v1/share/info' '/tmp/v1/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/v1/bin/marchande make[2] : on quitte le répertoire « /tmp/build » make[1] : on quitte le répertoire « /tmp/build » - Sorry, I don't have tomatoes. - Huh? The merchant did not understand what you were trying to say. marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - The merchant takes the radishes and put them aside for you. - And with this? - - The merchant waits patiently as you try to end your sentence. - The merchant takes the potatoes and put them aside for you. - And with this? - - You pay the merchant, take your belongings, and leave.
Bon, là pour l'instrumentalisation, ça n'est pas génial : les flux de sortie et d'erreur ne sont pas synchronisés, donc on peut avoir tout l'un avant que l'autre n'ait commencé à être écrit, et on ne voit pas ce que l'on tape.
Heureusement, on va pouvoir faire mieux avec readline.
4 Ré-usinage du code
4.1 Réutilisation du parseur existant
Nous avons déjà un parseur qui fonctionne. Il nous permet déjà de parser des poids, par exemple. On ne veut pas s'en séparer. Pour pouvoir réutiliser les règles d'analyse lexicale et les règles de grammaire, il y a une astuce toute simple : définir le mode dans lequel le parseur opère, comme expliqué dans la FAQ de bison.
Concrètement, on introduit un nouveau mot-clé, MODE_COMPLETE
, qui sera
segmenté artificiellement avant d'analyser le texte. Ensuite, les
règles de complétion auront la forme :
output: MODE_COMPLETE input
Pour introduire artificiellement le mot-clé MODE_COMPLETE
, il suffit
de modifier l'analyseur lexical pour qu'il le retourne (une seule
fois) avant de commencer.
Le deuxième problème, c'est que l'on doit introduire un mot-clé
nouveau entre le texte avant et le texte après, COMPLETE
. Ce
problème est plus difficile, et il faut procéder en deux temps :
- Si l'on cherche un caractère après le texte avant, il faut passer au texte après ;
- Si la longeur analysée totale dépasse la longueur de la première
chaîne, il faut introduire
COMPLETE
.
Ces deux points sont indépendants : l'analyseur peut prendre de l'avance avant de segmenter certains mots. Par exemple, s'il est en train de segmenter un chiffre, il aura besoin de voir le prochain caractère avant de se décider, puisque si c'est un chiffre il doit continuer d'attendre.
Ceci dit, nous allons devoir appeler le parseur dans plusieurs contextes différents. Dans ce genre de circonstances, il est bien vu d'écrire du code réentrant et réutilisable. C'est ce que nous allons commencer par écrire.
4.2 Une couche d'abstraction
De quel comportement avons-nous besoin ? En regardant le code que nous avons introduit dans le parseur, on retrouve :
- La fonction pour signaler une erreur de syntaxe ;
- La fonction pour acheter des patates ;
- La fonction pour acheter des radis ;
- La fonction en cas d'erreur de valeur ;
- La fonction pour obtenir le prochain caractère ;
- La fonction à exécuter avant de commencer à segmenter ;
- La fonction à exécuter juste avant le code pour chaque mot-clé.
Ça en fait un certain nombre. Nous allons utiliser à chaque fois des pointeurs de fonction. L'interface commune est présentée dans le programme 73.
typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_parser_behavior { void *data; void (*syntax_error) (void *data); void (*buy_potatoes) (void *data, double weight); void (*buy_radishes) (void *data, int bunches); void (*value_error) (void *data, const char *what); /* Return 0 if EOF, 1 otherwise */ int (*pull_char) (void *data, int prompt_type, char *c); /* Return non-zero if we must return immediately */ int (*prologue) (void *data, int *token, _MARCHANDE_STYPE *yylval); void (*before_token) (void *data, const char *text); };
Pour plus de commodité, nous allons remplir automatiquement une telle structure avec le comportement standard. Il suffit d'ajouter le programme 74 à l'interface, et implémenter avec le programme 82.
extern marchande_parser_behavior *marchande_default_parser_behavior;
static void pb_syntax_error (void *data) { (void) data; marchande_syntax_error (); }
static void pb_buy_potatoes (void *data, double weight) { (void) data; marchande_buy_potatoes (weight); }
static void pb_buy_radishes (void *data, int bunches) { (void) data; marchande_buy_radishes (bunches); }
static void pb_value_error (void *data, const char *what) { (void) data; marchande_value_error (what); }
static int pb_pull_char (void *data, int prompt_type, char *c) { int *need_prompt = (int *) data; int i; if (*need_prompt) { if (prompt_type == 1) { printf ("%s", marchande_main_prompt ()); } else { printf ("%s", marchande_secondary_prompt ()); } *need_prompt = 0; } i = getc (stdin); if (i == '\n') { *need_prompt = 1; } if (i == EOF) { return 0; } c[0] = i; return 1; }
static int pb_prologue (void *data, int *token, _MARCHANDE_STYPE *lval) { (void) data; (void) token; (void) lval; return 0; }
static void pb_before_token (void *data, const char *text) { (void) data; }
static void pb_syntax_error (void *data) { (void) data; marchande_syntax_error (); } static void pb_buy_potatoes (void *data, double weight) { (void) data; marchande_buy_potatoes (weight); } static void pb_buy_radishes (void *data, int bunches) { (void) data; marchande_buy_radishes (bunches); } static void pb_value_error (void *data, const char *what) { (void) data; marchande_value_error (what); } static int pb_pull_char (void *data, int prompt_type, char *c) { int *need_prompt = (int *) data; int i; if (*need_prompt) { if (prompt_type == 1) { printf ("%s", marchande_main_prompt ()); } else { printf ("%s", marchande_secondary_prompt ()); } *need_prompt = 0; } i = getc (stdin); if (i == '\n') { *need_prompt = 1; } if (i == EOF) { return 0; } c[0] = i; return 1; } static int pb_prologue (void *data, int *token, _MARCHANDE_STYPE *lval) { (void) data; (void) token; (void) lval; return 0; } static void pb_before_token (void *data, const char *text) { (void) data; } static int need_prompt = 1; static marchande_parser_behavior default_parser_behavior = { (void *) &need_prompt, &pb_syntax_error, &pb_buy_potatoes, &pb_buy_radishes, &pb_value_error, &pb_pull_char, &pb_prologue, &pb_before_token }; marchande_parser_behavior *marchande_default_parser_behavior = &default_parser_behavior;
Une fois ce comportement défini, on peut tranquillement réécrire les programmes 53 et 54 avec le comportement attendu. On obtient les programmes 83 et 84.
interaction: %empty | interaction command | interaction error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; }
command: THAT WILL BE ALL { YYACCEPT; } | weight OF POTATOES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bunches OF RADISHES { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | weight OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bunches OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); }
Nous disposons donc du nouveau fichier source du parseur, programme
93, et du nouveau fichier source de l'analyseur,
programme 94. Pour rendre le parseur réentrant, il
faut définir les options nécessaires dans les programmes
85 et 86. Une fois que le parseur est
défini, on peut l'isoler avec le programme 87. Pour
le lexeur, il faut également le rendre ré-entrant au moyen du
programme 88, et 89. Pour pouvoir utiliser
les paramètres prompt_type
et behavior
, nous nous servons d'une
structure ad hoc qui sera passée comme paramètre extra au lexeur.
La structure est définie par le programme 90, et on
l'utilise dans le programme 91. Comme yylval
est
maintenant un pointeur, il faut réécrire le programme 57
pour utiliser un pointeur à la place. Un simple remplacement par le
programme 92 fait l'affaire.
%define api.pure full
echo "%parse-param {$PARAM}"
echo "%define api.prefix {$PREFIX}"
%option reentrant
%option bison-bridge
%option prefix="_marchande_"
typedef struct { int *prompt_type; marchande_parser_behavior *behavior; } marchande_lexer_extra;
%option extra-type="marchande_lexer_extra"
sed 's/yylval\./yylval->/g' <<EOF that { return THAT; } will { return WILL; } be { return BE; } all { return ALL; } [0-9]+ { yylval.INTEGER = (unsigned int) strtoul (yytext, NULL, 10); return INTEGER; } [0-9]+\.[0-9]* { yylval.DECIMAL = strtod (yytext, NULL); return DECIMAL; } of { return OF; } kg { return KG; } a { return A; } bunch { return BUNCH; } bunches { return BUNCHES; } potatoes { return POTATOES; } radishes { return RADISHES; } [ \t\n]+ /* do nothing */ [^ \t\n.,?!0-9]+ { yylval.UNKNOWN_WORD = strdup (yytext); return UNKNOWN_WORD; } [.,?!] { return END_OF_PHRASE; } EOF
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %code requires { #include <config.h> #include <marchande.h> #include <marchande_private.h> } %{ #include <config.h> #include <marchande.h> #include <marchande_private.h> #include <stdio.h> #include <stdlib.h> #define _(String) String int _marchande_lex (_MARCHANDE_STYPE *yylval, void *scanner); void _marchande_error (marchande_parser_behavior *behavior, int *prompt_type, void *scanner, const char *error) { (void) error; } int _marchande_wrap () { return 1; } %} %define api.pure full %parse-param {marchande_parser_behavior *behavior} %parse-param {int *prompt_type} %param {void * scanner} %define api.prefix {_marchande_} %define api.value.type union %token THAT %token WILL %token BE %token ALL %token A %token KG %token BUNCH %token BUNCHES %token OF %token POTATOES %token RADISHES %token END_OF_PHRASE %token <int> INTEGER %token <double> DECIMAL %token <char *> UNKNOWN_WORD %destructor { free ($$); } UNKNOWN_WORD %type <int> bunches %type <double> weight %% interaction: %empty | interaction command | interaction error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; } command: THAT WILL BE ALL { YYACCEPT; } | weight OF POTATOES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bunches OF RADISHES { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | weight OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bunches OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } weight: DECIMAL KG { $$ = $1; } | INTEGER KG { $$ = (double) $1; } ; bunches: A BUNCH { $$ = 1; } | INTEGER BUNCHES { $$ = $1; } ; %%
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %{ #include <config.h> #include "parser.h" #include <string.h> #include <marchande.h> #define YY_INPUT(buf, result, max_size) { \ result = yyextra.behavior->pull_char (yyextra.behavior->data, * (yyextra.prompt_type), buf); \ } #define YY_USER_ACTION { \ * (yyextra.prompt_type) = 2; \ yyextra.behavior->before_token (yyextra.behavior->data, yytext); \ } #define YYSTYPE _MARCHANDE_STYPE %} %option extra-type="marchande_lexer_extra" %option bison-bridge %option prefix="_marchande_" %option reentrant %% %{ int ret; if (yyextra.behavior->prologue (yyextra.behavior->data, &ret, yylval)) { return ret; } %} that { return THAT; } will { return WILL; } be { return BE; } all { return ALL; } [0-9]+ { yylval->INTEGER = (unsigned int) strtoul (yytext, NULL, 10); return INTEGER; } [0-9]+\.[0-9]* { yylval->DECIMAL = strtod (yytext, NULL); return DECIMAL; } of { return OF; } kg { return KG; } a { return A; } bunch { return BUNCH; } bunches { return BUNCHES; } potatoes { return POTATOES; } radishes { return RADISHES; } [ \t\n]+ /* do nothing */ [^ \t\n.,?!0-9]+ { yylval->UNKNOWN_WORD = strdup (yytext); return UNKNOWN_WORD; } [.,?!] { return END_OF_PHRASE; } %% void marchande_parse (marchande_parser_behavior *behavior) { int prompt_type = 1; marchande_lexer_extra extra; yyscan_t scanner; extra.prompt_type = &prompt_type; extra.behavior = behavior; _marchande_lex_init_extra (extra, &scanner); _marchande_parse (behavior, &prompt_type, scanner); _marchande_lex_destroy (scanner); }
Les détails sont masqués dans l'API. On ajoute les programmes 95 et 96 pour déclarer et définir la fonction de parse.
/** * marchande_parse: * @param behavior: the behavior to implement. You can pass * 'marchande_default_parser_behavior' here. */ void marchande_parse (marchande_parser_behavior *behavior);
void marchande_parse (marchande_parser_behavior *behavior) { int prompt_type = 1; marchande_lexer_extra extra; yyscan_t scanner; extra.prompt_type = &prompt_type; extra.behavior = behavior; _marchande_lex_init_extra (extra, &scanner); _marchande_parse (behavior, &prompt_type, scanner); _marchande_lex_destroy (scanner); }
4.3 Le code
Grâce à ces changements, nous allons pouvoir faire une nouvelle version. Le code source de la bibliothèque évolue : nous avons maintenant les programmes 97 et 98. À cause du code commun privé au parseur et au lexeur, nous avons besoin d'introduire un fichier d'en-tête privé, programme 99.
/* * File: src/marchande.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_INCLUDED #define H_MARCHANDE_INCLUDED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ union _MARCHANDE_STYPE; typedef union _MARCHANDE_STYPE _MARCHANDE_STYPE; typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_parser_behavior { void *data; void (*syntax_error) (void *data); void (*buy_potatoes) (void *data, double weight); void (*buy_radishes) (void *data, int bunches); void (*value_error) (void *data, const char *what); /* Return 0 if EOF, 1 otherwise */ int (*pull_char) (void *data, int prompt_type, char *c); /* Return non-zero if we must return immediately */ int (*prologue) (void *data, int *token, _MARCHANDE_STYPE *yylval); void (*before_token) (void *data, const char *text); }; extern marchande_parser_behavior *marchande_default_parser_behavior; /** * marchande_init: * * Initializes the library. * * Returns: an error code, 0 on success or 1 if an error happened. */ int marchande_init (); /** * marchande_value_error */ void marchande_value_error (const char *what); /** * marchande_syntax_error */ void marchande_syntax_error (); /** * marchande_buy_radishes: */ void marchande_buy_radishes (int bunches); /** * marchande_buy_potatoes: */ void marchande_buy_potatoes (double weight); /** * marchande_exit: */ void marchande_exit (); /** * marchande_main_prompt: */ const char *marchande_main_prompt (); /** * marchande_secondary_prompt: */ const char *marchande_secondary_prompt (); /** * marchande_parse: * @param behavior: the behavior to implement. You can pass * 'marchande_default_parser_behavior' here. */ void marchande_parse (marchande_parser_behavior *behavior); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* not H_MARCHANDE_INCLUDED */
/* * File: src/libmarchande.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdio.h> #include <stdlib.h> #define _(String) (String) #define N_(String) (String) static int n_radishes; static double weight_potatoes; #include <marchande.h> int marchande_init () { n_radishes = 0; weight_potatoes = 0.0; printf (_ ("marchande Copyright (C) 2019 Vivien Kraus\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions.\nSee the GNU General Public License for details.\n\nTrying to recover from this unexpected assault of legalese, you look\nup to the merchant. She has:\n * a few bunches of radishes;\n * some potatoes.\n\n- Next! Hello :) What will it be?\n")); return 0; } void marchande_value_error (const char *what) { fprintf (stderr, _ ("- Sorry, I don't have %s.\n"), what); } void marchande_syntax_error () { fprintf (stderr, _ ("- Huh?\n\nThe merchant did not understand what you were trying to say.\n")); } void marchande_buy_radishes (int bunches) { n_radishes += bunches; printf (_ ("The merchant takes the radishes and put them aside for you.\n- And with this?\n")); } void marchande_buy_potatoes (double weight) { weight_potatoes += weight; printf (_ ("The merchant takes the potatoes and put them aside for you.\n- And with this?\n")); } void marchande_exit () { printf (_ ("You pay the merchant, take your belongings, and leave.\n")); } const char * marchande_main_prompt () { static const char *ret_c = N_("- "); return _ (ret_c); } const char * marchande_secondary_prompt () { static const char *ret_c = N_("The merchant waits patiently as you try to end your sentence.\n- "); return _ (ret_c); } #include <stdio.h> static void pb_syntax_error (void *data) { (void) data; marchande_syntax_error (); } static void pb_buy_potatoes (void *data, double weight) { (void) data; marchande_buy_potatoes (weight); } static void pb_buy_radishes (void *data, int bunches) { (void) data; marchande_buy_radishes (bunches); } static void pb_value_error (void *data, const char *what) { (void) data; marchande_value_error (what); } static int pb_pull_char (void *data, int prompt_type, char *c) { int *need_prompt = (int *) data; int i; if (*need_prompt) { if (prompt_type == 1) { printf ("%s", marchande_main_prompt ()); } else { printf ("%s", marchande_secondary_prompt ()); } *need_prompt = 0; } i = getc (stdin); if (i == '\n') { *need_prompt = 1; } if (i == EOF) { return 0; } c[0] = i; return 1; } static int pb_prologue (void *data, int *token, _MARCHANDE_STYPE *lval) { (void) data; (void) token; (void) lval; return 0; } static void pb_before_token (void *data, const char *text) { (void) data; } static int need_prompt = 1; static marchande_parser_behavior default_parser_behavior = { (void *) &need_prompt, &pb_syntax_error, &pb_buy_potatoes, &pb_buy_radishes, &pb_value_error, &pb_pull_char, &pb_prologue, &pb_before_token }; marchande_parser_behavior *marchande_default_parser_behavior = &default_parser_behavior;
/* * File: src/marchande_private.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_PRIVATE_INCLUDED #define H_MARCHANDE_PRIVATE_INCLUDED #include <marchande.h> typedef struct { int *prompt_type; marchande_parser_behavior *behavior; } marchande_lexer_extra; #endif /* not H_MARCHANDE_PRIVATE_INCLUDED */
En ce qui concerne le test unitaire, celui-ci ne change pas. On pourrait aussi envisager d'instrumentaliser le parseur 2. On a donc les programmes 100 et 101.
/* * File: src/check.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } printf ("%s1 bunch of radishes\n", marchande_main_prompt ()); marchande_buy_radishes (1); printf ("%s1kg of tomatoes\n", marchande_main_prompt ()); fflush (stdout); marchande_value_error ("tomatoes"); fflush (stderr); printf ("%s1kg\n", marchande_main_prompt ()); printf ("%sof potatoes\n", marchande_secondary_prompt ()); marchande_buy_potatoes (1.0); printf ("%sWhat do you think of Free Software?\n", marchande_main_prompt ()); fflush (stdout); marchande_syntax_error (); fflush (stderr); printf ("%sThat will be all.\n", marchande_main_prompt ()); marchande_exit (); return EXIT_SUCCESS; }
export LANG=C EXPECTED=$( cat <<EOF marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - 1 bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1kg of tomatoes - Sorry, I don't have tomatoes. - 1kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free Software? - Huh? The merchant did not understand what you were trying to say. - That will be all. You pay the merchant, take your belongings, and leave. EOF ) ACTUAL=$(./src/check 2>&1) echo "Expected:" echo "$EXPECTED" echo "Actual:" echo "$ACTUAL" if test "x$EXPECTED" = "x$ACTUAL" then echo "OK" else >&2 echo "Failed." exit 1 fi
Comme notre parseur ne sera utilisé que dans une bibliothèque, il faut définir un fichier source principal qui se contentera d'appliquer le comportement par défaut. C'est pour cette raison que l'on doit définir le programme 102.
#include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } marchande_parse (marchande_default_parser_behavior); marchande_exit (); return EXIT_SUCCESS; }
Le manuel d'utilisation n'a pas changé, à part pour la version. Le programme 103 donne le programme 104.
ORGFILE=$(mktemp XXXXXXX.org) trap "{ rm -rf $ORGFILE; }" EXIT cat > $ORGFILE <<EOF #+macro: version 1.1 # Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+subitile: version {{{version}}} of the program #+author: Vivien Kraus #+email: vivien@planete-kraus.eu #+options: ':t toc:t author:t email:t #+language: en #+texinfo_filename: marchande.info #+texinfo_dir_category: Games #+texinfo_dir_title: marchande: (marchande) #+texinfo_dir_desc: Marchande #+texinfo_printed_title: Marchande #+texinfo: @documentencoding UTF-8 This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction #+include: "./index.org::*Le jeu de la marchande, en anglais (désolé si c'est mal traduit)" :only-contents t * Invoking =marchande= #+include: "./index.org::*Description de la syntaxe, en anglais" :only-contents t EOF LANG=C emacs --batch \ --file $ORGFILE \ --eval "(require 'ox-texinfo)" \ -f org-texinfo-export-to-texinfo \ || exit 1 cat "$(basename $ORGFILE .org).texi"
\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename marchande.info @settitle Play the merchant @documentencoding UTF-8 @documentlanguage en @c %**end of header @copying This manual is for Marchande (version 1.1), an example about how to make a command-line interface. Copyright @copyright{} 2019 Vivien Kraus @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. @end quotation @end copying @dircategory Games @direntry * marchande: (marchande). Marchande. @end direntry @finalout @titlepage @title Marchande @author Vivien Kraus (@email{vivien@@planete-kraus.eu}) @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top @top Play the merchant @documentencoding UTF-8 This manual is for marchande version 1.1. @end ifnottex @menu * Introduction:: * Invoking @samp{marchande}:: @end menu @node Introduction @chapter Introduction You find yourself facing the organic vegetable seller. In front of her, on her stall, you see a crate containing @strong{potatoes} and @strong{bunches of radishes}. The seller thanks the previous customer and turns to you. @quotation @itemize @item Next! What will it be? @end itemize @end quotation You need to buy a few radishes and potatoes. You're going to have to be able to buy it from the merchant@dots{} @node Invoking @samp{marchande} @chapter Invoking @samp{marchande} When you run the @samp{marchande} program, you have a command-line interface. There are several options: @itemize @item say @samp{that will be all}, and the program exits; @item say @samp{a bunch of radishes}, or @samp{2 bunches of radishes}, or another number, to add some radishes; @item say @samp{1.3kg of potatoes}, to add some potatoes. @end itemize @bye
Pour le système de compilation, il faut modifier la version et demander explicitement Flex (programme 105). On doit aussi rajouter le fichier d'en-tête privé et le fichier principal du programme dans le programme 106.
dnl Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> dnl dnl This program is free software: you can redistribute it and/or dnl modify it under the terms of the GNU General Public License as dnl published by the Free Software Foundation, either version 3 of the dnl License, or (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see dnl <http://www.gnu.org/licenses/>. AC_PREREQ([2.69]) AC_INIT([marchande], [1.1], [vivien@planete-kraus.eu]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([m4]) AC_PROG_CC AM_MISSING_PROG([LEX], [flex]) AM_MISSING_PROG([YACC], [bison]) AM_INIT_AUTOMAKE([foreign subdir-objects]) LT_INIT AC_CONFIG_FILES([Makefile]) AC_OUTPUT
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. dist_noinst_SCRIPTS = src/run-test noinst_LTLIBRARIES = src/libmarchande.la include_HEADERS = src/marchande.h info_TEXINFOS = doc/marchande.texi check_PROGRAMS = src/check src_check_LDADD = src/libmarchande.la AM_CPPFLAGS = -I $(srcdir)/src -I . TESTS = src/run-test bin_PROGRAMS = src/marchande src_libmarchande_la_SOURCES = src/libmarchande.c src/parser.c src/lexer.c src_marchande_SOURCES = src/main.c src_marchande_LDADD = src/libmarchande.la EXTRA_DIST = src/parser.y src/parser.h src/parser.stamp src/lexer.l MAINTAINERCLEANFILES = src/parser.h src/parser.c src/parser.stamp src/lexer.c BUILT_SOURCES = src/parser.h dist_noinst_HEADERS = src/marchande_private.h .l.c: $(AM_V_GEN) (cd $(srcdir) && $(LEX) -o $@-t $<) @mv $(srcdir)/$@-t $(srcdir)/$@ $(srcdir)/src/parser.stamp: src/parser.y $(AM_V_GEN) (cd $(srcdir) && $(YACC) src/parser.y -o src/parser.c --defines=src/parser.h) @touch $(srcdir)/src/parser.stamp $(srcdir)/src/parser.h $(srcdir)/src/parser.c: $(srcdir)/src/parser.stamp @dry=; for f in x $$MAKEFLAGS; do \ case $$f in \ *=*|--*);; \ *n*) dry=:;; \ esac; \ done; \ if test -f $@; then :; else \ $$dry trap 'rm -rf $(srcdir)/src/parser.lock $(srcdir)/src/parser.stamp' 1 2 13 15; \ if $$dry mkdir $(srcdir)/src/parser.lock 2>/dev/null; then \ $$dry rm -f $(srcdir)/src/parser.stamp || exit 1; \ $(MAKE) $(AM_MAKEFLAGS) src/parser.stamp; \ $$dry rmdir $(srcdir)/src/parser.lock; \ else \ while test -d $(srcdir)/src/parser.lock && test -z "$$dry"; do \ sleep 1; \ done; \ $$dry test -f $(srcdir)/src/parser.stamp; exit $$?; \ fi; \ fi
4.4 Compilation et test
Pour obtenir la distribution source, j'ai fait ceci :
cd v1.1 autoreconf -vif 2>&1 ./configure 2>&1 make V=0 -j 16 all 2>&1 make V=0 -j 16 distcheck 2>&1 echo "Built"
autoreconf: Entering directory `.' autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal --force aclocal: warning: couldn't open directory 'm4': No such file or directory autoreconf: configure.ac: tracing autoreconf: running: libtoolize --copy --force libtoolize: putting auxiliary files in '.'. libtoolize: copying file './ltmain.sh' libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'. libtoolize: copying file 'm4/libtool.m4' libtoolize: copying file 'm4/ltoptions.m4' libtoolize: copying file 'm4/ltsugar.m4' libtoolize: copying file 'm4/ltversion.m4' libtoolize: copying file 'm4/lt~obsolete.m4' libtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am. autoreconf: running: /usr/bin/autoconf --force autoreconf: running: /usr/bin/autoheader --force autoreconf: running: automake --add-missing --copy --force-missing configure.ac:20: installing './compile' configure.ac:24: installing './config.guess' configure.ac:24: installing './config.sub' configure.ac:23: installing './install-sh' configure.ac:21: installing './missing' Makefile.am: installing './depcomp' Makefile.am:20: installing './texinfo.tex' parallel-tests: installing './test-driver' autoreconf: Leaving directory `.' checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands GEN src/parser.stamp make all-am make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1 » MAKEINFO doc/marchande.info GEN src/lexer.c CC src/main.o CC src/libmarchande.lo CC src/parser.lo CC src/lexer.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1 » make dist-gzip am__post_remove_distdir='@:' make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1 » make distdir-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1 » if test -d "marchande-1.1"; then find "marchande-1.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.1" || { sleep 5 && rm -rf "marchande-1.1"; }; else :; fi test -d "marchande-1.1" || mkdir "marchande-1.1" make \ top_distdir="marchande-1.1" distdir="marchande-1.1" \ dist-info make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1 » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1 » test -n "" \ || find "marchande-1.1" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-1.1" make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1 » tardir=marchande-1.1 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-1.1.tar.gz make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1 » if test -d "marchande-1.1"; then find "marchande-1.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.1" || { sleep 5 && rm -rf "marchande-1.1"; }; else :; fi case 'marchande-1.1.tar.gz' in \ *.tar.gz*) \ eval GZIP= gzip --best -dc marchande-1.1.tar.gz | ${TAR-tar} xf - ;;\ *.tar.bz2*) \ bzip2 -dc marchande-1.1.tar.bz2 | ${TAR-tar} xf - ;;\ *.tar.lz*) \ lzip -dc marchande-1.1.tar.lz | ${TAR-tar} xf - ;;\ *.tar.xz*) \ xz -dc marchande-1.1.tar.xz | ${TAR-tar} xf - ;;\ *.tar.Z*) \ uncompress -c marchande-1.1.tar.Z | ${TAR-tar} xf - ;;\ *.shar.gz*) \ eval GZIP= gzip --best -dc marchande-1.1.shar.gz | unshar ;;\ *.zip*) \ unzip marchande-1.1.zip ;;\ esac chmod -R a-w marchande-1.1 chmod u+w marchande-1.1 mkdir marchande-1.1/_build marchande-1.1/_build/sub marchande-1.1/_inst chmod a-w marchande-1.1 test -d marchande-1.1/_build || exit 0; \ dc_install_base=`CDPATH="${ZSH_VERSION+.}:" && cd marchande-1.1/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="${TMPDIR-/tmp}/am-dc-$$/" \ && am__cwd=`pwd` \ && CDPATH="${ZSH_VERSION+.}:" && cd marchande-1.1/_build/sub \ && ../../configure \ \ \ --srcdir=../.. --prefix="$dc_install_base" \ && make \ && make dvi \ && make check \ && make install \ && make installcheck \ && make uninstall \ && make distuninstallcheck_dir="$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$dc_destdir") \ && make DESTDIR="$dc_destdir" install \ && make DESTDIR="$dc_destdir" uninstall \ && make DESTDIR="$dc_destdir" \ distuninstallcheck_dir="$dc_destdir" distuninstallcheck; \ } || { rm -rf "$dc_destdir"; exit 1; }) \ && rm -rf "$dc_destdir" \ && make dist \ && rm -rf marchande-1.1.tar.gz \ && make distcleancheck \ && cd "$am__cwd" \ || exit 1 checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make all-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » CC src/main.o CC src/libmarchande.lo CC src/parser.lo CC src/lexer.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » TEXI2DVI doc/marchande.dvi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make check-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make src/check make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » CC src/check.o CCLD src/check make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make check-TESTS make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » PASS: src/run-test ============================================================================ Testsuite summary for marchande 1.1 ============================================================================ # TOTAL: 1 # PASS: 1 # SKIP: 0 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 ============================================================================ make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make install-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/include' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/bin' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/bin/marchande make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1]: rien à faire pour « installcheck ». make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/bin' && rm -f marchande ) rm -rf '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/doc/marchande/marchande.html' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/doc/marchande/marchande.dvi' ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/include' && rm -f marchande.h ) rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/doc/marchande/marchande.ps' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/doc/marchande/marchande.pdf' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' --remove '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info/marchande.info' cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make install-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » /bin/mkdir -p '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/include' /bin/mkdir -p '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/bin' /bin/mkdir -p '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' install-info --info-dir='/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/bin/marchande make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » ( cd '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/bin' && rm -f marchande ) rm -f '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/doc/marchande/marchande.dvi' ( cd '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/include' && rm -f marchande.h ) rm -f '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/doc/marchande/marchande.pdf' rm -rf '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/doc/marchande/marchande.html' rm -f '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/doc/marchande/marchande.ps' install-info --info-dir='/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' --remove '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info/marchande.info' cd '/tmp/am-dc-25436//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make dist-gzip am__post_remove_distdir='@:' make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make distdir-am make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » if test -d "marchande-1.1"; then find "marchande-1.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.1" || { sleep 5 && rm -rf "marchande-1.1"; }; else :; fi test -d "marchande-1.1" || mkdir "marchande-1.1" make \ top_distdir="marchande-1.1" distdir="marchande-1.1" \ dist-info make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » test -n "" \ || find "marchande-1.1" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-1.1" make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » tardir=marchande-1.1 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-1.1.tar.gz make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » if test -d "marchande-1.1"; then find "marchande-1.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.1" || { sleep 5 && rm -rf "marchande-1.1"; }; else :; fi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » test -z "doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html" \ || rm -rf doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html rm -rf .libs _libs test -z "src/libmarchande.la" || rm -f src/libmarchande.la rm -rf doc/marchande.t2d doc/marchande.t2p rm -f *.o test -z "src/run-test.log" || rm -f src/run-test.log rm -f src/marchande rm -f src/check rm -f *.lo rm -rf src/.libs src/_libs rm -f *.tab.c test -z "" || rm -f rm -f src/*.o test -z "src/run-test.trs" || rm -f src/run-test.trs test . = "../.." || test -z "" || rm -f rm -f config.h stamp-h1 rm -f libtool config.lt rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags test -z "test-suite.log" || rm -f test-suite.log rm -f doc/.dirstamp rm -f src/so_locations rm -f src/*.lo rm -f cscope.out cscope.in.out cscope.po.out cscope.files rm -f src/.deps/.dirstamp rm -f src/.dirstamp rm -f config.status config.cache config.log configure.lineno config.status.lineno rm -f src/.deps/check.Po rm -f src/.deps/lexer.Plo rm -f src/.deps/libmarchande.Plo rm -f src/.deps/main.Po rm -f src/.deps/parser.Plo rm -f Makefile make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v1.1/marchande-1.1/_build/sub » if test -d "marchande-1.1"; then find "marchande-1.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-1.1" || { sleep 5 && rm -rf "marchande-1.1"; }; else :; fi =============================================== marchande-1.1 archives ready for distribution: marchande-1.1.tar.gz =============================================== Built
Maintenant, pour faire le test, il n'y a pas besoin de tout cela.
cp v1.1/marchande-1.1.tar.gz /tmp cd /tmp tar xf marchande-1.1.tar.gz mkdir -p build cd build ../marchande-1.1/configure --prefix=/tmp/v1.1 2>&1 make V=0 -j 2>&1 make V=0 -j install 2>&1
checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make all-am make[1] : on entre dans le répertoire « /tmp/build » CC src/main.o CC src/parser.lo CC src/lexer.lo CC src/libmarchande.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande make[1] : on quitte le répertoire « /tmp/build » make install-am make[1] : on entre dans le répertoire « /tmp/build » make[2] : on entre dans le répertoire « /tmp/build » /bin/mkdir -p '/tmp/v1.1/include' /bin/mkdir -p '/tmp/v1.1/bin' /bin/mkdir -p '/tmp/v1.1/share/info' /usr/bin/install -c -m 644 ../marchande-1.1/src/marchande.h '/tmp/v1.1/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande '/tmp/v1.1/bin' /usr/bin/install -c -m 644 ../marchande-1.1/doc/marchande.info '/tmp/v1.1/share/info' install-info --info-dir='/tmp/v1.1/share/info' '/tmp/v1.1/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/v1.1/bin/marchande make[2] : on quitte le répertoire « /tmp/build » make[1] : on quitte le répertoire « /tmp/build »
Évidemment, le but de cette version est de changer le comportement interne, mais l'exemple précédent doit toujours donner le même résultat.
cat > test_input.txt <<EOF a bunch of radishes 1 kg of tomatoes 1.3 kg of potatoes What do you think of Free software? that will be all EOF /tmp/v1/bin/marchande < test_input.txt > v1_output.txt 2>v1_error.txt || exit 1 /tmp/v1.1/bin/marchande < test_input.txt > v11_output.txt 2>v11_error.txt || exit 1 md5sum v*_output.txt v*_error.txt
57c1afc1bbbd0104da3631bf8c65a4bf v11_output.txt 57c1afc1bbbd0104da3631bf8c65a4bf v1_output.txt f2a688e4abd31a2d045ebb0111f2ccea v11_error.txt f2a688e4abd31a2d045ebb0111f2ccea v1_error.txt
5 Auto-complétion contextuelle
Nous allons maintenant nous servir de ce que nous avons pour créer un
nouveau programme, marchande_complete
.
5.1 Invocation de marchande_complete
Le programme marchande_complete
est invoqué de la façon suivante :
marchande_complete "TEXTE AVANT" "TEXTE APRÈS"
Le programme affiche soit rien, soit la liste des possibilités pour le premier mot entre le texte avant et le texte après. En cas de nombre, on ne propose rien. En cas d'erreur, on quitte avec un code 1.
Par exemple, si l'on appelle le programme 107, on devrait obtenir le résultat 108.
echo "Complete 'that will be all'" \ && marchande_complete "" "" \ && echo "Complete 'that will be all'" \ && marchande_complete "" "will be all" \ && echo "Can't guess a number" \ && marchande_complete "1." "kg of potatoes" \ && echo "Don't expect radishes" \ && marchande_complete "1.3 kg of" "" \ && echo "Guess the unit" \ && marchande_complete "1 " "of radishes" \ && echo "Ambiguous" \ && marchande_complete "" "bunch of radishes"
Complete 'that will be all' that Complete 'that will be all' that Can't guess a number Don't expect radishes potatoes Guess the unit bunch Ambiguous 1 a
5.2 Invocation de marchande_complete
, en anglais
The marchande_complete
program is used in the following way:
marchande_complete "TEXT BEFORE" "TEXT AFTER"
The program prints either nothing, or the list of possibilities for the first word between the text before and the text after. In case of a number, nothing is proposed. In case of an error, the program exits with code 1.
5.3 Nouvelles règles de grammaire
Pour calculer l'auto-complétion, nous allons réutiliser le
fonctionnement de bison / flex à notre avantage. Lorsque
l'auto-complétion sera demandée, nous allons introduire un nouveau
mot-clé fictif, AUTOCOMPLETE
. On obtient le programme
109.
%token AUTOCOMPLETE
Les règles d'auto-complétion sont les suivantes :
- on complète la phrase "that wil be all" ;
- on complète le légume ;
- on complète l'unité ;
- on complète la quantité, quand on le peut.
Ces règles se traduisent de façon formelle par le programme
110. On voit qu'il nous faut définir une
fonction _marchande_add_completions
, et l'on doit passer un nouveau
paramètre, completions
.
completion: AUTOCOMPLETE { _marchande_add_completion (completions, "that"); /* Don't provide completions for the numbers */ } | AUTOCOMPLETE WILL { _marchande_add_completion (completions, "that"); } | THAT AUTOCOMPLETE { _marchande_add_completion (completions, "will"); } | THAT WILL AUTOCOMPLETE { _marchande_add_completion (completions, "be"); } | THAT WILL BE AUTOCOMPLETE { _marchande_add_completion (completions, "all"); } | weight OF AUTOCOMPLETE { _marchande_add_completion (completions, "potatoes"); } | INTEGER AUTOCOMPLETE { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE OF { _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE KG { /* Cannot complete a decimal number */ } | INTEGER AUTOCOMPLETE OF RADISHES { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } } | AUTOCOMPLETE BUNCH OF RADISHES { _marchande_add_completion (completions, "1"); _marchande_add_completion (completions, "a"); }
Pour gérer les deux types de modes, on rajoute une règle de plus haut
niveau qui définit si l'on est en mode de complétion ou d'action. On
pourrait s'en sortir en laissant Bison gérer l'ambiguïté, mais dans
notre cas on peut facilement s'en sortir en introduisant deux nouveaux
mots-clés : MODE_DEFAULT
et MODE_COMPLETE
. Si l'on croise d'abord
MODE_DEFAULT
, alors on interdira les règles de complétion. Si l'on
croise d'abord MODE_COMPLETE
, on interdit les règles d'action. Ce
premier mot-clé non ambigu permettra à Bison d'agir correctement
immédiatement, mais nous devrons artificiellement introduire l'un de
ces deux mots-clés au tout début de l'analyse lexicale. Les nouveaux
mots-clés, y compris AUTOCOMPLETE
, sont introduits dans le programme
111.
%token MODE_DEFAULT %token MODE_COMPLETE %token AUTOCOMPLETE
Pour lire l'entrée de l'utilisateur, on doit changer de paradigme. Là
où le programme 79
définissait une fonction pour demander la suite à l'utilisateur, ici
il n'y a rien à demander : on dispose du texte avant la demande de
complétion, et du texte après. Par conséquent, le comportement est
beaucoup plus simple. Il est défini dans le programme
113. On voit que l'on a besoin
d'une structure un peu plus précise que le simple pointeur vers une
valeur booléenne utilisée dans le programme
79. La structure
behavior_data
est définie dans l'en-tête partagé, au moyen du
programme 112.
typedef enum behavior_input_type behavior_input_type; enum behavior_input_type { MARCHANDE_STREAM, MARCHANDE_BATCH }; typedef struct behavior_input_stream behavior_input_stream; struct behavior_input_stream { int need_prompt; int produce_mode; }; typedef struct behavior_input_batch behavior_input_batch; struct behavior_input_batch { char *ptr; }; typedef union behavior_input_u behavior_input_u; union behavior_input_u { behavior_input_stream stream; behavior_input_batch batch; }; typedef struct behavior_data behavior_data; struct behavior_data { behavior_input_type t; behavior_input_u u; };
static int pb_pull_char (void *data, int prompt_type, char *c) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM) { int i = 0; if (behavior->u.stream.need_prompt) { if (prompt_type == 1) { printf ("%s", marchande_main_prompt ()); } else { printf ("%s", marchande_secondary_prompt ()); } behavior->u.stream.need_prompt = 0; } i = getc (stdin); if (i == '\n') { behavior->u.stream.need_prompt = 1; } if (i == EOF) { return 0; } c[0] = i; return 1; } else { if (strcmp (behavior->u.batch.ptr, "") == 0) { return 0; } c[0] = behavior->u.batch.ptr[0]; behavior->u.batch.ptr = & (behavior->u.batch.ptr[1]); return 1; } }
static int pb_prologue (void *data, int *token, _MARCHANDE_STYPE *lval) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM && behavior->u.stream.produce_mode) { behavior->u.stream.produce_mode = 0; *token = MODE_DEFAULT; return 1; } return 0; }
Pour faire l'analyse grammaticale, il faut :
- Injecter le mode, soit
MODE_DEFAULT
, soitMODE_COMPLETE
; - Lire les mots-clés du texte avant la complétion ;
- Injecter le mot-clé
AUTOCOMPLETE
; - Lire les mots-clés du texte après la complétion.
Comme cette démarche est assez dirigiste, nous aurons plus de facilités à conserver la main lors de cette opération. Le plus simple, c'est d'utiliser l'interface push du parseur. Pour ce faire, on rajoute le programme 115 à la configuration du parseur.
%define api.push-pull both
Maintenant, nous pouvons nous concentrer sur la fonction principale de
cette partie. On déclare la fonction marchande_complete
dans le
programme 116, et on l'implémente dans le
programme 118. Pour stocker les complétions de
manière interne, on utilise une liste chaînée définie dans le
programme 117.
/** * marchande_complete: * Returns: (array null-terminated) (transfer full): the list of * possible completions. */ char **marchande_complete (const char *left, const char *right);
typedef struct marchande_completer_candidate marchande_completer_candidate; struct marchande_completer_candidate { char *candidate; marchande_completer_candidate *previous; };
void _marchande_add_completion (marchande_completer_candidate **data, const char *candidate) { marchande_completer_candidate *next = malloc (sizeof (marchande_completer_candidate)); marchande_completer_candidate *old = *data; if (next == NULL) { abort (); } next->previous = old; next->candidate = strdup (candidate); *data = next; } char ** marchande_complete (const char *left, const char *right) { behavior_data data; _marchande_pstate *ps = _marchande_pstate_new (); int done = 0; int token = 0; _MARCHANDE_STYPE lval; yyscan_t scanner; marchande_parser_behavior behavior; marchande_lexer_extra extra; int prompt_type = 1; size_t n_completions, i_completion; marchande_completer_candidate *completions = NULL; marchande_completer_candidate *i, *aux; char **ret = NULL;; data.t = MARCHANDE_BATCH; behavior.data = &data; behavior.syntax_error = &pb_syntax_error; behavior.buy_potatoes = &pb_buy_potatoes; behavior.buy_radishes = &pb_buy_radishes; behavior.value_error = &pb_value_error; behavior.pull_char = &pb_pull_char; behavior.prologue = &pb_prologue; behavior.before_token = &pb_before_token; extra.prompt_type = &prompt_type; extra.behavior = &behavior;; data.u.batch.ptr = (char *) left; _marchande_lex_init_extra (extra, &scanner); _marchande_push_parse (ps, MODE_COMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, AUTOCOMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); data.u.batch.ptr = (char *) right; do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, 0, NULL, &behavior, &prompt_type, &completions, scanner); _marchande_pstate_delete (ps); _marchande_lex_destroy (scanner); n_completions = 0; for (i = completions; i != NULL; i = i->previous) { n_completions++; } ret = malloc ((n_completions + 1) * sizeof (char *)); if (ret == NULL) { abort (); } i_completion = 0; for (i = completions; i != NULL; i = aux) { ret[n_completions - (i_completion++) - 1] = i->candidate; aux = i->previous; free (i); } ret[n_completions] = NULL; return ret;; }
Le programme 118 est construit de la manière suivante : on commence par déclarer la fonction pour ajouter un candidat de complétion, programme 119, puis les variables de la fonction, programme 120, puis on définit la construction de l'état du comportement, programme 121, puis le code à proprement parler, programme 122.
void _marchande_add_completion (marchande_completer_candidate **data, const char *candidate) { marchande_completer_candidate *next = malloc (sizeof (marchande_completer_candidate)); marchande_completer_candidate *old = *data; if (next == NULL) { abort (); } next->previous = old; next->candidate = strdup (candidate); *data = next; }
behavior_data data; _marchande_pstate *ps = _marchande_pstate_new (); int done = 0; int token = 0; _MARCHANDE_STYPE lval; yyscan_t scanner; marchande_parser_behavior behavior; marchande_lexer_extra extra; int prompt_type = 1; size_t n_completions, i_completion; marchande_completer_candidate *completions = NULL; marchande_completer_candidate *i, *aux; char **ret = NULL;
data.t = MARCHANDE_BATCH; behavior.data = &data; behavior.syntax_error = &pb_syntax_error; behavior.buy_potatoes = &pb_buy_potatoes; behavior.buy_radishes = &pb_buy_radishes; behavior.value_error = &pb_value_error; behavior.pull_char = &pb_pull_char; behavior.prologue = &pb_prologue; behavior.before_token = &pb_before_token; extra.prompt_type = &prompt_type; extra.behavior = &behavior;
data.u.batch.ptr = (char *) left; _marchande_lex_init_extra (extra, &scanner); _marchande_push_parse (ps, MODE_COMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, AUTOCOMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); data.u.batch.ptr = (char *) right; do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, 0, NULL, &behavior, &prompt_type, &completions, scanner); _marchande_pstate_delete (ps); _marchande_lex_destroy (scanner); n_completions = 0; for (i = completions; i != NULL; i = i->previous) { n_completions++; } ret = malloc ((n_completions + 1) * sizeof (char *)); if (ret == NULL) { abort (); } i_completion = 0; for (i = completions; i != NULL; i = aux) { ret[n_completions - (i_completion++) - 1] = i->candidate; aux = i->previous; free (i); } ret[n_completions] = NULL; return ret;
Comme le parseur a changé, il faut aussi modifier l'implémentation de la fonction de parse générique. C'est le nouveau code 124. Pour ce faire, il suffit simplement d'ajouter un pointeur nul. C'est ce que fait le programme 123.
sed 's/_marchande_parse (behavior, &prompt_type, scanner);/_marchande_parse (behavior, \&prompt_type, NULL, scanner);/g' <<"EOF" void marchande_parse (marchande_parser_behavior *behavior) { int prompt_type = 1; marchande_lexer_extra extra; yyscan_t scanner; extra.prompt_type = &prompt_type; extra.behavior = behavior; _marchande_lex_init_extra (extra, &scanner); _marchande_parse (behavior, &prompt_type, scanner); _marchande_lex_destroy (scanner); } EOF
void marchande_parse (marchande_parser_behavior *behavior) { int prompt_type = 1; marchande_lexer_extra extra; yyscan_t scanner; extra.prompt_type = &prompt_type; extra.behavior = behavior; _marchande_lex_init_extra (extra, &scanner); _marchande_parse (behavior, &prompt_type, NULL, scanner); _marchande_lex_destroy (scanner); }
5.4 Adaptation du code
Il y a plusieurs choses à adapter. Passons-les dans l'ordre.
5.4.1 Le parseur
Avec les quelques ajouts supplémentaires, le parseur final est implémenté par le programme 125.
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %code requires { struct marchande_parser_behavior; typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_completer_candidate; typedef struct marchande_completer_candidate marchande_completer_candidate; } %{ #include <marchande_private.h> #include <stdio.h> #include <stdlib.h> #define _(String) String int _marchande_lex (_MARCHANDE_STYPE *yylval, void *scanner); void _marchande_error (marchande_parser_behavior *behavior, int *prompt_type, void *scanner, marchande_completer_candidate **completions, const char *error) { (void) error; } int _marchande_wrap () { return 1; } void _marchande_add_completion (marchande_completer_candidate **completions, const char *candidate); %} %define api.pure full %define api.push-pull both %parse-param {marchande_parser_behavior *behavior} %parse-param {int *prompt_type} %parse-param {marchande_completer_candidate **completions} %param {void * scanner} %define api.prefix {_marchande_} %define api.value.type union %token THAT %token WILL %token BE %token ALL %token A %token KG %token BUNCH %token BUNCHES %token OF %token POTATOES %token RADISHES %token END_OF_PHRASE %token <int> INTEGER %token <double> DECIMAL %token <char *> UNKNOWN_WORD %destructor { free ($$); } UNKNOWN_WORD %type <int> bunches %type <double> weight %token MODE_DEFAULT %token MODE_COMPLETE %token AUTOCOMPLETE %% run: MODE_DEFAULT interaction | MODE_COMPLETE completion | MODE_COMPLETE error { yyerrok; } ; interaction: %empty | interaction command | interaction error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; } command: THAT WILL BE ALL { YYACCEPT; } | weight OF POTATOES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bunches OF RADISHES { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | weight OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bunches OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } weight: DECIMAL KG { $$ = $1; } | INTEGER KG { $$ = (double) $1; } ; bunches: A BUNCH { $$ = 1; } | INTEGER BUNCHES { $$ = $1; } ; completion: AUTOCOMPLETE { _marchande_add_completion (completions, "that"); /* Don't provide completions for the numbers */ } | AUTOCOMPLETE WILL { _marchande_add_completion (completions, "that"); } | THAT AUTOCOMPLETE { _marchande_add_completion (completions, "will"); } | THAT WILL AUTOCOMPLETE { _marchande_add_completion (completions, "be"); } | THAT WILL BE AUTOCOMPLETE { _marchande_add_completion (completions, "all"); } | weight OF AUTOCOMPLETE { _marchande_add_completion (completions, "potatoes"); } | INTEGER AUTOCOMPLETE { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE OF { _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE KG { /* Cannot complete a decimal number */ } | INTEGER AUTOCOMPLETE OF RADISHES { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } } | AUTOCOMPLETE BUNCH OF RADISHES { _marchande_add_completion (completions, "1"); _marchande_add_completion (completions, "a"); } %%
5.4.2 Le lexeur
Nous allons ajouter l'implémentation de la fonction dans le fichier du lexeur, ainsi nous aurons accès à l'interface de programmation du parseur et du lexeur. Nous obtenons le programme 126.
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %{ #include <config.h> #include "parser.h" #include <marchande_private.h> #include <string.h> #include <marchande.h> #define YY_INPUT(buf, result, max_size) { \ result = yyextra.behavior->pull_char (yyextra.behavior->data, * (yyextra.prompt_type), buf); \ } #define YY_USER_ACTION { \ * (yyextra.prompt_type) = 2; \ yyextra.behavior->before_token (yyextra.behavior->data, yytext); \ } #define YYSTYPE _MARCHANDE_STYPE %} %option extra-type="marchande_lexer_extra" %option bison-bridge %option prefix="_marchande_" %option reentrant %% %{ int ret; if (yyextra.behavior->prologue (yyextra.behavior->data, &ret, yylval)) { return ret; } %} that { return THAT; } will { return WILL; } be { return BE; } all { return ALL; } [0-9]+ { yylval->INTEGER = (unsigned int) strtoul (yytext, NULL, 10); return INTEGER; } [0-9]+\.[0-9]* { yylval->DECIMAL = strtod (yytext, NULL); return DECIMAL; } of { return OF; } kg { return KG; } a { return A; } bunch { return BUNCH; } bunches { return BUNCHES; } potatoes { return POTATOES; } radishes { return RADISHES; } [ \t\n]+ /* do nothing */ [^ \t\n.,?!0-9]+ { yylval->UNKNOWN_WORD = strdup (yytext); return UNKNOWN_WORD; } [.,?!] { return END_OF_PHRASE; } %% void marchande_parse (marchande_parser_behavior *behavior) { int prompt_type = 1; marchande_lexer_extra extra; yyscan_t scanner; extra.prompt_type = &prompt_type; extra.behavior = behavior; _marchande_lex_init_extra (extra, &scanner); _marchande_parse (behavior, &prompt_type, NULL, scanner); _marchande_lex_destroy (scanner); } void _marchande_add_completion (marchande_completer_candidate **data, const char *candidate) { marchande_completer_candidate *next = malloc (sizeof (marchande_completer_candidate)); marchande_completer_candidate *old = *data; if (next == NULL) { abort (); } next->previous = old; next->candidate = strdup (candidate); *data = next; } char ** marchande_complete (const char *left, const char *right) { behavior_data data; _marchande_pstate *ps = _marchande_pstate_new (); int done = 0; int token = 0; _MARCHANDE_STYPE lval; yyscan_t scanner; marchande_parser_behavior behavior; marchande_lexer_extra extra; int prompt_type = 1; size_t n_completions, i_completion; marchande_completer_candidate *completions = NULL; marchande_completer_candidate *i, *aux; char **ret = NULL;; data.t = MARCHANDE_BATCH; behavior.data = &data; behavior.syntax_error = &pb_syntax_error; behavior.buy_potatoes = &pb_buy_potatoes; behavior.buy_radishes = &pb_buy_radishes; behavior.value_error = &pb_value_error; behavior.pull_char = &pb_pull_char; behavior.prologue = &pb_prologue; behavior.before_token = &pb_before_token; extra.prompt_type = &prompt_type; extra.behavior = &behavior;; data.u.batch.ptr = (char *) left; _marchande_lex_init_extra (extra, &scanner); _marchande_push_parse (ps, MODE_COMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, AUTOCOMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); data.u.batch.ptr = (char *) right; do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, 0, NULL, &behavior, &prompt_type, &completions, scanner); _marchande_pstate_delete (ps); _marchande_lex_destroy (scanner); n_completions = 0; for (i = completions; i != NULL; i = i->previous) { n_completions++; } ret = malloc ((n_completions + 1) * sizeof (char *)); if (ret == NULL) { abort (); } i_completion = 0; for (i = completions; i != NULL; i = aux) { ret[n_completions - (i_completion++) - 1] = i->candidate; aux = i->previous; free (i); } ret[n_completions] = NULL; return ret;; }
5.4.3 L'en-tête principal
Pour l'en-tête principal, nous nous contentons de recopier celui de la version précédente, en ajoutant l'interface pour la fonction de complétion. On obtient le programme 127.
/* * File: src/marchande.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_INCLUDED #define H_MARCHANDE_INCLUDED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ union _MARCHANDE_STYPE; typedef union _MARCHANDE_STYPE _MARCHANDE_STYPE; typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_parser_behavior { void *data; void (*syntax_error) (void *data); void (*buy_potatoes) (void *data, double weight); void (*buy_radishes) (void *data, int bunches); void (*value_error) (void *data, const char *what); /* Return 0 if EOF, 1 otherwise */ int (*pull_char) (void *data, int prompt_type, char *c); /* Return non-zero if we must return immediately */ int (*prologue) (void *data, int *token, _MARCHANDE_STYPE *yylval); void (*before_token) (void *data, const char *text); }; extern marchande_parser_behavior *marchande_default_parser_behavior; /** * marchande_init: * * Initializes the library. * * Returns: an error code, 0 on success or 1 if an error happened. */ int marchande_init (); /** * marchande_value_error */ void marchande_value_error (const char *what); /** * marchande_syntax_error */ void marchande_syntax_error (); /** * marchande_buy_radishes: */ void marchande_buy_radishes (int bunches); /** * marchande_buy_potatoes: */ void marchande_buy_potatoes (double weight); /** * marchande_exit: */ void marchande_exit (); /** * marchande_main_prompt: */ const char *marchande_main_prompt (); /** * marchande_secondary_prompt: */ const char *marchande_secondary_prompt (); /** * marchande_parse: * @param behavior: the behavior to implement. You can pass * 'marchande_default_parser_behavior' here. */ void marchande_parse (marchande_parser_behavior *behavior); /** * marchande_complete: * Returns: (array null-terminated) (transfer full): the list of * possible completions. */ char **marchande_complete (const char *left, const char *right); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* not H_MARCHANDE_INCLUDED */
5.4.4 L'implémentation de la bibliothèque
Pour tenir compte de la modification de l'implémentation du comportement du parseur, il faut revoir le programme 128.
/* * File: src/libmarchande.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdio.h> #include <stdlib.h> #define _(String) (String) #define N_(String) (String) static int n_radishes; static double weight_potatoes; #include <marchande.h> int marchande_init () { n_radishes = 0; weight_potatoes = 0.0; printf (_ ("marchande Copyright (C) 2019 Vivien Kraus\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions.\nSee the GNU General Public License for details.\n\nTrying to recover from this unexpected assault of legalese, you look\nup to the merchant. She has:\n * a few bunches of radishes;\n * some potatoes.\n\n- Next! Hello :) What will it be?\n")); return 0; } void marchande_value_error (const char *what) { fprintf (stderr, _ ("- Sorry, I don't have %s.\n"), what); } void marchande_syntax_error () { fprintf (stderr, _ ("- Huh?\n\nThe merchant did not understand what you were trying to say.\n")); } void marchande_buy_radishes (int bunches) { n_radishes += bunches; printf (_ ("The merchant takes the radishes and put them aside for you.\n- And with this?\n")); } void marchande_buy_potatoes (double weight) { weight_potatoes += weight; printf (_ ("The merchant takes the potatoes and put them aside for you.\n- And with this?\n")); } void marchande_exit () { printf (_ ("You pay the merchant, take your belongings, and leave.\n")); } const char * marchande_main_prompt () { static const char *ret_c = N_("- "); return _ (ret_c); } const char * marchande_secondary_prompt () { static const char *ret_c = N_("The merchant waits patiently as you try to end your sentence.\n- "); return _ (ret_c); } #include <marchande_private.h> #include "src/parser.h" static behavior_data default_behavior_data = { .t = MARCHANDE_STREAM, .u = { .stream = { .need_prompt = 1, .produce_mode = 1 } } }; static marchande_parser_behavior default_parser_behavior = { (void *) &default_behavior_data, &pb_syntax_error, &pb_buy_potatoes, &pb_buy_radishes, &pb_value_error, &pb_pull_char, &pb_prologue, &pb_before_token }; marchande_parser_behavior *marchande_default_parser_behavior = &default_parser_behavior;
5.4.5 L'implémentation de l'en-tête privé
Nous avons besoin de définir l'état du parseur pour l'entrée de l'utilisateur dans le programme 129, et de mettre à disposition les fonctions statiques du comportement par défaut.
/* * File: src/marchande_private.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_PRIVATE_INCLUDED #define H_MARCHANDE_PRIVATE_INCLUDED #include <config.h> #include <marchande.h> #include <string.h> #include <stdio.h> #include "src/parser.h" typedef struct marchande_completer_candidate marchande_completer_candidate; struct marchande_completer_candidate { char *candidate; marchande_completer_candidate *previous; }; typedef struct { int *prompt_type; marchande_parser_behavior *behavior; } marchande_lexer_extra; typedef enum behavior_input_type behavior_input_type; enum behavior_input_type { MARCHANDE_STREAM, MARCHANDE_BATCH }; typedef struct behavior_input_stream behavior_input_stream; struct behavior_input_stream { int need_prompt; int produce_mode; }; typedef struct behavior_input_batch behavior_input_batch; struct behavior_input_batch { char *ptr; }; typedef union behavior_input_u behavior_input_u; union behavior_input_u { behavior_input_stream stream; behavior_input_batch batch; }; typedef struct behavior_data behavior_data; struct behavior_data { behavior_input_type t; behavior_input_u u; }; static void pb_syntax_error (void *data) { (void) data; marchande_syntax_error (); } static void pb_buy_potatoes (void *data, double weight) { (void) data; marchande_buy_potatoes (weight); } static void pb_buy_radishes (void *data, int bunches) { (void) data; marchande_buy_radishes (bunches); } static void pb_value_error (void *data, const char *what) { (void) data; marchande_value_error (what); } static int pb_pull_char (void *data, int prompt_type, char *c) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM) { int i = 0; if (behavior->u.stream.need_prompt) { if (prompt_type == 1) { printf ("%s", marchande_main_prompt ()); } else { printf ("%s", marchande_secondary_prompt ()); } behavior->u.stream.need_prompt = 0; } i = getc (stdin); if (i == '\n') { behavior->u.stream.need_prompt = 1; } if (i == EOF) { return 0; } c[0] = i; return 1; } else { if (strcmp (behavior->u.batch.ptr, "") == 0) { return 0; } c[0] = behavior->u.batch.ptr[0]; behavior->u.batch.ptr = & (behavior->u.batch.ptr[1]); return 1; } } static int pb_prologue (void *data, int *token, _MARCHANDE_STYPE *lval) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM && behavior->u.stream.produce_mode) { behavior->u.stream.produce_mode = 0; *token = MODE_DEFAULT; return 1; } return 0; } static void pb_before_token (void *data, const char *text) { (void) data; } #endif /* not H_MARCHANDE_PRIVATE_INCLUDED */
5.4.6 L'implémentation du test
Le test est encore une fois le même. On obtient de nouveau les programmes 130 et 131.
/* * File: src/check.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } printf ("%s1 bunch of radishes\n", marchande_main_prompt ()); marchande_buy_radishes (1); printf ("%s1kg of tomatoes\n", marchande_main_prompt ()); fflush (stdout); marchande_value_error ("tomatoes"); fflush (stderr); printf ("%s1kg\n", marchande_main_prompt ()); printf ("%sof potatoes\n", marchande_secondary_prompt ()); marchande_buy_potatoes (1.0); printf ("%sWhat do you think of Free Software?\n", marchande_main_prompt ()); fflush (stdout); marchande_syntax_error (); fflush (stderr); printf ("%sThat will be all.\n", marchande_main_prompt ()); marchande_exit (); return EXIT_SUCCESS; }
export LANG=C EXPECTED=$( cat <<EOF marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - 1 bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1kg of tomatoes - Sorry, I don't have tomatoes. - 1kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free Software? - Huh? The merchant did not understand what you were trying to say. - That will be all. You pay the merchant, take your belongings, and leave. EOF ) ACTUAL=$(./src/check 2>&1) echo "Expected:" echo "$EXPECTED" echo "Actual:" echo "$ACTUAL" if test "x$EXPECTED" = "x$ACTUAL" then echo "OK" else >&2 echo "Failed." exit 1 fi
5.4.7 Le programme principal
Le programme principal ne change pas non plus, on a toujours le programme 102 pour obtenir 132.
#include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } marchande_parse (marchande_default_parser_behavior); marchande_exit (); return EXIT_SUCCESS; }
5.4.8 Le programme d'auto-complétion
Là où l'on change, c'est au niveau du programme d'auto-complétion. On crée le programme 133.
#include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char **completions; size_t i = 0; if (argc != 3) { fprintf (stderr, "Usage: complete \"text before\" \"text after\"\n"); return EXIT_FAILURE; } completions = marchande_complete (argv[1], argv[2]); for (i = 0; completions[i] != NULL; i++) { printf ("%s\n", completions[i]); free (completions[i]); } free (completions); return EXIT_SUCCESS; }
5.4.9 Le manuel
Pour le manuel, on doit ajouter la section 5.2.
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+author: Vivien Kraus #+email: vivien@planete-kraus.eu This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction * Invoking =marchande= * Invoking =marchande_complete=
ORGFILE=$(mktemp XXXXXXX.org) trap "{ rm -rf $ORGFILE; }" EXIT cat > $ORGFILE <<EOF #+macro: version 2 # Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+subitile: version {{{version}}} of the program #+author: Vivien Kraus #+email: vivien@planete-kraus.eu #+options: ':t toc:t author:t email:t #+language: en #+texinfo_filename: marchande.info #+texinfo_dir_category: Games #+texinfo_dir_title: marchande: (marchande) #+texinfo_dir_desc: Marchande #+texinfo_printed_title: Marchande #+texinfo: @documentencoding UTF-8 This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction #+include: "./index.org::*Le jeu de la marchande, en anglais (désolé si c'est mal traduit)" :only-contents t * Invoking =marchande= #+include: "./index.org::*Description de la syntaxe, en anglais" :only-contents t * Invoking =marchande_complete= #+include: "./index.org::*Invocation de =marchande_complete=, en anglais" :only-contents t EOF LANG=C emacs --batch \ --file $ORGFILE \ --eval "(require 'ox-texinfo)" \ -f org-texinfo-export-to-texinfo \ || exit 1 cat "$(basename $ORGFILE .org).texi"
\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename marchande.info @settitle Play the merchant @documentencoding UTF-8 @documentlanguage en @c %**end of header @copying This manual is for Marchande (version 2), an example about how to make a command-line interface. Copyright @copyright{} 2019 Vivien Kraus @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. @end quotation @end copying @dircategory Games @direntry * marchande: (marchande). Marchande. @end direntry @finalout @titlepage @title Marchande @author Vivien Kraus (@email{vivien@@planete-kraus.eu}) @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top @top Play the merchant @documentencoding UTF-8 This manual is for marchande version 2. @end ifnottex @menu * Introduction:: * Invoking @samp{marchande}:: * Invoking @samp{marchande_complete}:: @end menu @node Introduction @chapter Introduction You find yourself facing the organic vegetable seller. In front of her, on her stall, you see a crate containing @strong{potatoes} and @strong{bunches of radishes}. The seller thanks the previous customer and turns to you. @quotation @itemize @item Next! What will it be? @end itemize @end quotation You need to buy a few radishes and potatoes. You're going to have to be able to buy it from the merchant@dots{} @node Invoking @samp{marchande} @chapter Invoking @samp{marchande} When you run the @samp{marchande} program, you have a command-line interface. There are several options: @itemize @item say @samp{that will be all}, and the program exits; @item say @samp{a bunch of radishes}, or @samp{2 bunches of radishes}, or another number, to add some radishes; @item say @samp{1.3kg of potatoes}, to add some potatoes. @end itemize @node Invoking @samp{marchande_complete} @chapter Invoking @samp{marchande_complete} The @samp{marchande_complete} program is used in the following way: @example marchande_complete "TEXT BEFORE" "TEXT AFTER" @end example The program prints either nothing, or the list of possibilities for the first word between the text before and the text after. In case of a number, nothing is proposed. In case of an error, the program exits with code 1. @bye
5.4.10 La configuration avec autoconf
La configuration ne change pas, à part pour le numéro de version. On recopie le programme 105 pour obtenir le programme 137.
dnl Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> dnl dnl This program is free software: you can redistribute it and/or dnl modify it under the terms of the GNU General Public License as dnl published by the Free Software Foundation, either version 3 of the dnl License, or (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see dnl <http://www.gnu.org/licenses/>. AC_PREREQ([2.69]) AC_INIT([marchande], [2.0], [vivien@planete-kraus.eu]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([m4]) AC_PROG_CC AM_MISSING_PROG([LEX], [flex]) AM_MISSING_PROG([YACC], [bison]) AM_INIT_AUTOMAKE([foreign subdir-objects]) LT_INIT AC_CONFIG_FILES([Makefile]) AC_OUTPUT
5.4.11 Le Makefile
Étant donné que l'on rajoute un programme, il faut définir ses sources. C'est pourquoi on allonge un peu le programme 106 pour obtenir le programme 138.
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. dist_noinst_SCRIPTS = src/run-test noinst_LTLIBRARIES = src/libmarchande.la include_HEADERS = src/marchande.h info_TEXINFOS = doc/marchande.texi check_PROGRAMS = src/check src_check_LDADD = src/libmarchande.la AM_CPPFLAGS = -I $(srcdir)/src -I . TESTS = src/run-test bin_PROGRAMS = src/marchande src_libmarchande_la_SOURCES = src/libmarchande.c src/parser.c src/lexer.c src_marchande_SOURCES = src/main.c src_marchande_LDADD = src/libmarchande.la EXTRA_DIST = src/parser.y src/parser.h src/parser.stamp src/lexer.l MAINTAINERCLEANFILES = src/parser.h src/parser.c src/parser.stamp src/lexer.c BUILT_SOURCES = src/parser.h dist_noinst_HEADERS = src/marchande_private.h .l.c: $(AM_V_GEN) (cd $(srcdir) && $(LEX) -o $@-t $<) @mv $(srcdir)/$@-t $(srcdir)/$@ $(srcdir)/src/parser.stamp: src/parser.y $(AM_V_GEN) (cd $(srcdir) && $(YACC) src/parser.y -o src/parser.c --defines=src/parser.h) @touch $(srcdir)/src/parser.stamp $(srcdir)/src/parser.h $(srcdir)/src/parser.c: $(srcdir)/src/parser.stamp @dry=; for f in x $$MAKEFLAGS; do \ case $$f in \ *=*|--*);; \ *n*) dry=:;; \ esac; \ done; \ if test -f $@; then :; else \ $$dry trap 'rm -rf $(srcdir)/src/parser.lock $(srcdir)/src/parser.stamp' 1 2 13 15; \ if $$dry mkdir $(srcdir)/src/parser.lock 2>/dev/null; then \ $$dry rm -f $(srcdir)/src/parser.stamp || exit 1; \ $(MAKE) $(AM_MAKEFLAGS) src/parser.stamp; \ $$dry rmdir $(srcdir)/src/parser.lock; \ else \ while test -d $(srcdir)/src/parser.lock && test -z "$$dry"; do \ sleep 1; \ done; \ $$dry test -f $(srcdir)/src/parser.stamp; exit $$?; \ fi; \ fi bin_PROGRAMS += src/marchande_complete src_marchande_complete_SOURCES = src/complete.c src_marchande_complete_LDADD = src/libmarchande.la
5.5 Testons !
Pour obtenir la distribution source, j'ai fait ceci :
cd v2 autoreconf -vif 2>&1 ./configure 2>&1 make V=0 -j 16 all 2>&1 make V=0 -j 16 distcheck 2>&1 echo "Built"
autoreconf: Entering directory `.' autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal --force aclocal: warning: couldn't open directory 'm4': No such file or directory autoreconf: configure.ac: tracing autoreconf: running: libtoolize --copy --force libtoolize: putting auxiliary files in '.'. libtoolize: copying file './ltmain.sh' libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'. libtoolize: copying file 'm4/libtool.m4' libtoolize: copying file 'm4/ltoptions.m4' libtoolize: copying file 'm4/ltsugar.m4' libtoolize: copying file 'm4/ltversion.m4' libtoolize: copying file 'm4/lt~obsolete.m4' libtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am. autoreconf: running: /usr/bin/autoconf --force autoreconf: running: /usr/bin/autoheader --force autoreconf: running: automake --add-missing --copy --force-missing configure.ac:20: installing './compile' configure.ac:24: installing './config.guess' configure.ac:24: installing './config.sub' configure.ac:23: installing './install-sh' configure.ac:21: installing './missing' Makefile.am: installing './depcomp' Makefile.am:20: installing './texinfo.tex' parallel-tests: installing './test-driver' autoreconf: Leaving directory `.' checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands GEN src/parser.stamp make all-am make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2 » MAKEINFO doc/marchande.info GEN src/lexer.c CC src/libmarchande.lo CC src/parser.lo CC src/complete.o CC src/main.o CC src/lexer.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande CCLD src/marchande_complete make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2 » make dist-gzip am__post_remove_distdir='@:' make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2 » make distdir-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2 » if test -d "marchande-2.0"; then find "marchande-2.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.0" || { sleep 5 && rm -rf "marchande-2.0"; }; else :; fi test -d "marchande-2.0" || mkdir "marchande-2.0" make \ top_distdir="marchande-2.0" distdir="marchande-2.0" \ dist-info make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2 » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2 » test -n "" \ || find "marchande-2.0" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-2.0" make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2 » tardir=marchande-2.0 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-2.0.tar.gz make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2 » if test -d "marchande-2.0"; then find "marchande-2.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.0" || { sleep 5 && rm -rf "marchande-2.0"; }; else :; fi case 'marchande-2.0.tar.gz' in \ *.tar.gz*) \ eval GZIP= gzip --best -dc marchande-2.0.tar.gz | ${TAR-tar} xf - ;;\ *.tar.bz2*) \ bzip2 -dc marchande-2.0.tar.bz2 | ${TAR-tar} xf - ;;\ *.tar.lz*) \ lzip -dc marchande-2.0.tar.lz | ${TAR-tar} xf - ;;\ *.tar.xz*) \ xz -dc marchande-2.0.tar.xz | ${TAR-tar} xf - ;;\ *.tar.Z*) \ uncompress -c marchande-2.0.tar.Z | ${TAR-tar} xf - ;;\ *.shar.gz*) \ eval GZIP= gzip --best -dc marchande-2.0.shar.gz | unshar ;;\ *.zip*) \ unzip marchande-2.0.zip ;;\ esac chmod -R a-w marchande-2.0 chmod u+w marchande-2.0 mkdir marchande-2.0/_build marchande-2.0/_build/sub marchande-2.0/_inst chmod a-w marchande-2.0 test -d marchande-2.0/_build || exit 0; \ dc_install_base=`CDPATH="${ZSH_VERSION+.}:" && cd marchande-2.0/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="${TMPDIR-/tmp}/am-dc-$$/" \ && am__cwd=`pwd` \ && CDPATH="${ZSH_VERSION+.}:" && cd marchande-2.0/_build/sub \ && ../../configure \ \ \ --srcdir=../.. --prefix="$dc_install_base" \ && make \ && make dvi \ && make check \ && make install \ && make installcheck \ && make uninstall \ && make distuninstallcheck_dir="$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$dc_destdir") \ && make DESTDIR="$dc_destdir" install \ && make DESTDIR="$dc_destdir" uninstall \ && make DESTDIR="$dc_destdir" \ distuninstallcheck_dir="$dc_destdir" distuninstallcheck; \ } || { rm -rf "$dc_destdir"; exit 1; }) \ && rm -rf "$dc_destdir" \ && make dist \ && rm -rf marchande-2.0.tar.gz \ && make distcleancheck \ && cd "$am__cwd" \ || exit 1 checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make all-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » CC src/main.o CC src/libmarchande.lo CC src/parser.lo CC src/lexer.lo CC src/complete.o CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande CCLD src/marchande_complete make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » TEXI2DVI doc/marchande.dvi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make check-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make src/check make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » CC src/check.o CCLD src/check make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make check-TESTS make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » PASS: src/run-test ============================================================================ Testsuite summary for marchande 2.0 ============================================================================ # TOTAL: 1 # PASS: 1 # SKIP: 0 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 ============================================================================ make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make install-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/include' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin/marchande_complete make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1]: rien à faire pour « installcheck ». make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin' && rm -f marchande marchande_complete ) rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/doc/marchande/marchande.dvi' ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/include' && rm -f marchande.h ) rm -rf '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/doc/marchande/marchande.html' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/doc/marchande/marchande.ps' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/doc/marchande/marchande.pdf' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' --remove '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info/marchande.info' cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make install-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » /bin/mkdir -p '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/include' /bin/mkdir -p '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin' /bin/mkdir -p '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' install-info --info-dir='/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin/marchande_complete make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » ( cd '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/bin' && rm -f marchande marchande_complete ) ( cd '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/include' && rm -f marchande.h ) rm -f '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/doc/marchande/marchande.pdf' rm -rf '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/doc/marchande/marchande.html' rm -f '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/doc/marchande/marchande.dvi' rm -f '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/doc/marchande/marchande.ps' install-info --info-dir='/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' --remove '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info/marchande.info' cd '/tmp/am-dc-32489//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make dist-gzip am__post_remove_distdir='@:' make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make distdir-am make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » if test -d "marchande-2.0"; then find "marchande-2.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.0" || { sleep 5 && rm -rf "marchande-2.0"; }; else :; fi test -d "marchande-2.0" || mkdir "marchande-2.0" make \ top_distdir="marchande-2.0" distdir="marchande-2.0" \ dist-info make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » test -n "" \ || find "marchande-2.0" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-2.0" make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » tardir=marchande-2.0 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-2.0.tar.gz make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » if test -d "marchande-2.0"; then find "marchande-2.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.0" || { sleep 5 && rm -rf "marchande-2.0"; }; else :; fi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » test -z "doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html" \ || rm -rf doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html rm -rf .libs _libs test -z "src/libmarchande.la" || rm -f src/libmarchande.la rm -rf doc/marchande.t2d doc/marchande.t2p rm -f src/marchande src/marchande_complete rm -f src/check rm -f *.o test -z "src/run-test.log" || rm -f src/run-test.log rm -f *.lo rm -rf src/.libs src/_libs rm -f *.tab.c test -z "" || rm -f rm -f src/*.o test -z "src/run-test.trs" || rm -f src/run-test.trs rm -f config.h stamp-h1 rm -f libtool config.lt test . = "../.." || test -z "" || rm -f rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags rm -f src/so_locations rm -f src/*.lo test -z "test-suite.log" || rm -f test-suite.log rm -f doc/.dirstamp rm -f cscope.out cscope.in.out cscope.po.out cscope.files rm -f src/.deps/.dirstamp rm -f src/.dirstamp rm -f config.status config.cache config.log configure.lineno config.status.lineno rm -f src/.deps/check.Po rm -f src/.deps/complete.Po rm -f src/.deps/lexer.Plo rm -f src/.deps/libmarchande.Plo rm -f src/.deps/main.Po rm -f src/.deps/parser.Plo rm -f Makefile make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2/marchande-2.0/_build/sub » if test -d "marchande-2.0"; then find "marchande-2.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.0" || { sleep 5 && rm -rf "marchande-2.0"; }; else :; fi =============================================== marchande-2.0 archives ready for distribution: marchande-2.0.tar.gz =============================================== Built
Maintenant, pour faire le test, il n'y a pas besoin de tout cela.
cp v2/marchande-2.0.tar.gz /tmp cd /tmp tar xf marchande-2.0.tar.gz mkdir -p build cd build ../marchande-2.0/configure --prefix=/tmp/v2 2>&1 make V=0 -j 2>&1 make V=0 -j install 2>&1
checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make all-am make[1] : on entre dans le répertoire « /tmp/build » CC src/complete.o CC src/main.o CC src/libmarchande.lo CC src/lexer.lo CC src/parser.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande CCLD src/marchande_complete make[1] : on quitte le répertoire « /tmp/build » make install-am make[1] : on entre dans le répertoire « /tmp/build » make[2] : on entre dans le répertoire « /tmp/build » /bin/mkdir -p '/tmp/v2/include' /bin/mkdir -p '/tmp/v2/bin' /bin/mkdir -p '/tmp/v2/share/info' /usr/bin/install -c -m 644 ../marchande-2.0/src/marchande.h '/tmp/v2/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/tmp/v2/bin' /usr/bin/install -c -m 644 ../marchande-2.0/doc/marchande.info '/tmp/v2/share/info' install-info --info-dir='/tmp/v2/share/info' '/tmp/v2/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/v2/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /tmp/v2/bin/marchande_complete make[2] : on quitte le répertoire « /tmp/build » make[1] : on quitte le répertoire « /tmp/build »
On peut toujours tester l'adéquation avec la version 1 :
cat > test_input.txt <<EOF a bunch of radishes 1 kg of tomatoes 1.3 kg of potatoes What do you think of Free software? that will be all EOF /tmp/v1/bin/marchande < test_input.txt > v1_output.txt 2>v1_error.txt || exit 1 /tmp/v2/bin/marchande < test_input.txt > v2_output.txt 2>v2_error.txt || exit 1 md5sum v*_output.txt v*_error.txt
57c1afc1bbbd0104da3631bf8c65a4bf v11_output.txt 57c1afc1bbbd0104da3631bf8c65a4bf v1_output.txt 57c1afc1bbbd0104da3631bf8c65a4bf v2_output.txt f2a688e4abd31a2d045ebb0111f2ccea v11_error.txt f2a688e4abd31a2d045ebb0111f2ccea v1_error.txt f2a688e4abd31a2d045ebb0111f2ccea v2_error.txt
Mais il faut surtout tester le programme de complétion.
cat > completion_expected.txt <<EOF Complete 'that will be all' that Complete 'that will be all' that Can't guess a number Don't expect radishes potatoes Guess the unit bunch Ambiguous 1 a EOF export PATH=/tmp/v2/bin:$PATH ( echo "Complete 'that will be all'" \ && marchande_complete "" "" \ && echo "Complete 'that will be all'" \ && marchande_complete "" "will be all" \ && echo "Can't guess a number" \ && marchande_complete "1." "kg of potatoes" \ && echo "Don't expect radishes" \ && marchande_complete "1.3 kg of" "" \ && echo "Guess the unit" \ && marchande_complete "1 " "of radishes" \ && echo "Ambiguous" \ && marchande_complete "" "bunch of radishes" ) > completion_actual.txt || exit 1 md5sum completion_expected.txt completion_actual.txt
93362c72d2101054e85def2660fa742a completion_expected.txt 93362c72d2101054e85def2660fa742a completion_actual.txt
6 Intégration de readline//readline est une bibliothèque qui permet à l'utilisateur d'entrer
une ligne de commande. Elle a de nombreuses fonctionnalités, c'en est presque un éditeur de texte. En particulier, elle permet de demander l'auto-complétion ! Par conséquent, c'est exactement ce que l'on veut pour notre programme.
Heureusement, nous avons déjà fait presque tout le travail. Il y a
deux choses à modifier : la fonction pb_pull_char
, définie dans le
programme 113 (ainsi que le type
behavior_input_stream
, programme 112), et
l'utilisation de notre fonction d'auto-complétion dans
l'initialisation du programme principal (programme 132).
6.1 Changement de comportement pour charger l'entrée utilisateur
Nous allons devoir stocker la ligne toute entière, pour deux raisons :
- l'entrée est attendue octet par octet ;
- pour appeler l'auto-complétion, il faudra analyser toute la ligne. En vérité, il faudrait analyser toute la commande, c'est-à-dire tout le texte depuis la dernière commande, mais pour cette application nous allons nous contenter de la ligne.
On modifie donc le programme 112 en 139.
typedef enum behavior_input_type behavior_input_type; enum behavior_input_type { MARCHANDE_STREAM, MARCHANDE_BATCH }; typedef struct behavior_input_stream behavior_input_stream; struct behavior_input_stream { int produce_mode; char *last_line; size_t i_last_line; }; typedef struct behavior_input_batch behavior_input_batch; struct behavior_input_batch { char *ptr; }; typedef union behavior_input_u behavior_input_u; union behavior_input_u { behavior_input_stream stream; behavior_input_batch batch; }; typedef struct behavior_data behavior_data; struct behavior_data { behavior_input_type t; behavior_input_u u; };
Et on modifie le programme 113
en 140. Le résultat est à
peu près le même, mais comme readline
oublie le caractère de fin de
ligne il faut qu'on le rajoute à la main.
static char * add_lf (char *input) { size_t len = strlen (input); static const char *added = "\n"; size_t len_added = strlen (added); char *ret = malloc (len + len_added + 1); if (ret == NULL) { abort (); } strcpy (ret, input); strcat (ret, added); free (input); return ret; } static int pb_pull_char (void *data, int prompt_type, char *c) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM) { int i = 0; if (behavior->u.stream.last_line == NULL) { /* Initially, this is set to NULL. */ behavior->u.stream.last_line = malloc (1); behavior->u.stream.last_line[0] = '\0'; if (behavior->u.stream.last_line == NULL) { abort (); } } while (behavior->u.stream.last_line[behavior->u.stream.i_last_line] == '\0') { char *newline = NULL; if (prompt_type == 1) { newline = readline (marchande_main_prompt ()); } else { newline = readline (marchande_secondary_prompt ()); } if (newline == NULL) { return 0; } if (strcmp (newline, "") != 0) { add_history (newline); } newline = add_lf (newline); free (behavior->u.stream.last_line); behavior->u.stream.last_line = NULL; behavior->u.stream.last_line = newline; behavior->u.stream.i_last_line = 0; } i = behavior->u.stream.last_line[behavior->u.stream.i_last_line]; behavior->u.stream.i_last_line += 1; c[0] = i; return 1; } else { if (strcmp (behavior->u.batch.ptr, "") == 0) { return 0; } c[0] = behavior->u.batch.ptr[0]; behavior->u.batch.ptr = & (behavior->u.batch.ptr[1]); return 1; } }
6.2 Appel de la fonction d'auto-complétion
Pour mettre en place l'auto-complétion, il faut rajouter la fonction 141.
static char **completions_to_give; static size_t i_completion_to_give; static char * generator (const char *text, int state) { (void) state; if (completions_to_give[i_completion_to_give] == NULL) { return NULL; } if (strncmp (completions_to_give[i_completion_to_give], text, strlen (text)) == 0) { return completions_to_give[i_completion_to_give++]; } free (completions_to_give[i_completion_to_give++]); return generator (text, state); } static char ** get_readline_completions (const char *base, int start, int end) { char *left, *right; size_t line_buffer_len = strlen (rl_line_buffer); char **ret = NULL; rl_attempted_completion_over = 1; left = malloc (start + 1); right = malloc (line_buffer_len - end + 1); if (left == NULL || right == NULL) { abort (); } strncpy (left, rl_line_buffer, start); strncpy (right, rl_line_buffer + end, line_buffer_len - end); left[start] = '\0'; right[line_buffer_len - end] = '\0'; completions_to_give = marchande_complete (left, right); free (left); free (right); i_completion_to_give = 0; ret = rl_completion_matches (base, generator); free (completions_to_give); completions_to_give = NULL; return ret; } static void setup_readline () { rl_attempted_completion_function = get_readline_completions; }
6.3 Mise en place de la nouvelle version
Comme à notre habitude, recopions l'ensemble du code source.
6.3.1 Le parseur
Il ne change pas. On obtient toujours la même version, programme 142.
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %code requires { struct marchande_parser_behavior; typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_completer_candidate; typedef struct marchande_completer_candidate marchande_completer_candidate; } %{ #include <marchande_private.h> #include <stdio.h> #include <stdlib.h> #define _(String) String int _marchande_lex (_MARCHANDE_STYPE *yylval, void *scanner); void _marchande_error (marchande_parser_behavior *behavior, int *prompt_type, void *scanner, marchande_completer_candidate **completions, const char *error) { (void) error; } int _marchande_wrap () { return 1; } void _marchande_add_completion (marchande_completer_candidate **completions, const char *candidate); %} %define api.pure full %define api.push-pull both %parse-param {marchande_parser_behavior *behavior} %parse-param {int *prompt_type} %parse-param {marchande_completer_candidate **completions} %param {void * scanner} %define api.prefix {_marchande_} %define api.value.type union %token THAT %token WILL %token BE %token ALL %token A %token KG %token BUNCH %token BUNCHES %token OF %token POTATOES %token RADISHES %token END_OF_PHRASE %token <int> INTEGER %token <double> DECIMAL %token <char *> UNKNOWN_WORD %destructor { free ($$); } UNKNOWN_WORD %type <int> bunches %type <double> weight %token MODE_DEFAULT %token MODE_COMPLETE %token AUTOCOMPLETE %% run: MODE_DEFAULT interaction | MODE_COMPLETE completion | MODE_COMPLETE error { yyerrok; } ; interaction: %empty | interaction command | interaction error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; } command: THAT WILL BE ALL { YYACCEPT; } | weight OF POTATOES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bunches OF RADISHES { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | weight OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bunches OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } weight: DECIMAL KG { $$ = $1; } | INTEGER KG { $$ = (double) $1; } ; bunches: A BUNCH { $$ = 1; } | INTEGER BUNCHES { $$ = $1; } ; completion: AUTOCOMPLETE { _marchande_add_completion (completions, "that"); /* Don't provide completions for the numbers */ } | AUTOCOMPLETE WILL { _marchande_add_completion (completions, "that"); } | THAT AUTOCOMPLETE { _marchande_add_completion (completions, "will"); } | THAT WILL AUTOCOMPLETE { _marchande_add_completion (completions, "be"); } | THAT WILL BE AUTOCOMPLETE { _marchande_add_completion (completions, "all"); } | weight OF AUTOCOMPLETE { _marchande_add_completion (completions, "potatoes"); } | INTEGER AUTOCOMPLETE { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE OF { _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE KG { /* Cannot complete a decimal number */ } | INTEGER AUTOCOMPLETE OF RADISHES { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } } | AUTOCOMPLETE BUNCH OF RADISHES { _marchande_add_completion (completions, "1"); _marchande_add_completion (completions, "a"); } %%
6.3.2 Le lexeur
Il n'y a rien à changer non plus. On obtient toujours le programme 143.
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %{ #include <config.h> #include "parser.h" #include <marchande_private.h> #include <string.h> #include <marchande.h> #define YY_INPUT(buf, result, max_size) { \ result = yyextra.behavior->pull_char (yyextra.behavior->data, * (yyextra.prompt_type), buf); \ } #define YY_USER_ACTION { \ * (yyextra.prompt_type) = 2; \ yyextra.behavior->before_token (yyextra.behavior->data, yytext); \ } #define YYSTYPE _MARCHANDE_STYPE %} %option extra-type="marchande_lexer_extra" %option bison-bridge %option prefix="_marchande_" %option reentrant %% %{ int ret; if (yyextra.behavior->prologue (yyextra.behavior->data, &ret, yylval)) { return ret; } %} that { return THAT; } will { return WILL; } be { return BE; } all { return ALL; } [0-9]+ { yylval->INTEGER = (unsigned int) strtoul (yytext, NULL, 10); return INTEGER; } [0-9]+\.[0-9]* { yylval->DECIMAL = strtod (yytext, NULL); return DECIMAL; } of { return OF; } kg { return KG; } a { return A; } bunch { return BUNCH; } bunches { return BUNCHES; } potatoes { return POTATOES; } radishes { return RADISHES; } [ \t\n]+ /* do nothing */ [^ \t\n.,?!0-9]+ { yylval->UNKNOWN_WORD = strdup (yytext); return UNKNOWN_WORD; } [.,?!] { return END_OF_PHRASE; } %% void marchande_parse (marchande_parser_behavior *behavior) { int prompt_type = 1; marchande_lexer_extra extra; yyscan_t scanner; extra.prompt_type = &prompt_type; extra.behavior = behavior; _marchande_lex_init_extra (extra, &scanner); _marchande_parse (behavior, &prompt_type, NULL, scanner); _marchande_lex_destroy (scanner); } void _marchande_add_completion (marchande_completer_candidate **data, const char *candidate) { marchande_completer_candidate *next = malloc (sizeof (marchande_completer_candidate)); marchande_completer_candidate *old = *data; if (next == NULL) { abort (); } next->previous = old; next->candidate = strdup (candidate); *data = next; } char ** marchande_complete (const char *left, const char *right) { behavior_data data; _marchande_pstate *ps = _marchande_pstate_new (); int done = 0; int token = 0; _MARCHANDE_STYPE lval; yyscan_t scanner; marchande_parser_behavior behavior; marchande_lexer_extra extra; int prompt_type = 1; size_t n_completions, i_completion; marchande_completer_candidate *completions = NULL; marchande_completer_candidate *i, *aux; char **ret = NULL;; data.t = MARCHANDE_BATCH; behavior.data = &data; behavior.syntax_error = &pb_syntax_error; behavior.buy_potatoes = &pb_buy_potatoes; behavior.buy_radishes = &pb_buy_radishes; behavior.value_error = &pb_value_error; behavior.pull_char = &pb_pull_char; behavior.prologue = &pb_prologue; behavior.before_token = &pb_before_token; extra.prompt_type = &prompt_type; extra.behavior = &behavior;; data.u.batch.ptr = (char *) left; _marchande_lex_init_extra (extra, &scanner); _marchande_push_parse (ps, MODE_COMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, AUTOCOMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); data.u.batch.ptr = (char *) right; do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, 0, NULL, &behavior, &prompt_type, &completions, scanner); _marchande_pstate_delete (ps); _marchande_lex_destroy (scanner); n_completions = 0; for (i = completions; i != NULL; i = i->previous) { n_completions++; } ret = malloc ((n_completions + 1) * sizeof (char *)); if (ret == NULL) { abort (); } i_completion = 0; for (i = completions; i != NULL; i = aux) { ret[n_completions - (i_completion++) - 1] = i->candidate; aux = i->previous; free (i); } ret[n_completions] = NULL; return ret;; }
6.3.3 L'en-tête principal
Toujours rien à changer pour le programme 144.
/* * File: src/marchande.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_INCLUDED #define H_MARCHANDE_INCLUDED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ union _MARCHANDE_STYPE; typedef union _MARCHANDE_STYPE _MARCHANDE_STYPE; typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_parser_behavior { void *data; void (*syntax_error) (void *data); void (*buy_potatoes) (void *data, double weight); void (*buy_radishes) (void *data, int bunches); void (*value_error) (void *data, const char *what); /* Return 0 if EOF, 1 otherwise */ int (*pull_char) (void *data, int prompt_type, char *c); /* Return non-zero if we must return immediately */ int (*prologue) (void *data, int *token, _MARCHANDE_STYPE *yylval); void (*before_token) (void *data, const char *text); }; extern marchande_parser_behavior *marchande_default_parser_behavior; /** * marchande_init: * * Initializes the library. * * Returns: an error code, 0 on success or 1 if an error happened. */ int marchande_init (); /** * marchande_value_error */ void marchande_value_error (const char *what); /** * marchande_syntax_error */ void marchande_syntax_error (); /** * marchande_buy_radishes: */ void marchande_buy_radishes (int bunches); /** * marchande_buy_potatoes: */ void marchande_buy_potatoes (double weight); /** * marchande_exit: */ void marchande_exit (); /** * marchande_main_prompt: */ const char *marchande_main_prompt (); /** * marchande_secondary_prompt: */ const char *marchande_secondary_prompt (); /** * marchande_parse: * @param behavior: the behavior to implement. You can pass * 'marchande_default_parser_behavior' here. */ void marchande_parse (marchande_parser_behavior *behavior); /** * marchande_complete: * Returns: (array null-terminated) (transfer full): the list of * possible completions. */ char **marchande_complete (const char *left, const char *right); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* not H_MARCHANDE_INCLUDED */
6.3.4 L'implémentation de la bibliothèque
Le comportement par défaut du parseur ayant changé, il faut modifier cette valeur. On obtient le programme 145.
/* * File: src/libmarchande.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdio.h> #include <stdlib.h> #define _(String) (String) #define N_(String) (String) static int n_radishes; static double weight_potatoes; #include <marchande.h> int marchande_init () { n_radishes = 0; weight_potatoes = 0.0; printf (_ ("marchande Copyright (C) 2019 Vivien Kraus\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions.\nSee the GNU General Public License for details.\n\nTrying to recover from this unexpected assault of legalese, you look\nup to the merchant. She has:\n * a few bunches of radishes;\n * some potatoes.\n\n- Next! Hello :) What will it be?\n")); return 0; } void marchande_value_error (const char *what) { fprintf (stderr, _ ("- Sorry, I don't have %s.\n"), what); } void marchande_syntax_error () { fprintf (stderr, _ ("- Huh?\n\nThe merchant did not understand what you were trying to say.\n")); } void marchande_buy_radishes (int bunches) { n_radishes += bunches; printf (_ ("The merchant takes the radishes and put them aside for you.\n- And with this?\n")); } void marchande_buy_potatoes (double weight) { weight_potatoes += weight; printf (_ ("The merchant takes the potatoes and put them aside for you.\n- And with this?\n")); } void marchande_exit () { printf (_ ("You pay the merchant, take your belongings, and leave.\n")); } const char * marchande_main_prompt () { static const char *ret_c = N_("- "); return _ (ret_c); } const char * marchande_secondary_prompt () { static const char *ret_c = N_("The merchant waits patiently as you try to end your sentence.\n- "); return _ (ret_c); } #include <marchande_private.h> #include "src/parser.h" static behavior_data default_behavior_data = { .t = MARCHANDE_STREAM, .u = { .stream = { .produce_mode = 1, .last_line = NULL, .i_last_line = 0 } } }; static marchande_parser_behavior default_parser_behavior = { (void *) &default_behavior_data, &pb_syntax_error, &pb_buy_potatoes, &pb_buy_radishes, &pb_value_error, &pb_pull_char, &pb_prologue, &pb_before_token }; marchande_parser_behavior *marchande_default_parser_behavior = &default_parser_behavior;
6.3.5 L'implémentation de l'en-tête privé
L'en-tête privé change, puisqu'on a le nouveau comportement compatible readline. On obtient le programme 146.
/* * File: src/marchande_private.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_PRIVATE_INCLUDED #define H_MARCHANDE_PRIVATE_INCLUDED #include <config.h> #include <marchande.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include "src/parser.h" #include <readline/readline.h> #include <readline/history.h> typedef struct marchande_completer_candidate marchande_completer_candidate; struct marchande_completer_candidate { char *candidate; marchande_completer_candidate *previous; }; typedef struct { int *prompt_type; marchande_parser_behavior *behavior; } marchande_lexer_extra; typedef enum behavior_input_type behavior_input_type; enum behavior_input_type { MARCHANDE_STREAM, MARCHANDE_BATCH }; typedef struct behavior_input_stream behavior_input_stream; struct behavior_input_stream { int produce_mode; char *last_line; size_t i_last_line; }; typedef struct behavior_input_batch behavior_input_batch; struct behavior_input_batch { char *ptr; }; typedef union behavior_input_u behavior_input_u; union behavior_input_u { behavior_input_stream stream; behavior_input_batch batch; }; typedef struct behavior_data behavior_data; struct behavior_data { behavior_input_type t; behavior_input_u u; }; static void pb_syntax_error (void *data) { (void) data; marchande_syntax_error (); } static void pb_buy_potatoes (void *data, double weight) { (void) data; marchande_buy_potatoes (weight); } static void pb_buy_radishes (void *data, int bunches) { (void) data; marchande_buy_radishes (bunches); } static void pb_value_error (void *data, const char *what) { (void) data; marchande_value_error (what); } static char * add_lf (char *input) { size_t len = strlen (input); static const char *added = "\n"; size_t len_added = strlen (added); char *ret = malloc (len + len_added + 1); if (ret == NULL) { abort (); } strcpy (ret, input); strcat (ret, added); free (input); return ret; } static int pb_pull_char (void *data, int prompt_type, char *c) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM) { int i = 0; if (behavior->u.stream.last_line == NULL) { /* Initially, this is set to NULL. */ behavior->u.stream.last_line = malloc (1); behavior->u.stream.last_line[0] = '\0'; if (behavior->u.stream.last_line == NULL) { abort (); } } while (behavior->u.stream.last_line[behavior->u.stream.i_last_line] == '\0') { char *newline = NULL; if (prompt_type == 1) { newline = readline (marchande_main_prompt ()); } else { newline = readline (marchande_secondary_prompt ()); } if (newline == NULL) { return 0; } if (strcmp (newline, "") != 0) { add_history (newline); } newline = add_lf (newline); free (behavior->u.stream.last_line); behavior->u.stream.last_line = NULL; behavior->u.stream.last_line = newline; behavior->u.stream.i_last_line = 0; } i = behavior->u.stream.last_line[behavior->u.stream.i_last_line]; behavior->u.stream.i_last_line += 1; c[0] = i; return 1; } else { if (strcmp (behavior->u.batch.ptr, "") == 0) { return 0; } c[0] = behavior->u.batch.ptr[0]; behavior->u.batch.ptr = & (behavior->u.batch.ptr[1]); return 1; } } static int pb_prologue (void *data, int *token, _MARCHANDE_STYPE *lval) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM && behavior->u.stream.produce_mode) { behavior->u.stream.produce_mode = 0; *token = MODE_DEFAULT; return 1; } return 0; } static void pb_before_token (void *data, const char *text) { (void) data; } #endif /* not H_MARCHANDE_PRIVATE_INCLUDED */
6.3.6 L'implémentation du test
Le test est encore une fois le même. On obtient de nouveau les programmes 147 et 148.
/* * File: src/check.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } printf ("%s1 bunch of radishes\n", marchande_main_prompt ()); marchande_buy_radishes (1); printf ("%s1kg of tomatoes\n", marchande_main_prompt ()); fflush (stdout); marchande_value_error ("tomatoes"); fflush (stderr); printf ("%s1kg\n", marchande_main_prompt ()); printf ("%sof potatoes\n", marchande_secondary_prompt ()); marchande_buy_potatoes (1.0); printf ("%sWhat do you think of Free Software?\n", marchande_main_prompt ()); fflush (stdout); marchande_syntax_error (); fflush (stderr); printf ("%sThat will be all.\n", marchande_main_prompt ()); marchande_exit (); return EXIT_SUCCESS; }
export LANG=C EXPECTED=$( cat <<EOF marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - 1 bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1kg of tomatoes - Sorry, I don't have tomatoes. - 1kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free Software? - Huh? The merchant did not understand what you were trying to say. - That will be all. You pay the merchant, take your belongings, and leave. EOF ) ACTUAL=$(./src/check 2>&1) echo "Expected:" echo "$EXPECTED" echo "Actual:" echo "$ACTUAL" if test "x$EXPECTED" = "x$ACTUAL" then echo "OK" else >&2 echo "Failed." exit 1 fi
6.3.7 Le programme principal
Pour le programme principal, on rajoute simplement un appel à
setup_readline
. On obtient le programme 149.
#include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <readline/readline.h> #include <readline/history.h> static char **completions_to_give; static size_t i_completion_to_give; static char * generator (const char *text, int state) { (void) state; if (completions_to_give[i_completion_to_give] == NULL) { return NULL; } if (strncmp (completions_to_give[i_completion_to_give], text, strlen (text)) == 0) { return completions_to_give[i_completion_to_give++]; } free (completions_to_give[i_completion_to_give++]); return generator (text, state); } static char ** get_readline_completions (const char *base, int start, int end) { char *left, *right; size_t line_buffer_len = strlen (rl_line_buffer); char **ret = NULL; rl_attempted_completion_over = 1; left = malloc (start + 1); right = malloc (line_buffer_len - end + 1); if (left == NULL || right == NULL) { abort (); } strncpy (left, rl_line_buffer, start); strncpy (right, rl_line_buffer + end, line_buffer_len - end); left[start] = '\0'; right[line_buffer_len - end] = '\0'; completions_to_give = marchande_complete (left, right); free (left); free (right); i_completion_to_give = 0; ret = rl_completion_matches (base, generator); free (completions_to_give); completions_to_give = NULL; return ret; } static void setup_readline () { rl_attempted_completion_function = get_readline_completions; } int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } setup_readline (); marchande_parse (marchande_default_parser_behavior); marchande_exit (); return EXIT_SUCCESS; }
6.3.8 Le programme d'auto-complétion
Le programme d'auto-complétion ne change pas. On obtient toujours le programme 150.
#include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char **completions; size_t i = 0; if (argc != 3) { fprintf (stderr, "Usage: complete \"text before\" \"text after\"\n"); return EXIT_FAILURE; } completions = marchande_complete (argv[1], argv[2]); for (i = 0; completions[i] != NULL; i++) { printf ("%s\n", completions[i]); free (completions[i]); } free (completions); return EXIT_SUCCESS; }
6.3.9 Le manuel
Pour le manuel, on modifie simplement le numéro de version dans le programme 151 pour obtenir le programme 152.
ORGFILE=$(mktemp XXXXXXX.org) trap "{ rm -rf $ORGFILE; }" EXIT cat > $ORGFILE <<EOF #+macro: version 2.1 # Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+subitile: version {{{version}}} of the program #+author: Vivien Kraus #+email: vivien@planete-kraus.eu #+options: ':t toc:t author:t email:t #+language: en #+texinfo_filename: marchande.info #+texinfo_dir_category: Games #+texinfo_dir_title: marchande: (marchande) #+texinfo_dir_desc: Marchande #+texinfo_printed_title: Marchande #+texinfo: @documentencoding UTF-8 This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction #+include: "./index.org::*Le jeu de la marchande, en anglais (désolé si c'est mal traduit)" :only-contents t * Invoking =marchande= #+include: "./index.org::*Description de la syntaxe, en anglais" :only-contents t * Invoking =marchande_complete= #+include: "./index.org::*Invocation de =marchande_complete=, en anglais" :only-contents t EOF LANG=C emacs --batch \ --file $ORGFILE \ --eval "(require 'ox-texinfo)" \ -f org-texinfo-export-to-texinfo \ || exit 1 cat "$(basename $ORGFILE .org).texi"
\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename marchande.info @settitle Play the merchant @documentencoding UTF-8 @documentlanguage en @c %**end of header @copying This manual is for Marchande (version 2.1), an example about how to make a command-line interface. Copyright @copyright{} 2019 Vivien Kraus @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. @end quotation @end copying @dircategory Games @direntry * marchande: (marchande). Marchande. @end direntry @finalout @titlepage @title Marchande @author Vivien Kraus (@email{vivien@@planete-kraus.eu}) @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top @top Play the merchant @documentencoding UTF-8 This manual is for marchande version 2.1. @end ifnottex @menu * Introduction:: * Invoking @samp{marchande}:: * Invoking @samp{marchande_complete}:: @end menu @node Introduction @chapter Introduction You find yourself facing the organic vegetable seller. In front of her, on her stall, you see a crate containing @strong{potatoes} and @strong{bunches of radishes}. The seller thanks the previous customer and turns to you. @quotation @itemize @item Next! What will it be? @end itemize @end quotation You need to buy a few radishes and potatoes. You're going to have to be able to buy it from the merchant@dots{} @node Invoking @samp{marchande} @chapter Invoking @samp{marchande} When you run the @samp{marchande} program, you have a command-line interface. There are several options: @itemize @item say @samp{that will be all}, and the program exits; @item say @samp{a bunch of radishes}, or @samp{2 bunches of radishes}, or another number, to add some radishes; @item say @samp{1.3kg of potatoes}, to add some potatoes. @end itemize @node Invoking @samp{marchande_complete} @chapter Invoking @samp{marchande_complete} The @samp{marchande_complete} program is used in the following way: @example marchande_complete "TEXT BEFORE" "TEXT AFTER" @end example The program prints either nothing, or the list of possibilities for the first word between the text before and the text after. In case of a number, nothing is proposed. In case of an error, the program exits with code 1. @bye
6.3.10 La configuration avec autoconf
Pour la configuration, il faut maintenant chercher l'installation de
readline
. On obtient le programme 153.
dnl Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> dnl dnl This program is free software: you can redistribute it and/or dnl modify it under the terms of the GNU General Public License as dnl published by the Free Software Foundation, either version 3 of the dnl License, or (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see dnl <http://www.gnu.org/licenses/>. AC_PREREQ([2.69]) AC_INIT([marchande], [2.1], [vivien@planete-kraus.eu]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([m4]) AC_PROG_CC AM_MISSING_PROG([LEX], [flex]) AM_MISSING_PROG([YACC], [bison]) AM_INIT_AUTOMAKE([foreign subdir-objects]) LT_INIT AC_CHECK_HEADERS([readline/readline.h readline/history.h], [], [ AC_MSG_ERROR([Readline is required.]) ]) AC_SEARCH_LIBS([readline], [readline], [], [ AC_MSG_ERROR([Readline is required.]) ]) AC_SEARCH_LIBS([add_history], [readline], [], [ AC_MSG_ERROR([Readline history is required.]) ]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT
6.3.11 Le Makefile
On n'a en fait rien à rajouter ici. On obtient le programme 154.
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. dist_noinst_SCRIPTS = src/run-test noinst_LTLIBRARIES = src/libmarchande.la include_HEADERS = src/marchande.h info_TEXINFOS = doc/marchande.texi check_PROGRAMS = src/check src_check_LDADD = src/libmarchande.la AM_CPPFLAGS = -I $(srcdir)/src -I . TESTS = src/run-test bin_PROGRAMS = src/marchande src_libmarchande_la_SOURCES = src/libmarchande.c src/parser.c src/lexer.c src_marchande_SOURCES = src/main.c src_marchande_LDADD = src/libmarchande.la EXTRA_DIST = src/parser.y src/parser.h src/parser.stamp src/lexer.l MAINTAINERCLEANFILES = src/parser.h src/parser.c src/parser.stamp src/lexer.c BUILT_SOURCES = src/parser.h dist_noinst_HEADERS = src/marchande_private.h .l.c: $(AM_V_GEN) (cd $(srcdir) && $(LEX) -o $@-t $<) @mv $(srcdir)/$@-t $(srcdir)/$@ $(srcdir)/src/parser.stamp: src/parser.y $(AM_V_GEN) (cd $(srcdir) && $(YACC) src/parser.y -o src/parser.c --defines=src/parser.h) @touch $(srcdir)/src/parser.stamp $(srcdir)/src/parser.h $(srcdir)/src/parser.c: $(srcdir)/src/parser.stamp @dry=; for f in x $$MAKEFLAGS; do \ case $$f in \ *=*|--*);; \ *n*) dry=:;; \ esac; \ done; \ if test -f $@; then :; else \ $$dry trap 'rm -rf $(srcdir)/src/parser.lock $(srcdir)/src/parser.stamp' 1 2 13 15; \ if $$dry mkdir $(srcdir)/src/parser.lock 2>/dev/null; then \ $$dry rm -f $(srcdir)/src/parser.stamp || exit 1; \ $(MAKE) $(AM_MAKEFLAGS) src/parser.stamp; \ $$dry rmdir $(srcdir)/src/parser.lock; \ else \ while test -d $(srcdir)/src/parser.lock && test -z "$$dry"; do \ sleep 1; \ done; \ $$dry test -f $(srcdir)/src/parser.stamp; exit $$?; \ fi; \ fi bin_PROGRAMS += src/marchande_complete src_marchande_complete_SOURCES = src/complete.c src_marchande_complete_LDADD = src/libmarchande.la
6.4 Testons !
Pour obtenir la distribution source, j'ai fait ceci :
cd v2.1 autoreconf -vif 2>&1 ./configure 2>&1 make V=0 -j 16 all 2>&1 make V=0 -j 16 distcheck 2>&1 echo "Built"
autoreconf: Entering directory `.' autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal --force aclocal: warning: couldn't open directory 'm4': No such file or directory autoreconf: configure.ac: tracing autoreconf: running: libtoolize --copy --force libtoolize: putting auxiliary files in '.'. libtoolize: copying file './ltmain.sh' libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'. libtoolize: copying file 'm4/libtool.m4' libtoolize: copying file 'm4/ltoptions.m4' libtoolize: copying file 'm4/ltsugar.m4' libtoolize: copying file 'm4/ltversion.m4' libtoolize: copying file 'm4/lt~obsolete.m4' libtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am. autoreconf: running: /usr/bin/autoconf --force autoreconf: running: /usr/bin/autoheader --force autoreconf: running: automake --add-missing --copy --force-missing configure.ac:20: installing './compile' configure.ac:24: installing './config.guess' configure.ac:24: installing './config.sub' configure.ac:23: installing './install-sh' configure.ac:21: installing './missing' Makefile.am: installing './depcomp' Makefile.am:20: installing './texinfo.tex' parallel-tests: installing './test-driver' autoreconf: Leaving directory `.' checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking readline/readline.h usability... yes checking readline/readline.h presence... yes checking for readline/readline.h... yes checking readline/history.h usability... yes checking readline/history.h presence... yes checking for readline/history.h... yes checking for library containing readline... -lreadline checking for library containing add_history... none required checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands GEN src/parser.stamp make all-am make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1 » MAKEINFO doc/marchande.info GEN src/lexer.c CC src/main.o CC src/libmarchande.lo CC src/parser.lo CC src/complete.o CC src/lexer.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande CCLD src/marchande_complete make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1 » make dist-gzip am__post_remove_distdir='@:' make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1 » make distdir-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1 » if test -d "marchande-2.1"; then find "marchande-2.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.1" || { sleep 5 && rm -rf "marchande-2.1"; }; else :; fi test -d "marchande-2.1" || mkdir "marchande-2.1" make \ top_distdir="marchande-2.1" distdir="marchande-2.1" \ dist-info make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1 » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1 » test -n "" \ || find "marchande-2.1" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-2.1" make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1 » tardir=marchande-2.1 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-2.1.tar.gz make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1 » if test -d "marchande-2.1"; then find "marchande-2.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.1" || { sleep 5 && rm -rf "marchande-2.1"; }; else :; fi case 'marchande-2.1.tar.gz' in \ *.tar.gz*) \ eval GZIP= gzip --best -dc marchande-2.1.tar.gz | ${TAR-tar} xf - ;;\ *.tar.bz2*) \ bzip2 -dc marchande-2.1.tar.bz2 | ${TAR-tar} xf - ;;\ *.tar.lz*) \ lzip -dc marchande-2.1.tar.lz | ${TAR-tar} xf - ;;\ *.tar.xz*) \ xz -dc marchande-2.1.tar.xz | ${TAR-tar} xf - ;;\ *.tar.Z*) \ uncompress -c marchande-2.1.tar.Z | ${TAR-tar} xf - ;;\ *.shar.gz*) \ eval GZIP= gzip --best -dc marchande-2.1.shar.gz | unshar ;;\ *.zip*) \ unzip marchande-2.1.zip ;;\ esac chmod -R a-w marchande-2.1 chmod u+w marchande-2.1 mkdir marchande-2.1/_build marchande-2.1/_build/sub marchande-2.1/_inst chmod a-w marchande-2.1 test -d marchande-2.1/_build || exit 0; \ dc_install_base=`CDPATH="${ZSH_VERSION+.}:" && cd marchande-2.1/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="${TMPDIR-/tmp}/am-dc-$$/" \ && am__cwd=`pwd` \ && CDPATH="${ZSH_VERSION+.}:" && cd marchande-2.1/_build/sub \ && ../../configure \ \ \ --srcdir=../.. --prefix="$dc_install_base" \ && make \ && make dvi \ && make check \ && make install \ && make installcheck \ && make uninstall \ && make distuninstallcheck_dir="$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$dc_destdir") \ && make DESTDIR="$dc_destdir" install \ && make DESTDIR="$dc_destdir" uninstall \ && make DESTDIR="$dc_destdir" \ distuninstallcheck_dir="$dc_destdir" distuninstallcheck; \ } || { rm -rf "$dc_destdir"; exit 1; }) \ && rm -rf "$dc_destdir" \ && make dist \ && rm -rf marchande-2.1.tar.gz \ && make distcleancheck \ && cd "$am__cwd" \ || exit 1 checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking readline/readline.h usability... yes checking readline/readline.h presence... yes checking for readline/readline.h... yes checking readline/history.h usability... yes checking readline/history.h presence... yes checking for readline/history.h... yes checking for library containing readline... -lreadline checking for library containing add_history... none required checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make all-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » CC src/main.o CC src/libmarchande.lo CC src/parser.lo CC src/lexer.lo CC src/complete.o CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande CCLD src/marchande_complete make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » TEXI2DVI doc/marchande.dvi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make check-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make src/check make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » CC src/check.o CCLD src/check make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make check-TESTS make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » PASS: src/run-test ============================================================================ Testsuite summary for marchande 2.1 ============================================================================ # TOTAL: 1 # PASS: 1 # SKIP: 0 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 ============================================================================ make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make install-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/include' /usr/bin/install -c -m 644 ../../src/marchande.h '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/include' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin/marchande_complete make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1]: rien à faire pour « installcheck ». make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin' && rm -f marchande marchande_complete ) rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/doc/marchande/marchande.dvi' rm -rf '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/doc/marchande/marchande.html' ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/include' && rm -f marchande.h ) rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/doc/marchande/marchande.pdf' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/doc/marchande/marchande.ps' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' --remove '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info/marchande.info' cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make install-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » /bin/mkdir -p '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/include' /bin/mkdir -p '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' /bin/mkdir -p '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin' /usr/bin/install -c -m 644 ../../src/marchande.h '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' install-info --info-dir='/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin/marchande_complete make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » ( cd '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/bin' && rm -f marchande marchande_complete ) rm -rf '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/doc/marchande/marchande.html' rm -f '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/doc/marchande/marchande.dvi' ( cd '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/include' && rm -f marchande.h ) rm -f '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/doc/marchande/marchande.ps' rm -f '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/doc/marchande/marchande.pdf' install-info --info-dir='/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' --remove '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info/marchande.info' cd '/tmp/am-dc-7275//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make dist-gzip am__post_remove_distdir='@:' make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make distdir-am make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » if test -d "marchande-2.1"; then find "marchande-2.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.1" || { sleep 5 && rm -rf "marchande-2.1"; }; else :; fi test -d "marchande-2.1" || mkdir "marchande-2.1" make \ top_distdir="marchande-2.1" distdir="marchande-2.1" \ dist-info make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » test -n "" \ || find "marchande-2.1" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-2.1" make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » tardir=marchande-2.1 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-2.1.tar.gz make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » if test -d "marchande-2.1"; then find "marchande-2.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.1" || { sleep 5 && rm -rf "marchande-2.1"; }; else :; fi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » test -z "doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html" \ || rm -rf doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html rm -rf .libs _libs test -z "src/libmarchande.la" || rm -f src/libmarchande.la rm -f src/marchande src/marchande_complete rm -f src/check rm -rf doc/marchande.t2d doc/marchande.t2p rm -f *.o test -z "src/run-test.log" || rm -f src/run-test.log rm -f *.lo rm -f *.tab.c rm -rf src/.libs src/_libs rm -f src/*.o test -z "src/run-test.trs" || rm -f src/run-test.trs test -z "" || rm -f rm -f config.h stamp-h1 test . = "../.." || test -z "" || rm -f rm -f src/*.lo rm -f libtool config.lt rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags test -z "test-suite.log" || rm -f test-suite.log rm -f doc/.dirstamp rm -f cscope.out cscope.in.out cscope.po.out cscope.files rm -f src/so_locations rm -f src/.deps/.dirstamp rm -f src/.dirstamp rm -f config.status config.cache config.log configure.lineno config.status.lineno rm -f src/.deps/check.Po rm -f src/.deps/complete.Po rm -f src/.deps/lexer.Plo rm -f src/.deps/libmarchande.Plo rm -f src/.deps/main.Po rm -f src/.deps/parser.Plo rm -f Makefile make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v2.1/marchande-2.1/_build/sub » if test -d "marchande-2.1"; then find "marchande-2.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-2.1" || { sleep 5 && rm -rf "marchande-2.1"; }; else :; fi =============================================== marchande-2.1 archives ready for distribution: marchande-2.1.tar.gz =============================================== Built
Installons la version 2.1.
cp v2.1/marchande-2.1.tar.gz /tmp cd /tmp tar xf marchande-2.1.tar.gz mkdir -p build cd build ../marchande-2.1/configure --prefix=/tmp/v2.1 2>&1 make V=0 -j 2>&1 make V=0 -j install 2>&1
checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking readline/readline.h usability... yes checking readline/readline.h presence... yes checking for readline/readline.h... yes checking readline/history.h usability... yes checking readline/history.h presence... yes checking for readline/history.h... yes checking for library containing readline... -lreadline checking for library containing add_history... none required checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands make all-am make[1] : on entre dans le répertoire « /tmp/build » CC src/main.o CC src/libmarchande.lo CC src/parser.lo CC src/lexer.lo CC src/complete.o CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande CCLD src/marchande_complete make[1] : on quitte le répertoire « /tmp/build » make install-am make[1] : on entre dans le répertoire « /tmp/build » make[2] : on entre dans le répertoire « /tmp/build » /bin/mkdir -p '/tmp/v2.1/include' /bin/mkdir -p '/tmp/v2.1/bin' /usr/bin/install -c -m 644 ../marchande-2.1/src/marchande.h '/tmp/v2.1/include' /bin/mkdir -p '/tmp/v2.1/share/info' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/tmp/v2.1/bin' /usr/bin/install -c -m 644 ../marchande-2.1/doc/marchande.info '/tmp/v2.1/share/info' install-info --info-dir='/tmp/v2.1/share/info' '/tmp/v2.1/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/v2.1/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /tmp/v2.1/bin/marchande_complete make[2] : on quitte le répertoire « /tmp/build » make[1] : on quitte le répertoire « /tmp/build »
Avec readline, on obtient :
/tmp/v2.1/bin/marchande < test_input.txt 2>&1 || exit 1
marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - a bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1 kg of tomatoes - Sorry, I don't have tomatoes. - 1.3 kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free software? - Huh? The merchant did not understand what you were trying to say. - that will be all You pay the merchant, take your belongings, and leave.
Mais il faut aussi tester le programme de complétion.
export PATH=/tmp/v2.1/bin:$PATH ( echo "Complete 'that will be all'" \ && marchande_complete "" "" \ && echo "Complete 'that will be all'" \ && marchande_complete "" "will be all" \ && echo "Can't guess a number" \ && marchande_complete "1." "kg of potatoes" \ && echo "Don't expect radishes" \ && marchande_complete "1.3 kg of" "" \ && echo "Guess the unit" \ && marchande_complete "1 " "of radishes" \ && echo "Ambiguous" \ && marchande_complete "" "bunch of radishes" ) > completion_actual_21.txt || exit 1 md5sum completion_expected.txt completion_actual_21.txt
93362c72d2101054e85def2660fa742a completion_expected.txt 93362c72d2101054e85def2660fa742a completion_actual_21.txt
7 Internationalisation de la grammaire
Pour l'internationalisation de notre programme, il y a deux éléments à modifier :
- La sortie du programme doit être traduite ;
- L'entrée doit être traduite.
7.1 Internationalisation de la sortie du programme
Nous allons commencer dans l'ordre. L'internationalisation de la sortie du programme se fait traditionnellement avec gettext. Il y a quelques modifications à faire, passons-les en revue :
7.1.1 Modification de configure.ac
Le programme 155 contient toutes les modifications nécessaires pour utiliser gettext.
dnl Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> dnl dnl This program is free software: you can redistribute it and/or dnl modify it under the terms of the GNU General Public License as dnl published by the Free Software Foundation, either version 3 of the dnl License, or (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see dnl <http://www.gnu.org/licenses/>. AC_PREREQ([2.69]) AC_INIT([marchande], [3.0], [vivien@planete-kraus.eu]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([m4]) AC_PROG_CC AM_MISSING_PROG([LEX], [flex]) AM_MISSING_PROG([YACC], [bison]) AM_INIT_AUTOMAKE([foreign subdir-objects]) LT_INIT AC_CHECK_HEADERS([readline/readline.h readline/history.h], [], [ AC_MSG_ERROR([Readline is required.]) ]) AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.19.8]) AC_SEARCH_LIBS([readline], [readline], [], [ AC_MSG_ERROR([Readline is required.]) ]) AC_SEARCH_LIBS([add_history], [readline], [], [ AC_MSG_ERROR([Readline history is required.]) ]) AC_CONFIG_FILES([Makefile po/Makefile.in]) AC_OUTPUT
7.1.2 Modification du système de compilation
Nous devons créer le fichier po/Makevars
. C'est le programme
156.
DOMAIN = $(PACKAGE) subdir = po top_builddir = .. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ COPYRIGHT_HOLDER = Vivien Kraus PACKAGE_GNU = MSGID_BUGS_ADDRESS = vivien@planete-kraus.eu EXTRA_LOCALE_CATEGORIES = USE_MSGCTXT = no MSGMERGE_OPTIONS = MSGINIT_OPTIONS = PO_DEPENDS_ON_POT = yes DIST_DEPENDS_ON_UPDATE_PO = yes
La liste des fichiers contenant des chaînes de caractères à traduire doit être explicitée, dans le programme 157.
src/check.c src/complete.c src/lexer.l src/libmarchande.c src/main.c src/marchande.h src/marchande_private.h src/parser.y
De même, il faut faire la liste des langues traduites : c'est le programme 158.
fr
Enfin, il faut revoir le makefile principal. On obtient le programme 159.
# Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. dist_noinst_SCRIPTS = src/run-test noinst_LTLIBRARIES = src/libmarchande.la include_HEADERS = src/marchande.h info_TEXINFOS = doc/marchande.texi check_PROGRAMS = src/check src_check_LDADD = src/libmarchande.la AM_CPPFLAGS = -I $(srcdir)/src -I . TESTS = src/run-test bin_PROGRAMS = src/marchande src_libmarchande_la_SOURCES = src/libmarchande.c src/parser.c src/lexer.c src_marchande_SOURCES = src/main.c src_marchande_LDADD = src/libmarchande.la EXTRA_DIST = src/parser.y src/parser.h src/parser.stamp src/lexer.l MAINTAINERCLEANFILES = src/parser.h src/parser.c src/parser.stamp src/lexer.c BUILT_SOURCES = src/parser.h dist_noinst_HEADERS = src/marchande_private.h .l.c: $(AM_V_GEN) (cd $(srcdir) && $(LEX) -o $@-t $<) @mv $(srcdir)/$@-t $(srcdir)/$@ $(srcdir)/src/parser.stamp: src/parser.y $(AM_V_GEN) (cd $(srcdir) && $(YACC) src/parser.y -o src/parser.c --defines=src/parser.h) @touch $(srcdir)/src/parser.stamp $(srcdir)/src/parser.h $(srcdir)/src/parser.c: $(srcdir)/src/parser.stamp @dry=; for f in x $$MAKEFLAGS; do \ case $$f in \ *=*|--*);; \ *n*) dry=:;; \ esac; \ done; \ if test -f $@; then :; else \ $$dry trap 'rm -rf $(srcdir)/src/parser.lock $(srcdir)/src/parser.stamp' 1 2 13 15; \ if $$dry mkdir $(srcdir)/src/parser.lock 2>/dev/null; then \ $$dry rm -f $(srcdir)/src/parser.stamp || exit 1; \ $(MAKE) $(AM_MAKEFLAGS) src/parser.stamp; \ $$dry rmdir $(srcdir)/src/parser.lock; \ else \ while test -d $(srcdir)/src/parser.lock && test -z "$$dry"; do \ sleep 1; \ done; \ $$dry test -f $(srcdir)/src/parser.stamp; exit $$?; \ fi; \ fi bin_PROGRAMS += src/marchande_complete src_marchande_complete_SOURCES = src/complete.c src_marchande_complete_LDADD = src/libmarchande.la SUBDIRS = po src_libmarchande_la_SOURCES += gettext.h AM_CPPFLAGS += -DLOCALEDIR=\"$(localedir)\" BUILT_SOURCES += gettext.h $(srcdir)/gettext.h: $(AM_V_GEN) cp /usr/share/gettext/gettext.h .
7.1.3 Traduction !
Le fichier de traduction ci-dessous (programme 161) permet de traduire la sortie du programme. Pour gérer les citations sur plusieurs lignes, on utilise le programme 160.
(let ((results (save-excursion (org-babel-goto-named-src-block text) (let ((text (org-babel-expand-src-block))) (mapconcat (lambda (line) (format "%s" line)) (split-string text "\n") "\\n\"\n"))))) (replace-regexp-in-string "\"\n$" "" results))
# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Vivien Kraus # This file is distributed under the same license as the marchande package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: marchande 3\n" "Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n" "POT-Creation-Date: 2019-07-15 19:11+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/lexer.l:47 src/marchande_private.h:187 msgid "parser_language_en" msgstr "parser_language_fr" #: src/libmarchande.c:34 #, c-format msgid "" "marchande Copyright (C) 2019 Vivien Kraus\n" "This program comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions.\n" "See the GNU General Public License for details.\n" "\n" "Trying to recover from this unexpected assault of legalese, you look\n" "up to the merchant. She has:\n" " * a few bunches of radishes;\n" " * some potatoes.\n" "\n" "- Next! Hello :) What will it be?\n" msgstr "" "marchande Copyright (C) 2019 Vivien Kraus\n" "Ce programme n'est accompagné d'ABSOLUMENT AUCUNE GARANTIE.\n" "Ce programme est libre, et vous êtes invité à le redistribuer sous\n" "certaines conditions.\n" "Voir la License Publique Générale de GNU (GNU GPL) pour plus de\n" "détails.\n" "\n" "En essayant de vous rétablir de cette attaque de texte juridique\n" "inattendue, vous levez les yeux vers la marchande. Elle a :\n" " * quelques bottes de radis ;\n" " * quelques patates.\n" "\n" "- Au suivant ! Bonjour :) Qu'est-ce que ça sera ?\n" #: src/libmarchande.c:41 #, c-format msgid "- Sorry, I don't have %s.\n" msgstr "- Désolé, je n'ai pas de %s.\n" #: src/libmarchande.c:47 #, c-format msgid "" "- Huh?\n" "\n" "The merchant did not understand what you were trying to say.\n" msgstr "" "- Hein ?\n" "\n" "La marchande n'a pas compris ce que vous essayiez de dire.\n" #: src/libmarchande.c:54 #, c-format msgid "" "The merchant takes the radishes and put them aside for you.\n" "- And with this?\n" msgstr "" "La marchande prend les radis et vous les met de côté.\n" "- Et avec ceci ?\n" #: src/libmarchande.c:61 #, c-format msgid "" "The merchant takes the potatoes and put them aside for you.\n" "- And with this?\n" msgstr "" "La marchande pèse les pommes de terre et vous les met de côté.\n" "- Et avec ceci ?\n" #: src/libmarchande.c:67 #, c-format msgid "You pay the merchant, take your belongings, and leave.\n" msgstr "Vous payez la marchande, prenez vos affaires et partez.\n" #: src/libmarchande.c:73 msgid "- " msgstr "- " #: src/libmarchande.c:80 msgid "" "The merchant waits patiently as you try to end your sentence.\n" "- " msgstr "" "La marchande attent patiemment que vous finissiez votre phrase.\n" "- "
7.1.4 Adaptation du code
Il faut :
- Inclure le fichier
gettext.h
, programme 162 ; - Mettre en place gettext pour les programmes, avec le programme 163 ;
- Mettre en place gettext pour la bibliothèque, avec le programme 164 ;
- Re-définir les macros
_
etN_
pour utiliser gettext, avec le programme 165.
#include "gettext.h"
setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE);
bindtextdomain (PACKAGE, LOCALEDIR);
#define _(String) dgettext (PACKAGE, String) #define N_(String) (String)
7.2 Traduction du vocabulaire
Pour que le lexeur ne reconnaisse que le vocabulaire pertinent pour la langue concernée, il faut adapter le code en utilisant des conditions de départ.
Les conditions de départ sont définies dans le programme 166. Le nouveau vocabulaire est défini dans le programme 167.
%s fr %s en
<en>that { return THAT; } <en>will { return WILL; } <en>be { return BE; } <en>all { return ALL; } [0-9]+ { yylval->INTEGER = (unsigned int) strtoul (yytext, NULL, 10); return INTEGER; } <en>[0-9]+\.[0-9]* { yylval->DECIMAL = strtod (yytext, NULL); return DECIMAL; } <en>of { return OF; } kg { return KG; } <en>a { return A; } <en>bunch { return BUNCH; } <en>bunches { return BUNCHES; } <en>potatoes { return POTATOES; } <en>radishes { return RADISHES; } <fr>ce { return CE; } <fr>sera { return SERA; } <fr>tout { return TOUT; } <fr>[0-9]+,[0-9]* { yylval->DECIMAL = strtod (yytext, NULL); return DECIMAL; } <fr>de { return DE; } <fr>une { return UNE; } <fr>botte { return BOTTE; } <fr>bottes { return BOTTES; } <fr>patates { return PATATES; } <fr>radis { return RADIS; } [ \t\n]+ /* do nothing */ [^ \t\n.,?!0-9]+ { yylval->UNKNOWN_WORD = strdup (yytext); return UNKNOWN_WORD; } [.,?!] { return END_OF_PHRASE; }
On voit que l'on définit de nouveaux mots. Il faut donc mettre à jour le parseur avec le programme 168.
%token LANG_EN %token LANG_FR %token CE %token SERA %token TOUT %token DE %token UNE %token BOTTE %token BOTTES %token PATATES %token RADIS %type <int> bottes %type <double> poids
Pour que l'on soit dans la bonne condition du lexeur, il faut s'y mettre dès que possible. Nous pouvons le faire dans le prologue avec le programme 171.
parser_language_en
parser_language_fr
if (yyextra.enter_language && strcmp (_ ("parser_language_en"), "parser_language_fr") == 0) { yyextra.enter_language = 0; BEGIN (fr); } else if (yyextra.enter_language) { yyextra.enter_language = 0; BEGIN (en); }
Bien sûr, cela signifie qu'il faut modifier le type yyextra
et
l'initialisation du lexeur. On réécrit le programme 90 en
172. La fonction de parse est réimplémentée dans le
programme 173, et l'initialisation pour la complétion
est mise à jour dans le programme
174. Il faut en fait
rajouter le programme 175 à chaque fois que
l'on utilise le lexeur.
typedef struct { int *prompt_type; marchande_parser_behavior *behavior; int enter_language; } marchande_lexer_extra;
void marchande_parse (marchande_parser_behavior *behavior) { int prompt_type = 1; marchande_lexer_extra extra; yyscan_t scanner; extra.prompt_type = &prompt_type; extra.behavior = behavior; extra.enter_language = 1;; _marchande_lex_init_extra (extra, &scanner); _marchande_parse (behavior, &prompt_type, NULL, scanner); _marchande_lex_destroy (scanner); }
data.t = MARCHANDE_BATCH; behavior.data = &data; behavior.syntax_error = &pb_syntax_error; behavior.buy_potatoes = &pb_buy_potatoes; behavior.buy_radishes = &pb_buy_radishes; behavior.value_error = &pb_value_error; behavior.pull_char = &pb_pull_char; behavior.prologue = &pb_prologue; behavior.before_token = &pb_before_token; extra.prompt_type = &prompt_type; extra.behavior = &behavior;; extra.enter_language = 1;; data.produce_language = 1;
extra.enter_language = 1;
7.3 Traduction de la grammaire
Nous allons utiliser la même technique que pour le mode : le deuxième
mot-clé artificiel sera soit LANG_EN
, soit LANG_FR
, soit n'importe
quelle autre supportée. Pour nous on se limitera à 2. Les nouvelles
règles de grammaire pour le français sont ajoutées par le programme
176. Pour contrôler tout cela, nous allons
expliciter la règle de plus haut niveau, dans le programme
177.
interaction_fr: %empty | interaction_fr command_fr | interaction_fr error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; } ; command_fr: CE SERA TOUT { YYACCEPT; } | poids DE PATATES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bottes DE RADIS { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | poids DE UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bottes DE UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } ; poids: weight { $$ = $1; } ; bottes: UNE BOTTE { $$ = 1; } | INTEGER BOTTES { $$ = $1; } ; completion_fr: AUTOCOMPLETE { _marchande_add_completion (completions, "ce"); } | AUTOCOMPLETE SERA { _marchande_add_completion (completions, "ce"); } | CE AUTOCOMPLETE { _marchande_add_completion (completions, "sera"); } | CE SERA AUTOCOMPLETE { _marchande_add_completion (completions, "tout"); } | poids DE AUTOCOMPLETE { _marchande_add_completion (completions, "patates"); } | INTEGER AUTOCOMPLETE { if ($1 == 1) { _marchande_add_completion (completions, "botte"); } else { _marchande_add_completion (completions, "bottes"); } _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE DE { _marchande_add_completion (completions, "kg"); } | INTEGER AUTOCOMPLETE DE RADIS { if ($1 == 1) { _marchande_add_completion (completions, "botte"); } else { _marchande_add_completion (completions, "bottes"); } } | AUTOCOMPLETE BOTTE DE RADIS { _marchande_add_completion (completions, "1"); _marchande_add_completion (completions, "une"); } ;
run: MODE_DEFAULT LANG_EN interaction | MODE_DEFAULT LANG_FR interaction_fr | MODE_COMPLETE LANG_EN completion | MODE_COMPLETE LANG_FR completion_fr | MODE_COMPLETE error { yyerrok; } ;
Afin de savoir quel mot-clé de langue produire, on utilise bien sûr gettext. Le programme 178 se charge de produire tous les mots-clés artificiels. Comme on doit aussi modifier l'état du parseur, il faut aussi modifier le programme 112 en 179, et modifier le comportement par défaut dans le programme 180 et l'implémentation de la fonction de complétion dans le programme 182.
static int pb_prologue (void *data, int *token, _MARCHANDE_STYPE *lval) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM && behavior->u.stream.produce_mode) { behavior->u.stream.produce_mode = 0; *token = MODE_DEFAULT; return 1; } else if (behavior->produce_language) { behavior->produce_language = 0; if (strcmp (_ ("parser_language_en"), "parser_language_fr") == 0) { *token = LANG_FR; } else { *token = LANG_EN; } return 1; } return 0; }
typedef enum behavior_input_type behavior_input_type; enum behavior_input_type { MARCHANDE_STREAM, MARCHANDE_BATCH }; typedef struct behavior_input_stream behavior_input_stream; struct behavior_input_stream { int produce_mode; char *last_line; size_t i_last_line; }; typedef struct behavior_input_batch behavior_input_batch; struct behavior_input_batch { char *ptr; }; typedef union behavior_input_u behavior_input_u; union behavior_input_u { behavior_input_stream stream; behavior_input_batch batch; }; typedef struct behavior_data behavior_data; struct behavior_data { behavior_input_type t; behavior_input_u u; int produce_language; };
static behavior_data default_behavior_data = { .t = MARCHANDE_STREAM, .u = { .stream = { .produce_mode = 1, .last_line = NULL, .i_last_line = 0 } }, .produce_language = 1 }; static marchande_parser_behavior default_parser_behavior = { (void *) &default_behavior_data, &pb_syntax_error, &pb_buy_potatoes, &pb_buy_radishes, &pb_value_error, &pb_pull_char, &pb_prologue, &pb_before_token };
Pour la fonction de complétion, on va juste modifier le programme 182 pour ajouter simplement le programme 181.
data.produce_language = 1;
void _marchande_add_completion (marchande_completer_candidate **data, const char *candidate) { marchande_completer_candidate *next = malloc (sizeof (marchande_completer_candidate)); marchande_completer_candidate *old = *data; if (next == NULL) { abort (); } next->previous = old; next->candidate = strdup (candidate); *data = next; } char ** marchande_complete (const char *left, const char *right) { behavior_data data; _marchande_pstate *ps = _marchande_pstate_new (); int done = 0; int token = 0; _MARCHANDE_STYPE lval; yyscan_t scanner; marchande_parser_behavior behavior; marchande_lexer_extra extra; int prompt_type = 1; size_t n_completions, i_completion; marchande_completer_candidate *completions = NULL; marchande_completer_candidate *i, *aux; char **ret = NULL;; data.t = MARCHANDE_BATCH; behavior.data = &data; behavior.syntax_error = &pb_syntax_error; behavior.buy_potatoes = &pb_buy_potatoes; behavior.buy_radishes = &pb_buy_radishes; behavior.value_error = &pb_value_error; behavior.pull_char = &pb_pull_char; behavior.prologue = &pb_prologue; behavior.before_token = &pb_before_token; extra.prompt_type = &prompt_type; extra.behavior = &behavior;; extra.enter_language = 1;; data.produce_language = 1;; data.produce_language = 1;; data.u.batch.ptr = (char *) left; _marchande_lex_init_extra (extra, &scanner); _marchande_push_parse (ps, MODE_COMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, AUTOCOMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); data.u.batch.ptr = (char *) right; do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, 0, NULL, &behavior, &prompt_type, &completions, scanner); _marchande_pstate_delete (ps); _marchande_lex_destroy (scanner); n_completions = 0; for (i = completions; i != NULL; i = i->previous) { n_completions++; } ret = malloc ((n_completions + 1) * sizeof (char *)); if (ret == NULL) { abort (); } i_completion = 0; for (i = completions; i != NULL; i = aux) { ret[n_completions - (i_completion++) - 1] = i->candidate; aux = i->previous; free (i); } ret[n_completions] = NULL; return ret;; }
7.4 Mise en place de la nouvelle version
Comme à notre habitude, recopions l'ensemble du code source.
7.4.1 Le parseur
En rassemblant toutes les règles, on obtient le programme 183.
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %code requires { struct marchande_parser_behavior; typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_completer_candidate; typedef struct marchande_completer_candidate marchande_completer_candidate; } %{ #include <marchande_private.h> #include <stdio.h> #include <stdlib.h> int _marchande_lex (_MARCHANDE_STYPE *yylval, void *scanner); void _marchande_error (marchande_parser_behavior *behavior, int *prompt_type, void *scanner, marchande_completer_candidate **completions, const char *error) { (void) error; } int _marchande_wrap () { return 1; } void _marchande_add_completion (marchande_completer_candidate **completions, const char *candidate); %} %define api.pure full %define api.push-pull both %parse-param {marchande_parser_behavior *behavior} %parse-param {int *prompt_type} %parse-param {marchande_completer_candidate **completions} %param {void * scanner} %define api.prefix {_marchande_} %define api.value.type union %token THAT %token WILL %token BE %token ALL %token A %token KG %token BUNCH %token BUNCHES %token OF %token POTATOES %token RADISHES %token END_OF_PHRASE %token <int> INTEGER %token <double> DECIMAL %token <char *> UNKNOWN_WORD %destructor { free ($$); } UNKNOWN_WORD %type <int> bunches %type <double> weight %token LANG_EN %token LANG_FR %token CE %token SERA %token TOUT %token DE %token UNE %token BOTTE %token BOTTES %token PATATES %token RADIS %type <int> bottes %type <double> poids %token MODE_DEFAULT %token MODE_COMPLETE %token AUTOCOMPLETE %% run: MODE_DEFAULT LANG_EN interaction | MODE_DEFAULT LANG_FR interaction_fr | MODE_COMPLETE LANG_EN completion | MODE_COMPLETE LANG_FR completion_fr | MODE_COMPLETE error { yyerrok; } ; interaction: %empty | interaction command | interaction error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; } command: THAT WILL BE ALL { YYACCEPT; } | weight OF POTATOES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bunches OF RADISHES { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | weight OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bunches OF UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } weight: DECIMAL KG { $$ = $1; } | INTEGER KG { $$ = (double) $1; } ; bunches: A BUNCH { $$ = 1; } | INTEGER BUNCHES { $$ = $1; } ; completion: AUTOCOMPLETE { _marchande_add_completion (completions, "that"); /* Don't provide completions for the numbers */ } | AUTOCOMPLETE WILL { _marchande_add_completion (completions, "that"); } | THAT AUTOCOMPLETE { _marchande_add_completion (completions, "will"); } | THAT WILL AUTOCOMPLETE { _marchande_add_completion (completions, "be"); } | THAT WILL BE AUTOCOMPLETE { _marchande_add_completion (completions, "all"); } | weight OF AUTOCOMPLETE { _marchande_add_completion (completions, "potatoes"); } | INTEGER AUTOCOMPLETE { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE OF { _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE KG { /* Cannot complete a decimal number */ } | INTEGER AUTOCOMPLETE OF RADISHES { if ($1 == 1) { _marchande_add_completion (completions, "bunch"); } else { _marchande_add_completion (completions, "bunches"); } } | AUTOCOMPLETE BUNCH OF RADISHES { _marchande_add_completion (completions, "1"); _marchande_add_completion (completions, "a"); } interaction_fr: %empty | interaction_fr command_fr | interaction_fr error END_OF_PHRASE { *prompt_type = 1; behavior->syntax_error (behavior->data); yyerrok; } ; command_fr: CE SERA TOUT { YYACCEPT; } | poids DE PATATES { behavior->buy_potatoes (behavior->data, $1); *prompt_type = 1; } | bottes DE RADIS { behavior->buy_radishes (behavior->data, $1); *prompt_type = 1; } | poids DE UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } | bottes DE UNKNOWN_WORD { behavior->value_error (behavior->data, $3); *prompt_type = 1; free ($3); } ; poids: weight { $$ = $1; } ; bottes: UNE BOTTE { $$ = 1; } | INTEGER BOTTES { $$ = $1; } ; completion_fr: AUTOCOMPLETE { _marchande_add_completion (completions, "ce"); } | AUTOCOMPLETE SERA { _marchande_add_completion (completions, "ce"); } | CE AUTOCOMPLETE { _marchande_add_completion (completions, "sera"); } | CE SERA AUTOCOMPLETE { _marchande_add_completion (completions, "tout"); } | poids DE AUTOCOMPLETE { _marchande_add_completion (completions, "patates"); } | INTEGER AUTOCOMPLETE { if ($1 == 1) { _marchande_add_completion (completions, "botte"); } else { _marchande_add_completion (completions, "bottes"); } _marchande_add_completion (completions, "kg"); } | DECIMAL AUTOCOMPLETE DE { _marchande_add_completion (completions, "kg"); } | INTEGER AUTOCOMPLETE DE RADIS { if ($1 == 1) { _marchande_add_completion (completions, "botte"); } else { _marchande_add_completion (completions, "bottes"); } } | AUTOCOMPLETE BOTTE DE RADIS { _marchande_add_completion (completions, "1"); _marchande_add_completion (completions, "une"); } ; %%
7.4.2 Le lexeur
Le lexeur change également en plusieurs endroits.
/* * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ %{ #include <config.h> #include "parser.h" #include <marchande_private.h> #include <string.h> #include <marchande.h> #define YY_INPUT(buf, result, max_size) { \ result = yyextra.behavior->pull_char (yyextra.behavior->data, * (yyextra.prompt_type), buf); \ } #define YY_USER_ACTION { \ * (yyextra.prompt_type) = 2; \ yyextra.behavior->before_token (yyextra.behavior->data, yytext); \ } #define YYSTYPE _MARCHANDE_STYPE %} %option extra-type="marchande_lexer_extra" %option bison-bridge %option prefix="_marchande_" %option reentrant %s fr %s en %% %{ int ret; if (yyextra.enter_language && strcmp (_ ("parser_language_en"), "parser_language_fr") == 0) { yyextra.enter_language = 0; BEGIN (fr); } else if (yyextra.enter_language) { yyextra.enter_language = 0; BEGIN (en); } if (yyextra.behavior->prologue (yyextra.behavior->data, &ret, yylval)) { return ret; } %} <en>that { return THAT; } <en>will { return WILL; } <en>be { return BE; } <en>all { return ALL; } [0-9]+ { yylval->INTEGER = (unsigned int) strtoul (yytext, NULL, 10); return INTEGER; } <en>[0-9]+\.[0-9]* { yylval->DECIMAL = strtod (yytext, NULL); return DECIMAL; } <en>of { return OF; } kg { return KG; } <en>a { return A; } <en>bunch { return BUNCH; } <en>bunches { return BUNCHES; } <en>potatoes { return POTATOES; } <en>radishes { return RADISHES; } <fr>ce { return CE; } <fr>sera { return SERA; } <fr>tout { return TOUT; } <fr>[0-9]+,[0-9]* { yylval->DECIMAL = strtod (yytext, NULL); return DECIMAL; } <fr>de { return DE; } <fr>une { return UNE; } <fr>botte { return BOTTE; } <fr>bottes { return BOTTES; } <fr>patates { return PATATES; } <fr>radis { return RADIS; } [ \t\n]+ /* do nothing */ [^ \t\n.,?!0-9]+ { yylval->UNKNOWN_WORD = strdup (yytext); return UNKNOWN_WORD; } [.,?!] { return END_OF_PHRASE; } %% void marchande_parse (marchande_parser_behavior *behavior) { int prompt_type = 1; marchande_lexer_extra extra; yyscan_t scanner; extra.prompt_type = &prompt_type; extra.behavior = behavior; extra.enter_language = 1;; _marchande_lex_init_extra (extra, &scanner); _marchande_parse (behavior, &prompt_type, NULL, scanner); _marchande_lex_destroy (scanner); } void _marchande_add_completion (marchande_completer_candidate **data, const char *candidate) { marchande_completer_candidate *next = malloc (sizeof (marchande_completer_candidate)); marchande_completer_candidate *old = *data; if (next == NULL) { abort (); } next->previous = old; next->candidate = strdup (candidate); *data = next; } char ** marchande_complete (const char *left, const char *right) { behavior_data data; _marchande_pstate *ps = _marchande_pstate_new (); int done = 0; int token = 0; _MARCHANDE_STYPE lval; yyscan_t scanner; marchande_parser_behavior behavior; marchande_lexer_extra extra; int prompt_type = 1; size_t n_completions, i_completion; marchande_completer_candidate *completions = NULL; marchande_completer_candidate *i, *aux; char **ret = NULL;; data.t = MARCHANDE_BATCH; behavior.data = &data; behavior.syntax_error = &pb_syntax_error; behavior.buy_potatoes = &pb_buy_potatoes; behavior.buy_radishes = &pb_buy_radishes; behavior.value_error = &pb_value_error; behavior.pull_char = &pb_pull_char; behavior.prologue = &pb_prologue; behavior.before_token = &pb_before_token; extra.prompt_type = &prompt_type; extra.behavior = &behavior;; extra.enter_language = 1;; data.produce_language = 1;; data.produce_language = 1;; data.u.batch.ptr = (char *) left; _marchande_lex_init_extra (extra, &scanner); _marchande_push_parse (ps, MODE_COMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, AUTOCOMPLETE, NULL, &behavior, &prompt_type, &completions, scanner); data.u.batch.ptr = (char *) right; do { token = _marchande_lex (&lval, scanner); if (token != 0) { _marchande_push_parse (ps, token, &lval, &behavior, &prompt_type, &completions, scanner); } } while (token != 0); _marchande_push_parse (ps, 0, NULL, &behavior, &prompt_type, &completions, scanner); _marchande_pstate_delete (ps); _marchande_lex_destroy (scanner); n_completions = 0; for (i = completions; i != NULL; i = i->previous) { n_completions++; } ret = malloc ((n_completions + 1) * sizeof (char *)); if (ret == NULL) { abort (); } i_completion = 0; for (i = completions; i != NULL; i = aux) { ret[n_completions - (i_completion++) - 1] = i->candidate; aux = i->previous; free (i); } ret[n_completions] = NULL; return ret;; }
7.4.3 L'en-tête principal
Celui-ci ne change pas. On obtient toujours le programme 185.
/* * File: src/marchande.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_INCLUDED #define H_MARCHANDE_INCLUDED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ union _MARCHANDE_STYPE; typedef union _MARCHANDE_STYPE _MARCHANDE_STYPE; typedef struct marchande_parser_behavior marchande_parser_behavior; struct marchande_parser_behavior { void *data; void (*syntax_error) (void *data); void (*buy_potatoes) (void *data, double weight); void (*buy_radishes) (void *data, int bunches); void (*value_error) (void *data, const char *what); /* Return 0 if EOF, 1 otherwise */ int (*pull_char) (void *data, int prompt_type, char *c); /* Return non-zero if we must return immediately */ int (*prologue) (void *data, int *token, _MARCHANDE_STYPE *yylval); void (*before_token) (void *data, const char *text); }; extern marchande_parser_behavior *marchande_default_parser_behavior; /** * marchande_init: * * Initializes the library. * * Returns: an error code, 0 on success or 1 if an error happened. */ int marchande_init (); /** * marchande_value_error */ void marchande_value_error (const char *what); /** * marchande_syntax_error */ void marchande_syntax_error (); /** * marchande_buy_radishes: */ void marchande_buy_radishes (int bunches); /** * marchande_buy_potatoes: */ void marchande_buy_potatoes (double weight); /** * marchande_exit: */ void marchande_exit (); /** * marchande_main_prompt: */ const char *marchande_main_prompt (); /** * marchande_secondary_prompt: */ const char *marchande_secondary_prompt (); /** * marchande_parse: * @param behavior: the behavior to implement. You can pass * 'marchande_default_parser_behavior' here. */ void marchande_parse (marchande_parser_behavior *behavior); /** * marchande_complete: * Returns: (array null-terminated) (transfer full): the list of * possible completions. */ char **marchande_complete (const char *left, const char *right); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* not H_MARCHANDE_INCLUDED */
7.4.4 L'implémentation de la bibliothèque
Le comportement par défaut du parseur ayant changé, il faut modifier cette valeur. N'oublions pas non plus qu'il faut initialiser gettext. On obtient le programme 186.
/* * File: src/libmarchande.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <marchande.h> #include <marchande_private.h> #include "src/parser.h" static int n_radishes; static double weight_potatoes; int marchande_init () { bindtextdomain (PACKAGE, LOCALEDIR); n_radishes = 0; weight_potatoes = 0.0; printf (_ ("marchande Copyright (C) 2019 Vivien Kraus\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it\nunder certain conditions.\nSee the GNU General Public License for details.\n\nTrying to recover from this unexpected assault of legalese, you look\nup to the merchant. She has:\n * a few bunches of radishes;\n * some potatoes.\n\n- Next! Hello :) What will it be?\n")); return 0; } void marchande_value_error (const char *what) { fprintf (stderr, _ ("- Sorry, I don't have %s.\n"), what); }; void marchande_syntax_error () { fprintf (stderr, _ ("- Huh?\n\nThe merchant did not understand what you were trying to say.\n")); }; void marchande_buy_radishes (int bunches) { n_radishes += bunches; printf (_ ("The merchant takes the radishes and put them aside for you.\n- And with this?\n")); }; void marchande_buy_potatoes (double weight) { weight_potatoes += weight; printf (_ ("The merchant takes the potatoes and put them aside for you.\n- And with this?\n")); }; void marchande_exit () { printf (_ ("You pay the merchant, take your belongings, and leave.\n")); }; const char * marchande_main_prompt () { static const char *ret_c = N_("- "); return _ (ret_c); }; const char * marchande_secondary_prompt () { static const char *ret_c = N_("The merchant waits patiently as you try to end your sentence.\n- "); return _ (ret_c); }; static behavior_data default_behavior_data = { .t = MARCHANDE_STREAM, .u = { .stream = { .produce_mode = 1, .last_line = NULL, .i_last_line = 0 } }, .produce_language = 1 }; static marchande_parser_behavior default_parser_behavior = { (void *) &default_behavior_data, &pb_syntax_error, &pb_buy_potatoes, &pb_buy_radishes, &pb_value_error, &pb_pull_char, &pb_prologue, &pb_before_token };; marchande_parser_behavior *marchande_default_parser_behavior = &default_parser_behavior;
7.4.5 L'implémentation de l'en-tête privé
L'en-tête privé change un peu. On obtient le programme 187.
/* * File: src/marchande_private.h * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #ifndef H_MARCHANDE_PRIVATE_INCLUDED #define H_MARCHANDE_PRIVATE_INCLUDED #include <config.h> #include <marchande.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include "src/parser.h" #include <readline/readline.h> #include <readline/history.h> #include "gettext.h" #define _(String) dgettext (PACKAGE, String) #define N_(String) (String) typedef struct marchande_completer_candidate marchande_completer_candidate; struct marchande_completer_candidate { char *candidate; marchande_completer_candidate *previous; }; typedef struct { int *prompt_type; marchande_parser_behavior *behavior; int enter_language; } marchande_lexer_extra; typedef enum behavior_input_type behavior_input_type; enum behavior_input_type { MARCHANDE_STREAM, MARCHANDE_BATCH }; typedef struct behavior_input_stream behavior_input_stream; struct behavior_input_stream { int produce_mode; char *last_line; size_t i_last_line; }; typedef struct behavior_input_batch behavior_input_batch; struct behavior_input_batch { char *ptr; }; typedef union behavior_input_u behavior_input_u; union behavior_input_u { behavior_input_stream stream; behavior_input_batch batch; }; typedef struct behavior_data behavior_data; struct behavior_data { behavior_input_type t; behavior_input_u u; int produce_language; }; static void pb_syntax_error (void *data) { (void) data; marchande_syntax_error (); } static void pb_buy_potatoes (void *data, double weight) { (void) data; marchande_buy_potatoes (weight); } static void pb_buy_radishes (void *data, int bunches) { (void) data; marchande_buy_radishes (bunches); } static void pb_value_error (void *data, const char *what) { (void) data; marchande_value_error (what); } static char * add_lf (char *input) { size_t len = strlen (input); static const char *added = "\n"; size_t len_added = strlen (added); char *ret = malloc (len + len_added + 1); if (ret == NULL) { abort (); } strcpy (ret, input); strcat (ret, added); free (input); return ret; } static int pb_pull_char (void *data, int prompt_type, char *c) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM) { int i = 0; if (behavior->u.stream.last_line == NULL) { /* Initially, this is set to NULL. */ behavior->u.stream.last_line = malloc (1); behavior->u.stream.last_line[0] = '\0'; if (behavior->u.stream.last_line == NULL) { abort (); } } while (behavior->u.stream.last_line[behavior->u.stream.i_last_line] == '\0') { char *newline = NULL; if (prompt_type == 1) { newline = readline (marchande_main_prompt ()); } else { newline = readline (marchande_secondary_prompt ()); } if (newline == NULL) { return 0; } if (strcmp (newline, "") != 0) { add_history (newline); } newline = add_lf (newline); free (behavior->u.stream.last_line); behavior->u.stream.last_line = NULL; behavior->u.stream.last_line = newline; behavior->u.stream.i_last_line = 0; } i = behavior->u.stream.last_line[behavior->u.stream.i_last_line]; behavior->u.stream.i_last_line += 1; c[0] = i; return 1; } else { if (strcmp (behavior->u.batch.ptr, "") == 0) { return 0; } c[0] = behavior->u.batch.ptr[0]; behavior->u.batch.ptr = & (behavior->u.batch.ptr[1]); return 1; } } static int pb_prologue (void *data, int *token, _MARCHANDE_STYPE *lval) { behavior_data *behavior = data; if (behavior->t == MARCHANDE_STREAM && behavior->u.stream.produce_mode) { behavior->u.stream.produce_mode = 0; *token = MODE_DEFAULT; return 1; } else if (behavior->produce_language) { behavior->produce_language = 0; if (strcmp (_ ("parser_language_en"), "parser_language_fr") == 0) { *token = LANG_FR; } else { *token = LANG_EN; } return 1; } return 0; } static void pb_before_token (void *data, const char *text) { (void) data; } #endif /* not H_MARCHANDE_PRIVATE_INCLUDED */
7.4.6 L'implémentation du test
Le test est encore une fois le même, puisqu'on ne peut pas tester quelque chose qui dépende de la locale. On obtient de nouveau les programmes 188 et 189.
/* * File: src/check.c * Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> * * 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 3 of the * License, 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * <http://www.gnu.org/licenses/>. */ #include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main () { if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } printf ("%s1 bunch of radishes\n", marchande_main_prompt ()); marchande_buy_radishes (1); printf ("%s1kg of tomatoes\n", marchande_main_prompt ()); fflush (stdout); marchande_value_error ("tomatoes"); fflush (stderr); printf ("%s1kg\n", marchande_main_prompt ()); printf ("%sof potatoes\n", marchande_secondary_prompt ()); marchande_buy_potatoes (1.0); printf ("%sWhat do you think of Free Software?\n", marchande_main_prompt ()); fflush (stdout); marchande_syntax_error (); fflush (stderr); printf ("%sThat will be all.\n", marchande_main_prompt ()); marchande_exit (); return EXIT_SUCCESS; }
export LANG=C EXPECTED=$( cat <<EOF marchande Copyright (C) 2019 Vivien Kraus This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for details. Trying to recover from this unexpected assault of legalese, you look up to the merchant. She has: * a few bunches of radishes; * some potatoes. - Next! Hello :) What will it be? - 1 bunch of radishes The merchant takes the radishes and put them aside for you. - And with this? - 1kg of tomatoes - Sorry, I don't have tomatoes. - 1kg The merchant waits patiently as you try to end your sentence. - of potatoes The merchant takes the potatoes and put them aside for you. - And with this? - What do you think of Free Software? - Huh? The merchant did not understand what you were trying to say. - That will be all. You pay the merchant, take your belongings, and leave. EOF ) ACTUAL=$(./src/check 2>&1) echo "Expected:" echo "$EXPECTED" echo "Actual:" echo "$ACTUAL" if test "x$EXPECTED" = "x$ACTUAL" then echo "OK" else >&2 echo "Failed." exit 1 fi
7.4.7 Le programme principal
Pour le programme principal, on initialise simplement gettext
. On
obtient le programme 190.
#include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <readline/readline.h> #include <readline/history.h> #include <locale.h> #include "gettext.h" static char **completions_to_give; static size_t i_completion_to_give; static char * generator (const char *text, int state) { (void) state; if (completions_to_give[i_completion_to_give] == NULL) { return NULL; } if (strncmp (completions_to_give[i_completion_to_give], text, strlen (text)) == 0) { return completions_to_give[i_completion_to_give++]; } free (completions_to_give[i_completion_to_give++]); return generator (text, state); } static char ** get_readline_completions (const char *base, int start, int end) { char *left, *right; size_t line_buffer_len = strlen (rl_line_buffer); char **ret = NULL; rl_attempted_completion_over = 1; left = malloc (start + 1); right = malloc (line_buffer_len - end + 1); if (left == NULL || right == NULL) { abort (); } strncpy (left, rl_line_buffer, start); strncpy (right, rl_line_buffer + end, line_buffer_len - end); left[start] = '\0'; right[line_buffer_len - end] = '\0'; completions_to_give = marchande_complete (left, right); free (left); free (right); i_completion_to_give = 0; ret = rl_completion_matches (base, generator); free (completions_to_give); completions_to_give = NULL; return ret; } static void setup_readline () { rl_attempted_completion_function = get_readline_completions; } int main () { setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE);; if (marchande_init () != 0) { fprintf (stderr, "Could not initialize marchande.\n"); return EXIT_FAILURE; } setup_readline (); marchande_parse (marchande_default_parser_behavior); marchande_exit (); return EXIT_SUCCESS; }
7.4.8 Le programme d'auto-complétion
Le programme d'auto-complétion ne change pas : puisqu'il n'initialise pas marchande, il n'initialise pas non plus gettext pour la bibliothèque. On obtient toujours le programme 191.
#include <config.h> #include <marchande.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { char **completions; size_t i = 0; if (argc != 3) { fprintf (stderr, "Usage: complete \"text before\" \"text after\"\n"); return EXIT_FAILURE; } completions = marchande_complete (argv[1], argv[2]); for (i = 0; completions[i] != NULL; i++) { printf ("%s\n", completions[i]); free (completions[i]); } free (completions); return EXIT_SUCCESS; }
7.4.9 Le manuel
Pour le manuel, on modifie simplement le numéro de version dans le programme 192 pour obtenir le programme 193. En effet, le manuel est uniquement en anglais, donc il ne doit documenter que le comportement anglais.
ORGFILE=$(mktemp XXXXXXX.org) trap "{ rm -rf $ORGFILE; }" EXIT cat > $ORGFILE <<EOF #+macro: version 3 # Copyright (C) 2019 Vivien Kraus <vivien@planete-kraus.eu> # # 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 3 of the # License, 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. #+title: Play the merchant #+subitile: version {{{version}}} of the program #+author: Vivien Kraus #+email: vivien@planete-kraus.eu #+options: ':t toc:t author:t email:t #+language: en #+texinfo_filename: marchande.info #+texinfo_dir_category: Games #+texinfo_dir_title: marchande: (marchande) #+texinfo_dir_desc: Marchande #+texinfo_printed_title: Marchande #+texinfo: @documentencoding UTF-8 This manual is for marchande version {{{version}}}. * Copying :PROPERTIES: :COPYING: t :END: This manual is for Marchande (version {{{version}}}), an example about how to make a command-line interface. Copyright @@texinfo:@copyright{}@@ 2019 Vivien Kraus #+BEGIN_QUOTE Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. #+END_QUOTE * Introduction #+include: "./index.org::*Le jeu de la marchande, en anglais (désolé si c'est mal traduit)" :only-contents t * Invoking =marchande= #+include: "./index.org::*Description de la syntaxe, en anglais" :only-contents t * Invoking =marchande_complete= #+include: "./index.org::*Invocation de =marchande_complete=, en anglais" :only-contents t EOF LANG=C emacs --batch \ --file $ORGFILE \ --eval "(require 'ox-texinfo)" \ -f org-texinfo-export-to-texinfo \ || exit 1 cat "$(basename $ORGFILE .org).texi"
\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename marchande.info @settitle Play the merchant @documentencoding UTF-8 @documentlanguage en @c %**end of header @copying This manual is for Marchande (version 3), an example about how to make a command-line interface. Copyright @copyright{} 2019 Vivien Kraus @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. @end quotation @end copying @dircategory Games @direntry * marchande: (marchande). Marchande. @end direntry @finalout @titlepage @title Marchande @author Vivien Kraus (@email{vivien@@planete-kraus.eu}) @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top @top Play the merchant @documentencoding UTF-8 This manual is for marchande version 3. @end ifnottex @menu * Introduction:: * Invoking @samp{marchande}:: * Invoking @samp{marchande_complete}:: @end menu @node Introduction @chapter Introduction You find yourself facing the organic vegetable seller. In front of her, on her stall, you see a crate containing @strong{potatoes} and @strong{bunches of radishes}. The seller thanks the previous customer and turns to you. @quotation @itemize @item Next! What will it be? @end itemize @end quotation You need to buy a few radishes and potatoes. You're going to have to be able to buy it from the merchant@dots{} @node Invoking @samp{marchande} @chapter Invoking @samp{marchande} When you run the @samp{marchande} program, you have a command-line interface. There are several options: @itemize @item say @samp{that will be all}, and the program exits; @item say @samp{a bunch of radishes}, or @samp{2 bunches of radishes}, or another number, to add some radishes; @item say @samp{1.3kg of potatoes}, to add some potatoes. @end itemize @node Invoking @samp{marchande_complete} @chapter Invoking @samp{marchande_complete} The @samp{marchande_complete} program is used in the following way: @example marchande_complete "TEXT BEFORE" "TEXT AFTER" @end example The program prints either nothing, or the list of possibilities for the first word between the text before and the text after. In case of a number, nothing is proposed. In case of an error, the program exits with code 1. @bye
7.5 Testons !
Pour obtenir la distribution source, j'ai fait ceci :
cd v3 autoreconf -vif 2>&1 ./configure 2>&1 make V=0 -j 16 all 2>&1 make V=0 -j 16 distcheck 2>&1 echo "Built"
autoreconf: Entering directory `.' autoreconf: running: autopoint --force Copying file ABOUT-NLS Copying file config.rpath Creating directory m4 Copying file m4/codeset.m4 Copying file m4/extern-inline.m4 Copying file m4/fcntl-o.m4 Copying file m4/gettext.m4 Copying file m4/glibc2.m4 Copying file m4/glibc21.m4 Copying file m4/iconv.m4 Copying file m4/intdiv0.m4 Copying file m4/intl.m4 Copying file m4/intldir.m4 Copying file m4/intlmacosx.m4 Copying file m4/intmax.m4 Copying file m4/inttypes-pri.m4 Copying file m4/inttypes_h.m4 Copying file m4/lcmessage.m4 Copying file m4/lib-ld.m4 Copying file m4/lib-link.m4 Copying file m4/lib-prefix.m4 Copying file m4/lock.m4 Copying file m4/longlong.m4 Copying file m4/nls.m4 Copying file m4/po.m4 Copying file m4/printf-posix.m4 Copying file m4/progtest.m4 Copying file m4/size_max.m4 Copying file m4/stdint_h.m4 Copying file m4/threadlib.m4 Copying file m4/uintmax_t.m4 Copying file m4/visibility.m4 Copying file m4/wchar_t.m4 Copying file m4/wint_t.m4 Copying file m4/xsize.m4 Copying file po/Makefile.in.in Copying file po/Makevars.template Copying file po/Rules-quot Copying file po/boldquot.sed Copying file po/en@boldquot.header Copying file po/en@quot.header Copying file po/insert-header.sin Copying file po/quot.sed Copying file po/remove-potcdate.sin autoreconf: running: aclocal --force autoreconf: configure.ac: tracing autoreconf: running: libtoolize --copy --force libtoolize: putting auxiliary files in '.'. libtoolize: copying file './ltmain.sh' libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'. libtoolize: copying file 'm4/libtool.m4' libtoolize: copying file 'm4/ltoptions.m4' libtoolize: copying file 'm4/ltsugar.m4' libtoolize: copying file 'm4/ltversion.m4' libtoolize: copying file 'm4/lt~obsolete.m4' libtoolize: Consider adding '-I m4' to ACLOCAL_AMFLAGS in Makefile.am. autoreconf: running: /usr/bin/autoconf --force autoreconf: running: /usr/bin/autoheader --force autoreconf: running: automake --add-missing --copy --force-missing configure.ac:20: installing './compile' configure.ac:24: installing './config.guess' configure.ac:24: installing './config.sub' configure.ac:23: installing './install-sh' configure.ac:21: installing './missing' Makefile.am: installing './depcomp' Makefile.am:20: installing './texinfo.tex' parallel-tests: installing './test-driver' autoreconf: Leaving directory `.' checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking readline/readline.h usability... yes checking readline/readline.h presence... yes checking for readline/readline.h... yes checking readline/history.h usability... yes checking readline/history.h presence... yes checking for readline/history.h... yes checking whether NLS is requested... yes checking for msgfmt... /usr/bin/msgfmt checking for gmsgfmt... /usr/bin/msgfmt checking for xgettext... /usr/bin/xgettext checking for msgmerge... /usr/bin/msgmerge checking for ld used by gcc... /usr/bin/ld -m elf_x86_64 checking if the linker (/usr/bin/ld -m elf_x86_64) is GNU ld... yes checking for shared library run path origin... done checking for CFPreferencesCopyAppValue... no checking for CFLocaleCopyCurrent... no checking for GNU gettext in libc... yes checking whether to use NLS... yes checking where the gettext function comes from... libc checking for library containing readline... -lreadline checking for library containing add_history... none required checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating po/Makefile.in config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands config.status: executing po-directories commands config.status: creating po/POTFILES config.status: creating po/Makefile GEN src/parser.stamp GEN gettext.h make all-recursive make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » Making all in po make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » make marchande.pot-update make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » sed -e '/^#/d' remove-potcdate.sin > t-remove-potcdate.sed mv t-remove-potcdate.sed remove-potcdate.sed package_gnu=""; \ test -n "$package_gnu" || { \ if { if (LC_ALL=C find --version) 2>/dev/null | grep GNU >/dev/null; then \ LC_ALL=C find -L .. -maxdepth 1 -type f \ -size -10000000c -exec grep 'GNU marchande' \ /dev/null '{}' ';' 2>/dev/null; \ else \ LC_ALL=C grep 'GNU marchande' ../* 2>/dev/null; \ fi; \ } | grep -v 'libtool:' >/dev/null; then \ package_gnu=yes; \ else \ package_gnu=no; \ fi; \ }; \ if test "$package_gnu" = "yes"; then \ package_prefix='GNU '; \ else \ package_prefix=''; \ fi; \ if test -n 'vivien@planete-kraus.eu' || test 'vivien@planete-kraus.eu' = '@'PACKAGE_BUGREPORT'@'; then \ msgid_bugs_address='vivien@planete-kraus.eu'; \ else \ msgid_bugs_address='vivien@planete-kraus.eu'; \ fi; \ case `/usr/bin/xgettext --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \ /usr/bin/xgettext --default-domain=marchande --directory=.. \ --add-comments=TRANSLATORS: --keyword=_ --keyword=N_ \ --files-from=./POTFILES.in \ --copyright-holder='Vivien Kraus' \ --msgid-bugs-address="$msgid_bugs_address" \ ;; \ *) \ /usr/bin/xgettext --default-domain=marchande --directory=.. \ --add-comments=TRANSLATORS: --keyword=_ --keyword=N_ \ --files-from=./POTFILES.in \ --copyright-holder='Vivien Kraus' \ --package-name="${package_prefix}marchande" \ --package-version='3.0' \ --msgid-bugs-address="$msgid_bugs_address" \ ;; \ esac /usr/bin/xgettext: AVERTISSEMENT : pour le fichier « src/lexer.l », l'extension « l » est inconnue. On suppose que c'est du C /usr/bin/xgettext: AVERTISSEMENT : pour le fichier « src/parser.y », l'extension « y » est inconnue. On suppose que c'est du C test ! -f marchande.po || { \ if test -f ./marchande.pot-header; then \ sed -e '1,/^#$/d' < marchande.po > marchande.1po && \ cat ./marchande.pot-header marchande.1po > marchande.po; \ rm -f marchande.1po; \ fi; \ if test -f ./marchande.pot; then \ sed -f remove-potcdate.sed < ./marchande.pot > marchande.1po && \ sed -f remove-potcdate.sed < marchande.po > marchande.2po && \ if cmp marchande.1po marchande.2po >/dev/null 2>&1; then \ rm -f marchande.1po marchande.2po marchande.po; \ else \ rm -f marchande.1po marchande.2po ./marchande.pot && \ mv marchande.po ./marchande.pot; \ fi; \ else \ mv marchande.po ./marchande.pot; \ fi; \ } make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » test ! -f ./marchande.pot || \ test -z "fr.gmo" || make fr.gmo make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » /usr/bin/msgmerge --update --lang=fr fr.po marchande.pot ........ terminé. rm -f fr.gmo && /usr/bin/msgfmt -c --statistics --verbose -o fr.gmo fr.po /usr/bin/msgfmt: fr.po: AVERTISSEMENT : l'en-tête du fichier .po est approximatif (fuzzy) AVERTISSEMENT : les versions plus anciennes de « msgfmt » génèreront une erreur à cet endroit fr.po:8: AVERTISSEMENT : Le champ d'en-tête « PO-Revision-Date » a encore sa valeur initiale par défaut fr.po:8: AVERTISSEMENT : Le champ d'en-tête « Last-Translator » a encore sa valeur initiale par défaut fr.po:8: AVERTISSEMENT : Le champ d'en-tête « Language-Team » a encore sa valeur initiale par défaut fr.po : 9 messages traduits. make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » touch stamp-po make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » MAKEINFO doc/marchande.info GEN src/lexer.c CC src/main.o CC src/libmarchande.lo CC src/parser.lo CC src/complete.o CC src/lexer.lo CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande CCLD src/marchande_complete make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » make dist-gzip am__post_remove_distdir='@:' make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » make distdir-am make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » if test -d "marchande-3.0"; then find "marchande-3.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-3.0" || { sleep 5 && rm -rf "marchande-3.0"; }; else :; fi test -d "marchande-3.0" || mkdir "marchande-3.0" (cd po && make top_distdir=../marchande-3.0 distdir=../marchande-3.0/po \ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir) make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » test -z "update-po" || make update-po make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » make marchande.pot-update make[5] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » package_gnu=""; \ test -n "$package_gnu" || { \ if { if (LC_ALL=C find --version) 2>/dev/null | grep GNU >/dev/null; then \ LC_ALL=C find -L .. -maxdepth 1 -type f \ -size -10000000c -exec grep 'GNU marchande' \ /dev/null '{}' ';' 2>/dev/null; \ else \ LC_ALL=C grep 'GNU marchande' ../* 2>/dev/null; \ fi; \ } | grep -v 'libtool:' >/dev/null; then \ package_gnu=yes; \ else \ package_gnu=no; \ fi; \ }; \ if test "$package_gnu" = "yes"; then \ package_prefix='GNU '; \ else \ package_prefix=''; \ fi; \ if test -n 'vivien@planete-kraus.eu' || test 'vivien@planete-kraus.eu' = '@'PACKAGE_BUGREPORT'@'; then \ msgid_bugs_address='vivien@planete-kraus.eu'; \ else \ msgid_bugs_address='vivien@planete-kraus.eu'; \ fi; \ case `/usr/bin/xgettext --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \ /usr/bin/xgettext --default-domain=marchande --directory=.. \ --add-comments=TRANSLATORS: --keyword=_ --keyword=N_ \ --files-from=./POTFILES.in \ --copyright-holder='Vivien Kraus' \ --msgid-bugs-address="$msgid_bugs_address" \ ;; \ *) \ /usr/bin/xgettext --default-domain=marchande --directory=.. \ --add-comments=TRANSLATORS: --keyword=_ --keyword=N_ \ --files-from=./POTFILES.in \ --copyright-holder='Vivien Kraus' \ --package-name="${package_prefix}marchande" \ --package-version='3.0' \ --msgid-bugs-address="$msgid_bugs_address" \ ;; \ esac /usr/bin/xgettext: AVERTISSEMENT : pour le fichier « src/lexer.l », l'extension « l » est inconnue. On suppose que c'est du C /usr/bin/xgettext: AVERTISSEMENT : pour le fichier « src/parser.y », l'extension « y » est inconnue. On suppose que c'est du C test ! -f marchande.po || { \ if test -f ./marchande.pot-header; then \ sed -e '1,/^#$/d' < marchande.po > marchande.1po && \ cat ./marchande.pot-header marchande.1po > marchande.po; \ rm -f marchande.1po; \ fi; \ if test -f ./marchande.pot; then \ sed -f remove-potcdate.sed < ./marchande.pot > marchande.1po && \ sed -f remove-potcdate.sed < marchande.po > marchande.2po && \ if cmp marchande.1po marchande.2po >/dev/null 2>&1; then \ rm -f marchande.1po marchande.2po marchande.po; \ else \ rm -f marchande.1po marchande.2po ./marchande.pot && \ mv marchande.po ./marchande.pot; \ fi; \ else \ mv marchande.po ./marchande.pot; \ fi; \ } make[5] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » test -z "fr.po-update" || make fr.po-update make[5] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » fr: msgmerge --lang=fr fr.po marchande.pot -o fr.new.po ........ terminé. make[5] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » make update-gmo make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » dists="Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot Makevars POTFILES.in fr.po fr.gmo "; \ if test "marchande" = "gettext-tools"; then \ dists="$dists Makevars.template"; \ fi; \ if test -f ./marchande.pot; then \ dists="$dists marchande.pot stamp-po"; \ fi; \ if test -f ./ChangeLog; then \ dists="$dists ChangeLog"; \ fi; \ for i in 0 1 2 3 4 5 6 7 8 9; do \ if test -f ./ChangeLog.$i; then \ dists="$dists ChangeLog.$i"; \ fi; \ done; \ if test -f ./LINGUAS; then dists="$dists LINGUAS"; fi; \ for file in $dists; do \ if test -f $file; then \ cp -p $file ../marchande-3.0/po || exit 1; \ else \ cp -p ./$file ../marchande-3.0/po || exit 1; \ fi; \ done make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/po » make \ top_distdir="marchande-3.0" distdir="marchande-3.0" \ dist-info make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » test -n "" \ || find "marchande-3.0" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-3.0" make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » tardir=marchande-3.0 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-3.0.tar.gz make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3 » if test -d "marchande-3.0"; then find "marchande-3.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-3.0" || { sleep 5 && rm -rf "marchande-3.0"; }; else :; fi case 'marchande-3.0.tar.gz' in \ *.tar.gz*) \ eval GZIP= gzip --best -dc marchande-3.0.tar.gz | ${TAR-tar} xf - ;;\ *.tar.bz2*) \ bzip2 -dc marchande-3.0.tar.bz2 | ${TAR-tar} xf - ;;\ *.tar.lz*) \ lzip -dc marchande-3.0.tar.lz | ${TAR-tar} xf - ;;\ *.tar.xz*) \ xz -dc marchande-3.0.tar.xz | ${TAR-tar} xf - ;;\ *.tar.Z*) \ uncompress -c marchande-3.0.tar.Z | ${TAR-tar} xf - ;;\ *.shar.gz*) \ eval GZIP= gzip --best -dc marchande-3.0.shar.gz | unshar ;;\ *.zip*) \ unzip marchande-3.0.zip ;;\ esac chmod -R a-w marchande-3.0 chmod u+w marchande-3.0 mkdir marchande-3.0/_build marchande-3.0/_build/sub marchande-3.0/_inst chmod a-w marchande-3.0 test -d marchande-3.0/_build || exit 0; \ dc_install_base=`CDPATH="${ZSH_VERSION+.}:" && cd marchande-3.0/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="${TMPDIR-/tmp}/am-dc-$$/" \ && am__cwd=`pwd` \ && CDPATH="${ZSH_VERSION+.}:" && cd marchande-3.0/_build/sub \ && ../../configure \ \ \ --srcdir=../.. --prefix="$dc_install_base" \ && make \ && make dvi \ && make check \ && make install \ && make installcheck \ && make uninstall \ && make distuninstallcheck_dir="$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$dc_destdir") \ && make DESTDIR="$dc_destdir" install \ && make DESTDIR="$dc_destdir" uninstall \ && make DESTDIR="$dc_destdir" \ distuninstallcheck_dir="$dc_destdir" distuninstallcheck; \ } || { rm -rf "$dc_destdir"; exit 1; }) \ && rm -rf "$dc_destdir" \ && make dist \ && rm -rf marchande-3.0.tar.gz \ && make distcleancheck \ && cd "$am__cwd" \ || exit 1 checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking readline/readline.h usability... yes checking readline/readline.h presence... yes checking for readline/readline.h... yes checking readline/history.h usability... yes checking readline/history.h presence... yes checking for readline/history.h... yes checking whether NLS is requested... yes checking for msgfmt... /usr/bin/msgfmt checking for gmsgfmt... /usr/bin/msgfmt checking for xgettext... /usr/bin/xgettext checking for msgmerge... /usr/bin/msgmerge checking for ld used by gcc... /usr/bin/ld -m elf_x86_64 checking if the linker (/usr/bin/ld -m elf_x86_64) is GNU ld... yes checking for shared library run path origin... done checking for CFPreferencesCopyAppValue... no checking for CFLocaleCopyCurrent... no checking for GNU gettext in libc... yes checking whether to use NLS... yes checking where the gettext function comes from... libc checking for library containing readline... -lreadline checking for library containing add_history... none required checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating po/Makefile.in config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands config.status: executing po-directories commands config.status: creating po/POTFILES config.status: creating po/Makefile make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make all-recursive make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making all in po make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[3]: rien à faire pour « all ». make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » CC src/libmarchande.lo CC src/main.o CC src/parser.lo CC src/lexer.lo CC src/complete.o CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande_complete CCLD src/marchande make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making dvi in po make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[2]: rien à faire pour « dvi ». make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » TEXI2DVI doc/marchande.dvi make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make check-recursive make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making check in po make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[3]: rien à faire pour « check ». make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make src/check make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » CC src/check.o CCLD src/check make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make check-TESTS make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[5] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » PASS: src/run-test ============================================================================ Testsuite summary for marchande 3.0 ============================================================================ # TOTAL: 1 # PASS: 1 # SKIP: 0 # XFAIL: 0 # FAIL: 0 # XPASS: 0 # ERROR: 0 ============================================================================ make[5] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make install-recursive make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making install in po make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » installing ../../../po/fr.gmo as /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/locale/fr/LC_MESSAGES/marchande.mo if test "marchande" = "gettext-tools"; then \ /bin/mkdir -p /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/gettext/po; \ for file in Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot Makevars.template; do \ /usr/bin/install -c -m 644 ../../../po/$file \ /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/gettext/po/$file; \ done; \ for file in Makevars; do \ rm -f /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/gettext/po/$file; \ done; \ else \ : ; \ fi make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/include' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin' /bin/mkdir -p '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin/marchande_complete make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making installcheck in po make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[2]: rien à faire pour « installcheck ». make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[2]: rien à faire pour « installcheck-am ». make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making uninstall in po make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » catalogs='fr.gmo'; \ for cat in $catalogs; do \ cat=`basename $cat`; \ lang=`echo $cat | sed -e 's/\.gmo$//'`; \ for lc in LC_MESSAGES ; do \ rm -f /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/locale/$lang/$lc/marchande.mo; \ done; \ done if test "marchande" = "gettext-tools"; then \ for file in Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot Makevars.template; do \ rm -f /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/gettext/po/$file; \ done; \ else \ : ; \ fi make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin' && rm -f marchande marchande_complete ) ( cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/include' && rm -f marchande.h ) rm -rf '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/doc/marchande/marchande.html' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/doc/marchande/marchande.dvi' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/doc/marchande/marchande.pdf' rm -f '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/doc/marchande/marchande.ps' install-info --info-dir='/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' --remove '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info/marchande.info' cd '/builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make install-recursive make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making install in po make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » installing ../../../po/fr.gmo as /tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/locale/fr/LC_MESSAGES/marchande.mo if test "marchande" = "gettext-tools"; then \ /bin/mkdir -p /tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/gettext/po; \ for file in Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot Makevars.template; do \ /usr/bin/install -c -m 644 ../../../po/$file \ /tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/gettext/po/$file; \ done; \ for file in Makevars; do \ rm -f /tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/gettext/po/$file; \ done; \ else \ : ; \ fi make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » /bin/mkdir -p '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/include' /bin/mkdir -p '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin' /bin/mkdir -p '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' /usr/bin/install -c -m 644 ../../src/marchande.h '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/include' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin' /usr/bin/install -c -m 644 ../../doc/marchande.info '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' install-info --info-dir='/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin/marchande_complete make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making uninstall in po make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » catalogs='fr.gmo'; \ for cat in $catalogs; do \ cat=`basename $cat`; \ lang=`echo $cat | sed -e 's/\.gmo$//'`; \ for lc in LC_MESSAGES ; do \ rm -f /tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/locale/$lang/$lc/marchande.mo; \ done; \ done if test "marchande" = "gettext-tools"; then \ for file in Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot Makevars.template; do \ rm -f /tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/gettext/po/$file; \ done; \ else \ : ; \ fi make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » ( cd '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/bin' && rm -f marchande marchande_complete ) rm -rf '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/doc/marchande/marchande.html' ( cd '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/include' && rm -f marchande.h ) rm -f '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/doc/marchande/marchande.pdf' rm -f '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/doc/marchande/marchande.dvi' rm -f '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/doc/marchande/marchande.ps' install-info --info-dir='/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' --remove '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info/marchande.info' cd '/tmp/am-dc-16199//builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_inst/share/info' && rm -f marchande.info marchande.info-[0-9] marchande.info-[0-9][0-9] marchande.i[0-9] marchande.i[0-9][0-9] make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make dist-gzip am__post_remove_distdir='@:' make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make distdir-am make[3] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » if test -d "marchande-3.0"; then find "marchande-3.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-3.0" || { sleep 5 && rm -rf "marchande-3.0"; }; else :; fi test -d "marchande-3.0" || mkdir "marchande-3.0" (cd po && make top_distdir=../marchande-3.0 distdir=../marchande-3.0/po \ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir) make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » test -z "update-po" || make update-po make[5] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make marchande.pot-update make[6] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » sed -e '/^#/d' ../../../po/remove-potcdate.sin > t-remove-potcdate.sed mv t-remove-potcdate.sed remove-potcdate.sed package_gnu=""; \ test -n "$package_gnu" || { \ if { if (LC_ALL=C find --version) 2>/dev/null | grep GNU >/dev/null; then \ LC_ALL=C find -L ../../.. -maxdepth 1 -type f \ -size -10000000c -exec grep 'GNU marchande' \ /dev/null '{}' ';' 2>/dev/null; \ else \ LC_ALL=C grep 'GNU marchande' ../../../* 2>/dev/null; \ fi; \ } | grep -v 'libtool:' >/dev/null; then \ package_gnu=yes; \ else \ package_gnu=no; \ fi; \ }; \ if test "$package_gnu" = "yes"; then \ package_prefix='GNU '; \ else \ package_prefix=''; \ fi; \ if test -n 'vivien@planete-kraus.eu' || test 'vivien@planete-kraus.eu' = '@'PACKAGE_BUGREPORT'@'; then \ msgid_bugs_address='vivien@planete-kraus.eu'; \ else \ msgid_bugs_address='vivien@planete-kraus.eu'; \ fi; \ case `/usr/bin/xgettext --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \ /usr/bin/xgettext --default-domain=marchande --directory=../../.. \ --add-comments=TRANSLATORS: --keyword=_ --keyword=N_ \ --files-from=../../../po/POTFILES.in \ --copyright-holder='Vivien Kraus' \ --msgid-bugs-address="$msgid_bugs_address" \ ;; \ *) \ /usr/bin/xgettext --default-domain=marchande --directory=../../.. \ --add-comments=TRANSLATORS: --keyword=_ --keyword=N_ \ --files-from=../../../po/POTFILES.in \ --copyright-holder='Vivien Kraus' \ --package-name="${package_prefix}marchande" \ --package-version='3.0' \ --msgid-bugs-address="$msgid_bugs_address" \ ;; \ esac /usr/bin/xgettext: AVERTISSEMENT : pour le fichier « src/lexer.l », l'extension « l » est inconnue. On suppose que c'est du C /usr/bin/xgettext: AVERTISSEMENT : pour le fichier « src/parser.y », l'extension « y » est inconnue. On suppose que c'est du C test ! -f marchande.po || { \ if test -f ../../../po/marchande.pot-header; then \ sed -e '1,/^#$/d' < marchande.po > marchande.1po && \ cat ../../../po/marchande.pot-header marchande.1po > marchande.po; \ rm -f marchande.1po; \ fi; \ if test -f ../../../po/marchande.pot; then \ sed -f remove-potcdate.sed < ../../../po/marchande.pot > marchande.1po && \ sed -f remove-potcdate.sed < marchande.po > marchande.2po && \ if cmp marchande.1po marchande.2po >/dev/null 2>&1; then \ rm -f marchande.1po marchande.2po marchande.po; \ else \ rm -f marchande.1po marchande.2po ../../../po/marchande.pot && \ mv marchande.po ../../../po/marchande.pot; \ fi; \ else \ mv marchande.po ../../../po/marchande.pot; \ fi; \ } make[6] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » test -z "fr.po-update" || make fr.po-update make[6] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » fr: cd ../../../po && msgmerge --lang=fr fr.po marchande.pot -o fr.new.po .... terminé. make[6] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make update-gmo make[5] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[5] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » dists="Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot Makevars POTFILES.in ../../../po/fr.po ../../../po/fr.gmo "; \ if test "marchande" = "gettext-tools"; then \ dists="$dists Makevars.template"; \ fi; \ if test -f ../../../po/marchande.pot; then \ dists="$dists marchande.pot stamp-po"; \ fi; \ if test -f ../../../po/ChangeLog; then \ dists="$dists ChangeLog"; \ fi; \ for i in 0 1 2 3 4 5 6 7 8 9; do \ if test -f ../../../po/ChangeLog.$i; then \ dists="$dists ChangeLog.$i"; \ fi; \ done; \ if test -f ../../../po/LINGUAS; then dists="$dists LINGUAS"; fi; \ for file in $dists; do \ if test -f $file; then \ cp -p $file ../marchande-3.0/po || exit 1; \ else \ cp -p ../../../po/$file ../marchande-3.0/po || exit 1; \ fi; \ done make[5] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make \ top_distdir="marchande-3.0" distdir="marchande-3.0" \ dist-info make[4] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[4] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » test -n "" \ || find "marchande-3.0" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/bash /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "marchande-3.0" make[3] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » tardir=marchande-3.0 && ${TAR-tar} chof - "$tardir" | eval GZIP= gzip --best -c >marchande-3.0.tar.gz make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » if test -d "marchande-3.0"; then find "marchande-3.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-3.0" || { sleep 5 && rm -rf "marchande-3.0"; }; else :; fi make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » make[1] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » Making distclean in po make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » rm -f *.insert-header rm -f remove-potcdate.sed rm -f stamp-poT rm -f core core.* marchande.po marchande.1po marchande.2po *.new.po rm -fr *.o rm -f Makefile Makefile.in POTFILES *.mo make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub/po » make[2] : on entre dans le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » test -z "doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html" \ || rm -rf doc/marchande.dvi doc/marchande.pdf doc/marchande.ps \ doc/marchande.html rm -rf .libs _libs test -z "src/libmarchande.la" || rm -f src/libmarchande.la rm -rf doc/marchande.t2d doc/marchande.t2p rm -f src/marchande src/marchande_complete rm -f src/check rm -f *.o rm -rf src/.libs src/_libs test -z "src/run-test.log" || rm -f src/run-test.log rm -f *.lo rm -f *.tab.c test -z "" || rm -f rm -f src/*.o test -z "src/run-test.trs" || rm -f src/run-test.trs rm -f config.h stamp-h1 test . = "../.." || test -z "" || rm -f rm -f libtool config.lt rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags rm -f src/so_locations test -z "test-suite.log" || rm -f test-suite.log rm -f src/*.lo rm -f doc/.dirstamp rm -f cscope.out cscope.in.out cscope.po.out cscope.files rm -f src/.deps/.dirstamp rm -f src/.dirstamp make[2] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » rm -f config.status config.cache config.log configure.lineno config.status.lineno rm -f src/.deps/check.Po rm -f src/.deps/complete.Po rm -f src/.deps/lexer.Plo rm -f src/.deps/libmarchande.Plo rm -f src/.deps/main.Po rm -f src/.deps/parser.Plo rm -f Makefile make[1] : on quitte le répertoire « /builds/gugurumbe/programmer-une-interface-en-ligne-de-commande/public/v3/marchande-3.0/_build/sub » if test -d "marchande-3.0"; then find "marchande-3.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "marchande-3.0" || { sleep 5 && rm -rf "marchande-3.0"; }; else :; fi =============================================== marchande-3.0 archives ready for distribution: marchande-3.0.tar.gz =============================================== Built
Installons la version 3.0.
cp v3/marchande-3.0.tar.gz /tmp cd /tmp tar xf marchande-3.0.tar.gz mkdir -p build cd build ../marchande-3.0/configure --prefix=/tmp/v3 2>&1 make V=0 -j 2>&1 make V=0 -j install 2>&1
checking for gcc... gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... no checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ISO C89... none needed checking whether gcc understands -c and -o together... yes checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... no checking for mawk... mawk checking whether make sets $(MAKE)... yes checking whether make supports the include directive... yes (GNU style) checking whether make supports nested variables... yes checking dependency style of gcc... gcc3 checking build system type... x86_64-pc-linux-gnu checking host system type... x86_64-pc-linux-gnu checking how to print strings... printf checking for a sed that does not truncate output... /bin/sed checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for fgrep... /bin/grep -F checking for ld used by gcc... /usr/bin/ld checking if the linker (/usr/bin/ld) is GNU ld... yes checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B checking the name lister (/usr/bin/nm -B) interface... BSD nm checking whether ln -s works... yes checking the maximum length of command line arguments... 1879296 checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop checking for /usr/bin/ld option to reload object files... -r checking for objdump... objdump checking how to recognize dependent libraries... pass_all checking for dlltool... no checking how to associate runtime and link libraries... printf %s\n checking for ar... ar checking for archiver @FILE support... @ checking for strip... strip checking for ranlib... ranlib checking command to parse /usr/bin/nm -B output from gcc object... ok checking for sysroot... no checking for a working dd... /bin/dd checking how to truncate binary pipes... /bin/dd bs=4096 count=1 checking for mt... no checking if : is a manifest tool... no checking how to run the C preprocessor... gcc -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for dlfcn.h... yes checking for objdir... .libs checking if gcc supports -fno-rtti -fno-exceptions... no checking for gcc option to produce PIC... -fPIC -DPIC checking if gcc PIC flag -fPIC -DPIC works... yes checking if gcc static flag -static works... yes checking if gcc supports -c -o file.o... yes checking if gcc supports -c -o file.o... (cached) yes checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes checking whether -lc should be explicitly linked in... no checking dynamic linker characteristics... GNU/Linux ld.so checking how to hardcode library paths into programs... immediate checking whether stripping libraries is possible... yes checking if libtool supports shared libraries... yes checking whether to build shared libraries... yes checking whether to build static libraries... yes checking readline/readline.h usability... yes checking readline/readline.h presence... yes checking for readline/readline.h... yes checking readline/history.h usability... yes checking readline/history.h presence... yes checking for readline/history.h... yes checking whether NLS is requested... yes checking for msgfmt... /usr/bin/msgfmt checking for gmsgfmt... /usr/bin/msgfmt checking for xgettext... /usr/bin/xgettext checking for msgmerge... /usr/bin/msgmerge checking for ld used by gcc... /usr/bin/ld -m elf_x86_64 checking if the linker (/usr/bin/ld -m elf_x86_64) is GNU ld... yes checking for shared library run path origin... done checking for CFPreferencesCopyAppValue... no checking for CFLocaleCopyCurrent... no checking for GNU gettext in libc... yes checking whether to use NLS... yes checking where the gettext function comes from... libc checking for library containing readline... -lreadline checking for library containing add_history... none required checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating po/Makefile.in config.status: creating config.h config.status: executing depfiles commands config.status: executing libtool commands config.status: executing po-directories commands config.status: creating po/POTFILES config.status: creating po/Makefile make all-recursive make[1] : on entre dans le répertoire « /tmp/build » Making all in po make[2] : on entre dans le répertoire « /tmp/build/po » make[2]: rien à faire pour « all ». make[2] : on quitte le répertoire « /tmp/build/po » make[2] : on entre dans le répertoire « /tmp/build » CC src/main.o CC src/libmarchande.lo CC src/parser.lo CC src/lexer.lo CC src/complete.o CCLD src/libmarchande.la ar: `u' modifier ignored since `D' is the default (see `U') CCLD src/marchande CCLD src/marchande_complete make[2] : on quitte le répertoire « /tmp/build » make[1] : on quitte le répertoire « /tmp/build » make install-recursive make[1] : on entre dans le répertoire « /tmp/build » Making install in po make[2] : on entre dans le répertoire « /tmp/build/po » installing ../../marchande-3.0/po/fr.gmo as /tmp/v3/share/locale/fr/LC_MESSAGES/marchande.mo if test "marchande" = "gettext-tools"; then \ /bin/mkdir -p /tmp/v3/share/gettext/po; \ for file in Makefile.in.in remove-potcdate.sin quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot Makevars.template; do \ /usr/bin/install -c -m 644 ../../marchande-3.0/po/$file \ /tmp/v3/share/gettext/po/$file; \ done; \ for file in Makevars; do \ rm -f /tmp/v3/share/gettext/po/$file; \ done; \ else \ : ; \ fi make[2] : on quitte le répertoire « /tmp/build/po » make[2] : on entre dans le répertoire « /tmp/build » make[3] : on entre dans le répertoire « /tmp/build » /bin/mkdir -p '/tmp/v3/include' /usr/bin/install -c -m 644 ../marchande-3.0/src/marchande.h '/tmp/v3/include' /bin/mkdir -p '/tmp/v3/bin' /bin/mkdir -p '/tmp/v3/share/info' /bin/bash ./libtool --mode=install /usr/bin/install -c src/marchande src/marchande_complete '/tmp/v3/bin' /usr/bin/install -c -m 644 ../marchande-3.0/doc/marchande.info '/tmp/v3/share/info' install-info --info-dir='/tmp/v3/share/info' '/tmp/v3/share/info/marchande.info' libtool: install: /usr/bin/install -c src/marchande /tmp/v3/bin/marchande libtool: install: /usr/bin/install -c src/marchande_complete /tmp/v3/bin/marchande_complete make[3] : on quitte le répertoire « /tmp/build » make[2] : on quitte le répertoire « /tmp/build » make[1] : on quitte le répertoire « /tmp/build »
On peut maintenant tester le programme en français !
LANG=fr_FR.UTF-8 /tmp/v3/bin/marchande 2>&1 <<EOF une botte de radis 1 kg de tomates 1,3 kg de patates Que pensez-vous du logiciel libre ? ce sera tout EOF
marchande Copyright (C) 2019 Vivien Kraus Ce programme n'est accompagné d'ABSOLUMENT AUCUNE GARANTIE. Ce programme est libre, et vous êtes invité à le redistribuer sous certaines conditions. Voir la License Publique Générale de GNU (GNU GPL) pour plus de détails. En essayant de vous rétablir de cette attaque de texte juridique inattendue, vous levez les yeux vers la marchande. Elle a : * quelques bottes de radis ; * quelques patates. - Au suivant ! Bonjour :) Qu'est-ce que ça sera ? - une botte de radis La marchande prend les radis et vous les met de côté. - Et avec ceci ? - 1 kg de tomates - Désolé, je n'ai pas de tomates. - 1,3 kg La marchande attent patiemment que vous finissiez votre phrase. - de patates La marchande pèse les pommes de terre et vous les met de côté. - Et avec ceci ? - Que pensez-vous du logiciel libre ? - Hein ? La marchande n'a pas compris ce que vous essayiez de dire. - ce sera tout Vous payez la marchande, prenez vos affaires et partez.
Le programme de complétion reste en anglais, parce que l'initialisation de gettext ne se fait pas sans afficher le bonjour de la marchande.
export PATH=/tmp/v3/bin:$PATH ( echo "Complete 'that will be all'" \ && marchande_complete "" "" \ && echo "Complete 'that will be all'" \ && marchande_complete "" "will be all" \ && echo "Can't guess a number" \ && marchande_complete "1." "kg of potatoes" \ && echo "Don't expect radishes" \ && marchande_complete "1.3 kg of" "" \ && echo "Guess the unit" \ && marchande_complete "1 " "of radishes" \ && echo "Ambiguous" \ && marchande_complete "" "bunch of radishes" ) > completion_actual_3.txt || exit 1 md5sum completion_expected.txt completion_actual_3.txt
93362c72d2101054e85def2660fa742a completion_expected.txt 93362c72d2101054e85def2660fa742a completion_actual_3.txt
8 Conclusion
Dans ce petit exemple, nous avons vu un certain nombre de points intéressants et assez faciles à mettre en œuvre :
- Comment faire un parseur pour un langage ;
- Comment aider l'humain de l'autre côté du clavier avec l'auto-complétion contextuelle ;
- Comment traduire le langage pour que la grammaire soit dans la langue de la locale ;
- Vous avez musclé votre index à force de faire défiler l'écran !
Il reste des limites à cet exemple :
- Nous n'avons pas du tout fait d'effort sur les messages d'erreur : il est pourtant possible d'indiquer le texte qui a mené à une erreur avec ses positions précises ;
- La complétion contextuelle ne fonctionne qu'en isolation des lignes de texte passées. En pratique, si on sait où commencent et où se terminent les commandes (grâce à leurs positions), et qu'on suppose que les commandes sont indépendantes, il faudrait ne garder que le texte de la dernière commande pour l'auto-complétion.