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 40c9fadd4c20f23f608497e443a65a2972107868..3c30111cebf747b7316715bdcc672a4e373b441c 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 
     \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}
 
   \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
 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
 
 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
 (\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
 
 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.
 
 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
 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}}
 
 
 \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}.
 
 (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
 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
 
 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},
 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
 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
 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[])
 
 \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;
 {
     FILE *pipe[4];
     FILE *pipein;
@@ -425,42 +428,41 @@ int main(int argc, char *argv[], char *envp[])
     }
     exit(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");
 }
 void WriteMess(char *mess)
 {
     printf("Content-type: text/html\n\n");
     perror(mess);
     printf("<br>\n");
 }
-}
-
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
     \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}
 
 \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
 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}}
 
 
 \subsection{Le \textit{pipe} con nome, o \textit{fifo}}
index 4164acf1b2392782a0d74808fefb5ea1d310057f..6525889b1932eb92e1721a8f267c5f922e24dd17 100644 (file)
@@ -29,7 +29,7 @@
  * http://localhost/cgi-bin/barcode?string
  * where string is the code to be converted
  *
  * 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"
 #include <time.h>
 
 #include"macros.h"
-void WriteMess(char *mess);
-
 
 /* Program begin */
 int main(int argc, char *argv[], char *envp[])
 
 /* 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]));
     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);
 }
     /* 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");
+}