/* $Id: filter.c,v 1.2 2007-02-04 13:11:07-05 david Exp david $ */
/* Module: filter.c
   David Elins routine to loop through filenames on a command line
   reopening each as standard input and calling a routine to process them.
   The processing routine is called at least once. If there are no arguments
   (argc==1), the original standard input is used.
   Also, an argument consisting of a single '-' means use original standard
   The processing routine is passed a single argument, the filename argument
   from the command line or NULL if the original standard input is used.
   If the processing routine returns any value other that one, this routine
   terminates and returns that value.
   Otherwise this routine returns the value indicating successful exit
   status (different on different operating systems).

   10 Dec 1987 modification
   All filename arguments on the command line are processed, even if some
   can't be opened. If the last command line filename argument can not
   be opened , the error status indicating that open failure is returned.
   If RETURN_OPENFAIL is defined, the error status is returned whenever a
   file can not be opened.

        int argc;               how many command line arguments
        char *argv[];           command line arguments
        int (*process)();       function that processes each file
   Return value:
        1 (one) if process returns 1 each time it is called
        process return value if process does not return 1

   On Vms, nextargv() is used to expand wild cards and allow commas to
   separate arguments (unlike DCL, commas are optional). Nextargv()
   calls vmsfindfile(). Vmsfindfile defines the external variable
   'parsedefault' which can be used to supply default values for portions of
   the filename arguments (e.g. ".c" for the standard C source file type).

   On MS/DOS, wild cards are not expanded, but the MicroSoft routine
   \lib\setargv.obj can be used to do this.

   Also on MS/DOS, the external variable 'filtbin' is available. If the caller
   sets it TRUE, the input files are opened in binary mode ("rb").

   On all systems the external variable 'manyfiles' is available. This
   routine sets it TRUE or FALSE depending whether more than one file
   name argument is processed.

   Dependencies on other routines:
        standard C library routines and system calls
        Vms: nextargv instr

#if defined(__BORLANDC__) || defined(__MSDOS__) || defined(__CYGWIN32__)
#  ifndef _WIN32
#    define _WIN32      /* compile like Microsoft C */
#  endif

/* if RETURN_OPENFAIL defined, terminate loop when file open fails */
#  define RETURN_OPENFAIL break;        /* stop loop on error */
#  define RETURN_OPENFAIL continue      /* skip file on error */

extern int dup();
extern int strcmp();
extern void close();
#ifdef VMS
#  include stdio
#  include string
#  include errno
#  include ssdef
#  include rms
#  define ExitOk SS$_NORMAL
   extern int instr(char *src,char *sub);
   extern char *nextargv(),*strrchr();
   /* rms structures are externally visible */
   struct FAB ff_fab;   /* File access block      */
   struct NAM ff_nam;   /* File name block        */
#else   /* NEGATION OF #ifdef VMS */
#  define ExitOk 0
#  include <stdio.h>
#  include <errno.h>
   extern int errno;    /* system error variable */
#endif  /* END #ifdef VMS */
#ifdef TRUE
#  undef TRUE
#endif  /* END #ifdef TRUE */
#ifdef FALSE
#  undef FALSE
#endif  /* END #ifdef FALSE */
#define TRUE 1
#define FALSE 0
#ifdef _WIN32
        int filtbin=FALSE;     /* input files are opened in binary mode ? */
#endif  /* END #ifdef _WIN32 */
#define EQS(str1,str2) (strcmp((str1),(str2))==0)
extern char *strchr();
int manyfiles=FALSE;

    int argc,                   /* how many command line arguments */
    char *argv[],               /* command line arguments */
    int (*process)(char *file)  /* function that processes each file,
                                   the argument passed to process 
                                   is the name of the being processed
                                   (NULL if orig stdin)
                                   if process returns other than 1
                                   filter() terminates its loop
                                   and returns that value */

    register int fd=dup(0);     /* initial standard input */
    register int inorig;        /* 0=from stdin, else from file */
    register char *ap;          /* pointer to filename argument */
    register int retval;        /* return value */
    register int firstcall=TRUE;
    char *filtmode="r";
#ifndef VMS
    int argctr;
#endif  /* END #ifndef VMS */

    manyfiles = ((argc) > 2);
#ifdef _WIN32
    if (filtbin)
        filtmode = "rb";
#endif  /* END #ifdef _WIN32 */
    /* arguments are filenames to filter, "-" means standard input */
#ifdef VMS
    if (!manyfiles && (argc == 2)) {
        ap = argv[1];          /* used as scratch variable */
        retval = strlen(ap);    /* used as scratch variable */
        manyfiles = (strcspn(ap,"*%,") < retval) || (instr(ap,"...") < retval);

    ap = nextargv(argc,argv,0);
    for (; firstcall || (ap != NULL); ap = nextargv(argc,argv,0))
#else   /* NEGATION OF #ifdef VMS */
    for (ap=argv[argctr=1]; firstcall || argctr<argc; ap=argv[++argctr])
#endif  /* END #ifdef VMS */
        firstcall = FALSE;
        inorig = (ap == NULL) || EQS(ap,"-");
        if (inorig) {
            (void)close(0);    /* reset to initial standard input */
        /* set filename as standard input */
        else if (freopen(ap,filtmode,stdin) == NULL) {
            char string[48];
#ifdef VMS
            ap = ff_nam.nam$l_rsa;  /* actual name used */
            retval = RMS$_FNF;  /* return if error */
#else   /* NEGATION OF #ifdef VMS */
            retval = errno; /* return if error */
#endif  /* END #ifdef VMS */
            (void)sprintf(string,"cannot open %s", ap);

            RETURN_OPENFAIL;    /* break or continue (see comment above) */

        retval = (*process)(inorig?(char *)NULL:ap); /* do this file */
        if (retval != 1)
        else retval = ExitOk;

    if (!inorig) { /* leave stdin the same file as at entry */


 *                   Copyright 2010 by David M. Elins                   *
 *                                                                      *
 * 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 3 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 *
 * General Public License for more details.                             *
 *                                                                      *
 * A  copy  of  the  GNU  General  Public  License  (GPL)  be  found at *
 * <>.               *
 *                                                                      *
 * One  is  supposed  to be included here but doing so would bloat this *
 * source code too much.                                                *
// vim:tabstop=8:shiftwidth=4:noexpandtab
Comments, flames, broken links?
Please send email to