Sistemai gli esempi delle pipe con i CGI, riscritto il testo
authorSimone Piccardi <piccardi@gnulinux.it>
Sun, 30 Jun 2002 13:26:17 +0000 (13:26 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Sun, 30 Jun 2002 13:26:17 +0000 (13:26 +0000)
ipc.tex
sources/BarCode.c
sources/BarCodePage.c [new file with mode: 0644]

diff --git a/ipc.tex b/ipc.tex
index 40c9fad..3c30111 100644 (file)
--- 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("<br>\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}}
index 4164acf..6525889 100644 (file)
@@ -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 <time.h>
 
 #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("<br>\n");
-}
diff --git a/sources/BarCodePage.c b/sources/BarCodePage.c
new file mode 100644 (file)
index 0000000..ef48ce7
--- /dev/null
@@ -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 <sys/types.h>   /* predefined types */
+#include <sys/stat.h>    /* stat deinitiions */
+#include <unistd.h>      /* include unix standard library */
+/* */
+#include <stdio.h>      /* include standard I/O library */
+#include <stdlib.h>     /* include standard library */
+#include <string.h>     /* include string library */
+#include <wait.h>       /* include wait call */
+#include <fcntl.h>
+#include <assert.h>
+#include <time.h>
+
+#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("<br>\n");
+}