/* extrait des prototypes d'une liste de fichier et imprime sur stdout Trois options peut etre definie pour la compilation VERSION_SHARE : si la version compilé est le shareware VERSION_PROD : version commerciale (superset du shareware) VERSION_DEV : version de développement stable VERSION_ESSAI : version instable */ #include #include #include #include #include #include #include #include "assert.h" #include #include "proto.h" #include "proto.m" #include #define PROTO_VERSION 2 #define PROTO_RELEASE 40 #define VERSION_DEV 1 char proto_formatdos = 0; static void showver() { fprintf (stderr,"proto %d.%d (linuxconf-tools %d.%d)\n" ,PROTO_VERSION,PROTO_RELEASE ,TOOLS_VERSION,TOOLS_RELEASE); } static void near usage (const char *argv0) { showver(); static const char *msg=MSG_B(I_USAGE, "USAGE : proto [-option] fichiers ... [-option] fichiers ...\n" " : Génère le prototype des fonctions C et C++\n" " pour une liste de fichiers\n" "\n" " -aX : Accès par défaut pour fonctions membres C++\n" " -a0 --> private\n" " -a1 --> protected\n" " -a2 --> public\n" " Défaut: -a0\n" "\n" " -b : Met à jour un fichier d'inclusion à partir d'un autre\n" " -bX.h -> X.h += X.pm\n" " -bX.h+A.pm -> X.h += A.pm\n" " -bX.h+A.pm=R.h -> R.h = A.pm+X.h\n" " -b seul équivalent à -bX.h[pp] où X est le nom du\n" " répertoire courant\n" "\n" " -ceoprsu+di: Sélection des résultats générés\n" " + --> Sélection des fonctions membres C++\n" " Equivalent à la combinaison pru\n" " d --> documentation des fonctions\n" " e --> Sélection des fonctions \"export\"\n" " i --> index référence fonctions -> fichiers source\n" " o --> Sélection des fonctions ordinaires\n" " p --> Sélection des fonction membres \"private\" C++\n" " r --> Sélection des fonction membres \"protected\" C++\n" " s --> Sélection des fonctions \"static\"\n" " u --> Sélection des fonction membres \"public\" C++\n" " Défaut : -co\n" "\n" " -C : Ne traite pas les commentaires imbriqués\n" " Défaut : Supporte les commentaires imbriqués\n" "\n" " -Dx : définie le symbole \"x\"\n" " -Dx=y : définie le symbole \"x\" avec la valeur \"y\"\n" "\n" " -exxx : Termine la sortie dans le fichier xxx\n" "\n" " -fxxx : sortie dans fichier \"xxx\"\n" " +fxxx : sortie ajoutée au fichier \"xxx\"\n" " On peut générer plusieurs fichiers parallèlement\n" " avec un sélecteur différent pour chacun\n" " ex: proto -ceo -fprj.h -ced -f../h/prj.h *.c\n" "\n" " -hXXX : Décompose le fichier de prototypes C++ XXX\n" " en un fichiers par classes.\n" " Les fichiers auront le nom des classes (tronqués)\n" " avec l'extension .pp.\n" " -h seul: traite le fichier X.pm.\n" " (X est le nom du répertoire courant)\n" "\n" " -i : Traitement incrémental, seul les fichiers modifiés\n" " depuis le dernier traitement sont relus\n" " Première option sur la ligne\n" "\n" " -I : Enregistre une série de répertoire à consulter\n" " pour localiser les fichiers d'inclusions\n" "\n" " -k : Désactive les mots clés C++.\n" " -kx : Désactive un mot clé.\n" " -kexport élimine le mot-clé \"export\".\n" " -kx=y : Redéfinit un mot clé\n" " -kexport=EXPORT remplace \"export\" par \"EXPORT\".\n" "\n" " -lX=Y : Spécifie un nom alternatif(Y) pour une classe X\n" " lors de la décomposition (option -h)\n" "\n" " -m0 : Génération pour projet à un seul répertoire\n" " Equivalent à \"-co -fX.p -coi -fX.nar -cod -fX.nap\"\n" " -m1 : Génération pour projet à plusieurs répertoires\n" " Equivalent à \"-ceo -fX.p -ceoi -fX.nar -ceod -fX.nap\"\n" " et \"-ce -f../include/X.p -cei -f../doc/X.nar -ced\n" " -f../doc/X.nap\"\n" " -m2 : Génération pour projet à plusieurs répertoires\n" " Equivalent à \"-ceo -fX.p -ceoi -fX.nar -ceod -fX.nap\"\n" " et \"-ce -f../../include/X.p -cei -f../doc/X.nar -ced\n" " -f../../doc/X.nap\"\n" "\n" " -m0+ : Génération pour projet à un seul répertoire C++\n" " Equivalent à \"-co -fX.p -c+ -fX.pm -co+i -fX.nar\n" " -co+d -fX.nap\"\n" " -m1+ : Génération pour projet à plusieurs répertoires C++\n" " Equivalent à \"-ceo -fX.p -c+ -fX.pm -ceo+i -fX.nar\n" " -ceo+d -fX.nap\"\n" " et \"-ce -f../include/X.p -cerui -f../doc/X.nar -cerud\n" " -f../doc/X.nap\"\n" " -m2+ : Génération pour projet à plusieurs répertoires C++\n" " Equivalent à \"-ceo -fX.p -c+ -fX.pm -ceo+i -fX.nar\n" " -ceo+d -fX.nap\"\n" " et \"-ce -f../../include/X.p -cerui -f../doc/X.nar -cerud\n" " -f../../doc/X.nap\"\n" " (X est le nom du répertoire courant)\n" "\n" " -nXXX : Enregistre le préfixe XXX à insérer dans les fichiers\n" " index références fonctions.\n" " Par défaut: Chaine vide.\n" "\n" " -oxxx : Spécifie un nom alternatif pour option -m\n" "\n" " -p : Prototypes pour arguments suivants (inverse -x)\n" " (défaut)\n" "\n" " -P : Active préprocesseur C : Traitement des #include,...\n" " -qxxx : Extraction de la composition des classes pour\n" " le programme clsform.\n" " Le fichier xxx sera produit.\n" " +qxxx : Comme -q, ajoute au fichier xxx.\n" "\n" " -s : Opération sans messages\n" " -S : Tri les fonctions membres C++ par visibilité\n" " -t : Lit le source du terminal\n" " -v : Opération avec maximum d'information\n" " -x : Exclu les arguments suivants (inverse -p)\n" "\n" " @xxx : Lit les arguments du fichier \"xxx\"\n" " dans le répertoire courant ou ses ancêtres\n" " @ seul -> proto.cfg par défaut\n" , "USAGE : proto [-option] files ... [-option] files ...\n" " : Extract prototypes for C and C++ functions\n" " from a list of files\n" "\n" " -a : Default access control for C++ member functions\n" " -a0 --> private\n" " -a1 --> protected\n" " -a2 --> public\n" " Default: -a0\n" "\n" " -b : Update a header using an other one\n" " -bX.h -> X.h += X.pm\n" " -bX.h+A.pm -> X.h += A.pm\n" " -bX.h+A.pm=R.h -> R.h = A.pm+X.h\n" " -b alone is like -bX.h[pp] where X is the name of the\n" " current directory\n" "\n" " -ceoprsu+di: Output selector\n" " + --> Select C++ class member functions\n" " Same as pru\n" " d --> function documentation\n" " e --> Select \"export\" functions\n" " i --> cross reference functions -> source files\n" " o --> Select ordinary functions\n" " p --> Select C++ class member \"private\" functions\n" " r --> Select C++ class member \"protected\" functions\n" " s --> Select \"static\" functions\n" " u --> Select C++ class member \"public\" functions\n" " Default : -co\n" "\n" " -C : Disallow nested comments\n" " Default: Allow nested comments\n" "\n" " -Dx : define \"x\" symbol\n" " -Dx=y : défine symbol \"x\" with value \"y\"\n" "\n" " -exxx : Terminate output to file xxx\n" "\n" " -fxxx : Output in file \"xxx\"\n" " +fxxx : Output appended to file \"xxx\"\n" " Several output files may be generated at once\n" " each one with a different output selector\n" " ex: proto -ceo -fprj.h -ced -f../h/prj.h *.c\n" "\n" " -i : Incremental processing: Only the files modified\n" " since the last processing are scanned\n" " Must be the first option on the command line\n" "\n" " -I : directories for include files lookup\n" "\n" " -k : Desactivate all C++ keyword.\n" " -kx : Desactivate one keyword.\n" " -kexport kills the keyword \"export\".\n" " -kx=y : Reassign a keyword\n" " -kexport=EXPORT reassigns \"export\" to \"EXPORT\".\n" "\n" " -m0 : Processing for single directory projects\n" " Equivalent to \"-co -fX.p -coi -fX.nar -cod -fX.nap\"\n" " -m1 : Processing for multiple directories projects\n" " Equivalent to \"-ceo -fX.p -ceoi -fX.nar -ceod -fX.nap\"\n" " and \"-ce -f../include/X.p -cei -f../doc/X.nar -ced\n" " -f../doc/X.nap\"\n" " -m2 : Processing for multiple directories projects\n" " Equivalent to \"-ceo -fX.p -ceoi -fX.nar -ceod -fX.nap\"\n" " and \"-ce -f../../include/X.p -cei -f../doc/X.nar -ced\n" " -f../../doc/X.nap\"\n" "\n" " -m0+ : Processing for single directory projects C++\n" " Equivalent to \"-co -fX.p -c+ -fX.pm -co+i -fX.nar\n" " -co+d -fX.nap\"\n" " -m1+ : Processing for multiple directories projects C++\n" " Equivalent to \"-ceo -fX.p -c+ -fX.pm -ceo+i -fX.nar\n" " -ceo+d -fX.nap\"\n" " and \"-ce -f../include/X.p -cerui -f../doc/X.nar -cerud\n" " -f../doc/X.nap\"\n" " -m2+ : Processing for multiple directories projects C++\n" " Equivalent to \"-ceo -fX.p -c+ -fX.pm -ceo+i -fX.nar\n" " -ceo+d -fX.nap\"\n" " and \"-ce -f../../include/X.p -cerui -f../doc/X.nar -cerud\n" " -f../../doc/X.nap\"\n" " (X is the name of the current directory)\n" "\n" " -nXXX : Record prefix XXX to insert in cross reference files\n" " Default: nothing.\n" "\n" " -oxxx : Specify an alternative name for option -m\n" "\n" " -p : Enable processing for next arguments (reverse -x)\n" " (default)\n" "\n" " -P : Enable ANSI C preprocessor: processing of #include,...\n" " -qxxx : Extract class's composition for programm clsform.\n" " File xxx will be created.\n" " +qxxx : Like -q, but append to file xxx.\n" "\n" " -s : Silent operation\n" " -S : Sort C++ member function according to their visibility\n" " -t : Read source file from console\n" " -v : Verbose operation\n" " -x : Disable processing for next arguments (reverse -p)\n" "\n" " @xxx : Read arguments from file \"xxx\"\n" " xxx is located is the current directory or its ancestor\n" " @ alone -> proto.cfg is searched\n" ); fputs (msg,stderr); } /* Vérifie si un fichier a déjà été traité */ static int chkdeja (char *nomf) { static char *deja=NULL; static int nbf=0; char *pt; int i; if (deja == NULL) deja = (char *) malloc_err(5000,1); #ifdef MSDOS /* Patch pour etre compatible avec unix A premiere vue, ca semble une faiblesse de tool qui retourne des path en majuscule (Pour DOS). C'est probablement le cas. Toutefois il ne faut pas oublier que l'usager peut spécifier directement sur la ligne de commande un nom de fichier, en majuscule. */ strlwr (nomf); #endif pt = deja; for (i=0; i>16),datestr); time_u2a0 ((unsigned)(date&0xffff),timestr,'.'); protof_entete (filnam,datestr,timestr); if (gennewsrc) outsrc_open ("$$$"); cproto_main(gennewsrc); token_close(); protof_endcondit (); if (gennewsrc){ outsrc_close (); if (file_renameext (nomf,"old",0)!=-1){ file_rename ("$$$",nomf); }else{ erreur ( "Ne peut renommer %s\n" ,"Can't rename %s\n",nomf); } } }else{ erreur ( "Ne peut ouvrir le fichier\n" ,"Can't open file\n"); } erreur_setpre (""); } } } static void near resopen ( const char *strmode, const char *fname, const char *mode) { if (protof_open (fname,mode)==-1) exit(-1); if (verbose){ printf ("-> -c%-4s -f%s\n",strmode,fname); } } /* génère la combinaison d'option -c et -f selon une méthode et l'autre */ static void near methode ( char *modele, /* 0,1,0+,1+,2,2+ */ const char *nomsys) /* Nom de base des fichiers à générer, si */ /* différent du répertoire courant */ { typedef struct { int mode; /* mode d'output a sélectionner */ const char *modstr; /* mode sous forme ascii (void option -c) */ const char *path; /* path ou générer l'ouput avec %s */ } DEFTB; DEFTB *pt; if (strcmp(modele,"0") == 0 || strcmp(modele,"0+")==0 ){ static DEFTB tb[]={ {MODE_ORDIN, "o","%s.p"}, {MODE_ORDIN|MODE_COMMENT, "od","%s.nap"}, {MODE_ORDIN|MODE_INDEX, "oi","%s.nar"}, {0,0,0} }; static DEFTB tbplus[]={ {MODE_ORDIN, "o","%s.p"}, {MODE_CPLUS, "+","%s.pm"}, {MODE_ORDIN|MODE_CPLUS|MODE_COMMENT, "o+d","%s.nap"}, {MODE_ORDIN|MODE_CPLUS|MODE_INDEX, "o+i","%s.nar"}, {0,0,0} }; pt = modele[1] == '+' ? tbplus : tb; }else if (strcmp(modele,"1")==0 || strcmp(modele,"1+")==0){ static DEFTB tb[]={ {MODE_ORDIN|MODE_EXPORT, "eo","%s.p"}, {MODE_ORDIN|MODE_EXPORT|MODE_COMMENT, "eod","%s.nap"}, {MODE_ORDIN|MODE_EXPORT|MODE_INDEX, "eoi","%s.nar"}, {MODE_EXPORT, "e","../include/%s.p"}, {MODE_EXPORT|MODE_COMMENT, "ed","../doc/%s.nap"}, {MODE_EXPORT|MODE_INDEX, "ei","../doc/%s.nar"}, {0,0,0} }; static DEFTB tbplus[]={ {MODE_ORDIN|MODE_EXPORT, "eo","%s.p"}, {MODE_CPLUS, "+","%s.pm"}, {MODE_ORDIN|MODE_EXPORT|MODE_CPLUS|MODE_COMMENT, "eo+d","%s.nap"}, {MODE_ORDIN|MODE_EXPORT|MODE_CPLUS|MODE_INDEX, "eo+i","%s.nar"}, {MODE_EXPORT, "e","../include/%s.p"}, {MODE_EXPORT|MODE_PROTECTED|MODE_PUBLIC|MODE_COMMENT, "erud","../doc/%s.nap"}, {MODE_EXPORT|MODE_PROTECTED|MODE_PUBLIC|MODE_INDEX, "erui","../doc/%s.nar"}, {0,0,0} }; int skip = modele[1] == '+' ? 1 : 0; pt = modele[1] == '+' ? tbplus : tb; if (file_type("../include")!=1 && file_type("../h")==1){ #if defined(VERSION_DEV)||defined(VERSION_PROD) pt[3+skip].path = "../h/%s.p"; #else pt[2+skip].path = "../h/%s.p"; #endif } }else if (strcmp(modele,"2")==0 || strcmp(modele,"2+")==0){ static DEFTB tb[]={ {MODE_ORDIN|MODE_EXPORT, "eo","%s.p"}, {MODE_ORDIN|MODE_EXPORT|MODE_COMMENT, "eod","%s.nap"}, #if defined(VERSION_PROD)||defined(VERSION_DEV) {MODE_ORDIN|MODE_EXPORT|MODE_INDEX, "eoi","%s.nar"}, #endif {MODE_EXPORT, "e","../../include/%s.p"}, {MODE_EXPORT|MODE_COMMENT, "ed","../../doc/%s.nap"}, #if defined(VERSION_PROD)||defined(VERSION_DEV) {MODE_EXPORT|MODE_INDEX, "ei","../doc/%s.nar"}, #endif {0,0,0} }; static DEFTB tbplus[]={ {MODE_ORDIN|MODE_EXPORT, "eo","%s.p"}, {MODE_CPLUS, "+","%s.pm"}, {MODE_ORDIN|MODE_EXPORT|MODE_CPLUS|MODE_COMMENT, "eo+d","%s.nap"}, # if defined(VERSION_PROD)||defined(VERSION_DEV) {MODE_ORDIN|MODE_EXPORT|MODE_CPLUS|MODE_INDEX, "eo+i","%s.nar"}, # endif {MODE_EXPORT, "e","../../include/%s.p"}, {MODE_EXPORT|MODE_PROTECTED|MODE_PUBLIC|MODE_COMMENT, "erud","../../doc/%s.nap"}, # if defined(VERSION_PROD)||defined(VERSION_DEV) {MODE_EXPORT|MODE_PROTECTED|MODE_PUBLIC|MODE_INDEX, "erui","../doc/%s.nar"}, # endif {0,0,0} }; int skip = modele[1] == '+' ? 1 : 0; pt = modele[1] == '+' ? tbplus : tb; if (file_type("../../include")!=1 && file_type("../../h")==1){ # if defined(VERSION_DEV)||defined(VERSION_PROD) pt[3+skip].path = "../../h/%s.p"; # else pt[2+skip].path = "../../h/%s.p"; # endif } }else{ erreur ( "Option m : modèle '%s' invalide\n" ,"Option m : Invalid specifier '%s'\n",modele); return; } { char cwd[MAXSIZ_PATH]; if (nomsys[0] == '\0'){ path_getcwd (cwd,sizeof(cwd)); path_splitlex (cwd,NULL,cwd); }else{ strcpy (cwd,nomsys); } while (pt->mode != 0){ char buf[MAXSIZ_PATH]; protof_defmode (pt->mode); sprintf (buf,pt->path,cwd); resopen (pt->modstr,buf,"w"); pt++; } } protof_defmode (MODE_ORDIN); } /* Sélectionne le type d'output requis pour les fichiers subséquent */ static void near setmode (const char *arg) { const char *pt = arg; int mode = 0; while (*pt != '\0'){ int carac = islower(*pt) ? toupper (*pt) : *pt; switch (carac){ case 'D': mode |= MODE_COMMENT; break; case 'E': mode |= MODE_EXPORT; break; # if defined(VERSION_DEV)||defined(VERSION_PROD) case 'I': mode |= MODE_INDEX; break; # endif case 'O': mode |= MODE_ORDIN; break; case 'S': mode |= MODE_STATIC; break; case '+': mode |= MODE_CPLUS; break; case 'P': mode |= MODE_PRIVATE; break; case 'R': mode |= MODE_PROTECTED; break; case 'U': mode |= MODE_PUBLIC; break; default: erreur_signal (MSG_B(E_IVLDOPT_C ,"Option -c%c invalide\n" ,"Invalid option -c%c\n"),carac); } pt++; } if (mode == MODE_COMMENT || mode == MODE_INDEX){ erreur_signal (MSG_B(E_BADSELECT ,"sélecteur -c%s probablement erroné : Sans effet\n" ,"Incomplete selector spécification : Ignored\n") ,arg); }else{ protof_defmode (mode); } } /* Traite les arguments de la ligne de commande Cette routine est récursive pour les fichier @ */ static void near prcargv (int argc, char *argv[], char *strmode) { int i; static char *tb[2][2]={ {"$$", "$"}, {"$", NULL} }; char curpath[MAXSIZ_PATH]; char nomsys[MAXSIZ_PATH]; char *clsopen = ""; /* Fichier pour recueillir composition des */ /* classe, voir option -q */ char curdir[MAXSIZ_NAME]; tb[1][1] = curdir; nomsys[0] = '\0'; path_getcwd(curpath,sizeof(curpath)-1); path_splitlex (curpath,NULL,curdir); for (i=0; i= '0' && fi[2] <= '2'){ int def = fi[2] - '0'; static int tb[]={MODE_PRIVATE,MODE_PROTECTED,MODE_PUBLIC}; cplus_setdefault(def); cproto_setcplusdef(tb[def]); }else{ erreur_signal (MSG_B(E_IVLDOPT ,"Option %s invalide\n" ,"Invalid option %s\n"),fi); } }else if (strncmp(fi,"-b",2)==0){ splitcp_accummerge(fi+2); }else if (strncmp(fi,"-D",2)==0){ token_setdef (fi+2); }else if (strcmp(fi,"-C")==0){ comment_setmode (0); }else if (strncmp(fi,"-c",2)==0){ setmode (fi+2); strcpy (strmode,fi+2); }else if (strncmp(fi,"-h",2)==0){ splitcp_accumsplit (fi+2,".pp"); }else if (strcmp(fi,"-j")==0){ proto_formatdos = 1; }else if (strncmp(fi,"-n",2)==0){ protof_prefixnar (fi+2); }else if (strncmp(fi,"-l",2)==0){ cplus_setalt (fi+2); }else if (strcmp(fi,"-x")==0){ genproto = 0; }else if (strcmp(fi,"-p")==0){ genproto = 1; }else if (strcmp(fi,"-s")==0){ verbose = 0; }else if (strcmp(fi,"-S")==0){ cplus_setsort (true); }else if (strcmp(fi,"-v")==0){ verbose = 2; }else if (strncmp(fi,"-o",2)==0){ strcpy (nomsys,fi+2); }else if (strncmp(fi,"-m",2)==0){ methode (fi+2,nomsys); }else if (strncmp(fi,"-q",2)==0){ clsopen = fi+2; clsanal_open (clsopen,0); }else if (strncmp(fi,"+q",2)==0){ clsopen = fi+2; clsanal_open (clsopen,1); }else if (fi[0] == '-'){ erreur_signal (MSG_R(E_IVLDOPT),fi); }else{ /* fichier à traiter */ char *pt=fi; int wild = 0; while (*pt != '\0'){ if (*pt == '*' || *pt == '?') wild = 1; pt++; } if (wild){ char path[MAXSIZ_PATH]; char file[MAXSIZ_NAME]; char **tbstr = (char**)malloc_err (400 * sizeof(char*),1); path_split (fi,path,file); { int i; int nbstr = vdir_getlist (path,file,tbstr,400); for (i=0; i 0 ? -1 : 0; }