C2HTML

Description
c2html permet de formatter rapidement des sources C en utilisant la syntaxe du HTML pour publier des sources claires et lisibles sur le web.
Il réalise une coloration des mots-clés et des commentaires, et conserve l'indentation du code.
Son fichier de configuration (c2html.conf) permet de définir les mots-clés.

c2html.conf
Deux options sont disponibles pour l'instant :
- dstdir=repertoire indique le repertoire de destination des sources formattées. Par défaut, c'est le répertoire courant.
- keywords=mot1,mot2,mot3... pour définir les mots-clés à colorer.

Syntaxe
c2html source.c page.htm

Todo
- Compteur de lignes
- Options (pas d'entete html, couleurs, ...)

New
27/12/2002: correction du bug concernant la coloration des directives du préprocesseur


Sources (Visual C++) - 200 lignes

/*
Formattage d'un fichier source C
en utilisant le langage HTML
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define TAB "   "

#define COMMENT1      1
#define COMMENT2      2
#define PREPROCESS   3

int main(int argc, char **argv)
{
   /* Fichiers */
   FILE *src, *dst;
   
   /* Manipulation du contenu du fichier */
   char buf[512];
   char *p_deb, *p_fin, *p_save;
   
   /* Mots clés */
   char keywords[20][10];
   int word_count;
   
   int r=0, c, d, marge=20;
   short type=0, mot=0;
   
   /* Options */
   char dstdir[128];
   
   /*int ligne=2;*/

   /* Syntaxe correcte ? */
   if (argc<3)
   {
      printf("Syntaxe: c2html src.c dst.htm\n");
      return -1;
   }

   /* Chargement de la configuration */
   if ((src=fopen("c2html.conf", "rb"))==NULL)
   {
      printf("Impossible d'ouvrir le fichier de config\n");
      return -1;
   }

   word_count=0;
   *dstdir=0x00;
   while (fgets(buf, 511, src)!=NULL)
   {
      if ((p_deb=strchr(buf, '\r'))!=NULL)
         *p_deb=0x00;
      if ((p_deb=strchr(buf, '='))!=NULL)
      {
         *p_deb=0x00;
         p_deb++;
         if (strcmp(buf, "dstdir")==0)
         {
            strcpy(dstdir, p_deb);
            c=strlen(dstdir);
            if (dstdir[c-1]!='/' && dstdir[c-1]!='\\')
            {
               dstdir[c++]='/';
               dstdir[c]=0x00;
            }
         }
         else if (strcmp(buf, "keywords")==0)
         {
            while((p_save=strchr(p_deb, ','))!=NULL)
            {
               *p_save=0x00;
               strcpy(keywords[word_count++], p_deb);
               p_deb=p_save+1;
            }
            strcpy(keywords[word_count++], p_deb);
         }
         else
            printf("Option inconnue: %s\n", buf);
      }
   }

   fclose(src);

   printf("Loaded %d keywords\n", word_count);

   /* Ouverture de fichier source C */
   if ((src=fopen(argv[1], "rb"))==NULL)
   {
      printf("Ouverture de %s impossible\n", argv[1]);
      return -1;
   }

   /* Ouverture du fichier html */
   strcat(dstdir, argv[2]);
   if ((dst=fopen(dstdir, "wb"))==NULL)
   {
      printf("Ouverture de %s impossible\n", argv[2]);
      return -1;
   }

   /* Ecriture de l'entete */
   fputs("<html><head><title>\r\n", dst);
   fprintf(dst, "Source: %s\n", argv[1]);
   fputs("</title></head>\r\n", dst);
   fputs("<!- Formatte par c2html ->\r\n", dst);
   fputs("<body><pre><font face=\"Courier New\" size=2>", dst);
   
   r=c=0;
   /* Boucle de lecture */
   while ((r+=fread(buf+c, 1, 500-c, src))>c)
   {
      /* buf[r]='\0'; */

      /* Dernière lecture dans le fichier */
      if (r<500)
      {
         marge=0;
         /*printf("Theoriquement derniere lecture dans le fichier\n");*/
      }

      /* Caractère par caractère */
      for(p_deb=p_fin=buf; p_fin<buf+r-marge; p_fin++)
      {
         switch (*p_fin)
         {
            /* */
            case '#':
               if (type)
                  break;
               type=PREPROCESS;
               fwrite(p_deb, 1, p_fin-p_deb, dst);
               p_deb=p_fin;
               fputs("<FONT COLOR=blue>", dst);
               break;
            /* Probablement un commentaire */
            case '/':
               if (type)
                  break;
               if (*(p_fin+1)=='/')
                  type=COMMENT1;
               else if (*(p_fin+1)=='*')
                  type=COMMENT2;
               else
                  break;
               fwrite(p_deb, 1, p_fin-p_deb, dst);
               p_deb=p_fin;
               fputs("<FONT COLOR=green>", dst);
               break;
            /* Fin de ligne */
            case '\n':
               fwrite(p_deb, 1, p_fin-p_deb+1, dst);
               if (type==COMMENT1 || type==PREPROCESS)
               {
                  type=0;
                  fputs("</font>", dst);
               }
               /*fputs("<br>", dst);*/
               /* Numéro de ligne */
               /*fprintf(dst, "%d%s", ligne++, TAB);*/
               p_deb=p_fin+1;
               mot=1;
               break;
            /* Tabulation */
            case '\t':
               fwrite(p_deb, 1, p_fin-p_deb, dst);
               fputs(TAB, dst);
               p_deb=p_fin+1;
            /* Espace */
            case ' ':
               if (type==PREPROCESS)
               {
                  fwrite(p_deb, 1, p_fin-p_deb+1, dst);
                  fputs("</font>", dst);
                  p_deb=p_fin+1;
                  type=0;
               }
            /* Parenthèse */
            case '(':
               mot=1;
               break;
            /* Fin de commentaire */
            case '*':
               if ((type==COMMENT2) && (*(p_fin+1)=='/'))
               {
                  type=0;
                  p_fin+=2;
                  fwrite(p_deb, 1, p_fin-p_deb, dst);
                  fputs("</font>", dst);
                  p_deb=p_fin;
                  p_fin--;
               }
               break;
            /* Sinon html croit que c'est une balise */
            case '<':
               fwrite(p_deb, 1, p_fin-p_deb, dst);
               p_deb=p_fin+1;
               fputs("<", dst);
               break;
            /* Sinon html croit que c'est une balise */
            case '>':
               fwrite(p_deb, 1, p_fin-p_deb, dst);
               p_deb=p_fin+1;
               fputs(">", dst);
               break;
            /* Peut être un mot clé */
            default:
               if (type)
                  mot=0;
               if  (!mot)
                  break;
               /* Teste tous les mots-clé */
               for(p_save=p_fin, c=0; c<word_count && keywords[c][0]<=*p_fin; c++)
               {
                  p_save=p_fin;
                  /* Teste toutes les lettres du mot-clé*/
                  for(d=0; keywords[c][d]!='\0'; d++, p_save++)
                     if (*p_save!=keywords[c][d])
                        goto not_keyword;

                  if ((*p_save==' ') || (*p_save==',') || (*p_save==';') || (*p_save==':')
                     || (*p_save=='(') || (*p_save=='\r') || (*p_save==')'))
                  {
                     fwrite(p_deb, 1, p_fin-p_deb, dst);
                     fputs("<font color=blue>", dst);
                     p_deb=keywords[c];
                     fwrite(p_deb, 1, strlen(p_deb), dst);
                     fputs("</font>", dst);
                        
                     p_fin=p_save-1;
                     p_deb=p_save;
                     goto end_loop;
                  }
                  not_keyword:
                     /* nothing */;
               }
               end_loop:
               mot=0;
               break;
         }   /* switch */
      } /* for */
      
      fwrite(p_deb, 1, p_fin-p_deb, dst);

      buf[r]=0x00;
      strcpy(buf, p_fin);
      r=c=buf+r-p_fin;
   } /* while */

   fputs("</font></pre></body></html>\r\n", dst);
   
   fseek(dst, 0, SEEK_END);
   printf("Taille de %s: %d bytes\n", argv[2], ftell(dst));

   fclose(src);
   fclose(dst);

   return 0;
}