/* 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); }