#include #include #include #include #include #include #include "pagin.h" #include "permut.h" #include "nadoc.m" /* Initialisation de l'index des spécifications extraites des sources. Retourne -1 si erreur. */ PUBLIC COM_INDEX::COM_INDEX () { nbcom = 0; nbptr = 0; #ifdef MSDOS maxcom = 1000; maxptr = 10000; #else maxcom = 20000; maxptr = 100000; #endif tbcom = (COM_SPC*)malloc_err (maxcom*sizeof(COM_SPC),1); alloc_ptr = (char**)malloc_err (maxptr*sizeof(char*),1); } /* Retourne != 0 si l'objet est correctement initialisé. */ PUBLIC int COM_INDEX::ok() { return tbcom != NULL && alloc_ptr != NULL ? 1 : 0; } /* Libère le contenue complet d'un COM_INDEX */ PUBLIC COM_INDEX::~COM_INDEX() { for (int i=0; iident = strdup_err (ident,1); spc->fname = strdup_err (fname,1); spc->offset = offset; spc->noline = noline; spc->nbcle = nbcle; spc->tbcle = alloc_ptr + nbptr; spc->usage = 0; spc->specbeg = (char) specbeg; nbptr += nbcle; for (int i=0; itbcle[i] = strdup_err(tbcle[i],1); } assert (nbptr= 0){ suite = str_skip(suite); if (*suite == '\0') break; if (*suite == '/' && isspace(suite[1])){ *suite++ = '\0'; nbcle = nacom_addcle (debut,tbcle,nbcle,src); suite = str_skip(suite); debut = suite; }else{ suite = str_skipword(suite); } } if (nbcle >= 0 && suite != debut){ /* Enregistre dernière clé de classement */ nbcle = nacom_addcle (debut,tbcle,nbcle,src); } return nbcle; } /* Extraction des commentaires spécifications d'une série de fichier. Balaye les fichiers sources à la recherche des commentaires et fabrique un index. Recherche la séquence COMMENTAIRE #Mot-cle: classement / ... Retient le classement dans un index et la position dans le fichier. Retourne le nombre d'éléments placés dans l'index. */ PUBLIC int COM_INDEX::scansrc ( const char *fname) /* Fichier source à lire */ /* Ne retourne pas si fichier existe pas */ { int ret = 0; int err = 0; FILE *fin = vfopen_binerr (fname,"r",1); char buf[400]; int noline=1; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ char *pt = str_skip (buf); if (pt[0] == '/' && (pt[1] == '*' || pt[1] == '/')){ int specbeg = pt[1] == '/'; char mot[200]; char *suite; pt = str_skip(pt+2); /* Cherche le : ou la fin de la ligne ou un blanc */ if ((suite=str_copymot(mot,pt)) != NULL && mot[0] == '#' && strcmp(mot,"#define")!=0){ int len = strlen(mot); if (mot[len-1] != ':'){ fprintf (stderr,MSG_U(E_MISSINGCOLON ,"file %s line %d: Missing :, rejected\n%s") ,fname,noline,buf); err = 1; }else if (stricmp(mot,"#specend:")!=0){ /* #Spécification: Commentaire spécification / format La première ligne d'un commentaire spécification a le format suivant: COMTOK ESPACES #mot-cle: ESPACES classement [ ESPACES / ESPACES classement ... ] COMTOK: slash suivit d'un étoile que je ne peut écrire ici. Ou encore slash slash ESPACES: Au moins 1 espace. classement: Séquence de mot clés représentant une section d'un document. */ char *tbcle[100]; int nbcle; mot[len-1] = '\0'; nbcle = nacom_parse(suite,tbcle); if (nbcle == 0){ fprintf (stderr,MSG_U(E_MISSINGKEY ,"Missing classification key: " "File %s ligne %d\n%s") ,fname,noline,buf); err = 1; }else if (nbcle > 0){ /* Ajoute dans la table */ addspec (mot+1,fname ,ftell(fin),noline,tbcle,nbcle,specbeg); ret++; }else{ err = 1; } } } } noline++; } fclose (fin); return err ? -1 : ret; } /* Formatte l'entete du spécification selon le format d'origine dans le source */ void nacom_format( COM_SPC *spc, char *filespec, /* Position dans le fichier ou NULL */ char *buf) /* Clé de la spécification ou NULL */ { if (filespec != NULL){ sprintf (filespec,"[%s,%d]",spc->fname,spc->noline); } if (buf != NULL){ char *ctl = "%s"; buf += sprintf (buf,"#%s: ",spc->ident); for (int j=0; jnbcle; j++){ buf += sprintf (buf,ctl,spc->tbcle[j]); ctl = " / %s"; } } } void nacom_format_raw( COM_SPC *spc, char *buf) /* Clé de la spécification ou NULL */ { if (buf != NULL){ char *ctl = "%s"; for (int j=0; jnbcle; j++){ buf += sprintf (buf,ctl,spc->tbcle[j]); ctl = " / %s"; } } } static int nacom_cmp (const void *p1, const void *p2) { COM_SPC *pt1 = (COM_SPC*)p1; COM_SPC *pt2 = (COM_SPC*)p2; int ret = str_icmpfranc(pt1->ident,pt2->ident); if (ret == 0){ int i; int nbcle = pt1->nbcle; if (nbcle > pt2->nbcle) nbcle = pt2->nbcle; for (i=0; itbcle[i],pt2->tbcle[i]); } if (ret == 0){ ret = pt1->nbcle - pt2->nbcle; } } return ret; } /* Tri les spécifications par clé de classement */ PUBLIC void COM_INDEX::sort() { hsort (tbcom,nbcom,sizeof(tbcom[0]),nacom_cmp); } /* Imprime le texte de la spécification avec léger formattage Retourne -1 si erreur. */ int nacom_print ( COM_SPC *spc, PAGIN_V *pout, int quit_signal) /* 0 : silencieux, 1 : message d'erreur, 2 : 1 + quit */ { int ret = -1; FILE *fin = vfopen_binerr (spc->fname,"r",1); if (fseek (fin,spc->offset,SEEK_SET)!=-1){ char *tbl[1000]; int nbl = 0; int real_nbl = 0; /* Permet d'ignorer les lignes vides à la fin */ int minindent = 1000; char buf[300]; int specbeg = spc->specbeg; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ if (specbeg){ char *pt = str_skip (buf); if (pt[0] == '/' && pt[1] == '/'){ /* #Spécification: Commentaire spécification / format alternatif Une méthode alternative permet d'inscrire une section de code comme une spécification. Il s'agit d'encadrer la section entre une ligne // #Specbeg: ... et une ligne // #Specend: // #Specbeg: structure d'un record struct record { int a; // compteur int b; // bla bla }; // #Specend: */ pt = str_skip (pt+2); if (strncasecmp(pt,"#specend:",8)==0) break; } }else if (strstr(buf,"*/")!=NULL) break; str_strip(buf,buf); if (buf[0] != '\0'){ char *pt = buf; int indent; str_exptab (buf,4,buf); while (*pt == ' ') pt++; indent = (int)(pt-buf); if (indent < minindent) minindent = indent; real_nbl = nbl+1; } tbl[nbl++] = strdup_err (buf,1); } /* Affiche en sautant un certain nombre de blanc pour ne conserver qu'un seul tabulateur. */ int i; for (i=0; iset_format (PAG_FORMAT_NONE); for ( ; iprintf ("\t%s\n",tbl[i]+minindent); } pout->set_format (old_format); }else{ int old_format = pout->set_format (PAG_FORMAT_PARA); int format = 1; for ( ; inl (); }else{ char *pt = line; while (isspace (*pt)) pt++; if (pt[0] == '#' && pt[1] == '\0'){ format = !format; pout->set_format (format ? PAG_FORMAT_PARA : PAG_FORMAT_NONE); }else{ pout->printf ("\t%s\n",line+minindent); } } } pout->set_format (old_format); } tbstr_free (tbl,nbl); }else if(quit_signal){ const char *errmsg = MSG_U(E_CANTFINDSPEC ,"Can't locate again specification: " "File %s offset %ld\n\t%s\n%s\n"); char spec[200]; char filespec[200]; nacom_format (spc,filespec,spec); fprintf (stderr,errmsg,spc->fname,spc->offset,filespec,spec); if (quit_signal > 1){ exit(-1); } } fclose (fin); return ret; } #ifdef TEST #include static void nacom_dump (COM_INDEX *comi) { int i; for (i=0; inbcom; i++){ COM_SPC *spc = &comi->tbcom[i]; char spec[200]; char filespec[200]; nacom_format (spc,filespec,spec); if (i > 0) printf ("\n"); printf ("%s\n%s\n",filespec,spec); printf ("\n"); nacom_print (spc,stdout,2); } } int main (int argc, char *argv[]) { COM_INDEX comi; if (nacom_initindex(&comi)!=-1){ int i; for (i=1; i