about summary refs log tree commit diff
path: root/urt/rle_open_f.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-09-27 21:44:29 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2009-09-27 21:44:29 +0000
commit43939e66b1d4eeb2f3799c124f3598756755005a (patch)
tree15733092de55d52421a6ea02f5a43d5f8ff24393 /urt/rle_open_f.c
parent49f4336c9bba33650573ba780b70bc501b38643e (diff)
downloadnetpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.tar.gz
netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.tar.xz
netpbm-mirror-43939e66b1d4eeb2f3799c124f3598756755005a.zip
Rebase Stable series to current Advanced: 10.47.04
git-svn-id: http://svn.code.sf.net/p/netpbm/code/stable@995 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'urt/rle_open_f.c')
-rw-r--r--urt/rle_open_f.c422
1 files changed, 230 insertions, 192 deletions
diff --git a/urt/rle_open_f.c b/urt/rle_open_f.c
index d2575c11..07dbea01 100644
--- a/urt/rle_open_f.c
+++ b/urt/rle_open_f.c
@@ -1,10 +1,10 @@
 /* 
  * rle_open_f.c - Open a file with defaults.
  * 
- * Author : 	Jerry Winters 
- * 		EECS Dept.
- * 		University of Michigan
- * Date:	11/14/89
+ * Author :     Jerry Winters 
+ *      EECS Dept.
+ *      University of Michigan
+ * Date:    11/14/89
  * Copyright (c) 1990, University of Michigan
  */
 
@@ -15,19 +15,24 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#include "pm_c_util.h"
+#include "nstring.h"
+#include "rle.h"
+
+
+
+#define MAX_CHILDREN 100
+    /* Maximum number of children we track; any more than this remain
+       zombies.
+    */
+
+
 #ifndef NO_OPEN_PIPES
-/* Need to have a SIGCLD signal catcher. */
+/* Need to have a SIGCHLD signal catcher. */
 #include <signal.h>
 #include <sys/wait.h>
 #include <errno.h>
 
-#include "rle.h"
-
-/* Count outstanding children.  Assume no more than 100 possible. */
-#define MAX_CHILDREN 100
-static int catching_children = 0;
-static int pids[MAX_CHILDREN];
-
 
 
 static FILE *
@@ -43,55 +48,55 @@ my_popen(const char * const cmd,
     /* Check args. */
     if ( *mode != 'r' && *mode != 'w' )
     {
-	errno = EINVAL;
-	return NULL;
+        errno = EINVAL;
+        return NULL;
     }
 
     if ( pipe(pipefd) < 0 )
-	return NULL;
+        return NULL;
     
     /* Flush known files. */
     fflush(stdout);
     fflush(stderr);
     if ( (thepid = fork()) < 0 )
     {
-	close(pipefd[0]);
-	close(pipefd[1]);
-	return NULL;
+        close(pipefd[0]);
+        close(pipefd[1]);
+        return NULL;
     }
     else if (thepid == 0) {
-	/* In child. */
-	/* Rearrange file descriptors. */
-	if ( *mode == 'r' )
-	{
-	    /* Parent reads from pipe, so reset stdout. */
-	    close(1);
-	    dup2(pipefd[1],1);
-	} else {
-	    /* Parent writing to pipe. */
-	    close(0);
-	    dup2(pipefd[0],0);
-	}
-	/* Close anything above fd 2. (64 is an arbitrary magic number). */
-	for ( i = 3; i < 64; i++ )
-	    close(i);
-
-	/* Finally, invoke the program. */
-	if ( execl("/bin/sh", "sh", "-c", cmd, NULL) < 0 )
-	    exit(127);
-	/* NOTREACHED */
-    }	
+        /* In child. */
+        /* Rearrange file descriptors. */
+        if ( *mode == 'r' )
+        {
+            /* Parent reads from pipe, so reset stdout. */
+            close(1);
+            dup2(pipefd[1],1);
+        } else {
+            /* Parent writing to pipe. */
+            close(0);
+            dup2(pipefd[0],0);
+        }
+        /* Close anything above fd 2. (64 is an arbitrary magic number). */
+        for ( i = 3; i < 64; i++ )
+            close(i);
+
+        /* Finally, invoke the program. */
+        if ( execl("/bin/sh", "sh", "-c", cmd, NULL) < 0 )
+            exit(127);
+        /* NOTREACHED */
+    }   
 
     /* Close file descriptors, and gen up a FILE ptr */
     if ( *mode == 'r' )
     {
-	/* Parent reads from pipe. */
-	close(pipefd[1]);
-	retfile = fdopen( pipefd[0], mode );
+        /* Parent reads from pipe. */
+        close(pipefd[1]);
+        retfile = fdopen( pipefd[0], mode );
     } else {
-	/* Parent writing to pipe. */
-	close(pipefd[0]);
-	retfile = fdopen( pipefd[1], mode );
+        /* Parent writing to pipe. */
+        close(pipefd[0]);
+        retfile = fdopen( pipefd[1], mode );
     }
 
     /* Return the PID. */
@@ -99,8 +104,128 @@ my_popen(const char * const cmd,
 
     return retfile;
 }
+
+
+
+static void
+reapChildren(int *   const catchingChildrenP,
+             pid_t * const pids) {
+
+    /* Check for dead children. */
+
+    if (*catchingChildrenP > 0) {
+        unsigned int i;
+
+        /* Check all children to see if any are dead, reap them if so. */
+        for (i = 0; i < *catchingChildrenP; ++i) {
+            /* The assumption here is that if it's dead, the kill
+             * will fail, but, because we haven't waited for
+             * it yet, it's a zombie.
+             */
+            if (kill(pids[i], 0) < 0) {
+                int opid = pids[i], pid = 0;
+                /* Wait for processes & delete them from the list,
+                 * until we get the one we know is dead.
+                 * When removing one earlier in the list than
+                 * the one we found, decrement our loop index.
+                 */
+                while (pid != opid) {
+                    unsigned int j;
+                    pid = wait(NULL);
+                    for (j = 0;
+                         j < *catchingChildrenP && pids[j] != pid;
+                         ++j)
+                        ;
+                    if (pid < 0)
+                        break;
+                    if (j < *catchingChildrenP) {
+                        if (i >= j)
+                            --i;
+                        for (++j; j < *catchingChildrenP; ++j)
+                            pids[j-1] = pids[j];
+                        --*catchingChildrenP;
+                    }
+                }
+            }
+        }
+    }
+}
 #endif  /* !NO_OPEN_PIPES */
 
+
+
+static void
+dealWithSubprocess(const char *  const file_name,
+                   const char *  const mode,
+                   int *         const catchingChildrenP,
+                   pid_t *       const pids,
+                   FILE **       const fpP,
+                   bool *        const noSubprocessP,
+                   const char ** const errorP) {
+
+#ifdef NO_OPEN_PIPES
+    *noSubprocessP = TRUE;
+#else
+    const char *cp;
+
+    reapChildren(catchingChildrenP, pids);
+
+    /*  Real file, not stdin or stdout.  If name ends in ".Z",
+     *  pipe from/to un/compress (depending on r/w mode).
+     *  
+     *  If it starts with "|", popen that command.
+     */
+        
+    cp = file_name + strlen(file_name) - 2;
+    /* Pipe case. */
+    if (file_name[0] == '|') {
+        pid_t thepid;     /* PID from my_popen */
+
+        *noSubprocessP = FALSE;
+
+        *fpP = my_popen(file_name + 1, mode, &thepid);
+        if (*fpP == NULL)
+            *errorP = "%s: can't invoke <<%s>> for %s: ";
+        else {
+            /* One more child to catch, eventually. */
+            if (*catchingChildrenP < MAX_CHILDREN)
+                pids[(*catchingChildrenP)++] = thepid;
+        }
+    } else if (cp > file_name && *cp == '.' && *(cp + 1) == 'Z' ) {
+        /* Compress case. */
+        pid_t thepid;     /* PID from my_popen. */
+        const char * command;
+
+        *noSubprocessP = FALSE;
+        
+        if (*mode == 'w')
+            asprintfN(&command, "compress > %s", file_name);
+        else if (*mode == 'a')
+            asprintfN(&command, "compress >> %s", file_name);
+        else
+            asprintfN(&command, "compress -d < %s", file_name);
+        
+        *fpP = my_popen(command, mode, &thepid);
+
+        if (*fpP == NULL)
+            *errorP = "%s: can't invoke 'compress' program, "
+                "trying to open %s for %s";
+        else {
+            /* One more child to catch, eventually. */
+            if (*catchingChildrenP < MAX_CHILDREN)
+                pids[(*catchingChildrenP)++] = thepid;
+        }
+        strfree(command);
+    } else {
+        *noSubprocessP = TRUE;
+        *errorP = NULL;
+    }
+#endif
+}
+
+
+
+
 /* 
  *  Purpose : Open a file for input or ouput as controlled by the mode
  *  parameter.  If no file name is specified (ie. file_name is null) then
@@ -113,10 +238,10 @@ my_popen(const char * const cmd,
  *
  *  parameters
  *   input:
- *     prog_name: 	name of the calling program.
- *     file_name : 	name of the file to open
- *     mode : 		either "r" for read or input file or "w" for write or
- *            		output file
+ *     prog_name:   name of the calling program.
+ *     file_name :  name of the file to open
+ *     mode :       either "r" for read or input file or "w" for write or
+ *                  output file
  *
  *   output:
  *     a file pointer
@@ -127,150 +252,63 @@ rle_open_f_noexit(const char * const prog_name,
                   const char * const file_name, 
                   const char * const mode ) {
 
-    FILE *fp;
-    void perror();
-    CONST_DECL char *err_str;
-    const char *cp;
-    char *combuf;
+    FILE * retval;
+    FILE * fp;
+    const char * err_str;
+    int catching_children;
+    pid_t pids[MAX_CHILDREN];
 
-    if ( *mode == 'w' || *mode == 'a' )
+    catching_children = 0;
+
+    if (*mode == 'w' || *mode == 'a')
         fp = stdout;     /* Set the default value */
     else
         fp = stdin;
     
-    if ( file_name != NULL && strcmp( file_name, "-" ) != 0 )
-    {
-#ifndef NO_OPEN_PIPES
-        /* Check for dead children. */
-        if ( catching_children > 0 )
-        {
-            int i, j;
-
-            /* Check all children to see if any are dead, reap them if so. */
-            for ( i = 0; i < catching_children; i++ )
-            {
-                /* The assumption here is that if it's dead, the kill
-                 * will fail, but, because we haven't waited for
-                 * it yet, it's a zombie.
-                 */
-                if (kill(pids[i], 0) < 0) {
-                    int opid = pids[i], pid = 0;
-                    /* Wait for processes & delete them from the list,
-                     * until we get the one we know is dead.
-                     * When removing one earlier in the list than
-                     * the one we found, decrement our loop index.
-                     */
-                    while (pid != opid) {
-                        pid = wait( NULL );
-                        for ( j = 0;
-                              j < catching_children && pids[j] != pid;
-                              j++ )
-                            ;
-                        if ( pid < 0 )
-                            break;
-                        if ( j < catching_children ) {
-                            if ( i >= j )
-                                i--;
-                            for ( j++; j < catching_children; j++ )
-                                pids[j-1] = pids[j];
-                            catching_children--;
-                        }
-                    }
-                }
-            }
-        }
-
-        /*  Real file, not stdin or stdout.  If name ends in ".Z",
-         *  pipe from/to un/compress (depending on r/w mode).
-         *  
-         *  If it starts with "|", popen that command.
-         */
-	    
-        cp = file_name + strlen( (char*) file_name ) - 2;
-        /* Pipe case. */
-        if ( *file_name == '|' )
-        {
-            int thepid;		/* PID from my_popen */
-            if ( (fp = my_popen( file_name + 1, mode, &thepid )) == NULL )
-            {
-                err_str = "%s: can't invoke <<%s>> for %s: ";
-                goto err;
-            }
-            /* One more child to catch, eventually. */
-            if (catching_children < MAX_CHILDREN) {
-                pids[catching_children++] = thepid;
-            }
-        }
-
-        /* Compress case. */
-        else if ( cp > file_name && *cp == '.' && *(cp + 1) == 'Z' )
-        {
-            int thepid;		/* PID from my_popen. */
-            combuf = (char *)malloc( 20 + strlen( file_name ) );
-            if ( combuf == NULL )
-            {
-                err_str = "%s: out of memory opening (compressed) %s for %s";
-                goto err;
-            }
-
-            if ( *mode == 'w' )
-                sprintf( combuf, "compress > %s", file_name );
-            else if ( *mode == 'a' )
-                sprintf( combuf, "compress >> %s", file_name );
-            else
-                sprintf( combuf, "compress -d < %s", file_name );
-
-            fp = my_popen( combuf, mode, &thepid );
-            free( combuf );
-
-            if ( fp == NULL )
-            {
-                err_str =
-                    "%s: can't invoke 'compress' program, "
-                    "trying to open %s for %s";
-                goto err;
-            }
-            /* One more child to catch, eventually. */
-            if (catching_children < MAX_CHILDREN) {
-                pids[catching_children++] = thepid;
-            }
-        }
-        else
-#endif /* !NO_OPEN_PIPES */
-        {
-            /* Ordinary, boring file case. */
-            /* In the original code, the code to add the "b" was
-               conditionally included only if the macro STDIO_NEEDS_BINARY was
-               defined.  But for Netpbm, there is no need make a distinction;
-               we always add the "b".  -BJH 2000.07.20.  
-            */
-            char mode_string[32];	/* Should be enough. */
-
-            /* Concatenate a 'b' onto the mode. */
-            mode_string[0] = mode[0];
-            mode_string[1] = 'b';
-            strcpy( mode_string + 2, mode + 1 );
+    if (file_name != NULL && !streq(file_name, "-")) {
+        bool noSubprocess;
+        dealWithSubprocess(file_name, mode, &catching_children, pids,
+                           &fp, &noSubprocess, &err_str);
+        
+        if (!err_str) {
+            if (noSubprocess) {
+                /* Ordinary, boring file case. */
+                /* In the original code, the code to add the "b" was
+                   conditionally included only if the macro
+                   STDIO_NEEDS_BINARY was defined.  But for Netpbm,
+                   there is no need make a distinction; we always add
+                   the "b".  -BJH 2000.07.20.
+                */
+                char mode_string[32];   /* Should be enough. */
+
+                /* Concatenate a 'b' onto the mode. */
+                mode_string[0] = mode[0];
+                mode_string[1] = 'b';
+                strcpy( mode_string + 2, mode + 1 );
         
-            if ( (fp = fopen(file_name, mode_string)) == NULL )
-            {
-                err_str = "%s: can't open %s for %s: ";
-                goto err;
+                fp = fopen(file_name, mode_string);
+                if (fp == NULL )
+                    err_str = "%s: can't open %s for %s: ";
             }
         }
-    }
-
-    return fp;
+    } else
+        err_str = NULL;
+
+    if (err_str) {
+        fprintf(stderr, err_str,
+                prog_name, file_name,
+                (*mode == 'w') ? "output" :
+                (*mode == 'a') ? "append" :
+                "input" );
+        fprintf(stderr, "errno = %d (%s)\n", errno, strerror(errno));
+        retval = NULL;
+    } else
+        retval = fp;
+
+    return retval;
+}
 
-err:
-	fprintf( stderr, err_str,
-             prog_name, file_name,
-             (*mode == 'w') ? "output" :
-             (*mode == 'a') ? "append" :
-             "input" );
-	perror( "" );
-	return NULL;
 
-}
 
 FILE *
 rle_open_f(const char * prog_name, const char * file_name, const char * mode)
@@ -278,7 +316,7 @@ rle_open_f(const char * prog_name, const char * file_name, const char * mode)
     FILE *fp;
 
     if ( (fp = rle_open_f_noexit( prog_name, file_name, mode )) == NULL )
-	exit( -1 );
+        exit( -1 );
 
     return fp;
 }
@@ -290,21 +328,21 @@ rle_open_f(const char * prog_name, const char * file_name, const char * mode)
  * Close a file opened by rle_open_f.  If the file is stdin or stdout,
  * it will not be closed.
  * Inputs:
- * 	fd:	File to close.
+ *  fd: File to close.
  * Outputs:
- * 	None.
+ *  None.
  * Assumptions:
- * 	fd is open.
+ *  fd is open.
  * Algorithm:
- * 	If fd is NULL, just return.
- * 	If fd is stdin or stdout, don't close it.  Otherwise, call fclose.
+ *  If fd is NULL, just return.
+ *  If fd is stdin or stdout, don't close it.  Otherwise, call fclose.
  */
 void
 rle_close_f( fd )
-FILE *fd;
+    FILE *fd;
 {
     if ( fd == NULL || fd == stdin || fd == stdout )
-	return;
+        return;
     else
-	fclose( fd );
+        fclose( fd );
 }