/* #Spécification: classe / Présentation Après avoir extrait la composition des classes avec proto (option -q) on construit un joli rapport présentant sous forme d'arbre la relation entre les classes. */ #include #include #include #include #include #include #define CLSFORM_VERSION 1 #define CLSFORM_RELEASE 1 unsigned int _stklen=10000; static void near usage(void) { static const char *tbf[]={ "clsform fichier_proto [ resultat ]", "\n", " Formatte la hierarchie des classes extraite", " par proto.", NULL }; version_usagef (tbf,tbf,"CLSFORM","CLSFORM" # if defined(VERSION_SHARE) ,&version_share # elif defined(VERSION_PROD) ,&version_prod # elif defined(VERSION_DEV) ,&version_beta # elif defined(VERSION_ESSAI) ,&version_alpha # endif ,CLSFORM_VERSION,CLSFORM_RELEASE ,1992,0,0 ,NULL,NULL,NULL); } typedef struct { char *nom; /* Nom de la classe */ int nbbase; /* Nombre de classe de base */ int nbprint; /* Nombre de fois que la classe a été mentionnée */ } CLS_INFO; typedef struct { CLS_INFO *info; /* Nom de la classe */ char *opt; /* Option de dérivation */ CLS_INFO *base; /* Classe de base */ } CLS_DERIVE; typedef struct { CLS_INFO *tbinfo; int nbinfo; int maxinfo; CLS_DERIVE *tbder; int nbder; int maxder; }CLSFORM; static int clsform_init (CLSFORM *clss) { clss->tbinfo = (CLS_INFO*) malloc_err (1000*sizeof(CLS_INFO),1); clss->maxinfo = 1000; clss->nbinfo = 0; clss->tbder = (CLS_DERIVE*) malloc_err (1000*sizeof(CLS_DERIVE),1); clss->maxder = 1000; clss->nbder = 0; return 0; } static void clsform_end (CLSFORM *clss) { int i; CLS_DERIVE *ptder = clss->tbder; int nbder = clss->nbder; int nbinfo = clss->nbinfo; CLS_INFO *ptinfo = clss->tbinfo; for (i=0; iopt); } for (i=0; inom); } free (clss->tbder); free (clss->tbinfo); clss->maxder = clss->nbder = 0; clss->maxinfo = clss->nbinfo = 0; } /* Ajoute un record pour une classe. Si la classe est deja la, retourne son record sans ajouter. Retourne pas si manque de place. */ static CLS_INFO * near clsform_addclass (CLSFORM *clss, const char *nom) { int nbinfo = clss->nbinfo; CLS_INFO *ptinfo = clss->tbinfo; int i; for (i=0; inom,nom)==0) break; } if (i == nbinfo){ assert (imaxinfo); ptinfo->nom = strdup_err (nom,1); ptinfo->nbbase = 0; ptinfo->nbprint = 0; clss->nbinfo++; } return ptinfo; } /* Ajoute de l'information sur une dérivation. */ static void near clsform_addder ( CLSFORM *clss, CLS_INFO *info, /* Classe a documenter */ CLS_INFO *base, /* Classe de base d'où provient info */ const char *opt) /* Option de dérivation */ { CLS_DERIVE *der; if (clss->nbder == clss->maxder){ clss->maxder += 500; clss->tbder = (CLS_DERIVE*) realloc_err (clss->tbder ,clss->maxder*sizeof(CLS_DERIVE),1); } der = clss->tbder + clss->nbder++; der->info = info; info->nbbase++; der->base = base; der->opt = strdup_err (opt,1); } /* Lit un fichier produit par option -q de proto. Cette fonction peut être appelée plusieurs fois. Retourne -1 si erreur, nombre de ligne lue sinon. */ static int clsform_read (CLSFORM *clss, const char *fname) { int ret = 0; FILE *fin = fopen_err (fname,"r",1); char buf[300]; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ char cls_cur[100]; char cls_base[100]; char exp[100]; char virt[100]; int nb = sscanf(buf,"%s %s %s %s",cls_cur,cls_base,exp,virt); if (nb == 4){ char option[100]; CLS_INFO *info = clsform_addclass (clss,cls_cur); CLS_INFO *base = clsform_addclass (clss,cls_base); if (virt[0] == '-'){ if (exp[0] == '-'){ option[0] = '\0'; }else{ strcpy (option,exp); } }else{ sprintf (option,"%s %s",exp,virt); } clsform_addder (clss,info,base,option); ret++; }else if (nb > 0){ error_bprintf ("fichier %s, ligne %d: Format invalide\n\t%s\n" ,"File %s, line %d: invalid format\n\t\n" ,fname,ret+1,buf); ret = -1; break; } } fclose (fin); return ret; } /* Affiche récursivement l'arbre de dérivation. */ static int near clsform_printr ( CLSFORM *clss, const char *base, FILE *fout, int indent) { int nxtindent = indent + 4; int i; CLS_DERIVE *ptder = clss->tbder; int nbder = clss->nbder; for (i=0; ibase->nom,base)==0){ CLS_INFO *info = ptder->info; fprintf (fout,"%*s%s %s",indent,"",info->nom,ptder->opt); info->nbprint++; if (info->nbbase > 1){ fprintf (fout," %d/%d",info->nbprint,info->nbbase); } fprintf (fout,"\n"); if (info->nbprint == 1){ clsform_printr (clss,info->nom,fout,nxtindent); } } } return 0; } static int cmp (const void *p1, const void *p2) { CLS_DERIVE *d1 = (CLS_DERIVE *)p1; CLS_DERIVE *d2 = (CLS_DERIVE *)p2; return strcmp(d1->info->nom,d2->info->nom); } /* Ajoute des définitions bidons pour les classes de base inconnue. On ajoute simplement qu'elle sont dérivée de la racine. */ static void near clsform_unknown (CLSFORM *clss) { int nbinfo = clss->nbinfo; CLS_INFO *ptinfo = clss->tbinfo+1; int i; for (i=1; inbbase == 0){ clsform_addder (clss,ptinfo,clss->tbinfo,""); } } } /* Affiche les classes sous forme d'arbre. Les classes de base apparaissent à gauche. */ static int clsform_print (CLSFORM *clss, FILE *fout) { int nbinfo = clss->nbinfo; CLS_INFO *ptinfo = clss->tbinfo; int i; for (i=0; inbprint = 0; } hsort (clss->tbder,clss->nbder,sizeof(CLS_DERIVE),cmp); clsform_printr(clss,"-",fout,0); return 0; } /* Génère le code de déclaration d'une classe. Ne fait rien si c'est déjà fait. */ static void near clsform_gentest0 ( CLSFORM *clss, CLS_INFO *info, FILE *fout) { if (info->nbprint == 0){ int i; CLS_DERIVE *ptder = clss->tbder; int nbder = clss->nbder; char buffer[500]; int premder = 1; const char *nom = info->nom; char *pt = buffer + sprintf(buffer,"class %s",nom); for (i=0; iinfo == info && ptder->base->nom[0] != '-'){ CLS_INFO *base = ptder->base; clsform_gentest0 (clss,base,fout); *pt++ = premder ? ':' : ','; premder = 0; pt += sprintf (pt,"%s %s",ptder->opt,base->nom); } } info->nbprint++; fprintf (fout,"%s{\npublic:\n",buffer); fprintf (fout,"\tchar data_%s[%d];\n",nom,i); if (premder){ fprintf (fout,"\tchar *nomcls;\n\tvoid printbase();\n"); } fprintf (fout,"\t%s();\n\tvirtual void print();\n};\n",nom); fprintf (fout,"%s::%s(){\n\tnomcls=\"%s\";\n}\n",nom,nom,nom); if (premder){ fprintf (fout,"void %s::printbase(){\n\tprint();\n}\n",nom); } fprintf (fout,"void %s::print(){\n",nom); fprintf (fout,"\tprintf (\"%%s %s\\n\",nomcls);\n",nom,nom); fprintf (fout,"}\n"); } } /* Génère un fichier permettant de tester des cas de dérivation extrait de programme réel. */ static int clsform_gentest (CLSFORM *clss, FILE *fout) { int nbinfo = clss->nbinfo; CLS_INFO *ptinfo = clss->tbinfo+1; int i; clss->tbinfo[0].nbprint = 1; for (i=1; inbprint = 0; } ptinfo = clss->tbinfo+1; for (i=1; itbinfo+1; fprintf (fout,"int main (int, char *[])\n{\n"); for (i=1; inom,ptinfo->nom); fprintf (fout,"\tv_%s.printbase();\n",ptinfo->nom); } fprintf (fout,"\treturn 0;\n}\n"); return 0; } int main (int argc, char *argv0[]) { int ret = -1; ARGP argp[26]; char *argv[100]; argc = anlparm_indir(argc,argv0,argv,100,argp,"t"); if (argc != 2 && argc != 3){ usage(); }else{ CLSFORM clss; if (clsform_init (&clss) != -1){ /* Assure que la classe racine est la première enregistrée */ /* Pour clsform_unknown */ clsform_addclass (&clss,"-"); if (clsform_read (&clss,argv[1]) != -1){ FILE *fout = stdout; if (argc == 3) fout = fopen_err (argv[2],"w",1); clsform_unknown (&clss); if (argp['t'-'a'].ptr != NULL){ ret = clsform_gentest (&clss,fout); }else{ ret = clsform_print (&clss,fout); } if (argc == 3) fclose (fout); } clsform_end(&clss); } } return ret; }