From 1fd361a1ea06e44286c213ca1f814f49306fdc43 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sat, 19 Aug 2006 03:12:28 +0000 Subject: Create Subversion repository git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- urt/rle_open_f.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 urt/rle_open_f.c (limited to 'urt/rle_open_f.c') diff --git a/urt/rle_open_f.c b/urt/rle_open_f.c new file mode 100644 index 00000000..d2575c11 --- /dev/null +++ b/urt/rle_open_f.c @@ -0,0 +1,310 @@ +/* + * rle_open_f.c - Open a file with defaults. + * + * Author : Jerry Winters + * EECS Dept. + * University of Michigan + * Date: 11/14/89 + * Copyright (c) 1990, University of Michigan + */ + +#define _XOPEN_SOURCE /* Make sure fdopen() is in stdio.h */ + +#include +#include +#include +#include + +#ifndef NO_OPEN_PIPES +/* Need to have a SIGCLD signal catcher. */ +#include +#include +#include + +#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 * +my_popen(const char * const cmd, + const char * const mode, + int * const pid) { + + FILE *retfile; + int thepid = 0; + int pipefd[2]; + int i; + + /* Check args. */ + if ( *mode != 'r' && *mode != 'w' ) + { + errno = EINVAL; + return NULL; + } + + if ( pipe(pipefd) < 0 ) + return NULL; + + /* Flush known files. */ + fflush(stdout); + fflush(stderr); + if ( (thepid = fork()) < 0 ) + { + 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 */ + } + + /* Close file descriptors, and gen up a FILE ptr */ + if ( *mode == 'r' ) + { + /* 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 ); + } + + /* Return the PID. */ + *pid = thepid; + + return retfile; +} +#endif /* !NO_OPEN_PIPES */ + +/* + * 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 + * a pointer to stdin or stdout will be returned. The calling routine may + * call this routine with a file name of "-". For this case rle_open_f + * will return a pointer to stdin or stdout depending on the mode. + * If the user specifies a non-null file name and an I/O error occurs + * when trying to open the file, rle_open_f will terminate execution with + * an appropiate error message. + * + * 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 + * + * output: + * a file pointer + * + */ +FILE * +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; + + 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 ( (fp = fopen(file_name, mode_string)) == NULL ) + { + err_str = "%s: can't open %s for %s: "; + goto err; + } + } + } + + return fp; + +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) +{ + FILE *fp; + + if ( (fp = rle_open_f_noexit( prog_name, file_name, mode )) == NULL ) + exit( -1 ); + + return fp; +} + + +/***************************************************************** + * TAG( rle_close_f ) + * + * 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. + * Outputs: + * None. + * Assumptions: + * fd is open. + * Algorithm: + * 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; +{ + if ( fd == NULL || fd == stdin || fd == stdout ) + return; + else + fclose( fd ); +} -- cgit 1.4.1