/******************************************************************/ /**** Scritto Da F.Sacco *****************************/ /**** Ultima mod. 17 Gennaio 2017 */ /**** File: CGI.H *****************************/ /*** Tratto da cgi_sql.c (routine di base X cgi) */ /*** in piu' mask() per maschere di ritorno (caratteri '$' */ /******************************************************************/ /** Gen 2017 --> aggiunto upload() per caricare immagini .jpg **/ /** Feb 2014: corretto riconoscimento caratteri esa (es. '/', ',',':' **/ /** funzionalitą nuova in debug() --> vedo vcgi[] posizioni */ /** Implementato request(nomecampo) --> ritorna il contenuto o NULL se non c'e' /** Il modulo" cgi.h", puo' essere utile per interpretare la QUERY_STRING in ricezione da un applicativo C CGI. Il metodo sopportato, e' sia il GET che il POST. I campi NON sopportati sono i TEXTAREA. Viene fatta la sostituzione del solo carattere particolare '+' in ' ' (spazio). Il parsing della query string viene fatto alla chiamata della funzione "cgi()". La funzione "cgi()" prende l'input dalla stringa d'ambiente QUERY_STRING (percio' e' possibile anche simularne il lancio impostando con il comando dos/unix "set QUERY_STRING=.......") e ne spezza il contenuto in un vettore di strutture cgi(); la struttura cgi contiene due campi: "nome" che conterra' il nome del campo FORM assegnato dal modulo HTML. "contenuto" che sara' cio' che l'utente ha scritto nel campo "nome" Una volta chiamata la funzione cgi(), e' possibile cercare cio' che e' stato digitato dall'utente nel modulo HTML (modulo FORM) direttamente conoscendo il nome del campo, utilizzando la funzione cerca(). La cerca(), riceve in ingresso il nome del campo e ritorna il contenuto */ /** ATTENZIONE: il programma CGI deve costruire il modulo HTML: possono essere utili le funzioni: 1) testa() : apre il documento HTML, segnalando anche al browser (explorer o netscape) il tipo di documento di ritorno (content type). Il documento e' generato dinamicamente dall'applicativo CGI, dopo aver chiamato la funzione cgi(). 2) piede() : chiude il documento HTML generato dinamicamente 3) fatalerror(): interrompe l'esecuzione del programma CGI e segnala l'errore direttamente al BROWSER. Utile per condizioni anomale o debug... 4) debug(): Fatta il 26-02-2004, per stampare il vettore vcgi[] in forma di tabella ***********/ #include #include #include #include #include #include #include #include #define MAX 128 /* massimo numero campi nel modulo */ #define LMAX 32000 /* massima lunghezza di un nome variabile o di un suo contenuto */ #define ARRAY char* /// (per cscanf: CgiScanf() : 2017 ) struct cgi { char *nome; /* nome variabile */ char *contenuto; /* contenuto */ } vcgi[MAX]; char buffer[LMAX]; /* buffer di appoggio: LMAX */ char campo[LMAX/2]; /* Max lunghezza di un contenuto di campo */ int numerocampi = 0; /* numero campi modulo cgi */ // Nuova 2017 !!! char *request(char nomecampo[]) // come $_REQUEST di PHP { int i; static char *b=buffer; for (i=0; i < numerocampi; i++) if (strcmp(vcgi[i].nome,nomecampo)==0) { strcpy(buffer,vcgi[i].contenuto); return buffer; } return NULL; } void testa(void) /* testa per ogni HTML generato dinamicamente */ { printf("Content-type: text/html\n\n"); /* Senza questa, il browser non interpreta l'HTML di ritorno!!!*/ printf("\n"); /* Parte da qui l'HTML di ritorno.. dinamico!! */ printf("\n"); } void piede() /* CHIUDE il documento HTML .. dinamico */ { printf(""); printf(""); } void fatalerror(char *msgerr) /* errore che implica la terminzione */ /* Interfaccia standard in HTML */ { testa(); printf("


Errore [%s]

",msgerr); piede(); exit(1) ; /* Il cgi termina qui...*/ } // Nov 2002: traduzione in una stringa della codifica '+' in spazio // e %hh in valore carattere (es %25 -> '%', %3d -> '=', etc... // Febbraio 2014 :: modificata con sscanf: static int valore(char s[]) // Ricevuto %hh ritorna valore decimale { int v; char appoggio[10]; strncpy(appoggio,s+1,2); appoggio[2]='\0'; sscanf(appoggio,"%x",&v); // printf("
stringa=[%s] valore=[%d] carattere=[%c]\n",appoggio,v,v); return v; } char *decod(char cod[]) // riceve la stringa CODificata { // e la DECodifica, ritornandola // in se stessa, visto che la // dimensione della stringa decodificata // dovrebbe essere minore dell'originale char *l, *s; // (l)eggo, (s)crivo l = s = cod; while(*l) { switch (*l) { case '+': // spazio NON dovrebbe esserci... *s = ' '; break; case '&': // NON dovrebbe esserci *s = '\n'; /// ????? break; case '%': *s = valore(l); if ( s[1] && s[2]) // c'e' ancora qualcosa... l+=2; // salto 2 caratteri, dopo il % break; default: *s = *l; } ++s; ++l; // prox carattere... } *s = '\0'; // chiudo la stringa ... se serve return(cod); } /* la getword NON fa controlli sulla lunghezza stringhe... in certi ambiti la sicurezza potrebbe essere NON sufficiente... La funzione spezza in parole la stringa QUERY_STRING ritornando il puntatore al punto in cui si era interrotta nel penultimo richiamo. Inoltre vengono trasformati i '+' in spazi ' '*/ char *getword(char *s, char *w) /* restituisce in w la prossima parola presa da *s */ /* (fino al carattere '&', '=' o a '\0') */ /* trasforma i '+' in spazi in w */ { for (; *s && *s != '&' && *s != '='; s++) *w++ = (*s == '+') ? ' ': *s; *w = '\0'; if (*s != '\0') ++s; return s; } void *duplica(char *s) /* duplica con malloc() una stringa *s */ /* e ritorna il puntatore alla copia */ { void *p = malloc(strlen(s)+1); if (p) { strcpy((char *)p,s); } else fatalerror("Malloc: fine memoria"); return p; } void cgi(void) /* interpretazione query_string con getword() */ { int i; char *query; /* punatore alla query_strimg */ char *method; /* puntatore alls request_method */ char *env; /* puntatore di appoggio... */ int ldati; /* numero byte in input (caratteri ricevuti) */ method = getenv("REQUEST_METHOD"); if ( method == NULL) fatalerror("Non trovo var. REQUEST_METHOD"); if (strcmp(method,"GET") == 0) { query = getenv("QUERY_STRING"); if ( query == NULL) fatalerror("Non trovo var. QUERY_STRING\n"); strcpy(buffer,query); /* La metto nel buffer */ ldati = strlen(query); } else if (strcmp(method,"POST") == 0) { // attenzione, sotto windows 98, c'e' un limite piu' stretto // con UNA SOLA READ... ; in UNIX e' OK!! // (per migliorare, se e' il caso usare CONTENT_LENGHT // e piu' di una write()! ldati = read(0,buffer,LMAX); /* pesco dall'input standard */ /* e metto nel buffer */ } env = buffer; // Buffer OK sia per GET che per POST !! // FUNZIONA CON env == buffer la getword ??? BOH!!!! // eventualmente dichiarare un secondo buffer... for (i = 0; i < MAX && *env; i++) { env = getword(env,campo); /* pesco nome */ vcgi[i].nome = (char *)duplica(campo); env = getword(env,campo); /* pesco contenuto */ vcgi[i].contenuto = (char *) duplica(decod(campo)); } if (i == MAX) fatalerror("Troppi campi nel modulo!"); numerocampi = i; /* numero campi del modulo */ } char *cerca(char *nomevariabile) /* dato il nome della variabile */ /* mi ritorna il suo contenuto */ { int i; char *errore = "VARIABILE NON TROVATA!"; for (i =0; i < numerocampi; i++) if (strcmp(nomevariabile,vcgi[i].nome) == 0) return(vcgi[i].contenuto); return (errore); } void debug(void) { int i; printf("\n"); printf("\n"); printf("\n"); for (i=0; i < numerocampi; i++) { printf("\n", vcgi[i].nome, request(vcgi[i].nome),i,vcgi[i].nome,vcgi[i].contenuto); } printf("
Funzione debug()
request()Vettore CGINome CampoContenuto
request(\"%s\")==%svcgi[%d]%s%s
\n"); } /* Ultima modifica 27-04-2002 ********/ /* Programma CGI-MASK.C - per sostituire maschere */ /* Uso: richiamare mask("nomefile.html"), dopo aver lanciato cgi() **********/ /* Il seguente modulo C serve per organizzare le risposte dell'applicativo */ /* CGI, in modo da semplificare l'output in HTML; la funzione mask() e' */ /* LA FUNZIONE principale, E VA USATA con il nome del file (html) che si */ /* intende usare come maschera fissa HTML di risposta dati. */ /* la funzione mask() accetta anche in ingresso un vettore di strutture */ /* di tipo "struct cgi" ed il numero di campi contenuti. */ /* Per quanto riguarda il tipo "struct cgi" si veda il file cgi-sql.c; */ /* in pratica la struttura cgi, viene utilizzata da mask() per sostituire*/ /* i campi dinamici (marcati dal carattere "$" (dollaro)) che devono essere*/ /* presenti sia nel file html (il cui nome costituisce il primo parametro */ /* in ingresso per la mask() ) che nel vettore di strutture cgi ( passato */ /* sempre alla mask() come secondo parametro in ingresso); */ /* nel vettore di strutture cgi, i campi "nome" NON debbono invece */ /* cominciare con il carattere speciale "$" (dollaro) */ #define SMAX 512 /* lunghezza massima stringhe locali */ /* funzioni di base */ /* rimpiazza nella stringa stringa[], la parola vecchia oldword[] con la parola nuova newword[]. NON usa caratteri speciali '$' */ void replace(char stringa[], char oldword[], char newword[]) { char buffer[SMAX]; int car; char *o; o = strstr(stringa,oldword); if ( o == NULL) return; /* NON POSSO FARE replace */ car = (int) (o - stringa); strncpy(buffer,stringa,car); /* copio la prima parte */ sprintf(buffer+car,"%s",newword); strcat(buffer,o+strlen(oldword)); strcpy(stringa,buffer); } int loadfile(char file[], char *vs[], int max) /* carica un file in un vettore di max-1 puntatori. Attenzione alla */ /* lunghezza stringa che nel file NON deve superare SMAX */ /* Viene allocata la memoria per ogni stringa caricata */ /* vs[] = vettore di stringhe; carico un file in vs[], allocando memoria */ /* Metto ultimo pointer a NULL e ritorno anche numero linee lette ...*/ /* viene usata dalla mask() per caricare in memoria il file HTML */ { FILE *fd; char buffer[SMAX]; int i; fd = fopen(file,"r"); if (fd == NULL) fatalerror("Errore loadfile() apertura file ..."); for ( i = 0; i < max-1 && (fgets(buffer,SMAX-1,fd)!=NULL); i++) { vs [i] = (char *) malloc(strlen(buffer)+1); if (vs[i] == NULL) fatalerror("Da loadfile, funz. malloc()"); strcpy(vs[i],buffer); } fclose(fd); vs[i] = NULL; return (i); } int sostituisci(char *vs[], char oldword[], char newword[]) { /* scandisce un file di testo e per ogni occorrenza di parole oldword[], viene sostituita la parola oldword[] con newword[]. Se strlen(newword) > strlen(oldword) viene riallocata la memoria ... per contenerla...!!; ATTENZIONE: Occorre che il puntatore in fondo a vs[] sia NULL per segnalare la dimensione (come, ad es. il '\0' nelle stringhe..) del vettore di stringhe vs[]; Ritorna al chiamante il numero di sostituzioni fatte. E' usata direttamente dalla mask() ***/ int i, sostituzioni; char buffer[SMAX]; /* appoggio */ for (i=0, sostituzioni = 0; vs[i]; i++) { strcpy(buffer,vs[i]); /* buffer[] dovrebbe essere abbastanza capiente ...*/ while(strstr(buffer,oldword) != NULL) /* finche ho sostituito almeno una stringa oldword[] */ { replace(buffer,oldword,newword); sostituzioni++; } if (strlen(buffer) > strlen(vs[i])) { /* occore fare spazio....*/ free(vs[i]); vs[i] = (char *)malloc(strlen(buffer)+1); if (vs[i] == NULL) fatalerror("da sostituisci(), malloc()"); } strcpy(vs[i],buffer); } return sostituzioni; } void stampavs(char *vs[]) /* stampa un vettore di stringhe sull'output */ /* viene usata dalla mask(), una volta sostituiti i campi dinamici con '$'*/ /* l'output viene rediretto dal server web (apache..) direttamente al */ /* browser (client) */ { int i=0; while(vs[i]) printf("%s",vs[i++]); } /* libero memoria */ void freevs(char *vs[]) /* una volta caricato il file da mask() in un vettore di pointer a stringa */ /* e, dopo essere stato stampato con stampavs(), viene liberata la memoria */ /* allocata da loadfile con malloc() */ { int i; for (i = 0; vs[i]; i++) { free(vs[i]); vs[i] = NULL; } } static char *dollaro(char str[]) /* ritorna una stringa con un dollaro in testa */ /* in questo modo NON e' necessario immettere forzamente un '$' nei campi*/ /* di tipo "nome", nel vettore di struct cgi passato alla mask()*/ /* Attenzione alla lunghezza SMAX delle stringhe ...*/ /* Il vettore e' STATICO INTERNO, cioe' privato .. ma SEMPRE definito */ { static char buffer[SMAX]; strcpy(buffer,"$"); strcat(buffer,str); return buffer; } /*** mask() ==> funzione principale. Vedi la documentazione a linea 1 */ void mask(char file[], struct cgi vcgi[], int numerocampi) /* FUNZIONE PRINCIPALE */ { char *vs[SMAX]; int i; loadfile(file,vs,SMAX); for (i = 0; i < numerocampi; i++) sostituisci(vs,dollaro(vcgi[i].nome),vcgi[i].contenuto); stampavs(vs); freevs(vs); } /** Upload() : tratto da: David Cutting http://www.purplepixie.org/dave/ http://blog.purplepixie.org/ dcutting [at] purplepixie [dot] org Code Copyright DMC 22/05/2011 Modificato da F. Sacco 17 Gennaio 2017 **/ /*** esempio va_list double average(int num,...) { va_list valist; double sum = 0.0; int i; /* initialize valist for num number of arguments * va_start(valist, num); /* access all the arguments assigned to valist * for (i = 0; i < num; i++) { sum += va_arg(valist, int); } /* clean memory reserved for valist * va_end(valist); return sum/num; } Esempio stringhe ShowMsg(style1, "w", "w", "q", NULL); Yielded result: "asdwwq" This behaviour is strange because each time this function is called joinedString is initialized. Does va_list holds values previously used? I'm using C, not C++ and I know, using std::string will be far more easy. int ShowMsg(MSGBOXSTYLE msgStyle, char* str, ...) { char* title = "", *joinedString = "", *theArg = ""; wchar_t* convertedTitle = "", *convertedString = ""; va_list args; theArg = str; va_start( args, str ); while(theArg != NULL) { if(msgStyle == WARN) { title = theArg; } else { strcat( joinedString, theArg ); strcat( joinedString, "\n\r" ); } theArg = va_arg(args, char*); } va_end(args); ... ***/ char** explode(char* a_str, const char a_delim) /** esplosione stringa come in PHP*/ { char** result = 0; size_t count = 0; char* tmp = a_str; char* last_comma = 0; char delim[2]; delim[0] = a_delim; delim[1] = 0; /* Count how many elements will be extracted. */ while (*tmp) { if (a_delim == *tmp) { count++; last_comma = tmp; } tmp++; } /* Add space for trailing token. */ count += last_comma < (a_str + strlen(a_str) - 1); /* Add space for terminating null string so caller knows where the list of returned strings ends. */ count++; result = malloc(sizeof(char*) * count); if (result) { size_t idx = 0; char* token = strtok(a_str, delim); while (token) { assert(idx < count); *(result + idx++) = strdup(token); token = strtok(0, delim); } assert(idx == count - 1); *(result + idx) = 0; } return result; } /* * cscanf(fmt,va_alist) Implementazione mia x scanf: CgiScanf */ /* * sscanf(buf,fmt,va_alist) */ /** Nuovi parametri: %S = stringa senza spazi */ int cscanf (char *campo, const char *fmt, ...) { ///request(nomecampo) --> ritorna il contenuto o NULL se non c'e' int count; va_list ap; char *contenuto,*p; char messaggio[256]; va_start (ap, fmt); ///count = vsscanf (buf, fmt, ap); contenuto=request(campo); if (fmt == NULL) /// per sicurezza { sprintf(messaggio,"Attenzione: funzione Scanf(): hai dimenticato di specificare il parametro"); fatalerror(messaggio); } if (contenuto==NULL) { sprintf(messaggio,"Attenzione: funzione Scanf(): campo [%s] non trovato",campo); fatalerror(messaggio); } p= (char*)fmt; ///printf("

p=%s

",p); if (p[1]=='S') /// CASO STRINGA: pesco anche gli spazi { ///printf("

Entrato in p[1]=='S'

"); p = va_arg(ap,char*); strcpy(p,request(campo)); } else if (p[1]=='V') /// vettore di pointer { int i=0; ///printf("

Entrato in p[1]=='V'

"); char **p=va_arg(ap,char**); char **q=explode(request(campo),' '); /** for (;q && q[i]; i++) printf("v[%d]=%s
\n",i,q[i]);**/ for(i=0; q && q[i]; i++) p[i]=q[i]; p[i]=NULL; } else count = vsscanf (request(campo), fmt, ap); /// richiamo sscanf originale del C va_end (ap); return (count); } /// 22 Gennaio 2017: OK per immagini jpeg sia windows che linux!!! void upload(void) /// Upload per file .jpg /// Occorre fare la cartella upload sotto www o htdocs { #ifdef _WIN32 # include # include # define SET_BINARY_MODE(handle) setmode(handle, O_BINARY) char *dir="../htdocs/upload/"; /// windows --> ha problemi a funzionare... #else char *dir="../www/upload/"; ///linux # define SET_BINARY_MODE(handle) ((void)0) #endif FILE *out; char *rawdata; // pointer for rawdata char *data; // will be an offset of rawdata after the two newlines unsigned long length; // length of data to be read used for malloc unsigned long writelength; // use for the length of the write char *pos; // used in the loop char buffer[256],nomefile[256]; // printf("Content-type: text/html\n\n
"); // for debug output
// Various bits of debug output are included - comment out for live
// and replace with whatever output you'd like to send to the client


    length=atol(getenv("CONTENT_LENGTH"));
    writelength=length;

    printf("Content Length: %u\n",length);

    rawdata=malloc(length+1); // malloc required buffer

	SET_BINARY_MODE(0);

    fread(rawdata, length, 1, stdin); // read into buffer
    pos=strstr(rawdata,"filename");
    if (pos) /// trovato nome file
    {
        char *p;
        pos+=10; /// mi porto dopo filename="
        for(p=pos; *p && *p!='"'; p++)
            ;
        *p='\0'; /// tolgo l'ultimo doppio apice dal nome file
        strcpy(nomefile,pos);
       ///printf("
da upload(): Filename=[%s]
\n",pos); } else /// non dovrebbe mai succedere, non e' riuscito a pescare il nome del file strcpy(nomefile,"null.jpg"); sprintf(buffer,"%s%s",dir,nomefile); out=fopen(buffer,"wb+"); // open the output file if (out == NULL ) { sprintf(buffer,"Errore: non riesco a creare il file %s%s",dir,nomefile); fatalerror(buffer); } // now comes the loop, there are better ways but not that I can find quickly enough for (pos=rawdata; pos<(rawdata+length-4); pos++) { writelength--; // decrement the write length //printf("%c %d\n",pos[0],pos[0]); // used for debug output (comment out for live) if ( (pos[0]==13) && (pos[1]==10) && (pos[2]==13) && (pos[3]==10) && ( (pos[4]<32)||(pos[4]>127) ) ) // pattern to find two double-newlines { data=pos+4; // move data pointer forward 4 to start of actual data pos=rawdata+length+2; // break loop //printf("Found\n"); // another debug line - comment out for live writelength-=3; // decrement writelength by three (done one already above for this loop) } } //printf("Writelength: %u\n",writelength); // yet another debug // write the data to the file fwrite(data, 1, writelength, out); // close the file fclose(out); free(rawdata); // free memory printf("Upload Complete in file: %s",buffer); // debug - comment out for live }