Newsgroup: it.comp.os.linux.development
Titolo: Parsing di file-testo


ICQ: <38811133>

di utilizzare flex o bison ma non so come.
Ti consiglio di riciclare quello usato da BIND e INN 2, non vale la pena
di riscriverne uno da zero.
-- 
ciao, | [Per rispondere togli "toglimi" dal mio indirizzo.]
Marco | * The Internet is full. Go away.  -- Joel Furr *
      | (Ri)scoprire fidonet: 
http://bbs.mi.linux.it

si parla di come utilizzare flex da un'altro file C).
flex non si usa da un programma in C, flex genera un programma in C
in base a delle regole contenute in un file, il programma generato, prende in
input dei caratteri e restituisce i token riconosciuti in base alle regole
messe nel file passato a flex.
se il linguaggio usato nel file è molto complesso
usa pure flex (analizzatore sintattico) e bison (analizzatore lessicale),
altrimenti scriviti il parser usando le semplici funzioni di libreria.
esiste un ottimo testo universitario in inglese che spiega l'uso
di flex e bison,
il titolo è "compilers: principles and tecniques" non so altro.
ciao.

di utilizzare flex o bison ma non so come.
IMVHO non ne vale la pena. Un programmino stupido che fa qualcosa del genere,
usando un formato abbastanza comune (puah) e con svariati punti da migliorare
(ci sono quattro potenziali root exploits, solo tre sono indicati ;-) ):
/* Manipolazione di files .INI
   La struttura di un file .INI e' la seguente:
; Linea di commento, individuata dal primo carattere ';'
[Sezione]
Chiave=Valore
*/
#ifndef __MSDOS__
#define	stricmp		strcasecmp
#define strnicmp	strncasecmp
#endif
#include <stdio.h>
#include <string.h>
#define	MAXLINEA	256	/* Max lungh di una linea INI */
enum
{
	INI_IN_RICERCA,
	INI_SEZIONE_OK,
	INI_CHIAVE_OK,
	INI_SALTA,
	INI_TUTTO_OK
};
int SetINIValue(const char *inifile,	/* Il file INI da manipolare	*/
		const char *sezione,	/* La sezione da consultare	*/
		const char *chiave,     /* La chiave da cercare 	*/
		char *nuovo_valore)     /* Il valore da dare alla chiave*/
/*	Valori di ritorno:  0 = OK
			   -1 = errore sul file
*/
{
	FILE	*fp, *np;
	char 	linea[MAXLINEA];
	char	chiave_sezione[80];
	int	status = 0;
	/* La sezione viene convertita in una chiave */
	/* Per es. PIPPO diventa [PIPPO] seguito da un line-feed */
	/* Non viene fatto controllo su lungh. di chiave_sezione, il che
	   risulta in un possibile exploit. Usare snprintf. */
	sprintf(chiave_sezione,"[%s]\n", sezione);
	/* Il file inifile viene rinominato in un file temporaneo */
	/* Secondo possibile exploit. Usare tmpnam. */
	rename(inifile, "iniwork.tmp");
	/* Grosso problema nel gestire le concorrenze. Un altro programma
	   o istanza potrebbe leggere un file incompleto. Occorrerebbe di
	   conseguenza lavorare su un inifile.lok e solo dopo rinominarlo
	   opportunamente. Sempre vulnerabile, ma la finestra e' minore.
	*/
	if ((np    = fopen (inifile, "w+t")) == NULL)
	{
		rename("iniwork.tmp", inifile);
		return -1;
	}
	fp = fopen("iniwork.tmp", "rt");
	if (fp)
	{
		while (!feof(fp))
		{
			*linea=0;
			switch(status)
			{
				case INI_IN_RICERCA:
					fgets(linea, MAXLINEA, fp);
					if (*linea==0 || *linea==';' ||
*linea=='#')
						break;
					if (!stricmp(linea, chiave_sezione))
						status = INI_SEZIONE_OK;
					break;
				case INI_SEZIONE_OK:
					sprintf(linea,"%s=%s\n", chiave,
nuovo_valore);
					status = INI_CHIAVE_OK;
					break;
				case INI_CHIAVE_OK:
					fgets(linea, MAXLINEA, fp);
					if (*linea==0 || *linea==';' ||
*linea=='#')
						break;
					if (*linea=='[')
						status = INI_TUTTO_OK;
					if (!strnicmp(linea, chiave,
strlen(chiave)))
					{
/* Se abbiamo trovato la chiave, dobbiamo
   scartarla. Per essere sicuri di averla
   trovata, si deve tener presente che si
   puo' avere:
   chiave cercata: "Quel ramo"
   linee nel file:
   "Quel = "
   "Quel ramo del lago di Como = "
   "Quel ramo     = "
   e che a noi interessa la _terza_ riga.
   All' interno di questo IF, sappiamo di
   aver eliminato il falso match (1) e il
   (2). Ma dobbiamo ancora riconoscere il
   VERO match (3).
   Possiamo avere:
   Quel=
   Quel =
   Quel\t=
   Quel\t \t\t=\t\t
   e TUTTI devono essere riconosciuti.
*/
						char *ptr;
						ptr = linea + strlen(chiave) -1;
						while (*ptr++)
						{
							if (*ptr == ' ')
								continue;
							if (*ptr == '\t')
								continue;
							if (*ptr == '=')
								status =
INI_SALTA;
							break;
						}
					}
					break;
				case INI_SALTA:
					status = INI_TUTTO_OK;
				case INI_TUTTO_OK:
					fgets(linea, MAXLINEA, fp);
					break;
			}
			if (status != INI_SALTA)
				if (*linea)
					fputs(linea, np);
		}
		fclose(fp);
	}
	remove("iniwork.tmp");
	if(status==INI_IN_RICERCA)	/* Manca TUTTO! */
	{
		fprintf(np, chiave_sezione);
		fprintf(np,"%s=%s\n", chiave, nuovo_valore);
		fprintf(np, "\n");
	}
	fclose(np);
	return 0;
}
char *GetINIValue(const char *inifile,	/* Il file INI da manipolare	*/
		const char *sezione,	/* La sezione da consultare	*/
		const char *chiave,     /* La chiave da cercare 	*/
		char *valore)     	/* Dove salvarne il valore 	*/
/*
	Valore di ritorno: NULL se la chiave non c'e' (perche' il file e'
	errato, la sezione mancante, o la chiave non trovata).
	Altrimenti, punta alla chiave, priva del \n finale.
	Se 'valore' in ingresso e' NULL, ritorna un puntatore ad una area
	statica contenente i primi 79 caratteri della chiave.
	ATTENZIONE: prima di passare un valore non nullo, occorre essere
	ben sicuri che il puntatore che si passa punti ad un'area grande
	abbastanza da contenere la chiave.
*/
{
	FILE	*fp;
	char 	linea[MAXLINEA];
	char	chiave_sezione[80];
	static	char keyvalue [80];
	char	*kptr = keyvalue;
	int	status = 0;
	if (valore)
		kptr = valore;
	/* La sezione viene convertita in una chiave */
	/* Per es. PIPPO diventa [PIPPO] seguito da un line-feed */
	/* Vedasi sopra per snprintf. */
	sprintf(chiave_sezione,"[%s]\n", sezione);
	if ((fp = fopen(inifile, "rt")) == NULL)
		return NULL;
	while (!feof(fp))
	{
		*linea=0;
		fgets(linea, MAXLINEA, fp);
		if (*linea==0 || *linea==';' || *linea=='#')
			continue;
		if (strchr(linea,'\r'))
			strcpy(strchr(linea,'\r'),"\n");
		switch(status)
		{
			case INI_IN_RICERCA:
				if (!stricmp(linea, chiave_sezione))
					status = INI_SEZIONE_OK;
				break;
			case INI_SEZIONE_OK:
				if (*linea=='[')
				{
					fclose(fp);
					return NULL;
				}
				if (!strnicmp(linea, chiave, strlen(chiave)))
				{
					char *ptr;
					ptr = linea + strlen(chiave) -1;
					while (*ptr++)
					{
						if (*ptr == ' ')
							continue;
						if (*ptr == '\t')
							continue;
						if (*ptr == '=')
						{
							while (*ptr++)
							{
								if (*ptr == ' ')
continue;
								if (*ptr ==
'\t')
continue;
						/* Chiave trovata */
								strncpy(kptr,
ptr, 80);
								kptr[80]=0;
								ptr =
strchr(kptr,'\n');
								if (ptr)
									*ptr =
0;
								fclose(fp);
								return kptr;
							}
						}
						break;
					}
				}
		}
	}
	fclose(fp);
	return NULL;
}
#ifndef _NO_TEST
/* Test
Sintassi: 	INITOOL inifile sezione chiave --> mostra il valore
		INITOOL inifile sezione chiave nuovovalore --> imposta il valore
*/
int main(int argc, char **argv)
{
	char *ptr;
	switch (argc)
	{
		case 4:	/* GET value */
			ptr = GetINIValue(argv[1], argv[2], argv[3], NULL);
			if (ptr == NULL)
				printf("File non trovato, sezione non valida, o
chiave mancante\n");
			else
				printf("%s->%s.%s=%s\n",
					argv[1],
					argv[2],
					argv[3],
					ptr);
			break;
		case 5:	/* SET value */
			if (SetINIValue(argv[1], argv[2], argv[3], argv[4]))
				printf("Impossibile impostare il valore.\n");
			else
				printf("OK!\n");
			break;
		default:
			fprintf(stderr,
				"Sintassi: 	%s inifile sezione chiave -->
mostra il valore\n"
				"		%s inifile sezione chiave
nuovovalore --> imposta il valore\n"
			, *argv, *argv);
	}
	return 0;
}
/* Questa riga e' messa in modo da incasinare il Visual C */
#endif
Leonardo
".signature": bad command or file name

Penso che mi scrivero` qualche funzione direttamente che esegua un parsing.
Grazie a tutti!


(ci sono quattro potenziali root exploits, solo tre sono indicati ;-) ):
                             ^^^^
Questo se le funzioni sono utilizzate da un daemon con permessi di root,
ovviamente
Leonardo precisante


 
Credo che tu ti stia riferendo al "dragon book": "Compilers:
principles, tecniques and tools" di Aho, Sethi e Ullman. 
IMHO questo testo e' piu' adatto ai corsi universitari
sull'implementazione di compilatori; per il problema di Massimo credo
sia piu' indicato "Lex & Yacc" della O'Reilly.
Soffrendo un po' di piu' pero' si puo' anche imparare dalla
documentazione in linea: consiglio info bison e man lex.
Ciao,
-- 
Diego    | Per le repliche elimina dal mio indirizzo le 
Dainese  | `x' e inverti le due parole intorno alla `@'

Pape' Satan, pape' Satan aleppe, comincio' Diego con voce chioccia:
DD> IMHO questo testo e' piu' adatto ai corsi universitari
DD> sull'implementazione di compilatori; per il problema di Massimo credo
DD> sia piu' indicato "Lex & Yacc" della O'Reilly.
IMHO fa prima ad andare su 
www.fsf.org
, seguire i link alla
documentazione da stampare (purtroppo non mi ricordo di preciso quali
erano i link) e prendersi la versione postscript dei manuali di flex
e bison (quest'ultimo scritto da un tale Charles Donnelly e
nientepocodimenoche Richard Stallman)
-- 
ciao,
Claudio


ho sofferto molto, ma imparato poco, che vuol dire?
ciao;-)

 ciao;-)
Che e' decisamente meglio puntare sul libro ;-)


 parsing ho pensato di utilizzare flex o bison ma non so come.
  se devi solo settare un numero limitato variabili, che ne dici di
#!/bin/sh
var1=default1 # commento sulla variabile 1
var2=default2 # ...
...
source $HOME/.init
export var1 var2 ...
exec myprog
  ed usare dei bei getenv nel programma?

  ed usare dei bei getenv nel programma?
Mmmmmh... un'ibridazione linguaggio interpretato + compilato... non so.
Comunque ci sono troppe variabili.
Grazie comunque del consiglio.
