/* Produit les fichiers d'interface pour un serveur. deux fichier .h et un .c sont produit pour les clients. Un fichier .c est produit pour le serveur. */ #include #include #include #include #include #include #include #include "bserv.h" #include "bserv.m" #define BSERV_VERSION 1 #define BSERV_RELEASE 3 static void usage (void) { const char *msg = MSG_U(I_USAGE ,"bserv [options ...] fichier.pm classe [ classes de base ]\n" "Générateur d'interface pour protocole TLMP\n" "\n" "-b : Insère une spécification de dérivation pour la définition\n" " client:\n" "\n" "-i : commande d'inclusion à placer dans les fichiers produits\n" "\n" "-m : Génère un interface pour serveur multi-connection\n" "-v : Génère une classe virtuelle pour créer des\n" " des variations de ce serveur.\n" "Les fichiers suivants seront générés pour une class X:\n" "\n" "Interface pour les clients:\n" " S_X.c et S_X.h\n" "Interface pour le serveur:\n" " C_X.c et C_X.h\n" "Définition pour dériver des variations du serveur:\n" " V_X.h\n"); fputs (msg,stderr); } /* G‚nŠre le d‚but d'un fichier d'inclusion. Ne retourne pas si erreur. */ static FILE *bserv_genheader ( const char *fname_out, char *path_h, char **tbincl, int nbincl) { file_chgext (fname_out,path_h,".h"); FILE *fout = fopen_err (path_h,"w",1); char bname[MAXSIZ_NAME]; path_splitlex (fname_out,NULL,bname); file_baseext (bname,bname,NULL); fprintf (fout,"#ifndef %s_H\n#define %s_H\n\n",bname,bname); fprintf (fout,"#ifndef PCOMM_H\n#include \n#endif\n\n"); for (int i=0; igetnb(); i++){ FCT_INFO *ptinfo = lfct->getitem(i); /* Evite le constructeur et le destructeur */ if (!ptinfo->is_construct() && !ptinfo->is_destruct()){ fprintf (fout,"\t\""); ptinfo->prtcle (fout); fprintf (fout,"\"\n"); } } fprintf (fout,";\n"); } /* G‚nŠre les fichiers requis pour compiler le serveur. G‚nŠre un fichier d'inclusion et un source. Retourne -1 si erreur. */ static int bserv_genserv ( FCT_LISTE *lfct, const char *cls, const char *fname_out, /* Fichier produit avec extension .c et .h */ char **tbincl, // Fichiers d'inclusion … inscrire dans header. int nbincl, // Nombre de fichier. int multi) // Le serveur accepte plusieurs connections ? // G‚nŠre une classe sp‚ciale pour ce cas. { char path_h[MAXSIZ_PATH]; FILE *fout = bserv_genheader(fname_out,path_h,tbincl,nbincl); fprintf (fout,"class C_%s: public TLMP_CLIENT, public %s{\n" ,cls,cls); fprintf (fout,"public:\n"); // Premier constructeur qui recoit simplement un handle // deja "connecte". // Ce constructeur est generalement utilise pour les serveurs // multi-clients. fprintf (fout,"\tC_%s (int _handle);\n",cls); fprintf (fout,"\tC_%s (int argc, char *argv[]",cls); FCT_INFO *ptinfo = lfct->locatefct (cls); // Cherche constructeur if (ptinfo != NULL && ptinfo->nbarg > 0){ ptinfo->prtarg(fout,", %s", ", %s"); fprintf (fout,");\n"); }else{ fprintf (fout,");\n"); } fprintf (fout,"protected:\n\tvoid _dispatch();\n"); fprintf (fout,"};\n"); if (multi){ fprintf (fout,"class C_%s_S: public TLMP_CLIENTS{\n",cls); fprintf (fout,"public:\n" "\tC_%s_S (int argc, char *argv[]);\n",cls); fprintf (fout,"\tTLMP_CLIENT *_new_client(int handle);\n"); fprintf (fout,"};\n"); } fprintf (fout,"\n\n#endif\n"); fclose (fout); /* G‚nŠre le source */ char path_c[MAXSIZ_PATH]; file_chgext (fname_out,path_c,".c"); fout = fopen_err (path_c,"w",1); fprintf (fout,"#include \"%s\"\n",path_h); bserv_gencle (fout,"C",lfct,cls); // Constructeurs fprintf (fout,"C_%s::C_%s (int _handle)\n",cls,cls); fprintf (fout,"\t\t: TLMP_CLIENT (_handle,C_class_%s_key){}\n",cls); fprintf (fout,"C_%s::C_%s (int argc, char *argv[]",cls,cls); if (ptinfo != NULL && ptinfo->nbarg > 0){ ptinfo->prtarg(fout,", %s", ", %s"); fprintf (fout,")\n\t:%s (",cls); ptinfo->prtarg(fout,"%s", ", %s"); fprintf (fout,"),\n\t"); }else{ fprintf (fout,")\n\t:"); } fprintf (fout,"TLMP_CLIENT(argc,argv,C_class_%s_key) {}\n",cls); if (multi){ fprintf (fout,"C_%s_S::C_%s_S (int argc, char *argv[])\n" "\t:TLMP_CLIENTS(argc,argv){}\n",cls,cls); } fprintf (fout,"void C_%s::_dispatch()\n{\n",cls); fprintf (fout,"\tswitch(nocall){\n"); int no_fct = 0; for (int i=0; igetnb(); i++){ FCT_INFO *ptinfo = lfct->getitem(i); /* Evite le constructeur */ if (!ptinfo->is_construct() && !ptinfo->is_destruct()){ fprintf (fout,"\tcase %d:\n\t\t{\n",no_fct++); for (int a = 0; anbarg; a++){ FCT_ARG *arg = &ptinfo->args[a]; int categ = arg->categ(); char buf[100]; arg->format(buf); if (categ == 0){ fprintf (fout,"\t\t%s = _getarg_%s();\n",buf,arg->gettype()); }else{ fprintf (fout,"\t\t%s;\n\t\t%s._getarg(this);\n" ,buf,arg->getnom()); } } int retval = !ptinfo->type.isvoid(); if (retval){ fprintf (fout,"\t\t%s retval = %s(",ptinfo->type.getdecl() ,ptinfo->nom); }else{ fprintf (fout,"\t\t%s(",ptinfo->nom); } ptinfo->prtarg(fout,"%s", ", %s"); fprintf (fout,");\n"); if (retval){ int categ = ptinfo->type.categ(); if (categ == 0){ fprintf (fout,"\t\t_sendret (retval);\n"); }else{ fprintf (fout,"\t\tretval._setret (this);\n"); fprintf (fout,"\t\t_sendret();\n"); } } fprintf (fout,"\t\t}\n\t\tbreak;\n"); } } fprintf (fout,"\t}\n}\n"); if (multi){ fprintf (fout,"TLMP_CLIENT *C_%s_S::_new_client(int handle)\n",cls); fprintf (fout,"{\n\treturn new C_%s(handle);\n",cls); fprintf (fout,"}\n"); } fclose (fout); return 0; } /* G‚nŠre le code pour le client. */ static int bserv_genclient( FCT_LISTE *lfct, const char *cls, const char *fname_out, char **tbincl, // Fichiers d'inclusion … inscrire dans header. int nbincl, // Nombre de fichier./ const char *herit, // Chaine … ins‚rer aprŠs le nom de la classe // au moment de la d‚finition. // Cette chaine contient g‚n‚ralement une // sp‚cification de d‚rivation. // Souvent NULL. const char *vname_out) // G‚nŠre le fichier V_xxx.h // pour d‚river des variations de ce serveur. // Agit comme parametre et comme flag { char path_h[MAXSIZ_PATH]; FILE *fout = bserv_genheader(fname_out,path_h,tbincl,nbincl); // G‚nŠre la d‚claration de la class dans le fichier d'inclusion if (vname_out != NULL){ fprintf (fout,"#ifndef %s_H\n",vname_out); fprintf (fout,"#include <%s.h>\n",vname_out); fprintf (fout,"#endif\n\n"); fprintf (fout,"class S_%s: public %s, public TLMP_SERVEUR" ,cls,vname_out); }else{ fprintf (fout,"class S_%s: public TLMP_SERVEUR",cls); } if (herit != NULL) fprintf (fout,", %s",herit); fprintf (fout,"{\n"); fprintf (fout,"public:\n"); fprintf (fout,"\tS_%s (const char *nomsym" ", const char *progargs,int quit);\n",cls); for (int i=0; igetnb(); i++){ FCT_INFO *ptinfo = lfct->getitem(i); /* Evite le constructeur et le destructeur */ if (!ptinfo->is_construct() && !ptinfo->is_destruct()){ fprintf (fout,"\t%s %s (",ptinfo->type.getdecl() ,ptinfo->nom); ptinfo->prtargd (fout,"\n\t\t%s",",\n\t\t%s"); fprintf (fout,");\n"); } } fprintf (fout,"};\n"); fprintf (fout,"\n\n#endif\n"); fclose (fout); if (vname_out != NULL){ char vpath_h[MAXSIZ_PATH]; fout = bserv_genheader(vname_out,vpath_h,tbincl,nbincl); // G‚nŠre la d‚claration de la class virtuel // dans le fichier d'inclusion fprintf (fout,"class V_%s {\n",cls); fprintf (fout,"public:\n"); for (int i=0; igetnb(); i++){ FCT_INFO *ptinfo = lfct->getitem(i); /* Evite le constructeur et le destructeur */ if (!ptinfo->is_construct() && !ptinfo->is_destruct()){ fprintf (fout,"\tvirtual %s %s (",ptinfo->type.getdecl() ,ptinfo->nom); ptinfo->prtargd (fout,"\n\t\t%s",",\n\t\t%s"); fprintf (fout,")=0;\n"); } } fprintf (fout,"};\n"); fprintf (fout,"\n\n#endif\n"); fclose (fout); } /* G‚nŠre le source */ char path_c[MAXSIZ_PATH]; file_chgext (fname_out,path_c,".c"); fout = fopen_err (path_c,"w",1); fprintf (fout,"#include \"%s\"\n",path_h); bserv_gencle (fout,"S",lfct,cls); fprintf (fout,"S_%s::S_%s (const char *nomsym" ", const char *progargs,int quit)\n",cls,cls); fprintf (fout,"\t:TLMP_SERVEUR(nomsym,progargs,quit,S_class_%s_key){\n" ,cls); fprintf (fout,"}\n"); int no_fct=0; for (int i=0; igetnb(); i++){ FCT_INFO *ptinfo = lfct->getitem(i); /* Evite le constructeur */ if (!ptinfo->is_construct() && !ptinfo->is_destruct()){ fprintf (fout,"%s S_%s::%s(",ptinfo->type.getdecl() ,cls,ptinfo->nom); ptinfo->prtargd (fout,"\n\t\t%s",",\n\t\t%s"); fprintf (fout,")\n"); /* Corps de la fonction, les arguments sont passe 1 a 1 */ fprintf (fout,"{\n\t_setcall(%d);\n",no_fct++); for (int a = 0; anbarg; a++){ const char *nom = ptinfo->args[a].getnom(); if (nom != NULL){ int categ = ptinfo->args[a].categ(); if (categ == 0){ fprintf (fout,"\t_setarg(%s);\n",nom); }else{ fprintf (fout,"\t%s._setarg(this);\n",nom); } } } fprintf (fout,"\t_docall();\n"); /* Y a t'il une valeur de retourne a attendre */ if (!ptinfo->type.isvoid()){ fprintf (fout,"\t_waitret();\n"); fprintf (fout,"\t%s retval;\n",ptinfo->type.getdecl()); int categ = ptinfo->type.categ(); if (categ == 0){ fprintf (fout,"\t_getret(retval);\n"); }else{ fprintf (fout,"\tretval._getret(this);\n"); } fprintf (fout,"\treturn retval;\n"); } fprintf (fout,"}\n"); } } fclose (fout); return 0; } int main (int argc, char *argv[]) { int ret = -1; etc_loadmsg(); ARGP_MULTI argp[26]; argc = anlparm_multi (argc,argv,argp,"bi*mv"); if (argc < 3){ usage(); }else{ /* #Sp‚cification: bserv / ligne de commande / -v FAUX: L'option -v de la ligne de commande indique que le bserv opŠre en mode verbose. */ int verbose = argp['v'-'a'].ptr != NULL; /* #Sp‚cification: bserv / ligne de commande / -m L'option -m de la ligne de commande indique que le serveur supporte plusieurs connection simultan‚. */ int multi = argp['m'-'a'].ptr != NULL; /* #Sp‚cification: bserv / ligne de commande / -m L'option -m permet d'enregistrer la sp‚cification de d‚rivation pour la version client de la classe produite. Pour une classe X, normalement, une classe pour les clients est g‚n‚r‚e. class X { ... }; L'option -bY insŠre :Y aprŠs X: class X :Y { ... }; bserv ne tente pas de valider quoi que ce soit. */ char *herit = argp['b'-'a'].ptr; const char *fpm = argv[1]; const char *cls = argv[2]; FCT_LISTE lfct; int nbfct = lfct.collect(fpm,(const char**)argv+2,argc-2); if (nbfct <= 0){ fprintf (stderr,MSG_B(E_NOMEMBERFCT ,"Aucune fonction membre pour la classe %s\n" ,"No member function for class %s\n") ,argv[2]); }else{ // lfct.dump(); /* Fabrique les noms de fichiers de sorties */ char client_out[MAXSIZ_PATH]; char serveur_out[MAXSIZ_PATH]; sprintf (client_out,"S_%s",cls); sprintf (serveur_out,"C_%s",cls); char *vname_out = NULL; char vname_path[MAXSIZ_PATH]; if (argp['v'-'a'].ptr != NULL){ /* #Sp‚cification: bserv / ligne de commande / -v L'option -v de la ligne de commande produit un fichier d'inclusion contenant une copie des fonctions membres dont tout les membres sont virtuel pure. Ca permet de realiser des variations de ce serveur. Le Pr‚fixe V_ sera ins‚rer pour former le nom du fichier d'inclusion et de la classe. */ sprintf (vname_path,"V_%s",cls); vname_out = vname_path; } /* #Sp‚cification: bserv / ligne de commande / -i L'option -i de la ligne de commande permet d'enregistrer une s‚rie de fichier d'inclusion … ins‚rer au d‚but des fichiers produits: L'option -i est r‚p‚t‚ pour chaque fichier d'inclusion. ex: -istdio.h #include sera inscrit au d‚but des fichiers d'inclusion produits. */ char **includes = argp['i' - 'a'].ptrs; int nbincl = argp['i' - 'a'].nbptr; if (bserv_genserv(&lfct,cls,serveur_out,includes,nbincl,multi) != -1 && bserv_genclient (&lfct,cls,client_out,includes,nbincl ,herit,vname_out) != -1){ ret = 0; } } } return ret; }