_ _ __ ____
_ __ ___ _ _ _ __ _ __(_)_ __ | |_ / _|/ /\ \
| '_ ` _ \| | | | | '_ \| '__| | '_ \| __| |_| | | |
| | | | | | |_| | | |_) | | | | | | | |_| _| | | |
|_| |_| |_|\__, |____| .__/|_| |_|_| |_|\__|_| | | | |
|___/_____|_| \_\/_/
Groupe de News: epita.cours.c-unix.st_printf
Date de rendu: mercredi 30 octobre 2002 - 08:00:42
Repertoire de rendu: ~/c/rendu/mp/my_printf
Droits sur le rep et les exos: 700 sur ~/c/rendu/mp/ et ~/c/rendu/mp/my_printf
700 pour les scripts tels que configure
600 pour les fichiers
o+x ~/ ~/c/ ~/c/rendu/
-------------------------------------------------------------------------------
Syscalls, fonctions et macros autorisees
-------------------------------------------------------------------------------
malloc(3) free(3) assert(3)
va_{start,arg,end}(3)
fwrite(3) perror(3)
write(2)
isnan(3) isinf(3)
-------------------------------------------------------------------------------
Manuels autorises
-------------------------------------------------------------------------------
Aucun, les seuls manuels autorises sont les man de printf(3) sur NetBSD,
FreeBSD, Linux et OSF/1, et le manuel de printf(1).
Pour savoir ce que fait une option, cherchez dans chacun de ces manuels avant
de poser la question. Toutes les versions de printf(3) n'implementent pas les
memes possibilites.
-------------------------------------------------------------------------------
Description
-------------------------------------------------------------------------------
_____________
< c'est parti >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Prototype:
int my_printf(const char *fmt, ...);
Il s'agit de coder la fonction my_printf(), qui est basee sur la fonction
printf(3) de la bibliotheque standard, dont vous avez vu le fonctionnement
en cours. Le comportement devra etre exactement le meme que celui de printf(3)
de NetBSD, du moins pour les possibilites communes entre votre my_printf() et
le printf(3) de NetBSD.
Cette fonction produit une sortie bufferisee sur stdout dont le format est
decrit dans l'argument `fmt'. Cela signifie que la chaine de caracteres `fmt'
controle la facon dont seront interpretes les arguments qui suivent. En effet,
comme vous avez pu le constater, le type des arguments suivant `fmt' n'est pas
declare dans le prototype de my_printf().
La valeur de retour de la fonction my_printf() est le nombre de caracteres
ecrits sur la sortie standart.
Votre fonction devra au moins implementer les `indicateurs de conversion'
(`conversion specifiers' en anglais) suivants pour acceder au niveau 1, et
commencer a gagner des points :
`d' `i' `u' `o' `x' `X' `s' `c'
Reportez vous a la page de manuel printf(3) pour connaitre leur signification.
Note: Il est bien entendu *evident* qu'un acu doit pouvoir afficher le
caractere '%' avec votre fonction...
Comme d'habitude, une fois implementee la partie obligatoire, vous avez la
possibilite d'implementer incrementalement les differents niveaux decrits
ci-dessous.
-------------------------------------------------------------------------------
Niveau 1
-------------------------------------------------------------------------------
______________________________________________________
< allez un peu de courage, c'est que le premier niveau >
------------------------------------------------------
\ ^__^
\ (..)\_______
(__)\ )\/\
||----w |
|| ||
Pour commencer ce niveau, vous devez implementer l'identificateur de
conversion `p'.
Maintenant que votre my_printf() fonctionne pour une utilisation basique, il
serait agreable d'avoir des possibilites de formatage plus avancees, meme si a
priori vous n'aurez que rarement a vous en servir dans votre vie... ;)
Vous devez donc implementer les flags suivants :
`#' `0' ` ' `-' `+'
ainsi que la largeur minimum du champ (`minimum field width' dans le man), la
precision, les `{,un}signed short int', les `{,un}signed long int' ainsi que
les `signed char' et `unsigned char' (c'est a dire des char interpretes comme
de petits entiers).
A vous de trouver dans les manuels fournis la syntaxe a utiliser.
/*
** Ce passage est deliberement flou pour vous obliger a reflechir et a bien
** comprendre chacune des options de printf(3) en lisant les manuels.
*/
Note: Notez bien qu'il est possible de specifier la largeur minimum du champ et
la precision, non pas dans la chaine de format, mais dans les arguments. Vous
trouverez la syntaxe dans le manuel (vous n'avez pas a implementer la
possibilite de dire << je veux utiliser le 3eme argument comme largeur minimum
du champ ou comme precision >>).
Attention: Parfois les implementations de printf(3) conservent des options qui
sont maintenant obsoletes, par souci de compatibilite avec les anciennes
applications. Vous n'etes pas censes supporter cette `backward compatibility',
vous ne serez bien entendu pas penalise si vous le faites. En revanche vous
devez absolument supporter les versions standards de ces options.
-------------------------------------------------------------------------------
Niveau 2
-------------------------------------------------------------------------------
_______________________________________________________
< allez encore un effort, vous etes presque a la moitie >
-------------------------------------------------------
\ ^__^
\ (xx)\_______
(__)\ )\/\
U ||----w |
|| ||
Vous devez gerer l'identificateur de conversion `n' (ainsi que "%hn"), reportez
vous au manuel (celui d'OSF/1 ou de Linux pour "%hn")...
De la meme facon, vous devez implementer l'identificateur de conversion `b'.
Cela permet d'interpreter les chaines de caracteres de type "\n", etc... Pour
avoir une description exacte de cet identificateur de conversion, reportez-vous
a la page de manuel printf(1).
Attention: lorsque vous specifiez "\n" dans un fichier C, le compilateur va
l'interpreter et le remplacer par un unique caractere (dont le code ASCII est
10). Si vous ne souhaitez pas ce comportementi (ie. vous souhaitez vraiment avoir les 2 caracteres "\n" dans votre chaine), utilisez "\\n".
La partie amusante, et peu orthodoxe, est decrite ci-dessous :
* "%r" permet d'afficher une chaine a l'envers
ex:
my_printf("%r", "i love epita"); /* affiche "atipe evol i" */
my_printf("%r", "kayak"); /* affiche "kayak" */
* "%a" permet d'afficher une adresse IPv4 sous la forme XXX.XXX.XXX.XXX
(ou XXX represente un nombre en base 10). Dans ce cas le parametre
passe est de type uint32_t.
ex:
my_printf("%a", 0xC0A82A03); /* affiche "192.168.42.3" */
* "%A" permet d'afficher une addresse IPv6 sous la forme
XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX (ou XXXX represente 2 octets
ecrits en base 16). Dans ce cas le parametre passe est de type
uint32_t[4] (ce n'est pas correct en C, mais vous comprennez que
c'est un tableau de 4 uint32_t).
ex:
uint32_t addr6[4] = { 0, 0, 0, 10 };
my_printf("%A", addr6}; /* affiche 0:0:0:0:0:0:0:a */
* "%z" permet d'afficher la lettre 'z' ;o) (ca vous manquait hein ?)
* "%y" permet d'afficher les modes d'un fichier, tel que le fait ls -l.
ex:
struct stat st;
stat("/", &st);
my_printf("%y", st.st_mode); /* affiche "drwxr-xr-x" */
Note: Ces identificateurs de conversions ne sont pas standards, cela implique
generalement que tous les flags et les champs optionnel qui peuvent etre
places avant un identificateur de conversion (voir niveau 1) n'auront pas
necessairement une signification. A vous de determiner quels flags et quels
champs optionnels il est possible d'utiliser avec chacun des identificateurs
de conversion non standards.
-------------------------------------------------------------------------------
Niveau 3
-------------------------------------------------------------------------------
________________________________________
/ vous etes encore vivant ? encore une \
| etape et vous eclatez tous les scores. |
\ A VOUS LES POINTS !! /
----------------------------------------
\ ^__^
\ ($$)\_______
(__)\ )\/\
||----w |
|| ||
Vous devez implenter les identificateurs `e' `E' `f' `F' `g' `G' qui permettent
d'afficher des double. Bien entendu, si vous gerez les `long double' egalement,
ce sera appreciable.
-------------------------------------------------------------------------------
Bonus
-------------------------------------------------------------------------------
Implementez "%ttz" et "%mouf", qui permettent respectivement d'afficher un
singe et un chien en ascii-art.
-------------------------------------------------------------------------------
Modalites de rendus et contraintes
-------------------------------------------------------------------------------
Votre repertoire de rendu doit contenir vos sources, un fichier Makefile, et
optionnellement un script configure, ou un fichier Rules.make, ...
Votre Makefile doit construire une bibliotheque contenant la fonction
my_printf(), sous la forme d'une archive autonome dont le nom sera :
libmy_printf_`uname -m`-`uname -s`.a
Evidemment comme l'impose la norme ("tout fichier C doit avoir son header
correspondant"), le fichier my_printf.h contiendra le prototype de votre
fonction my_printf(). Vous pouvez utiliser plusieurs fichiers C et H pour
implementer votre mini-projet -c'est d'ailleurs conseille-.
Afin de gerer les entrees sorties bufferisee, vous pouvez utiliser les
fonction fopen(3), fclose(3) et fwrite(3). Si vous utilisez votre libstream a
la place, vous aurez un bonus. Bien entendu, si vous utilisez votre libstream,
arrangez vous pour ne surtout pas faire de lseek(2) ou de read(2). En effet,
si votre libstream effectue un appel systeme non autorise a votre insu, la
note de 0 vous sera attribue. Attention egalement a d'eventuels bugs dont
souffrirait vos libstream, il serait dommage que ces bugs vous penalisent pour
deux mini-projets (libstream et my_printf).
Toujours comme d'habitude, votre bibliotheque *NE DOIT PAS* contenir de
fonction main().
Les tests susceptibles d'etre effectues par la moulinette de correction
appartiennent a l'ensemble des tests qui ne produisent pas de warnings avec
gcc et les options "-Wall -W -pedantic -std=c99". Attention, seul gcc 3.x
gère le standard c99; une version 3.2 est dispo ici:
/u/dp/public/arch/i386-NetBSD/bin/gcc-3.2
Les autres modalites de rendu (regles de Makefile, options de compilation),
ainsi que vos sources, doivent etre conformes aux specifications
correspondantes du CSS << norme >>.
Note: N'oubliez pas le fichier AUTHORS, specifie dans le CSS.
-------------------------------------------------------------------------------
Archive de rendu
-------------------------------------------------------------------------------
Une fois que vous avez termine votre travail, vous devez rendre vos sources
dans le fichier :
~/c/rendu/$USER-mp-my_printf.tar.gz.gpg
Pour generer ce fichier, utilisez le script ~acu/mbin/rendu.sh, comme suit :
~acu/mbin/rendu.sh mp my_printf
Attention: Cette archive doit etre lisible par tout le monde.
-------------------------------------------------------------------------------
Rappels
-------------------------------------------------------------------------------
Avant de poser une question sur les news, reflechissez, relisez le passage
correspondant dans le sujet et dans les manuels fournis.
Tout ce qui n'est pas explicitement demande n'est pas a faire.
Dorenavant les questions jugees inutiles ou ayant leur reponse dans le sujet
ou dans les pages de manuels seron ignorees par les ACUs.
Nous sommes en effet au troisieme mini-projet, il est temps de vous prendre en
charge et de ne plus avoir besoin qu'on vous prenne par la main.
|