From f554a11afa7c50c2b0267e890fb7581b6605384d Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 30 Jun 2002 13:26:17 +0000 Subject: [PATCH] Sistemai gli esempi delle pipe con i CGI, riscritto il testo --- ipc.tex | 152 +++++++++++++++++++++--------------------- sources/BarCode.c | 14 +--- sources/BarCodePage.c | 133 ++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+), 87 deletions(-) create mode 100644 sources/BarCodePage.c diff --git a/ipc.tex b/ipc.tex index 40c9fad..3c30111 100644 --- a/ipc.tex +++ b/ipc.tex @@ -217,7 +217,8 @@ int main(int argc, char *argv[], char *envp[]) \end{lstlisting} \end{minipage} \normalsize - \caption{Codice del \textit{CGI} \cmd{BarCodePage}.} + \caption{Sezione principale del codice del \textit{CGI} + \file{BarCodePage.c}.} \label{fig:ipc_barcode_code} \end{figure} @@ -240,10 +241,13 @@ corrispondente, e poi scrive il risultato direttamente sullo standard output. Per poter utilizzare queste caratteristiche prima di eseguire \cmd{barcode} si chiude (\texttt{\small 20}) il capo aperto in scrittura della prima pipe, e se ne collega (\texttt{\small 21}) il capo in lettura allo standard input, usando -\func{dup2}. Dato che \cmd{barcode} scrive l'immagine postscript del codice a -barre sullo standard output, per poter effettuare una ulteriore redirezione il -capo in lettura della seconda pipe viene chiuso (\texttt{\small 22}) mentre il -capo in scrittura viene collegato allo standard output (\texttt{\small 23}). +\func{dup2}. Si ricordi che invocando \func{dup2} il secondo file, qualora +risulti aperto, viene, come nel caso corrente, chiuso prima di effettuare la +duplicazione. Allo stesso modo, dato che \cmd{barcode} scrive l'immagine +postscript del codice a barre sullo standard output, per poter effettuare una +ulteriore redirezione il capo in lettura della seconda pipe viene chiuso +(\texttt{\small 22}) mentre il capo in scrittura viene collegato allo standard +output (\texttt{\small 23}). In questo modo all'esecuzione (\texttt{\small 25}) di \cmd{barcode} (cui si passa in \var{size} la dimensione della pagina per l'immagine) quest'ultimo @@ -254,9 +258,9 @@ Al contempo una volta lanciato il primo figlio, il processo padre prima chiude (\texttt{\small 26}) il capo inutilizzato della prima pipe (quello in input) e poi scrive (\texttt{\small 27}) la stringa da convertire sul capo in output, così che \cmd{barcode} possa riceverla dallo standard input. A questo punto -l'uso della prima pipe è finito ed essa può essere definitivamente chiusa -(\texttt{\small 28}), si attende poi (\texttt{\small 29}) che l'esecuzione di -\cmd{barcode} sia completata. +l'uso della prima pipe da parte del padre è finito ed essa può essere +definitivamente chiusa (\texttt{\small 28}), si attende poi (\texttt{\small + 29}) che l'esecuzione di \cmd{barcode} sia completata. Alla conclusione della sua esecuzione \cmd{barcode} avrà inviato l'immagine postscript del codice a barre sul capo in scrittura della seconda pipe; a @@ -276,15 +280,15 @@ provvedendo gli appositi switch che consentono di leggere il file da convertire dallo standard input e di inviare la conversione sullo standard output. -Per completare le operazioni il processo padre chiude \texttt{\small 44}) il +Per completare le operazioni il processo padre chiude (\texttt{\small 44}) il capo in scrittura della seconda pipe, e attende la conclusione del figlio -\texttt{\small 45}); a questo punto può \texttt{\small 46}). Si tenga conto -che l'operazione di chiudere il capo in scrittura della seconda pipe è -necessaria, infatti se non venisse chiusa \cmd{gs}, che legge il suo stardard -input da detta pipe, resterebbe bloccato in attesa di ulteriori dati in -ingresso (l'unico modo che un programma ha per sapere che l'input è terminato -è rilevare che lo standard input è stato chiuso), e la \func{wait} non -ritornerebbe. +(\texttt{\small 45}); a questo punto può (\texttt{\small 46}) uscire. Si tenga +conto che l'operazione di chiudere il capo in scrittura della seconda pipe è +necessaria, infatti, se non venisse chiusa, \cmd{gs}, che legge il suo +stardard input da detta pipe, resterebbe bloccato in attesa di ulteriori dati +in ingresso (l'unico modo che un programma ha per sapere che l'input è +terminato è rilevare che lo standard input è stato chiuso), e la \func{wait} +non ritornerebbe. \subsection{Le funzioni \func{popen} e \func{pclose}} @@ -339,64 +343,63 @@ attendendo la terminazione del processo ad essa associato. (tramite \func{wait4}) la conclusione del processo creato dalla precedente \func{popen}. -Per illustrare l'uso di queste due funzioni riprenderemo il problema -precedente; il programma mostrato in \figref{fig:ipc_barcode_code} per quanto -funzionante, è (volutamente) codificato in maniera piuttosto complesso; +Per illustrare l'uso di queste due funzioni riprendiamo il problema +precedente: il programma mostrato in \figref{fig:ipc_barcode_code} per quanto +funzionante, è (volutamente) codificato in maniera piuttosto complessa, inoltre nella pratica sconta un problema di \cmd{gs} che non è in grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di -riconoscere correttamente l'encapsulated postscript, per cui tutte le volte -generata una pagina intera, invece che semplice figura delle dimensioni -corrispondenti al codice a barre. - -Se si vuole generare una immagine di dimensioni corrette si deve usare un -approccio diverso; una possibilità sarebbe quella di ricorrere ad ulteriore -programma, \cmd{epstopsf}, per convertire in PDF il file EPS generato da -\cmd{barcode} (utilizzando lo switch \cmd{-E} di quest'ultimo). Utilizzando un -PDF al posto di un EPS \cmd{gs} esegue la conversione rispettando le -dimensioni originarie del codice a barre e produce un JPEG delle dimensioni -adeguate. +riconoscere correttamente l'encapsulated postscript, per cui deve essere usato +il postscript e tutte le volte viene generata una pagina intera, invece che +una immagine delle dimensioni corrispondenti al codice a barre. + +Se si vuole generare una immagine di dimensioni appropriate si deve usare un +approccio diverso. Una possibilità sarebbe quella di ricorrere ad ulteriore +programma, \cmd{epstopsf}, per convertire in PDF un file EPS (che può essere +generato da \cmd{barcode} utilizzando lo switch \cmd{-E}). Utilizzando un PDF +al posto di un EPS \cmd{gs} esegue la conversione rispettando le dimensioni +originarie del codice a barre e produce un JPEG delle dimensioni adeguate. Questo però ci porta a scontrarci con una caratteristica peculiare delle pipe, che a prima vista non è evidente. Per poter effettuare la conversione di un PDF infatti è necessario, per la struttura del formato, dover eseguire delle -\func{lseek} sul file da convertire; una pipe però è rigidamente sequenziale, -ed il tentativo di eseguire detta funzioni su un file descriptor associato ad -una pipe comporta l'immediato fallimento con un errore di \macro{ESPIPE}. - -Per questo motivo si è utilizzata una strada diversa, che prevede la +\func{lseek} sul file da convertire; se si esegue \cmd{gs} su un file normale +non ci sono problemi, ma una pipe però è rigidamente sequenziale, ed il +tentativo di eseguire detta operazione su una pipe comporta l'immediato +fallimento con un errore di \macro{ESPIPE}. Questo ci dice che in generale la +concatenazione di vari programmi funzionerà soltanto quando tutti prevedono +una lettura sequenziale del loro input. + +Per questo motivo si è dovuto utilizzare una strada diversa, che prevede la conversione attraverso \cmd{gs} del PS in un altro formato intermedio, il PPM,\footnote{il \textit{Portable PixMap file format} è un formato usato spesso come formato intermedio per effettuare conversioni, è estremamente inefficiente, ma molto facile da manipolare dato che usa caratteri ASCII per memorizzare le immagini.} dal quale poi si può ottenere un'immagine di dimensioni corrette attraverso vari programmi di manipolazione (\cmd{pnmcrop}, -\cmd{pnmmargin}) che può essere infine trasformata in PNG. +\cmd{pnmmargin}) che può essere infine trasformata in PNG (con \cmd{pnm2png}). -In questo caso però occorre eseguire sequenza ben quattro comandi diversi, +In questo caso però occorre eseguire in sequenza ben quattro comandi diversi, inviando l'output di ciascuno all'input del successivo, per poi ottenere il -risultato finale sullo standard output, il caso più classico dell'uso delle -pipe. - +risultato finale sullo standard output; un caso classico di utilizzazione +delle pipe, in cui l'uso di \func{popen} e \func{pclose} permette di +semplificare notevolmente la stesura del codice. -Dato che questo caso ciascun processo deve scrivere il suo output sullo +Nel nostro caso, dato che ciascun processo deve scrivere il suo output sullo standard input del successivo, occorrerà usare \func{popen} aprendo la pipe in -scrittura. - -Il codice del nuovo programma è riportato in \figref{fig:ipc_barcode2_code}; -come si può notare l'ordine di invocazione dei programmi è l'inverso di quello -in cui ci si aspetta vengano effettivamente eseguiti. Questo non comporta -nessun problema; infatti la lettura su una pipe è bloccante, per cui ciascun -processo, per quanto lanciato per primo, si bloccherà in attesa di ricevere -sullo standard input il risultato dell'elaborazione del precendente, benchè -quest'ultimo venga invocato dopo. +scrittura. Il codice del nuovo programma è riportato in +\figref{fig:ipc_barcode2_code}. Come si può notare l'ordine di invocazione +dei programmi è l'inverso di quello in cui ci si aspetta vengano +effettivamente eseguiti. Questo non comporta nessun problema; infatti la +lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato +per primo, si bloccherà in attesa di ricevere sullo standard input il +risultato dell'elaborazione del precendente, benchè quest'ultimo venga +invocato dopo. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} \begin{lstlisting}{} int main(int argc, char *argv[], char *envp[]) -{ -int main(int argc, char *argv[], char *envp[]) { FILE *pipe[4]; FILE *pipein; @@ -425,42 +428,41 @@ int main(int argc, char *argv[], char *envp[]) } exit(0); } -/* - * Routine to produce an HTML error message on output - */ void WriteMess(char *mess) { printf("Content-type: text/html\n\n"); perror(mess); printf("
\n"); } -} - \end{lstlisting} \end{minipage} \normalsize - \caption{Codice del \textit{cgi-bin} \cmd{BarCode2}.} - \label{fig:ipc_barcode2_code} + \caption{Codice completo del \textit{CGI} \file{BarCode.c}.} + \label{fig:ipc_barcode_code} \end{figure} -Nel nostro caso il primo passo (\texttt{\small 12}) è scrivere il mime-type +Nel nostro caso il primo passo (\texttt{\small 14}) è scrivere il mime-type sullo standard output; a questo punto il processo padre non necessita più di eseguire ulteriori operazioni sullo standard output e può tranquillamente -provvedere alla redirezione. Il primo processo figlio ad essere invocato -(\texttt{\small 14}) è necessariamente l'ultimo della sequenza, in quanto è -lui che deve uscire sullo standard output, gli altri saranno tutti rediretti. - -Una volta lanciato il processo finale si può iniziare la catena delle -redirezioni; ogni volta (\texttt{\small 16} e \texttt{\small 20}) duplicheremo -il file restituito dalla chiamata precedente a \func{popen} sullo standard -output, in questo modo alla successiva chiamata di \func{popen} il processo -eseguito scriverà il suo standard output sulla pipe collegata allo standard -input del precedente. - -Alla fine tutto quello che resta da fare è scrivere (\texttt{\small 22}) la -stringa del codice a barre sulla pipe collegata allo standard input -dell'ultimo processo lanciato, e poi chiudere tutte le pipe create con -\func{pclose}. +provvedere alla redirezione. + +Dato che i vari programmi devono essere lanciati in successione, si è +approntato un ciclo (\texttt{\small 15--19}) che esegue le operazioni in +sequenza: prima crea una pipe (\texttt{\small 17}) per la scrittura eseguendo +il programma con \func{popen}, in modo che essa sia collegata allo standard +input, e poi redirige (\texttt{\small 18}) lo standard output su detta pipe. + +In questo modo il primo processo ad essere invocato (che è l'ultimo della +catena) scriverà ancora sullo standard output del processo padre, ma i +successivi, a causa di questa redirezione, scriveranno sulla pipe associata +allo standard input del processo invocato nel ciclo precedente. + +Alla fine tutto quello che resta da fare è lanciare (\texttt{\small 21}) il +primo processo della catena, che nel caso è \cmd{barcode}, e scrivere +(\texttt{\small 23}) la stringa del codice a barre sulla pipe, che è collegata +al suo standard input, infine si può eseguire (\texttt{\small 24--27}) un +ciclo, che chiuda, nell'ordine inverso rispetto a quello in cui le si sono +create, tutte le pipe create con \func{pclose}. \subsection{Le \textit{pipe} con nome, o \textit{fifo}} diff --git a/sources/BarCode.c b/sources/BarCode.c index 4164acf..6525889 100644 --- a/sources/BarCode.c +++ b/sources/BarCode.c @@ -29,7 +29,7 @@ * http://localhost/cgi-bin/barcode?string * where string is the code to be converted * - * $Id: BarCode.c,v 1.5 2002/06/28 21:07:21 piccardi Exp $ + * $Id: BarCode.c,v 1.6 2002/06/30 13:26:17 piccardi Exp $ * ****************************************************************/ /* @@ -48,8 +48,6 @@ #include #include"macros.h" -void WriteMess(char *mess); - /* Program begin */ int main(int argc, char *argv[], char *envp[]) @@ -78,18 +76,10 @@ int main(int argc, char *argv[], char *envp[]) pipein = popen("barcode", "w"); /* send barcode string to barcode program */ write(fileno(pipein), argv[1], strlen(argv[1])); + pclose(pipein); /* close all pipes (in reverse order) */ for (i=4; i==0; i--) { pclose((pipe[i])); } exit(0); } -/* - * Routine to produce an HTML error message on output - */ -void WriteMess(char *mess) -{ - printf("Content-type: text/html\n\n"); - perror(mess); - printf("
\n"); -} diff --git a/sources/BarCodePage.c b/sources/BarCodePage.c new file mode 100644 index 0000000..ef48ce7 --- /dev/null +++ b/sources/BarCodePage.c @@ -0,0 +1,133 @@ +/* BarCodeOld.c + * + * Copyright (C) 2002 Simone Piccardi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/**************************************************************** + * + * Program barcode + * CGI for barcode generation + * + * Author: Simone Piccardi + * Jun. 2002 + * + * Usage: cgi-bin for apache. + * Called by downloading something like: + * http://localhost/cgi-bin/barcode?string + * where string is the code to be converted + * + * $Id: BarCodePage.c,v 1.1 2002/06/30 13:26:17 piccardi Exp $ + * + ****************************************************************/ +/* + * Include needed headers + */ +#include /* predefined types */ +#include /* stat deinitiions */ +#include /* include unix standard library */ +/* */ +#include /* include standard I/O library */ +#include /* include standard library */ +#include /* include string library */ +#include /* include wait call */ +#include +#include +#include + +#include"macros.h" +void WriteMess(char *mess); + + +/* Program begin */ +int main(int argc, char *argv[], char *envp[]) +{ +/* + * Variables definition + */ + pid_t pid; + int retval; + int pipein[2]; + int pipeout[2]; + char content[]="Content-type: image/jpeg\n\n"; + char size[]="-pA9"; + /* + * Begin + */ + /* create two pipes to handle process communication */ + if ( (retval = pipe(pipein)) ) { + WriteMess("input pipe creation error"); + exit(0); + } + if ( (retval = pipe(pipeout)) ) { + WriteMess("output pipe creation error"); + exit(0); + } + /* fork child to run barcode program */ + pid = fork(); + if (pid == -1) { + WriteMess("child creation error"); + exit(0); + } + /* if child */ + if (pid == 0) { + /* + * Child exec barcode program, that take input (string to encode) + * from pipein, remapped to stdin, and write the output (a PS + * image) to stdout, remapped to pipeout + */ + close(pipein[1]); /* close output side of input pipe */ + dup2(pipein[0], STDIN_FILENO); /* remap stdin in pipe input */ + close(pipeout[0]); + dup2(pipeout[1], STDOUT_FILENO); /* remap stdout in pipe output */ + execlp("barcode", "barcode", size, NULL); //"-o", "-", NULL); + } + /* + * Parent write string to pipe input and close it, + * then wait child execution and results form pipeout, + * then fork to convert PS to JPEG using gs + */ + close(pipein[0]); /* close input side of input pipe */ + write(pipein[1], argv[1], strlen(argv[1])); + close(pipein[1]); + waitpid(pid, NULL, 0); + /* Second fork use child to run ghostscript*/ + pid = fork(); + if (pid == -1) { + WriteMess("child creation error"); + exit(0); + } + /* second child, convert PS to JPEG */ + if (pid == 0) { + close(pipeout[1]); /* close write end */ + dup2(pipeout[0], STDIN_FILENO); /* remap read end to stdin */ + /* send mime type */ + write(STDOUT_FILENO, content, strlen(content)); + execlp("gs", "gs", "-q", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL); + } + /* still parent */ + close(pipeout[1]); + waitpid(pid, NULL, 0); + exit(0); +} +/* + * Routine to produce an HTML error message on output + */ +void WriteMess(char *mess) +{ + printf("Content-type: text/html\n\n"); + perror(mess); + printf("
\n"); +} -- 2.30.2