#######################################
#                                     #
#     Norme de développement in *     #
#                                     #
#     Made by Nicolas Sadirac         #
#     Login   rn@epita.fr             #
#                                     #
#######################################

Version du 11 octobre 2000  04h45.


Cette norme a pour but d'uniformiser l'écriture des programmes au sein
d'EPITA et d'EPITECH. Elle concerne:

1) La nomination des objets

2) La présentation globale (paragraphes)

3) La présentation locale (lignes)

4) Headers (fichier includes)

5) Des recommandations (non obligatoires)

6) Un exemple de Makefile


1) La nomination des objets :

Les objets (variable, fonctions, macros, types, fichiers ou
répertoires) doivent avoir des noms les plus explicites ou
mnémoniques.

Les abréviations sont TOLEREES dans la mesure ou elles permettent de
réduire significativement la taille du nom sans en perdre le sens. Les
parties des noms composites serons séparées par '_'.

ex:

	#define MAX_LINE_SIZE           256
	#define COMMENT_CHAR            '#'
	#define MAX_ANIM_NAME_LENGTH    64
	#define MAX_FILE_NAME_LENGTH    1024

* Tous les identifiants (fonctions, macros, types, variables etc.) doivent
  être en anglais.

* Les noms de variables et de fonctions de fichiers et de répertoires
  doivent être composes exclusivement de minuscules, de chiffres et
  de '_'.

* Les noms de macros doivent être en majuscules.  Leurs paramètres ont
  des noms comme `Ceci', pas comme `CA', et pas plus `ainsi'.

	# define XFREE(Var)     \
	   do			\
	     {			\
	       if (Var)		\
		 free(Var);	\
	     }			\
	   while (0)

* Dans  le  cas  de  la  déclaration  d'une  structure  le  nom
  commencera par "s_", pour un type par "t_", pour une union par
  "u_" et  pour une enum "e_".

	ex:

	typedef unsigned char   t_cmap[CMAP_NBR_COL*CMAP_SIZE];
	typedef unsigned char   t_pixel;

	struct 		s_picture
	{
	  int           width;
	  int           height;
	  t_cmap        cmap;
	  t_pixel       *picture;
	};

	typedef struct s_picture        t_picture;

  ATTENTION on peut avoir aussi :

	typedef struct 		s_picture
	{
	  	int           	width;
	  	int           	height;
	  	t_cmap        	cmap;
	  	t_pixel       	*picture;
	}			t_picture;

* Les noms de globales (si il doit absolument y en avoir) commenceront
  par "gl_"


2) Présentation globale

* L'indentation  sera  celle obtenue avec Emacs (avec la config dans
  /u/a1/.env/.emacs)

	int		get_type(char type_char)
	{
	  t_types	*types;

	  for (types = types_tab; types->type_val; types++)
	    if (types->type_val == type_char)
	      return (types->type_val);
	  return (FALSE);
	}

* On passe toujours a la ligne après '{', '}' ou une structure de
  contrôle.  On indente une première fois pour les accolades, puis une
  seconde pour leur contenu.

	if (cp) return (cp);	/* Incorrect */

	if (cp) {return (cp);}	/* Incorrect */

        if (cp)                 /* Admis */
        {
          return (cp);
        }

        if (cp)                 /* Correct */
          {
            return (cp);
          }

  Selon sa configuration, Emacs indentera comme dans le troisième ou
  quatrième exemple.  Les deux sont acceptés, le dernier préféré.
  Pour les mêmes raisons, la taille du saut de l'indentation peut varier.
  On préfèrera 2 espaces.

* On sautera une ligne entre la déclaration de variable et les
  instructions.  On met une variable par ligne. Il ne doit pas y avoir
  d'autres lignes vides dans les blocs. si vous avez envie de séparer
  des parties d'un bloc faites soit plusieurs blocs, soit une
  fonction, soit une macro.

	t_script        *load_script(char *file_name)
	{
	  FILE          *fd;
	  t_script      *script_head;
	  t_script      *last_script;
	  char          line_buff[MAX_LINE_SIZE+2];
	  int		current_line;
	  int		nbr_line;

	  current_line = 0;
	  nbr_line = 0;
	  script_head = SCRIPT_END;
	  F_FOPEN(fd, file_name, "r", "script file");
          ...

* Une ligne ne doit pas exceder 80 caracteres.

* On fera attention à avoir des fonctions courtes et claires,
  de 25 lignes maximum (entre les 2 accolades).
  On évitera aussi d'avoir plus de 5 fonctions par fichier, une
  serait l'idéal.

* Il ne doit pas y avoir de commentaires dans les fonctions. Si il y a
  besoin de commentaires ils doivent se trouver avant la la fonction.
	/*
	** cette fonction calcule ....
	*/
	void	*func_mort_de_rire()
	{
	}

* Les commentaires sont commencés et terminés par une ligne seule.  Toutes
  les lignes intermédiaires s'alignent sur elles, et commencent par `**'

	/*
	** Correct
	*/

	/*
	 * Incorrect
	 */

* La déclaration de paramètre se fera a la syntaxe ISO/ANSI C

	type	func(type1 p1, type2 p2, type3 p3)
	{
	}

  voire

	type	func(type1 p1,
		     type2 p2,
		     type3 p3)
	{
	}


3) Présentation locale

* Un espace derrière le `;' et derrière la `,' :

	for (i = 0; i < 255; i++)
	  sum(&acu, i);

* Pas d'espace entre le nom d'une fonction et la '(' par contre toujours
  un espace entre un mot clé C (avec argument) et la '('

	script_head = SCRIPT_END;
	F_FOPEN(fd, file_name, "r", "script file");
	while (!feof(fd))
	  {
	    if (!fgets(line_buff, MAX_LINE_SIZE+1, fd)
	        || *line_buff == COMMENT_CHAR)
	      continue;
	    line_buff[strlen(line_buff) - 1] = END_OF_STRING;
	#if (DEBUG&D_LOAD)
	    my_printf("got:\"%s\"\n", line_buff);
	#endif
	    put_in_script(&script_head, &last_script, line_buff);
	  }
	...

  Ceci concerne `for' etc. mais aussi `return' et `sizeof'.

* On remarquera que `return' est une structure de contrôle du C, et `exit'
  une fonction, donc attention aux espaces devant la parenthèse.

	/* Correct */
	if (!cp)
	  exit(1);
	return (cp)

	/* Deux fois incorrect */
	if (!cp)
	  exit (1);
	return(cp)

  Lorsque `return' prend un argument, ce dernier doit etre entre parentheses:

	/* Correct */
	return (0);

	/* Incorrect */
	return 0;

* Au maximum on doit trouver 4 paramètres dans une fonction.  (La
  fonction qui possédera au maximum 4 paramètres aura une vitesse
  exécution plus rapide que celle qui en passera plus).  Pour passer
  plus d'information faites une structure et passez un pointeur sur
  cette structure.

* Le symbole de pointeur (*) porte toujours sur la variable (ou
  fonction), et jamais sur le type:

	char *cp;	/* Correct */
	char* cp;	/* Incorrect */

* On alignera les déclarations avec des tab (sous Emacs M-I)

	type		v1;
	struct s_toto	*first_toto;
	struct s_toto	my_struct_toto;
	int		*tmp_int;

* Lorsqu'on déclare une variable on ne peut affecter en même temps une
  valeur excepte lorsqu'on utilise une variable static.

	int		bidon = 1;	/* Incorrect */
	static int	pipot = 1;	/* Correct */
	int		dum;		/* Correct */

* Affectations : il doit y avoir un espace entre la variable gauche et
  le signe d'affectation, de même pour la variable a droite.

	var1 = var2
	var1 += var2
	var1 *= var2

* Opérateurs unaires.  Pas d'espace.

	*cp
	&cp
	-n

* Opérateurs bi/ternaires.  Tous les opérateurs binaires et ternaires
  sont séparés des arguments par un espace de part et d'autre.

	if (a % 10)

	return (cp ? cp : DEFAULT_STRING)

* Les #if et #ifdef indentent d'un caractère les directives cpp
  qui suivent.  Les #else et #endif marquent les conditions dont
  ils sont issus.

	#ifndef DEV_BSIZE
	# ifdef BSIZE
	#  define DEV_BSIZE BSIZE
	# else /* !BSIZE */
	#  define DEV_BSIZE 4096
	# endif /* !BSIZE */
	#endif /* !DEV_BSIZE */

4) Mots interdits

* Vous n'avez pas droit au switch.


5) Headers

* La norme dans son intégralité est valide pour les headers.

* On les protégera contre double inclusion.  Si le fichier est foo.h,
  la macro témoin est FOO_H_

	#ifndef FOO_H_
	# define FOO_H_
	/*
	** Content of foo.h
	*/
	#endif /* !FOO_H_ */

* Toutes les fonctions, variables etc. exportées par foo.c sont
  prototypées dans foo.h.

* Les fonctions et variables non exportées par foo.c sont déclarées
  static.

* foo.c inclue toujours foo.h.

* Les headers ne doivent pas faire d'include eux-mêmes.  A l'extrême
  limite on pourra inclure des headers non systèmes, mais *jamais*
  d'inclusion de headers systèmes.

6) Recommandations

Le suivi de ces recommandations est conseillé, mais pas obligatoire.

* Certaines fonctions de la bibliothèque C peuvent retourner une
  valeur particulière lorsqu'elles échouent.  Le code principal ne
  doit pas être polué par le traitement de ces valeurs
  exceptionnelles, aussi faut-il introduire des versions de ces
  fonctions qui traitent les erreurs elles-mêmes par un appel à exit.
  Ces fonctions doivent porter le nom de la fonction de la lib C,
  préfixé par "x".

	void	*xmalloc(size_t n)
	{
	  void	*p;

	  p = malloc(n);
	  if (p == 0)
	    {
	       fprintf(stderr, "Virtual memory exhausted\n");
	       exit(1);
	    }

	  return (p);
	}

* Il est recommandé de commenter en anglais.

7) Un exemple de Makefile :

On prendra soin de toujours compiler avec les options d'optimisation
(-g).

#
# Makefile for PCE in play
#
# Made by zool
# Login   
#
# Started on  Sat Oct 16 11:41:48 1993 zool
## Last update Fri Oct 20 10:35:30 2000 assistant c unix
#
CC	= cc
YACC	= yacc -d
COMP	= gzip -f
UNCOMP	= gunzip -f
RM	= rm -f
STRIP	= echo strip
#
NAME	= play
IPATH	= -I. -I../include
OPTI	= -g #-O2
LPATH	= -L.
#
CFLAGS	= $(OPTI) $(IPATH)
LDFLAGS = $(OPTI) $(LPATH)
LIBS	=
#
#
L_SRC	= main.c load_script.c send_it.c play_it.c proto_init.c\
	proto_send.c proto_pict.c
L_OBJS	= main.o load_script.o send_it.o play_it.o proto_init.o \
	proto_send.o proto_pict.o

INCL	= gen.h ../include/spe.h config.h\
	local_func.h play.h proto.h

SRC	= $(L_SRC)
OBJS	= $(L_OBJS)
#
#
#
all	: $(NAME)
$(NAME) : $(OBJS)
	$(CC)  $(LDFLAGS) -o $(NAME) $(OBJS) $(LIBS)
	$(STRIP) $(NAME)

re	: clean all

clean	:
	-$(RM) $(OBJS)
	-$(RM) *~
	-$(RM) \#*

fclean	: clean
	-$(RM) $(NAME)

comp	: fclean
	$(COMP) $(SRC) $(INCL)

ucomp	:
	$(UNCOMP) $(SRC) $(INCL)

.y.o	:
	$(YACC) $<
	$(CC) -c $(CFLAGS) y.tab.c
	-@$(RM) y.tab.c
	mv y.tab.o $*.o
	mv y.tab.h $*.h


.SUFFIXES: .h.Z .c.Z .y.Z .l.Z .x.Z .x\
	    .c.gz .h.gz .l.gz .y.gz .x.gz \
	   .x.z .c.z .h.z .l.z .y.z

.c.Z.c .h.Z.h .l.Z.l .y.Z.y .x.Z.x \
c.gz.c .h.gz.h .l.gz.l y.gz.y .x.gz.x \
.x.z.x .c.z.c .h.z.h .l.z.l .y.z.y :
	 -$(UNCOMP) $<

.x.h	:
	rpcgen $*.x
	@-$(RM) rnusers_svc.c

.c.o	:
	$(CC) $(CFLAGS) -c $<

#
# deps
#
$(OBJS) 	: $(INCL)
main.o		: main.c
load_script.o	: load_script.c
send_it.o	: send_it.c
play_it.o	: play_it.c
proto_init.o	: proto_init.c
proto_send.o	: proto_send.c
proto_pict.o	: proto_pict.c