/* File: crea-pagina.c Author: Paolo Caressa Date: November 2004 Version: 1.9 Note: added to 1.8 the convert_link, convert_url functions, modified the target behaviour in a href tags: target="_self" is now dropped. Note: Questo programma consente di creare le pagine WEB del sito caressa.it. Per farlo si deve porre in uno o pi file di descrizione ".des" la struttura della/e pagina/e. Il programma effettua il parsing del/dei file ".des" e fornisce in output il/i corrispondenti file ".html" ed un file "menu_item.js", che vanno posti tutti nella medesima directory. NOTA: il nome del file menu_item prodotto fisso, quindi necessario rinominarlo dopo che stato prodotto se si tratta della versione inglese in "menu_item-en.js" I contenuti del sito devono essere posti in dei file che contengono brani di html e che vanno indicati nel file di descrizione. Un file di descrizione ".des" ha la seguente sintassi: un file di testo che contiene una sequenza di definizioni della forma tag = valore separate da caratteri blank, dove nome una keyword, e valore pu essere una stringa o una lista. I possibili tag sono: - alt (il valore una stringa che contiene la descrizione alternativa dell'immagine) - desc (il valore una stringa che contiene la descrizione della pagina a fianco dell'immagine) - dump (il valore una stringa che contiene il nome del file .html da produrre in relazione alle informazioni correnti: questa keyword ha l'effetto di produrre il file ed azzerare le altre informazioni) - icon (il valore una stringa col nome dell'immagine in alto a sinistra) - keywords (il valore una stringa di keyword da mettere come meta-dato) - lang (il valore una stringa "it" o "en") - link (come dump, solo che non produce un file .html ma considera la stringa come un link ad un file gi esistente) - menu (il valore una lista) - title (il valore una stringa col titolo della pagina) Una stringa una sequenza di caratteri racchiusa fra " e " (per far comparire un carattere " al suo interno si usa \"). Un elemento della lista menu ha la forma seguente struttura: [ link, nome_link, desc_link ] oppure [ link, nome_link, desc_link, lista_menu ] oppure ! url dove: - link pu essere: una stringa che contiene il nome del file da inserire nella pagina e che d il contenuto del link; oppure essere formato da un @ seguito da una stringa che rappresenta un URL a cui saltare; oppure essere uno dei due precedenti seguito da > e da una stringa che contiene il nome della finestra dove visualizzare il link (il campo target del tag a); - nome_link una stringa contenente il nome del link che si sta inserendo, quale appare all'utente, oppure una stringa seguita da | e da un'altra stringa che ne rappresenta una versione abbreviata da usare nei menu; - desc_link una stringa contenente la descrizione del link che si mette di seguito all'ancora contenente il link, oppure una stringa seguita da | e da un'altra stringa che ne rappresenta una versione abbreviata da usare nei menu; - lista_menu un'altra lista menu. - url una stringa che contiene la url di un file che viene inserito nel codice HTML senza dar luogo n a link n a voci di menu. Nota: se le versioni brevi del nome e della descrizione del link sono omesse, allora le versioni lunghe sono automaticamente utilizzate al loro posto. Se il target di un link omesso, il link aperto nella stessa finestra dove compare la sua ancora. Ad esempio [ [ "file1.html", "Primo punto" | "1.", ": la prima cosa che descriviamo" | "Per primo", [ [ "file11.html", "Primo sottopunto di 1" | "1.1", ": primo sottopunto di 1" | "1.1." ], [ "file12.html", "Secondo sottopunto di 1" | "1.2", ": secondo sottopunto di 1" | "1.2." ] ] ], [ "file2.html" , "Secondo punto" | "2.", ": la seconda cosa che descriviamo" | "Per secondo", [ [ "file21.html", "Primo sottopunto di due" | "2.1", ": secondo sottopunto di 2" | "2.1.", [ [ "file211.html", "Primo sottopunto di 2.1" | "2.1.1", ": primo sottopunto di 2.1" | "2.1.1." ], [ "file212.html", "Secondo sottopunto di 2.1" | "2.1.2", ": secondo sottopunto di 2.1" | "2.1.2." ] ] ], [ @ "http://www.boh.com" > "_blank" , "Destinazione ignota", "boh!" ] [ @ "mailto:whoami@boh.com", "Per informazioni", "info" ] ] ] I file "file1.html" etc. contengono il testo html da inserire nella pagina, mentre "http://www.boh.com" verr solo linkato e non inserito nel file come contenuto: il link verr aperto in una nuova finestra "_blank". Le assegnazioni possono ripetersi, e si sovrappongono, mentre dopo una assegnazione dump=... tutti i valori sono annullati. Nel file ".des" si possono inserire commenti come in JavaScript: usando la doppia barra // fino a fine riga, oppure la barra / seguita dall' asterisco * fino ad un asterisco * seguito da una barra /. License: This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include /*** COSTANTI ***/ #define PROGNAME "crea-pagina v1.9, (c) 2004 by Paolo Caressa" #define NAMESIZ 64 /* lunghezza di un nome */ #define STRSIZ 2048 /* lunghezza di una stringa */ const int ERROR = 1; const char FILE_MENU_NAME[] = "menu_item.js"; /* codici HTML: si noti che il file prodotto un file xhtml */ const char HTML_HEAD[] = "\n\ \n\ \n\ \n\ www.caressa.it: %s\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\n\n"; const char HTML_HEAD_EN[] = "\n\ \n\ \n\ \n\ www.caressa.it: %s\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\n\n"; const char HTML_NOSCRIPT[] = "\ \n"; const char HTML_NOSCRIPT_EN[] = "\ \n"; const char HTML_BEGIN[] = "\n\ \n\n\ \n\n\ \n\n"; const char HTML_BEGIN_MOTTO[] = "\ \n\n\ \n\ \n\n\ \n\n"; const char HTML_TOC_AT[] = "
%s%s\n"; const char HTML_TOC_AT_TARGET[] = "
%s%s"; const char HTML_TOC[] = "
%s%s"; const char HTML_TOC_TARGET[] = "
%s%s"; const char HTML_SUBTOC_AT[] = "\n %s%s"; const char HTML_SUBTOC_AT_TARGET[] = "\n %s%s"; const char HTML_SUBTOC[] = "\n %s%s"; const char HTML_SUBTOC_TARGET[] = "\n %s%s"; const char HTML_TOC_END[] = "
\n"; const char HTML_VALIDATION[] = "
\n\n\n\n\ \
\"Valid\"Valid\"Made
\n"; const char HTML_PAGE[] = "\n
\n\n

%s

\n\n"; const char HTML_SUBPAGE[] = "\n
\n\n\n"; const char HTML_END[] = "\n\n\ \n\n\n\n\n\n\n"; /* codici JavaScript (per il pacchetto TigraMenu) */ const char JS_BEGIN[] = "/* File di definizione del menu in accordo col formato Tigra Menu\n\ [created on %s by %s] */\n\n// Struttura del menu:\nvar MENU_ITEMS = "; const char JS_HEAD[] = "// %s\n[ \"
%s
\", \"%s\", { \"sb\" : \"%s\" }, "; const char JS_MENU_ITEM[] = "[ \"    %s\", \"%s#%s\", { \"tw\" : \"%s\", \"sb\" : \"%s\" }, "; const char JS_MENU_ITEM_AT[] = "[ \"    %s\", \"%s\", { \"tw\" : \"%s\", \"sb\" : \"%s\" }, "; const char JS_END[] = "\n];\nvar MENU_POS = [ {\n\ 'height': 1.4, 'width': 8.33, // item size\n\ 'block_top': 1.33, 'block_left': 9.67, // offset\n\ 'top': 0, 'left': 8.33, // offest in the same level\n\ 'expd_delay': 300, 'hide_delay': 300, // menu operation times\n\ 'css': { 'outer': ['menu_outer_out', 'menu_outer_over', 'menu_outer_down'],\n\ 'inner': ['menu_inner_out', 'menu_inner_over', 'menu_inner_down']}\n}, {\n\ 'height': 1.4, 'width': 12.5,\n\ 'block_top': 1.33, 'block_left': 4.67,\n\ 'top': 1.67, 'left': 0\n}\n];"; /*const char JS_END[] = "\n];\nvar MENU_POS = [ {\n\ 'height': 22, 'width': 110,\n 'block_top': 16, 'block_left': 116,\n\ 'top': 0, 'left': 110, 'expd_delay': 300, 'hide_delay': 300,\n\ 'css' : {\n\ 'outer': ['menu_mouse_out', 'menu_mouse_over', 'menu_mouse_down'],\n\ 'inner': ['menu_mouse_out', 'menu_mouse_over', 'menu_mouse_down']\n\ }\n}, {\n\ 'height': 20, 'width': 150,\n 'block_top': 16, 'block_left': 56,\n\ 'top': 20, 'left': 0\n}\n];";*/ /* nomi delle keyword */ const char KEY_ALT[] = "alt"; const char KEY_DESC[] = "desc"; const char KEY_DUMP[] = "dump"; const char KEY_ICON[] = "icon"; const char KEY_KEYWORDS[] = "keywords"; const char KEY_LANG[] = "lang"; const char KEY_LINK[] = "link"; const char KEY_MENU[] = "menu"; const char KEY_TITLE[] = "title"; /* messaggi di errore */ const char MSG_BUFFER_EXPECTED[] = "Atteso un buffer invece di '%s'"; const char MSG_CANT_OPEN[] = "Impossibile aprire il file '%s'"; const char MSG_CLOSE_EXPECTED[] = "Atteso ']' invece di '%s'"; const char MSG_COMMA_EXPECTED[] = "Attesa ',' invece di '%s'"; const char MSG_EMPTY_DOC[] = "Documento senza titolo"; const char MSG_EOF_INSIDE_COMMENT[] = "EOF dentro un commento"; const char MSG_EOF_INSIDE_STR[] = "EOF dentro una stringa"; const char MSG_ERROR[] = "ERRORE "; const char MSG_EXPECTED[] = "Atteso '?' invece di '%s'"; const char MSG_INVALID_ASSIGN[] = "Assegnazione '%s=e' non valida"; const char MSG_MEMORY[] = "Errore di allocazione [%i byte]"; const char MSG_NAME_EXPECTED[] = "Atteso un nome invece di '%s'"; const char MSG_NAME_TOO_LONG[] = "Nome troppo lungo"; const char MSG_OPEN_EXPECTED[] = "Atteso '[' invece di '%s'"; const char MSG_STRING_EXPECTED[] = "Attesa una stringa invece di '%s'"; const char MSG_STRING_TOO_LONG[] = "Stringa troppo lunga"; const char MSG_USAGE[] = "Uso:\t crea-pagina file1.des ... filen.des\n"; const char MSG_WARNING[] = "ATTENZIONE: "; const char MSG_WHERE[] = " nel file '%s' alla riga %i.\n"; /*** TIPI ***/ typedef char BUFFER[BUFSIZ]; typedef char NAME[NAMESIZ]; typedef char STRING[STRSIZ]; typedef enum TOKEN { TOK_NAME, TOK_STRING, TOK_BUFFER, TOK_COMMA = ',', TOK_OPEN = '[', TOK_CLOSE = ']', TOK_EQ = '=', TOK_AT = '@', TOK_OR = '|', TOK_GT = '>', TOK_EXCL = '!' } TOKEN; typedef struct MENU_LIST { NAME name; struct MENU *menu; struct MENU_LIST *next; } MENU_LIST; typedef struct MENU { NAME name, brief_name, brief_desc, target; BUFFER link, desc; struct MENU *son, *next; } MENU; /*** VARIABILI GLOBALI ***/ struct { BUFFER alt, icon, lang, title; STRING desc, keywords; MENU *menu; } Document; FILE *File; /* file ".des" attualmente aperto */ FILE *FileMenu; /* file ".js" sul quale scrivere il codice per i menu */ BUFFER HtmlName; /* nome del file html sul quale si sta scrivendo */ BUFFER FileName; /* nome di File */ STRING LastString; /* ultimo token scandito (nome, buffer o stringa) */ int Line; /* numero di linea corrente in File */ char NextDelimiter; /* prossimo separatore da scrivere sul file FileMenu */ MENU_LIST *Summary; /*** PROTOTIPI DELLE FUNZIONI ***/ char *convert_link( char *, char * ); char *convert_url( char *, char * ); void dump_html( void ); void dump_menu( void ); void dump_tigra_menu( MENU * ); void erase_doc( void ); void error( const char *, char * ); TOKEN get_token( void ); void insert_file( FILE *, char * ); int main( int, char ** ); void* new( size_t ); FILE *open( char *, char * ); void parse_description( void ); MENU *parse_menu( void ); TOKEN parse_token( TOKEN ); void warning( const char *, char * ); /*** IMPLEMENTAZIONE DELLE FUNZIONI (IN ORDINE ALFABETICO) */ #define CORRECT(c) ( isalnum(c) || (c)=='.' || (c)=='-' || (c)=='_' ) /* converts its first argument to a well formed link to be used in a "name" attribute e.g. , and dumps the result on its secund argument, which must be already allocated. It just avoid all non alphanumerical characters*/ char *convert_link( char *source, char *target ) { register char c, *p, *q; q = target; p = source; c = *p; while ( c != '\0' ) { if ( CORRECT(c) ) *q++ = c; else *q++ = '-'; c = *++p; } *q = '\0'; return target; } #undef CORRECT /* converts its first argument to a well formed url, and dumps the result on its secund argument, which must be already allocated */ char *convert_url( char *source, char *target ) { register char c, hi, lo, *p, *q; q = target; p = source; c = *p; while ( c != '\0' ) { if ( c >= 0x21 && c <= 0x7E ) *q++ = c; else { hi = c / 16; lo = c - hi * 16; *q++ = '%'; *q++ = '0' + ( hi < 10 ? hi : 'A'-10 + hi); *q++ = '0' + ( lo < 10 ? lo : 'A'-10 + lo ); } c = *++p; } *q = '\0'; return target; } /* dump_html() - produce un file ".html" che segue la descrizione della struttura Document: il nome del file da produrre sta in HtmlName */ void dump_html( void ) { FILE *f; time_t now; MENU *s, *ss; STRING url; f = open(HtmlName, "w"); if ( strcmp(Document.lang, "it") && strcmp(Document.lang, "IT") && strcmp(Document.lang, "It") ) { fprintf(f, HTML_HEAD_EN, Document.title, Document.keywords); fputs(HTML_NOSCRIPT_EN, f); } else { fprintf(f, HTML_HEAD, Document.title, Document.keywords); fputs(HTML_NOSCRIPT, f); } if ( Document.desc[0] != '\0' ) fprintf(f, HTML_BEGIN, Document.icon, Document.alt, Document.desc); else fprintf(f, HTML_BEGIN_MOTTO, Document.icon, Document.alt); /* scrive il sommario del documento */ for ( s = Document.menu; s != NULL; s = s->next ) { /* distingue fra un link interno a un documento ed uno esterno: gli ultimi hanno il nome che inizia per '@'; un link il cui nome inizia per '!' non viene compilato */ if ( s->link[0] == TOK_AT ) { /* distingue fra un link con target ed uno senza */ if ( s->target[0] == '\0' ) fprintf(f, HTML_TOC_AT, convert_url(s->link+1, url), s->name, s->desc); else fprintf(f, HTML_TOC_AT_TARGET, convert_url(s->link+1, url), s->target, s->name, s->desc); } else /* link interno */ /* distingue fra un link con target ed uno senza */ if ( s->link[0] != TOK_EXCL ) { if ( s->target[0] == '\0' ) fprintf(f, HTML_TOC, convert_link(s->name, url), s->name, s->desc); else fprintf(f, HTML_TOC_TARGET, convert_link(s->name, url), s->target, s->name, s->desc); } else continue; /* sotto sommario (NB: ci si spinge fino ad un solo livello) */ for ( ss = s->son; ss != NULL; ss = ss->next ) if ( ss->link[0] == TOK_AT ) { if ( ss->target[0] == '\0' ) fprintf(f, HTML_SUBTOC_AT, convert_url(ss->link+1, url), ss->name, ss->desc); else fprintf(f, HTML_SUBTOC_AT_TARGET, convert_url(ss->link+1, url), ss->target, ss->name, ss->desc); } else if ( ss->link[0] != TOK_EXCL ) { if ( ss->target[0] == '\0' ) fprintf(f, HTML_SUBTOC, convert_link(ss->name, url), ss->name, ss->desc); else fprintf(f, HTML_SUBTOC_TARGET, convert_link(ss->name, url), ss->target, ss->name, ss->desc); } fputs(HTML_TOC_END, f); } fprintf(f, HTML_VALIDATION, HtmlName); /* Ora scandisce il sommario e scrive le pagine */ for ( s = Document.menu; s != NULL; s = s->next ) if ( s->link[0] != '\0' && s->link[0] != TOK_AT ) { if ( s->link[0] == TOK_EXCL ) { insert_file(f, s->link+1); } else { fprintf(f, HTML_PAGE, /*s->name,*/ convert_link(s->name, url), s->name); insert_file(f, s->link); /* sottosommario (NB: ci si spinge fino ad un solo livello) */ for ( ss = s->son; ss != NULL; ss = ss->next ) if ( ss->link[0] != TOK_AT ) { fprintf(f, HTML_SUBPAGE, /*ss->name,*/ convert_link(ss->name, url)); insert_file(f, ss->link); } } } now = time(NULL); fprintf(f, HTML_END, PROGNAME, ctime(&now)); fclose(f); } /* dump_menu() - stampa sul file .js FileMenu una lista che descrive il menu della pagina, in accordo con il formato usato dal pacchetto Tigra Menu */ void dump_menu( void ) { fprintf(FileMenu, "%c\n", NextDelimiter); fprintf(FileMenu, JS_HEAD, Document.title, Document.title, HtmlName, Document.title); dump_tigra_menu(Document.menu); fputs(" ]", FileMenu); NextDelimiter = ','; } /* dump_tigra_menu(MENU*) - produce da una voce di sommario una lista JavaScript di un corrispondente menu item secondo il formato del pacchetto Tigra Menu e la scrive nel file FileMenu */ void dump_tigra_menu( MENU *m ) { enum { INDENT = 4 }; static int tab = INDENT; /* indentazione */ STRING url; fputc('\n', FileMenu); if ( m != NULL ) { for ( ;; ) { register int i; for ( i=0; ilink[0] == TOK_EXCL ) { m = m->next; if ( m == NULL ) { fputs("\n", FileMenu); return; } } else { if ( m->link[0] == TOK_AT ) fprintf(FileMenu, JS_MENU_ITEM_AT, m->brief_name, convert_url(m->link+1, url), m->target, m->brief_desc); else fprintf(FileMenu, JS_MENU_ITEM, m->brief_name, HtmlName, convert_link(m->name, url), m->target, m->brief_desc); if ( m->son == NULL ) fputs("null ]", FileMenu); else { tab += INDENT; dump_tigra_menu(m->son); tab -= INDENT; for ( i=0; inext; if ( m == NULL ) { fputs("\n", FileMenu); return; } fputs(",\n", FileMenu); } } } } #if !defined(NDEBUG) /* dump_summary(MENU*) - usata per il debug: mostra il contenuto di un sommario */ void dump_summary( MENU *s ) { enum { INDENT = 4 }; static int tab = INDENT; /* indentazione */ int i; puts("["); while ( s != NULL ) { for (i=0; i \"%s\", \"%s\" | \"%s\", \"%s\" | \"%s\"", s->link, s->target, s->name, s->brief_name, s->desc, s->brief_desc); if ( s->son != NULL ) { fputs(", ", stdout); tab += INDENT; dump_summary(s->son); tab -= INDENT; } s = s->next; if ( s != NULL ) fputs(" ],\n", stdout); } fputs(" ]\n]", stdout); } /* dump_document() - usata per il debug: mostra il contenuto di Document */ void dump_document( void ) { printf("Document = {\nTitle = \"%s\"\nKeywords = \"%s\"\nIcon = \"%s\"", Document.title, Document.keywords, Document.icon); printf("\nAlt = \"%s\"\nDesc = \"%s\"\nSummary = ", Document.title, Document.keywords); dump_summary(Document.menu); puts("\n}"); } #endif /* erase_doc() - azzera il documento corrente */ void erase_doc( void ) { *Document.alt = '\0'; *Document.desc = '\0'; *Document.icon = '\0'; *Document.keywords = '\0'; *Document.title = '\0'; Document.menu = NULL; } /* error(char*, char*) - stampa un errore ed esce con disonore */ void error( const char* s1, char* s2 ) { printf(MSG_ERROR); printf(s1, s2); printf(MSG_WHERE, FileName, Line); exit(ERROR); } /* get_token() - scandisce un token dal File: un token pu essere un identificatore (sequenza di lettere e/o cifre), una stringa (racchiusa fra doppi apici) o un separatore ('=', '[', ']' oppure ','); se il file finisce durante la scansione, viene ritornato EOF come valore */ TOKEN get_token( void ) { for (;;) { register int c = fgetc(File); if ( c == '\n' ) { ++ Line; continue; } if ( isspace(c) ) continue; LastString[0] = c; LastString[1] = '\0'; if ( isalnum(c) ) { /* identificatore: un NAME */ register int i = 1; for (;;) { c = fgetc(File); if ( !isalnum(c) ) break; /* fine identificatore */ if ( i < NAMESIZ ) LastString[i] = c; else if ( i == NAMESIZ ) warning(MSG_NAME_TOO_LONG, ""); ++ i; } LastString[ ( i < NAMESIZ ) ? i : NAMESIZ-1 ] = '\0'; ungetc(c, File); return TOK_NAME; } if ( c == '/' ) { /* possibile commento */ c = fgetc(File); if ( c == '/' ) { /* fino a fine linea */ do c = fgetc(File); while ( c != '\n' && c != EOF ); ++ Line; continue; /* ciclo for(;;) esterno */ } if ( c == '*' ) { /* commento multilinea */ c = fgetc(File); do { /* ignora tutto fino al prossimo * / */ while ( c != '*' ) { c = fgetc(File); if ( c == EOF ) { warning(MSG_EOF_INSIDE_COMMENT, ""); return EOF; } if ( c == '\n' ) ++ Line; } c = fgetc(File); } while ( c != '/' ); continue; /* ciclo for(;;) esterno */ } return '/'; } if ( c == '"' ) { /* stringa senza apici */ register int i = 0; for (;;) { /* ne registra i primi STRSIZ caratteri */ c = fgetc(File); if ( c == EOF ) { warning(MSG_EOF_INSIDE_STR, ""); return EOF; } if ( c == '\n' ) ++ Line; if ( c == '"') break; /* fine stringa */ if ( c == '\\' ) c = fgetc(File); /* escape */ if ( i < STRSIZ ) LastString[i] = c; else if ( i == STRSIZ ) warning(MSG_STRING_TOO_LONG, ""); ++ i; } if ( i >= STRSIZ ) i = STRSIZ-1; LastString[i] = '\0'; /* a seconda della lunghezza classifica il tipo di stringa */ if ( i < NAMESIZ ) return TOK_NAME; if ( i < BUFSIZ ) return TOK_BUFFER; return TOK_STRING; } return c; } } /* insert_file(FILE*,char*) - inserisce nel file un altro file il cui nome dato dal secondo parametro stringa */ void insert_file( FILE *f, char* ins ) { FILE *ins_file; STRING buffer; if ( ins != NULL && *ins != '\0' ) { ins_file = fopen(ins, "r"); if ( ins_file == NULL ) { warning(MSG_CANT_OPEN, ins); } else { fprintf(f, "\n\n", ins); while ( fgets(buffer, sizeof(buffer)-1, ins_file) != NULL ) fputs(buffer, f); fclose(ins_file); } } } /* Funzione principale */ int main( int n_args, char** args ) { int i; time_t now; if ( n_args == 1 ) { puts(MSG_USAGE); return ERROR; } /* apre il file .js del menu: vi scrive ogni volta che incontra un "dump" nel file ".des" */ FileMenu = open(FILE_MENU_NAME, "w"); NextDelimiter = '['; /* il '[' in "var MENU_ITEM = [" nel FileMenu */ now = time(NULL); fprintf(FileMenu, JS_BEGIN, ctime(&now), PROGNAME); Summary = NULL; for ( i=1; ilink[0] = TOK_EXCL; strcpy(menu->link+1, LastString); } else { if ( t == TOK_CLOSE ) { free(menu); return NULL; } if ( t != TOK_OPEN ) error(MSG_OPEN_EXPECTED, LastString); /* ora mi aspetto la seguente sintassi, dove s e t sono stringhe e t opzionale col carattere che la precede: @ s > t , s | t , s | t */ /* LINK */ t = get_token(); /* mi aspetto '@', una stringa oppure ']' */ if ( t == TOK_AT ) { /* metto un '@' all'inizio della stringa */ parse_token(TOK_BUFFER); menu->link[0] = TOK_AT; strcpy(menu->link+1, LastString); } else { if ( t == TOK_CLOSE ) { free(result); return NULL; } if ( t != TOK_BUFFER && t != TOK_NAME ) error(MSG_BUFFER_EXPECTED, LastString); strcpy(menu->link, LastString); } /* TARGET (OPZIONALE) */ t = get_token(); /* mi aspetto '>' stringa oppure ',' */ if ( t == TOK_GT ) { parse_token(TOK_NAME); strcpy(menu->target, LastString); parse_token(TOK_COMMA); } else { if ( t != TOK_COMMA ) error(MSG_COMMA_EXPECTED, LastString); menu->target[0] = '\0'; } /* NOME DEL LINK */ parse_token(TOK_BUFFER); strcpy(menu->name, LastString); /* NOME ABBREVIATO DEL LINK (OPZIONALE) */ t = get_token(); /* mi aspetto stringa oppure stringa|stringa */ if ( t == TOK_OR ) { parse_token(TOK_NAME); strcpy(menu->brief_name, LastString); parse_token(TOK_COMMA); } else { if ( t != TOK_COMMA ) error(MSG_COMMA_EXPECTED, LastString); strncpy(menu->brief_name, menu->name, NAMESIZ); } /* DESCRIZIONE DEL LINK */ parse_token(TOK_BUFFER); strcpy(menu->desc, LastString); /* DESCRIZIONE ABBREVIATA DEL LINK (OPZIONALE) */ t = get_token(); /* mi aspetto stringa oppure stringa|stringa */ if ( t == TOK_OR ) { parse_token(TOK_NAME); strcpy(menu->brief_desc, LastString); t = get_token(); /* ',' oppure ']' */ } else strncpy(menu->brief_desc, menu->desc, NAMESIZ); /* ora ci pu essere ',' oppure ']' */ if ( t == TOK_COMMA ) { /* sottosommario */ parse_token(TOK_OPEN); menu->son = parse_menu(); t = get_token(); } else menu->son = NULL; if ( t != TOK_CLOSE ) error(MSG_CLOSE_EXPECTED, LastString); } /* ora l'elemento del sommario chiuso: ci pu essere quindi la chiusura del sommario stesso ']' o la sua prosecuzione ',' */ t = get_token(); if ( t == TOK_CLOSE ) { menu->next = NULL; return result; } if ( t != TOK_COMMA ) error(MSG_COMMA_EXPECTED, LastString); /* aggiunge il prossimo elemento da scrivere */ menu->next = new(sizeof(struct MENU)); menu = menu->next; } } /* parse_token(TOKEN) - scandisce un token e d un errore se il token realmente scandito non quello atteso. NB: se incontra la fine del file non d un errore ma torna EOF */ TOKEN parse_token( TOKEN expected ) { STRING err_msg; register TOKEN t = get_token(); if ( t == expected || t == EOF ) return t; /* un buffer pu essere un nome */ if ( expected == TOK_BUFFER ) { if ( t == TOK_NAME ) return TOK_BUFFER; error(MSG_BUFFER_EXPECTED, LastString); } /* una stringa pu essere un nome o un buffer */ if ( expected == TOK_STRING ) { if ( t == TOK_NAME || t == TOK_BUFFER ) return TOK_STRING; error(MSG_STRING_EXPECTED, LastString); } if ( expected == TOK_NAME ) error(MSG_NAME_EXPECTED, LastString); strcpy(err_msg, MSG_EXPECTED); *( strchr(err_msg,'\'') + 1 ) = expected; error(err_msg, LastString); } /* warning(char*, char*) - stampa un errore */ void warning( const char* s1, char* s2 ) { printf(MSG_WARNING); printf(s1, s2); printf(MSG_WHERE, FileName, Line); }