Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
rle_open_f.c
Go to the documentation of this file.
1 /*
2  * rle_open_f.c - Open a file with defaults.
3  *
4  * Author : Jerry Winters
5  * EECS Dept.
6  * University of Michigan
7  * Date: 11/14/89
8  * Copyright (c) 1990, University of Michigan
9  */
10 
11 #include "rle_config.h"
12 #ifndef _XOPEN_SOURCE
13 #define _XOPEN_SOURCE /* Make sure fdopen() is in stdio.h */
14 #endif /* !_XOPEN_SOURCE */
15 
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 
20 #ifndef NO_OPEN_PIPES
21 /* Need to have a SIGCLD signal catcher. */
22 #include <signal.h>
23 #include <sys/wait.h>
24 #include <errno.h>
25 
26 /* Count outstanding children. Assume no more than 100 possible. */
27 #define MAX_CHILDREN 100
28 static int catching_children = 0;
29 static int pids[MAX_CHILDREN];
30 
31 static FILE *my_popen();
32 #endif /* !NO_OPEN_PIPES */
33 
34 
35 /*
36  * Purpose : Open a file for input or ouput as controlled by the mode
37  * parameter. If no file name is specified (ie. file_name is null) then
38  * a pointer to stdin or stdout will be returned. The calling routine may
39  * call this routine with a file name of "-". For this case rle_open_f
40  * will return a pointer to stdin or stdout depending on the mode.
41  * If the user specifies a non-null file name and an I/O error occurs
42  * when trying to open the file, rle_open_f will terminate execution with
43  * an appropiate error message.
44  *
45  * parameters
46  * input:
47  * prog_name: name of the calling program.
48  * file_name : name of the file to open
49  * mode : either "r" for read or input file or "w" for write or
50  * output file
51  *
52  * output:
53  * a file pointer
54  *
55  */
56 FILE *
58 char *prog_name, *file_name, *mode;
59 {
60  FILE *fp;
61  void perror();
62  CONST_DECL char *err_str;
63  register char *cp;
64  char *combuf;
65 
66 #ifdef STDIO_NEEDS_BINARY
67  char mode_string[32]; /* Should be enough. */
68 
69  /* Concatenate a 'b' onto the mode. */
70  mode_string[0] = mode[0];
71  mode_string[1] = 'b';
72  strcpy( mode_string + 2, mode + 1 );
73  mode = mode_string;
74 #endif
75 
76  if ( *mode == 'w' || *mode == 'a' )
77  fp = stdout; /* Set the default value */
78  else
79  fp = stdin;
80 
81  if ( file_name != NULL && strcmp( file_name, "-" ) != 0 )
82  {
83 #ifndef NO_OPEN_PIPES
84  /* Check for dead children. */
85  if ( catching_children > 0 )
86  {
87  int i, j;
88 
89  /* Check all children to see if any are dead, reap them if so. */
90  for ( i = 0; i < catching_children; i++ )
91  {
92  /* The assumption here is that if it's dead, the kill
93  * will fail, but, because we haven't waited for
94  * it yet, it's a zombie.
95  */
96  if (kill(pids[i], 0) < 0) {
97  int opid = pids[i], pid = 0;
98  /* Wait for processes & delete them from the list,
99  * until we get the one we know is dead.
100  * When removing one earlier in the list than
101  * the one we found, decrement our loop index.
102  */
103  while (pid != opid) {
104  pid = wait( NULL );
105  for ( j = 0;
106  j < catching_children && pids[j] != pid;
107  j++ )
108  ;
109 #ifdef DEBUG
110  fprintf( stderr, "Reaping %d at %d for %d at %d\n",
111  pid, j, opid, i );
112  fflush( stderr );
113 #endif
114  if ( pid < 0 )
115  break;
116  if ( j < catching_children ) {
117  if ( i >= j )
118  i--;
119  for ( j++; j < catching_children; j++ )
120  pids[j-1] = pids[j];
122  }
123  }
124  }
125  }
126  }
127 
128  /* Real file, not stdin or stdout. If name ends in ".Z",
129  * pipe from/to un/compress (depending on r/w mode).
130  *
131  * If it starts with "|", popen that command.
132  */
133 
134  cp = file_name + strlen( file_name ) - 2;
135  /* Pipe case. */
136  if ( *file_name == '|' )
137  {
138  int thepid; /* PID from my_popen */
139  if ( (fp = my_popen( file_name + 1, mode, &thepid )) == NULL )
140  {
141  err_str = "%s: can't invoke <<%s>> for %s: ";
142  goto err;
143  }
144  /* One more child to catch, eventually. */
146 #ifdef DEBUG
147  fprintf( stderr, "Forking %d at %d\n",
148  thepid, catching_children );
149  fflush( stderr );
150 #endif
151  pids[catching_children++] = thepid;
152  }
153  }
154 
155  /* Compress case. */
156  else if ( cp > file_name && *cp == '.' && *(cp + 1) == 'Z' )
157  {
158  int thepid; /* PID from my_popen. */
159  combuf = (char *)malloc( 20 + strlen( file_name ) );
160  if ( combuf == NULL )
161  {
162  err_str = "%s: out of memory opening (compressed) %s for %s";
163  goto err;
164  }
165 
166  if ( *mode == 'w' )
167  sprintf( combuf, "compress > %s", file_name );
168  else if ( *mode == 'a' )
169  sprintf( combuf, "compress >> %s", file_name );
170  else
171  sprintf( combuf, "compress -d < %s", file_name );
172 
173  fp = my_popen( combuf, mode, &thepid );
174  free( combuf );
175 
176  if ( fp == NULL )
177  {
178  err_str =
179  "%s: can't invoke 'compress' program, trying to open %s for %s";
180  goto err;
181  }
182  /* One more child to catch, eventually. */
184 #ifdef DEBUG
185  fprintf( stderr, "Forking %d at %d\n", thepid, catching_children );
186  fflush( stderr );
187 #endif
188  pids[catching_children++] = thepid;
189  }
190  }
191 
192  /* Ordinary, boring file case. */
193  else
194 #endif /* !NO_OPEN_PIPES */
195  if ( (fp = fopen(file_name, mode)) == NULL )
196  {
197  err_str = "%s: can't open %s for %s: ";
198  goto err;
199  }
200  }
201 
202  return fp;
203 
204 err:
205  fprintf( stderr, err_str,
206  prog_name, file_name,
207  (*mode == 'w') ? "output" :
208  (*mode == 'a') ? "append" :
209  "input" );
210  perror( "" );
211  return NULL;
212 
213 }
214 
215 FILE *
217 char *prog_name, *file_name, *mode;
218 {
219  FILE *fp;
220 
221  if ( (fp = rle_open_f_noexit( prog_name, file_name, mode )) == NULL )
222  exit( -1 );
223 
224  return fp;
225 }
226 
227 
228 /*****************************************************************
229  * TAG( rle_close_f )
230  *
231  * Close a file opened by rle_open_f. If the file is stdin or stdout,
232  * it will not be closed.
233  * Inputs:
234  * fd: File to close.
235  * Outputs:
236  * None.
237  * Assumptions:
238  * fd is open.
239  * Algorithm:
240  * If fd is NULL, just return.
241  * If fd is stdin or stdout, don't close it. Otherwise, call fclose.
242  */
243 void
245 FILE *fd;
246 {
247  if ( fd == NULL || fd == stdin || fd == stdout )
248  return;
249  else
250  fclose( fd );
251 }
252 
253 
254 #ifndef NO_OPEN_PIPES
255 static FILE *
257 char *cmd, *mode;
258 int *pid;
259 {
260  FILE *retfile;
261  int thepid = 0;
262  int pipefd[2];
263  int i;
264  char *argv[4];
265 
266  /* Check args. */
267  if ( *mode != 'r' && *mode != 'w' )
268  {
269  errno = EINVAL;
270  return NULL;
271  }
272 
273  if ( pipe(pipefd) < 0 )
274  return NULL;
275 
276  /* Flush known files. */
277  fflush(stdout);
278  fflush(stderr);
279  if ( (thepid = fork()) < 0 )
280  {
281  close(pipefd[0]);
282  close(pipefd[1]);
283  return NULL;
284  }
285  else if (thepid == 0) {
286  /* In child. */
287  /* Rearrange file descriptors. */
288  if ( *mode == 'r' )
289  {
290  /* Parent reads from pipe, so reset stdout. */
291  close(1);
292  dup2(pipefd[1],1);
293  } else {
294  /* Parent writing to pipe. */
295  close(0);
296  dup2(pipefd[0],0);
297  }
298  /* Close anything above fd 2. (64 is an arbitrary magic number). */
299  for ( i = 3; i < 64; i++ )
300  close(i);
301 
302  /* Finally, invoke the program. */
303  if ( execl("/bin/sh", "sh", "-c", cmd, NULL) < 0 )
304  exit(127);
305  /* NOTREACHED */
306  }
307 
308  /* Close file descriptors, and gen up a FILE ptr */
309  if ( *mode == 'r' )
310  {
311  /* Parent reads from pipe. */
312  close(pipefd[1]);
313  retfile = fdopen( pipefd[0], mode );
314  } else {
315  /* Parent writing to pipe. */
316  close(pipefd[0]);
317  retfile = fdopen( pipefd[1], mode );
318  }
319 
320  /* Return the PID. */
321  *pid = thepid;
322 
323  return retfile;
324 }
325 #endif /* !NO_OPEN_PIPES */
FILE * rle_open_f(char *prog_name, char *file_name, char *mode)
Definition: rle_open_f.c:216
static int catching_children
Definition: rle_open_f.c:28
static FILE * my_popen(char *cmd, char *mode, int *pid)
Definition: rle_open_f.c:256
void rle_close_f(FILE *fd)
Definition: rle_open_f.c:244
#define CONST_DECL
Definition: rle_config.h:42
#define MAX_CHILDREN
Definition: rle_open_f.c:27
FILE * rle_open_f_noexit(char *prog_name, char *file_name, char *mode)
Definition: rle_open_f.c:57
static int pids[100]
Definition: rle_open_f.c:29