#include #include #include #include #include #include #include #include #include "lexc.h" #include "lexc.m" #define FILESRC_BUFSIZE (40*512) /* #Specification: preprocesseur / limites Nombre maximum de niveau d'inclusion 100 */ #define MAX_INCLUDE 100 static FILE *fin[MAX_INCLUDE]; static const char *tbname[MAX_INCLUDE]; static char bslash_2_slash=0; /* Conversion des paths pour DJGCC */ int filesrc_level; /* Niveau d'inclusion */ /* Consulter par cpp.c pour annuler les appels */ /* de fonction */ static int tbline[MAX_INCLUDE]; int filesrc_noline; int filesrc_eof=1; static FILE *filesrc_trace=NULL; /* Produit une trace des */ /* sous-inclusions */ static struct { char *line; int pos; } tbsave[MAX_INCLUDE]; /* tbfind[] permet de retenir où un fichier d'inclusion a été trouvé */ /* dans tbpath[]. C'est pour la commande include_next */ static unsigned char tbfind[MAX_INCLUDE]; /* Enregistre le FILE * pour tracer la hiérarchie des inclusions. Si NULL, désactive le traçage. Par défaut, pas de traçage. */ void filesrc_settrace (FILE *_trace) { filesrc_trace = _trace; } /* Sélection stdin comme source du texte à analyser */ void filesrc_setstdin(void) { fin[0] = stdin; filesrc_level = 0; filesrc_noline=0; filesrc_eof = 0; tbline[0] = 0; tbname[0] = strdup_err("console",1); tbfind[0] = 0; } /* Ouverture avec limitation du nom de base (tronque OS/2 seulement) */ static FILE * near filesrc_vfopen (const char *name) { FILE *ret = vfopen_bin (name,"r"); #ifdef OS2 /* #Spécification: OS2 / tronque OS/2 ne fait pas comme DOS et ne tronque pas les noms trop long, ce qui fait que certain sources UNIX (X11) ne compile pas sous OS/2 (#include ) On verifie le nom de base et on tronque dans OS/2 seulement */ if (ret == NULL){ char path[MAXSIZ_PATH]; char bname[MAXSIZ_NAME]; path_splitlex (name,path,bname); char ext[MAXSIZ_EXTENSION]; file_baseext (bname,bname,ext); if (strlen (bname)>8){ bname[8] = '\0'; file_chgext (bname,bname,ext); path_make (path,bname,path); ret = vfopenbin (path,"r"); if (ret != NULL){ bfprintf (stderr,"Attention: %s tronqué -> %s\n" ,"Warning: %s truncate to %s\n" ,name,path); } } } #endif if (ret != NULL) setvbuf (ret,NULL,_IOFBF,FILESRC_BUFSIZE); return ret; } static char *dejavue[300]; static int nbdeja = 0; static char deja_mode = 0; static char deja_verbose = 0; /* Enregistre le mode de controle des doubles inclusions. Normalement le préprocesseur n'interfère pas et inclue un fichier autant de fois que demander. On peut lui demander de limiter le nombre d'inclusion des fichiers. Cela augmente la performance. Voir filesrc_setxdeja() pour contrecarrer ce mecanisme. */ export void filesrc_setdeja (int mode, int verbose) { deja_mode = (char)mode; deja_verbose = (char)verbose; } struct XDEJAVUE{ char *nom; char type; // 0: fichier avec path spécifique // 1: Répertoire avec path spécifique // 2: fichier sans path }; static XDEJAVUE xdejavue[30]; static int xnbdeja=0; /* Escamote le mode d'inclusion unique pour un fichier ou un répertoire */ export void filesrc_setxdeja (const char *fname) { if (xnbdeja == 30){ fprintf (stderr,MSG_B(E_TOOMANYEXCLUDE ,"Trop d'exclusion pour option -K, maximum 30.\n" "Essayez d'exclure des répertoires au complet.\n" ,"Too many exclude with option -K, maximum 30.\n" "maybe you should exclude complete directories.\n")); exit (-1); } XDEJAVUE *xdj = xdejavue + xnbdeja++; xdj->nom = strdup_err (fname,1); if (strchr(fname,TOOL_OS_SEP)==NULL){ xdj->type = 2; }else{ xdj->type = (char)(file_type(fname) == 1 ? 1 : 0); } } /* Lit un fichier contenant des paths. La table des fichiers d'inclusions déjà vue est ainsi chargée d'une session précédante. */ export void filesrc_readdeja (const char *fname) { FILE *fin = fopen_binerr (fname,"r",1); char buf[300]; while (fgets_strip(buf,sizeof(buf)-1,fin,'\\','#',NULL)!=NULL){ dejavue[nbdeja++] = strdup_err (buf,1); } fclose (fin); } /* Ecrit dans un fichier la liste des fichiers d'inclusions processé durant la session courante. */ export void filesrc_writedeja (const char *fname) { FILE *fout = fopen_err (fname,"w",1); for (int i=0; i %d\n",fname,ret); if (ret != 0){ // Le fichier a déjà été visité. Peut-être que l'usager a demandé // l'exclusion pour ce fichier. XDEJAVUE *xdj = xdejavue; for (i=0; itype == 1){ char path[MAXSIZ_PATH]; path_splitlex (fname,path,NULL); if (strcmp(path,xdj->nom)==0){ ret = 0; break; } }else if (xdj->type == 2){ char nom[MAXSIZ_NAME]; path_splitlex (fname,NULL,nom); if (strcmp(nom,xdj->nom)==0){ ret = 0; break; } }else if (strcmp(xdj->nom,fname)==0){ // On fait comme si on l'avait jamais vue ret = 0; break; } } if (ret == 0 && deja_verbose){ fprintf (stderr,MSG_B(I_MULTIPLEINCL ,"OK\tInclusion multiple: %s\n" ,"OK\tMultiple include: %s\n"),fname); } } if (ret == 1 && deja_verbose){ fprintf (stderr,MSG_B(E_MULTIPLEINCL ,"\tInclusion multiple: %s\n" ,"\tMultiple inclusion: %s\n"),fname); } return ret; } /* Ouvre un fichier d'input en conservant celui déjà ouvert dans une pile Cherche le fichier dans les répertoires founis dans le filesrc_setfpath() Préserve la position et le contenu de la ligne courante. A la fin de la lecture, ces informations permettront de repartir l'analyse à la même position dans la ligne. */ void filesrc_pushopen ( const char *fname, int methode, /* 0 : recherche dans le répertoire local en premier */ /* 1 : recherche a partir de 0 dans tbpath */ /* 2 : recherche a partir du repertoire où on */ /* a trouvé le fichier courant */ /* 3 : recherche a partir du repertoire suivant */ /* où on a trouvé le fichier courant */ char *ptl, /* Position de traitement dans la ligne */ /* La ligne sera tronque si on débute dans */ /* dans le nouveau fichier */ char *line) // Ligne en traitement { if (filesrc_level==MAX_INCLUDE-1){ lexcerr_bprintf ("Trop de sous-inclusion: maximum %d\n" ,"Too many sub-includes: maximum %d\n",MAX_INCLUDE); }else{ FILE *f=NULL; char fpath[MAXSIZ_PATH]; int find_level = 0; int deja = 0; if (methode == 0){ strcpy (fpath,fname); deja = filesrc_chkdeja(fname); if (!deja) f = filesrc_vfopen (fname); } if (f == NULL && !deja){ if (methode >= 2){ find_level = tbfind[filesrc_level]; if (methode == 3) find_level++; } int nbpath = tbpath.getnb(); for (; find_levelget(),fname,fpath); deja = filesrc_chkdeja(fpath); if (deja) break; f = filesrc_vfopen (fpath); if (f != NULL) break; } } if (!deja){ if (f == NULL){ lexcerr_bprintf ( "Ne peut ouvrir fichier d'inclusion %s\n" ,"Can't locate include file %s\n",fname); }else{ if (deja_mode) dejavue[nbdeja++] = strdup_err (fpath,1); tbsave[filesrc_level].line = strdup_err (line,1); tbsave[filesrc_level].pos = (int)(ptl - line); /* Force le traitement dans le fichier d'inclusion, le reste de la ligne étant automatiquement retraité (voir filesrc_pushopen()) */ *ptl = '\0'; if (filesrc_trace != NULL){ char point[80]; int indent = filesrc_level*4; memset (point,'.',indent); point[indent] = '\0'; fprintf (filesrc_trace,"%s%-4d%s\n",point ,tbline[filesrc_level],fpath); } filesrc_level++; fin[filesrc_level] = f; tbfind[filesrc_level] = (unsigned char)find_level; { char *npath = filesrc_dupname(fpath); tbname[filesrc_level] = npath; if (bslash_2_slash) path_2unix (npath,npath); } tbline[filesrc_level] = 0; tbforce[filesrc_level] = (char)(force_ins != NULL); } } } } /* Ferme le fichier d'input du source */ void filesrc_close (void) { if (fin[0]!=stdin && fin[0] != NULL){ fclose (fin[0]); } fin[0] = NULL; } static int tab_val=8; /* Enregistre la valeur pour expansion de tab. Par défaut 8. Cela est important pour la regénération des sources. */ export void filesrc_settab (int tab) { tab_val = tab; } static char exp_tab = 1; /* Enregistre si filesrc.c doit faire l'expansion des tab ou pas Par défaut, c'est ce qui est fait. */ export void filesrc_settabmode(int _exp_tab) { exp_tab = (char)_exp_tab; } /* Lit une nouvelle ligne dans le fichier d'input Traite le caractère de continuation \ en concaténant la ligne suivante. Doit être le dernier caractère de la ligne Fait l'expansion des tab. Retourne -1 si fin de fichier Si aucun fichier n'a été ouvert, retourne -1 */ int filesrc_fill (char *linres) { if (filesrc_eof){ filesrc_noline++; return (-1); } while (1){ char local_line[1000]; char *line = exp_tab ? local_line : linres; while (1){ if (tbforce[filesrc_level]){ strcpy (line,force_ins); tbforce[filesrc_level] = 0; filesrc_noline++; break; }else{ char *pt = fgets (line,sizeof(local_line)-1 ,fin[filesrc_level]); preproc_resetmacronb(); if (pt == NULL){ fclose (fin[filesrc_level]); fin[filesrc_level] = NULL; free ((void*)tbname[filesrc_level]); if (filesrc_level > 0){ filesrc_level--; /* Repart analyse immédiatement après le " ou le > de l'énoncé include (voir filesrc_pushopen() */ strcpy (line,tbsave[filesrc_level].line); free ((void*)tbsave[filesrc_level].line); memset (line,' ',tbsave[filesrc_level].pos); /* certaines boucles attendent un changement de ligne */ filesrc_noline++; break; }else{ linres[0] = '\0'; filesrc_eof = 1; /* certaines boucles attendent un changement de ligne */ filesrc_noline++; return (-1); } }else if (line[0] == '#' && strncmp(line+1,"line",4)==0 && isspace(line[5])){ char *pt = str_skip (line+5); if (isdigit(*pt)){ int num = atoi(pt); char *endpt; pt = str_skip(str_skipdig(pt)); if (pt[0] == '"') pt++; endpt = strip_end(pt) -1; if (endpt[0] == '"') endpt[0] = '\0'; tbline[filesrc_level] = num; free ((void*)tbname[filesrc_level]); tbname[filesrc_level] = filesrc_dupname (pt); }else{ lexcerr_bprintf ("Enoncé #line invalide\n\t%s\n" ,"Invalid #line statement\n\t%s\n" ,line); } }else{ filesrc_noline++; tbline[filesrc_level]++; break; } } } char *last = strip_end (line) -1; // Supporte les blancs et ^Z après \ // Elimine les \r de fichier DOS pour UNIX if (last >= line){ if (exp_tab){ // fait l'expansion des tabs char *pt1 = line; int col = 0; char carac = 0; while (*pt1 != '\0'){ carac = *pt1++; if (carac == '\t'){ col %= tab_val; while (col++ < tab_val) *linres++ = ' '; col = 0; }else{ col++; *linres++ = carac; } } *linres = '\0'; if (carac != '\\') break; linres--; }else{ if (*last != '\\') break; linres = last; } } } return (0); } /* Présente la position de lecture avec la hiérarchie des inclusions */ void filesrc_showpos (FILE *fout) { for (int i=0; i<=filesrc_level; i++){ fprintf (fout,"%s: %d\n",tbname[i],tbline[i]); } }