From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 28-FEB-1991 03:32:39.75
To:	ARISIA::EVERHART
CC:	
Subj:	Add input argument wild card expansion to C programs

From:	RELAY-INFO-VAX@CRVAX.SRI.COM@SMTP@CRDGW2
To:	Everhart@Arisia@MRGATE

Received:  by crdgw1.ge.com (5.57/GE 1.87)
	 id AA21327; Thu, 28 Feb 91 03:17:19 EST
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Wed, 27 FEB 91 05:02:04 PST
Received: by ucbvax.Berkeley.EDU (5.63/1.42)
	id AA26275; Wed, 27 Feb 91 04:51:39 -0800
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 27 Feb 91 11:17:39 GMT
From: mcsun!inesc!news@uunet.uu.net  (USENET News System)
Organization: INESC - Inst. Eng. Sistemas e Computadores, LISBOA, PORTUGAL.
Subject: Add input argument wild card expansion to C programs
Message-Id: <1668@inesc.UUCP>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

/*
 * Parse input arguments and expands VMS wild cards to matching file names.
 *
 * The purpouse of this module is to emulate the beavior of unix shells.
 * In unix, wild card expansion is done by the shell before calling a
 * program. In VMS wild cards are not expanded by the DCL interpreter.
 * This C module will expand VMS wild cards and then call a function
 * _MAIN_(argc, argv). If you have a C program and wish to add the
 * capability to expand input argument wild cards, then just rename
 * your main function to _MAIN_ and link with WILD_CARD.OBJ
 *
 * The input arguments with no wild cards will be passed directly.
 *
 * The arguments passed to _MAIN_ will have the same file specification
 * format of the input argument. That is, if input argument has a disk
 * (or logical name specification) the expanded file name will have
 * that specification to. The same aplies to directory names.
 * If you want the full file specification #define FULL_FILE_NAME
 *
 * Version numbers are treated specially. WILD_CARD will substitute
 * the ';' character with '\0' hiding the version number. You can access
 * the version number in the argument, because it is not destroyed (see
 * the built in _MAIN_ function).
 * #define DONT_HIDE_VERSION_NUMBER if you want version numbers.
 *
 * If you want to test WILD_CARD, #define BUILT_IN_MAIN, compile, link
 * and run it with some wild card argument.
 *
 * THIS IS PUBLIC DOMAIN. AS USUAL NO WARRANTIES
 *
 * Author : Fernando P. Jesus, INESC, LISBOA, PORTUGAL
 *  Questions, bug reports (fixes) and sugestions : email fpj@sabrina.inesc.pt
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <ssdef.h>
#include <descrip.h>

/*
 * My library does not have a strdup.
 */
char *strdup (str)
char *str;
{
    char *ptr;

    if ( (ptr = (char *) malloc ( sizeof(char) * (strlen(str) + 1))) == NULL)
	return (NULL);

    strcpy (ptr, str);
    return (ptr);
}

#define    MAX_FILE_NAME_LENGTH   1024
#define    TAMALOCADO   16

/*
 * See if input string has some wild cards
 * It scans str for '*', '%' and for "..."
 */
int IsWildCard (str)
char *str;
{
    int i;

    if (*str == '"') return (0); /* ignore quoted strings */

    for (i=0 ; str[i] ; i++)
	if (str[i] == '*' || str[i] == '%' ||
	    (str[i] == '.' && str[i+1] == '.' && str[i+2] == '.'))
	    return (1);

    /*
     * No wild cards
     */
    return (0);
}

/*
 * Associates string with VAX-VMS string descriptor desc
 */
void descriptor(desc,string)    
struct dsc$descriptor_s *desc;
char *string; 
{
    desc->dsc$w_length=strlen(string);      
    desc->dsc$b_dtype=DSC$K_DTYPE_T;        /* data type code */
    desc->dsc$b_class=DSC$K_CLASS_S;        /* descriptor class code */
    desc->dsc$a_pointer=string;     /* address of first byte of data element */
}

#ifdef BUILT_IN_MAIN

int _MAIN_ (argc, argv)
int argc;
char **argv;
{
    int i;

    /*
     * Lists input arguments (including version numbers)
     */
    for (i=0; i < argc ; i++)
	printf ("%s %s\n", argv[i], (i) ? &argv[i][strlen(argv[i]) + 1] : "");

    /*
     * exit status 0
     */
    return (0);
}

#endif

main (argc, argv)
int argc;
char **argv;
{
    static char aux[MAX_FILE_NAME_LENGTH];
    $DESCRIPTOR(DescAux,aux);
    struct dsc$descriptor_s DescNome;
    long       Context = 0;
    int        arg;		/* Index to scan argv */
    char      *OutArgv[1024];	/* Output argv */
    unsigned   SizeOutArgv = 1, /* Current size of OutArgv **NOT USED (now)***/
               OutArgc = 1;	/* Output argc */
    int        rtn,		/* to hold return value of _MAIN_ */
               WildCardsPresent = 0, /* true if some wild cards present */
               NumberOfMatches  = 0; /* No comments !! */
    
    /*
     * First output argument is the program name.
     * It will be the first output argument.
     */
    OutArgv[0] = argv[0];

    /*
     * Scan all input arguments
     */
    for (arg = 1 ; arg < argc ; arg++)
    {
	int i;
	char *AuxPtr;
#ifndef FULL_FILE_NAME
	int SpecToDel;

	/*
	 * See if input argument has disk (or logical name)
	 * specification, directory specification or none
	 */
	SpecToDel = (strchr (argv[arg], ':') != NULL) ? 0 :
	    (strchr (argv[arg], '[') != NULL) ? 1 : 2;

#endif /* FULL_FILE_NAME */

	/*
	 * associate string descriptor DescNome with current input argument
	 */
	descriptor(&DescNome, argv[arg]);

	/*
	 * If input argument contains wild cards translates them,
	 * else, add input argument to output argv.
	 */
	if (!IsWildCard (argv[arg]))
	{
	    /*
	     * Just copy input argument.
	     * Allocate space for the argument and the null version number.
	     */
	    OutArgv[OutArgc] = malloc(sizeof(char) * (strlen(argv[arg]) + 2));
	    /*
	     * Copy the current input argument
	     */
	    strcpy(OutArgv[OutArgc], argv[arg]);

#ifdef DONT_HIDE_VERSION_NUMBER
	    OutArgv[OutArgc][strlen(argv[arg])+1] = 0; /* No version number */
#endif
	    OutArgc++;
	}
	else  /* input argument has wild cards */
	{
	    WildCardsPresent = 1;   /* Whe have found some wild cards */
	    /*
	     * Translate the input argument into the files matching
	     * the wild cards.
	     */
	    while (lib$find_file(&DescNome, &DescAux, &Context) & 1)
	    {
		NumberOfMatches++;    /* one more match */
#ifndef FULL_FILE_NAME
		/*
		 * If current input argument does not have a disk
		 * (or logical name) specification, delete
		 * disk specification from the new file name.
		 * Same for directory.
		 */
		AuxPtr = (SpecToDel == 0) ? aux :
		    (SpecToDel == 1) ? strchr (aux, ':') + sizeof(char) :
			strchr (aux, ']') + sizeof(char);
#else /* FULL_FILE_NAME */
		AuxPtr = aux;
#endif

		/*
		 * Terminates the string (append a '\0')
		 */
		for (i=0 ; AuxPtr[i] != ' ' && AuxPtr[i] != 0 ; i++);
		AuxPtr[i] = 0;
		/*
		 * Copy file name to output argv and increment output argc
		 */
		OutArgv[OutArgc] = strdup (AuxPtr);
		AuxPtr = OutArgv[OutArgc++];

#ifndef DONT_HIDE_VERSION_NUMBER
		/*
		 * Hide version number
		 */
		for (i=0 ; AuxPtr[i] != ';' && AuxPtr[i] ; i++);
		AuxPtr[i] = 0;
#endif /* DONT_HIDE_VERSION_NUMBER */

		/*
		 * Next file name.
		 */
	    }
	    /*
	     * No more files
	     */
	    lib$find_file_end(&Context);
	}
    }

    /*
     * If there are wild cards in input arguments, and 
     * number of matches = 0, exit and display error message.
     */
    if (WildCardsPresent && !NumberOfMatches)
    {
	fprintf (stderr, "No match.\n");
	exit (1);
    }

    /*
     * Terminates output argv
     */
    OutArgv[OutArgc] = NULL;

    /*
     * Call the real main
     */
    rtn = _MAIN_(OutArgc, OutArgv);

    /*
     * Free the alocated space
     */
    for (OutArgc-- ; OutArgc ; OutArgc--)
	free (OutArgv[OutArgc]);
    /*
     * and exit with the return status of _MAIN_
     */
    exit (rtn);
}
--------
Fernando Jesus, INESC, LISBOA, PORTUGAL
Mail:
	Fernando Pereira Jesus
	Rua Alves Redol 9, 6o
	1000 LISBOA
	PORTUGAL
email : fpj@sabrina.inesc.pt

