From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 18-APR-1991 22:49:57.98
To:	ARISIA::EVERHART
CC:	
Subj:	Re: U*x shar/unshar for VMS

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

Received:  by crdgw1.ge.com (5.57/GE 1.97)
	 id AA01628; Thu, 18 Apr 91 22:34:30 EDT
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Thu, 18 APR 91 11:04:17 PDT
Received: by ucbvax.Berkeley.EDU (5.63/1.42)
	id AA15580; Thu, 18 Apr 91 11:01:00 -0700
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: 17 Apr 91 13:52:19 GMT
From: eru!hagbard!sunic!mcsun!hp4nl!sara5!gerben@bloom-beacon.mit.edu
Subject: Re: U*x shar/unshar for VMS
Message-Id: <1991Apr17.145219.2843@news.sara.nl>
References: <1991Apr16.143905.7785@cc.curtin.edu.au>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

In article <1991Apr16.143905.7785@cc.curtin.edu.au>,
crobw@cc.curtin.edu.au writes:
> Does anyone have a shar archiver (unarchiver) for VMS? There is such a lot of
> good X-windows stuff on comp.sources.x which really needs a VMS-specific
> unarchiver.

Here is a program I use. it is not great, but it works.
It does NOT create directories on the fly, so first glance thru your
shar file it to see which directories have to be made. (shar -l
sharfile)

It uses a getredirection() routine i received also over the net.
This routine might be handy anyway. It simulates Unix i/o redirection
and filename expansion (the last i added to Jerry Leichters version)

Here it is,

Gerben Jansen,
SARA, Academic Computing Services,
Amsterdam,
The Netherlands.

gerben@hasara5.bitnet  or
gerben@sara.nl
======================================================================
/*
 * Usage:
 * shar :== $disk:[directory]shar.exe
 * shar options and parameters
 *
 *  Shar puts readable text files together in a package
 *
 *  from which they are easy to extract.
 *
 *
 *    v 870424 G. Jansen (gerben@hasara5.bitnet) for VAX/VMS
 *	- added more sed support : only remove pattern if present
 *	- add a -l this options only lists the files in shar file.
 *    v 870307 T. Stark (h462batms@gallua.bitnet) for VAX/VMS
 *      - added a -f (shar) switch because of lack of > in DCL.
 *
 *    v 860716 M. Kersenbrock (tektronix!copper!michaelk) for Z80-CPM
 *      - enhanced usage message
 *
 *    v 860712 D. Wecker for ULTRIX and the AMIGA
 *      - stripped down.. does patterns but no directories
 *      - added a -u (unshar) switch
 */
     
#define VMS
     
#ifdef CPM
#include "c:stdio.h"
#include "c:fcntl.h"
#else
#include <stdio.h>
#endif
     
#ifdef CPM
#define void int
#define fputc putc
extern char *getenv(),*malloc(),*index(),*rindex();
int cpmversion;
     
#endif
     
#ifdef  AMIGA
#include <exec/types.h>
extern char *getenv(),*scdir(),*malloc(),*index();
#endif
     
#ifdef  ULTRIX
#include <sys/types.h>
extern char *getenv(),*scdir(),*malloc(),*index();
#endif
     
#ifdef  VMS
#include <types.h>
extern char *getenv(),*scdir(),*malloc();
#endif
     
     
#define BADCH   ((int)'?')
#define EMSG    ""
#define tell(s) {fputs(*nargv,stderr);fputs((s),stderr);\
                 fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
#define rescanopts()    (optind = 1)
     
int     optind = 1,             /* index into parent argv vector */
        optopt;                 /* character checked for validity */
long    fsize;                  /* length of file */
char    *optarg;                /* argument associated with option */
char    *sav[100];              /* saved file names */
int     savind;                 /* save index */
     
/* OPTIONS */
int     Verbose = 0;           /* provide append/extract feedback */
int     Basename = 0;          /* extract into basenames */
int     Count = 0;             /* count characters to check transfer */
char    *Delim = "SHAR_EOF";   /* put after each file */
char    Filter[100] = "cat";   /* used to extract archived files */
char    *Prefix = NULL;        /* line prefix to avoid funny chars */
int     UnShar = 0;            /* do we unshar an input file? */
int     ListOnly = 0;          /* list contents of input file  */
     
char Usage1[] =
"\nSHAR: Create/extract file archive for extraction by /bin/sh (normally).\n";

char Usage1a[] = 
"\n\usage:\n\n\  shar [-u shar] [-l shar] [[-a] [-p prefix] [-d delim] [-bcv] [-f shar] files [> shar]]\n";

char Usage1b[] = 
"\n\        where:\t\t-a  all the options (v,c,b,-pXX)\n";
     
char Usage2[] =
"\t\t-b  extract absolute paths into current directory\n\t\t-c  check filesizes on extraction\n                -d  use this EOF delimiter instead of SHAR_EOF\n";
     
char Usage3[] =
"\t\t-f  shar <archive>\n\t\t-p  use this as prefix to each line in archived files\n                -u  unshar <archive>\n";
     
char Usage4[] =
"\t\t-v  verbose on extraction, incl. echoing filesizes\n\t\t-l  list shar contents\n";
     
#define SED "sed 's/^%s//'"    /* used to remove prefix from lines */
     
#ifdef CPM
#define OPTSTRING "U:L:AP:D:BCV:F:"
#else
#define OPTSTRING "u:l:ap:d:bcv:f:"
#endif
     
#ifdef  VMS
char *index(s,c)
char    *s;
char    c;
{
    while (*s != 0 && *s != c) s++;
    if (*s == 0 && *s != c) s = 0;
    return(s);
}
#endif
     
int header(ppchFiles)
char *ppchFiles[];
{
    extern char *ctime();
    register int i;
    auto long clock;
    register char **ppchList;
    char *pchOrg;
    char *pchName;
    register int  problems = 0;
     
    pchOrg = getenv("ORGANIZATION");
    pchName = getenv("NAME");
     
    puts("#\tThis is a shell archive.");
    puts("#\tRemove everything above and including the cut line.");
    puts("#\tThen run the rest of the file through sh.");
    puts("#----cut here-----cut here-----cut here-----cut here----#");
    puts("#!/bin/sh");
    puts("# shar:    Shell Archiver");
    puts("#\tRun the following text with /bin/sh to create:");
    for (ppchList = ppchFiles; *ppchList; ++ppchList)
        printf("#\t%s\n", *ppchList);
#ifdef CPM
  if (cpmversion >= 0x30) {
#endif
    (void) time(& clock);
    printf("# This archive created: %s", ctime(&clock));
#ifdef CPM
  }
#endif
    if (pchName)
        printf("# By:\t%s (%s)\n", pchName,
        pchOrg ? pchOrg : "Dave Wecker Midnight Hacks");
    return(0);
}
     
int archive(input, output)
char *input, *output;
{
    auto char line[BUFSIZ];
    register FILE *ioptr;

#ifdef VMS
    char *pdot;

    strcpy(line, output);
    if( (pdot=strchr(line, '.')) && *(pdot+1) == '\0')
    	*pdot = '\0';
    if (ioptr = fopen(input, "r")) {
        printf("%s << \\%s > %s\n", Filter, Delim, line);
#else  VMS
    if (ioptr = fopen(input, "r")) {
        printf("%s << \\%s > %s\n", Filter, Delim, output);
#endif VMS     
        while(fgets(line, BUFSIZ, ioptr)) {
            if (Prefix) fputs(Prefix, stdout);
            fputs(line, stdout);
            if (Count) fsize += strlen(line);
        }
        puts(Delim);
        (void) fclose(ioptr);
        return(0);
    }
    else {
        fprintf(stderr, "shar: Can't open '%s'\n", input);
        return(1);
    }
}
     
     
void shar(file)
char *file;
{
    register char *basefile;
    basefile = file;
    if (!strcmp(file, "."))
        return;
    fsize = 0;
    if (Basename) {
        while(*basefile)
            basefile++;        /* go to end of name */
        while(basefile > file && *(basefile-1) != '/')
            basefile--;
    }
    if (Verbose) printf("echo shar: extracting %s\n", basefile);
    if (archive(file, basefile)) exit();
    if (Count) {
        printf("if test %ld -ne \"`wc -c %s`\"\n",fsize,basefile);
        printf("then\necho shar: error transmitting %s ",basefile);
        printf("'(should have been %ld characters)'\nfi\n",fsize);
    }
}
     
int main(argc, argv)
int argc;
char **argv;
{
    auto char *ppchFiles[256];
    register int  C;
    register char **ppchList = ppchFiles;
    register int errflg = 0;

    getredirection(&argc, &argv);
     
#ifdef CPM
    cpmversion = (bdoshl(0x0c,0) & 0xff);
#endif
     
    while(EOF != (C = getopt(argc, argv, OPTSTRING))) {
#ifdef CPM
        switch(isupper(C) ? tolower(C) : C ) {
#else
        switch(C) {
#endif
        case 'v':
            Verbose++;
            break;
        case 'c':
            Count++;
            break;
        case 'b':
            Basename++;
            break;
        case 'd':
            Delim = optarg;
            break;
        case 'a': /* all the options */
            optarg = "XX";
            Verbose++;
            Count++;
            Basename++;
            /* fall through to set prefix */
        case 'p':
            (void) sprintf(Filter, SED, Prefix = optarg);
            break;
	case 'l':
	    ListOnly++;
	    /* fall through to list */
        case 'u':
            UnShar++;
            dounshar(optarg);
            break;
        case 'f':
            if (!(stdout = fopen(optarg,"w", "rat=cr", "rfm=var")))
              {
                fprintf(stderr, "shar: can't open archive %s\n",optarg);
                exit();
              }
            break;
        default:
            errflg++;
        }
    }
    if (UnShar) exit();
     
    C = getarg(argc, argv);
    if (errflg || EOF == C) {
        if (EOF == C)
            fprintf(stderr, "shar: No input files\n");
	fprintf(stderr, "%s", Usage1);
	fprintf(stderr, "%s", Usage1a);
	fprintf(stderr, "%s", Usage1b);
	fprintf(stderr, "%s", Usage2);
	fprintf(stderr, "%s", Usage3);
	fprintf(stderr, "%s", Usage4);
        exit();
    }
     
    savind = 0;
    do {
        if (getpat(optarg)) exit();
    }
    while (EOF != (C = getarg(argc, argv)));
     
    sav[savind] = 0;
    header(sav);
    for (ppchList = sav; *ppchList; ++ppchList) {
     
#ifdef CPM
         strlower(*ppchList);
#endif
     
         shar(*ppchList);
    }
    puts("#\tEnd of shell archive");
    puts("exit 0");
    fclose(stdout);
    exit();
}
     
getpat(pattern)
char *pattern;
{
    register char *ptr;
    int temp;
     
#ifdef AMIGA
    while (ptr = scdir(pattern)) {
#else
    ptr = pattern;
    {
#endif
        sav[savind] = malloc(strlen(ptr)+1);
        strcpy(sav[savind++],ptr);
#ifdef CPM
        temp = open(ptr,O_RDONLY);
        if (temp == -1) {
#else
        if (access(ptr,4)) {
#endif
            printf("No read access for file: %s\n",ptr);
            return(-1);
        }
     
#ifdef CPM
        close(temp);
#endif
    }
    return(0);
}
     
     
/*
 * get option letter from argument vector
 */
int
getopt(nargc, nargv, ostr)
int nargc;
char **nargv, *ostr;
{
    register char    *oli;        /* option letter list index */
    static char    *place = EMSG;    /* option letter processing */
    if(!*place) {            /* update scanning pointer */
        if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
                 return(EOF);
        if (*place == '-') {    /* found "--" */
            ++optind;
            return EOF;
        }
    }                /* option letter okay? */
    if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
        if(!*place) ++optind;
        tell(": illegal option -- ");
    }
    if (*++oli != ':') {        /* don't need argument */
        optarg = NULL;
        if (!*place)
            ++optind;
    }
    else {                /* need an argument */
        if (*place) {            /* no white space */
            optarg = place;
        }
        else {
                if (nargc <= ++optind) {    /* no arg */
                        place = EMSG;
                        tell(": option requires an argument -- ");
                }
                else {
                    optarg = nargv[optind];    /* white space */
                }
        }
        place = EMSG;
        ++optind;
    }
    return(optopt);            /* dump back option letter */
}
     
     
int
getarg(nargc, nargv)
int nargc;
char **nargv;
{
    if (nargc <= optind) {
        optarg = (char *) 0;
        return EOF;
    }
    else {
        optarg = nargv[optind++];
        return 0;
    }
}
     
dounshar(ArcNam)
char *ArcNam;
{
    register int i,j;
    register FILE *inptr,*outptr;
    auto char line[BUFSIZ];
#ifdef VMS
    char buf[BUFSIZ];
#endif VMS
    int DirNum = -1;
    int Prefix = 0;
    char Dirs[5][40],FilNam[128],Delim[40],ScrStr[128];
    char *ptr;
     
    if (!(inptr = fopen(ArcNam,"r"))) {
        fprintf(stderr,"shar: Can't open archive '%s'\n", ArcNam);
        return;
    }
    if( ListOnly )
	fprintf(stderr, "Shell Archive :  %s\n-----------------------------------------\n",
			ArcNam);
#ifdef VMS
    buf[0] = '\0';
#endif VMS
    while (fgets(line,BUFSIZ,inptr)) {
        if (strncmp(line,"sed ",4) == 0) {
            Prefix = 0;
            if (!(ptr = index(line,'/'))) goto getfil;
            if (*++ptr == '^') ++ptr;
            while (*ptr++ != '/')
#ifdef VMS
                buf[Prefix++] = *(ptr-1);
#else
		Prefix++;
#endif VMS
            goto getfil;
        }
        else if (strncmp(line,"cat ",4) == 0) {
            Prefix = 0;
            ;
getfil:
     
#ifdef    VMS
            buf[Prefix] = '\0';
#endif
            FilNam[0] = 0;
     
            for (i = 0; i <= DirNum; i++) {
     
                strcat(FilNam,Dirs[i]);
                strcat(FilNam,"/");
     
            }
     
     
     
            getshpar(line,">",ScrStr);
            strcat(FilNam,ScrStr);
     
#ifdef CPM
            tocpmformat(FilNam);        /* tweek format as needed */
#endif
            getshpar(line,"<<",Delim);
	    if( !ListOnly ) {
                fprintf(stderr,"Creating %s ...",FilNam);
                outptr = fopen(FilNam,"w", "rat=cr", "rfm=var");
                while (fgets(line,BUFSIZ,inptr)) {
                    if (strncmp(line,Delim,strlen(Delim)) == 0) break;
#ifdef VMS
		    if(Prefix && !strncmp(buf, line, Prefix)) {
#endif VMS
                        if (outptr) fputs(&line[Prefix],outptr);
#ifdef VMS
                    }
                    else
                        if (outptr) fputs(line, outptr);
#endif VMS
                }
                if (outptr) {
                    fclose(outptr);
                    fprintf(stderr,"...done\n");
                }
                else fprintf(stderr,"...error in creating file\n");
            }
	    else {    /* Only list file-name */
	        fprintf(stderr, " - %s\n", FilNam);
	    }
        }
        else if (strncmp(line,"mkdir ",6) == 0) {
            fprintf(stderr,"Need to make directory: %s\n",&line[6]);
        }
        else if (strncmp(line,"chdir ",6) == 0) {
            if (line[6] == '.' && line[7] == '.') DirNum--;
            else strcpy(Dirs[++DirNum],&line[6]);
            if (DirNum < -1) DirNum = -1;
        }
        else if (strncmp(line,"cd ",3) == 0) {
            if (line[3] == '.' && line[4] == '.') DirNum--;
            else strcpy(Dirs[++DirNum],&line[3]);
            if (DirNum < -1) DirNum = -1;
        }
    }
    fclose(inptr);
    if( ListOnly )
	fprintf(stderr, "-----------------------------------------\n");
}
     
getshpar(line,sea,par)
char *line,*sea,*par;
{
    register int i,j,k;
    register char *scr1,*scr2;
     
    while (*line) {
        scr1 = line;
        scr2 = sea;
        while (*scr1 && *scr2 && *scr1 == *scr2) {
            scr1++;
            scr2++;
        }
        if (*scr2 == 0) {
            if (*scr1 == 0) {
                *par = 0;
                return;
            }
            while ( *scr1 == ' ' || *scr1 == '\t' ||
                *scr1 == '\\' || *scr1 == '\'' || *scr1 == '"') scr1++;
            while ( *scr1 != 0 && *scr1 != ' ' && *scr1 != '\t' &&
                *scr1 != '\\' && *scr1 != '\'' && *scr1 != '"' &&
                *scr1 != '\n' && *scr1 != '\r') *par++ = *scr1++;
            *par = 0;
            return;
        }
        line++;
    }
    *par = 0;
}
     
     
#ifdef CPM
     
tocpmformat(filename)
char *filename;
{
        char buffer[100];
        char extension[100];
        register char *temp;
        int mod = 0;
     
        strcpy(buffer,filename);
     
        /*
         * Make sure we get rid of any pathnames
         */
        if ((temp=rindex(buffer,'/')) != 0) {
                strcpy(buffer,(char *)((temp-buffer)+filename+1));
                mod = 1;
        }
     
        if (strlen(filename) <= 8) {
                if (mod != 0) {
                        strcpy(filename,buffer);
                }
                return(0);
        }
     
        /*
         * If it already is in "CPM" format we'll check if we need
         * to truncate the front filename part.
         */
        if ((temp=index(buffer,'.')) != 0 ) {
                if ((temp-buffer) < 8) {
                        if (mod != 0) {
                                strcpy(filename,buffer);
                        }
                        return(0);
                }
                else {
                        strcpy(extension,temp);
                        strcpy(&buffer[8],extension);
                        buffer[12] = '\0';
                        strcpy(filename,buffer);
                        return(1);
                }
        }
     
        /*
         * OK, filename is longer than can be handled, and it doesnt have
         * a filetype "." marker already.  We will put one in to minimize
         * truncation.
         */
        strcpy(extension,&buffer[8]);
        buffer[8] = '.';
        strcpy(&buffer[9],extension);
        buffer[12] = '\0';
        strcpy(filename,buffer);
        return(2);
}
     
     
     
strlower(string)
char *string;
{
        register char *pointer;
        char c;
        for (pointer = string ; (c=*pointer) != '\0' ; pointer++ ) {
                if (isupper(c))
                        *pointer = tolower(c);
        }
}
     
#endif

/*
 * getredirection() is intended to aid in porting C programs
 * to VMS (Vax-11 C) which does not support '>' and '<'
 * I/O redirection.  With suitable modification, it may
 * useful for other portability problems as well.
 *
 * Modified, 24-Jan-86 by Jerry Leichter
 *	When creating a new output file, force the maximum record size to
 *	512; otherwise, it ends up as 0 (though the C I/O system won't write
 *	a record longer than 512 bytes anyway) which will cause problems if
 *	the file is later opened for APPEND - if the maximum record size is
 *	0, C will use the length of the longest record written to the file
 *	for its buffer!
 *
 * Modified 17-May-88 by Gerben Jansen
 *	When the redirection character (<, > or >>) are followed by a blank,
 *	use the next argument as filename.
 *	Changed exit status of routine.
 */

#ifdef	vms
#include	<stdio.h>
#include	<errno.h>
#include	<ssdef.h>
#include	<rms.h>

#define	MAXARGS	1024

int
getredirection(pargc, pargv)
int		*pargc;
char		***pargv;
/*
 * Process vms redirection arg's.  Exit if any error is seen.
 * If getredirection() processes an argument, it is erased
 * from the vector.  getredirection() returns a new argc value.
 *
 * Warning: do not try to simplify the code for vms.  The code
 * presupposes that getredirection() is called before any data is
 * read from stdin or written to stdout.
 *
 * Normal usage is as follows:
 *
 *	main(argc, argv)
 *	int		argc;
 *	char		*argv[];
 *	{
 *		getredirection(&argc, &argv);
 *	}
 */
{
	register char		*ap;	/* Argument pointer	*/
	int			i;	/* argv[] index		*/
	int			j;	/* Output index		*/
	int			n;	/* Number of expansions	*/
	int			nargc;	/* New argc		*/
	char			**nargv;/* New argv		*/
	int			in;	/* Index in new argv	*/
	int			file;	/* File_descriptor 	*/
	int			has_semicolon;
	char			*expanded[MAXARGS];
	char			tmp[BUFSIZ], *ptmp;
	int			argc;
	char			**argv;

	argc = *pargc;
	argv = *pargv;

	for (j = i = 1; i < argc; i++) {   /* Do all arguments	*/
	    switch (*(ap = argv[i])) {
	    case '<':			/* <file		*/
	    	if( !*++ap ) {
	    		if( ++i >= argc ) {
	    			fprintf(stderr, "<: missing input filename\n");
	    			exit(SS$_BADPARAM);
	    		}
	    		ap = argv[i];
	    	}
		if (freopen(ap, "r", stdin) == NULL) {
		    perror(ap);		/* Can't find file	*/
		    exit(vaxc$errno);	/* Is a fatal error	*/
		}
		break;

	    case '>':			/* >file or >>file	*/
		if (*++ap == '>') {	/* >>file		*/
		    /*
		     * If the file exists, and is writable by us,
		     * call freopen to append to the file (using the
		     * file's current attributes).  Otherwise, create
		     * a new file with "vanilla" attributes as if
		     * the argument was given as ">filename".
		     * access(name, 2) is TRUE if we can write on
		     * the specified file.
		     */
	    	    if( !*++ap ) {
	    		if( ++i >= argc ) {
	    		    fprintf(stderr, ">>: missing output filename\n");
	    		    exit(SS$_BADPARAM);
	    		}
	    		ap = argv[i];
	    	    }
		    if (access(ap, 2) == 0) {
			if (freopen(ap, "a", stdout) != NULL)
			    break;	/* Exit case statement	*/
			perror(ap);	/* Error, can't append	*/
			exit(vaxc$errno);	/* After access test	*/
		    }			/* If file accessable	*/
		}
		/*
		 * On vms, we want to create the file using "standard"
		 * record attributes.  create(...) creates the file
		 * using the caller's default protection mask and
		 * "variable length, implied carriage return"
		 * attributes. dup2() associates the file with stdout.
		 */
	    	if( !*ap ) {
	    		if( ++i >= argc ) {
	    			fprintf(stderr, ">: missing output filename\n");
	    			exit(SS$_BADPARAM);
	    		}
	    		ap = argv[i];
	    	}
		if ((file = creat(ap, 0, "rat=cr", "rfm=var", "mrs=512"))
			== -1
		 || dup2(file, fileno(stdout)) == -1) {
		    perror(ap);		/* Can't create file	*/
		    exit(vaxc$errno);	/* is a fatal error	*/
		}			/* If '>' creation	*/
		break;			/* Exit case test	*/

	    default:
		argv[j++] = ap;		/* Not a redirector	*/
		break;			/* Exit case test	*/
	    }
	}				/* For all arguments	*/

	argv[j] = NULL;			/* Terminate argv[]	*/

	nargc = j;
	nargv = malloc( (nargc+1) * sizeof( char * ) );
	for(i=0; i<= nargc; i++)
		nargv[i] = argv[i];

	/* Blow up wildcard specs */
	for(i=1; i<nargc;) {
		expanded[MAXARGS-1] = NULL;
		has_semicolon = strchr(nargv[i], ';');
		strcpy(tmp, nargv[i]);
		if( !has_semicolon )
			strcat(tmp, ";");
		n = fgen(tmp, expanded, MAXARGS);
		if( n < 0 && expanded[MAXARGS-1] ) {
			fprintf(stderr, "Too many matches (> %d)\n", MAXARGS);
	    		exit(SS$_BADPARAM);
		}
		
		if( n > 0 ) {
			nargv = realloc(nargv, (nargc+n+1)*(sizeof( char * )));
			for(j=nargc+n-1; j>i; j--)
				nargv[j] = nargv[j-n+1];
			for(j=0; j<n; j++) {
				if( !has_semicolon && (ptmp=strchr(expanded[j], ';')) )
					*ptmp = '\0';
				nargv[i+j] = expanded[j];
			}
			i += n;
			nargc += (n-1);
		}
		else
			i++;
	}
	*pargc = nargc;			/* New argc	*/
	*pargv = nargv;			/* New argv	*/
	return;
}
#else
getredirection(argc, argv)
int		argc;
char		*argv[];
/*
 * Dummy routine.
 */
{
	return (argv[0], argc);
}
#endif

#include descrip
#include rms
#include smail

/*
 * fgen(pattern, result_array, array_length)
 *   fgen generates filenames of files, matching a VMS pattern,
 *   the results are stored in an array, space for the strings is allocated
 *   by using malloc.
 * Return values:
 *   -1    : error in pattern
 *    0    : no files found
 *   n(>0) : number of matching filenames. (Stored in result_array [0] - [n-1])
 *
 * Wildcard expansion for VMS is easy;  we just use a run-time library call.
 */

fgen(pat,resarry,len)
char *pat,*resarry[];
int len;
{
    struct dsc$descriptor_s file_spec, result, deflt;
    long context;
    int count, slen, status, plen;
    char *pp, *rp, result_string[256], *strchr();
 
    file_spec.dsc$w_length  = strlen(pat);
    file_spec.dsc$b_dtype   = DSC$K_DTYPE_T;
    file_spec.dsc$b_class   = DSC$K_CLASS_S;
    file_spec.dsc$a_pointer = pat;
 
    result.dsc$w_length  = sizeof result_string;
    result.dsc$b_dtype   = DSC$K_DTYPE_T;
    result.dsc$b_class   = DSC$K_CLASS_S;
    result.dsc$a_pointer = result_string;
 
    deflt.dsc$w_length  = 3;
    deflt.dsc$b_dtype   = DSC$K_DTYPE_T;
    deflt.dsc$b_class   = DSC$K_CLASS_S;
    deflt.dsc$a_pointer = "*.*";
 
    count = 0;
    context = 0;
    pp = strrchr(pat, ']');
    if ( !pp ) pp = strrchr(pat, ':');
    if ( !pp ) plen = 0;
    else plen = pp - pat + 1;
    while (count < len
           && (status = LIB$FIND_FILE(&file_spec, &result, &context, &deflt))
                                                              == RMS$_NORMAL) {
        rp = strrchr(result_string, ']') + 1;
        if( !rp )
        	rp = result_string;
        slen = strchr(rp, ' ') - rp;
            resarry[count] = malloc(slen + plen + 1);
        if (plen != 0)
            strncpy(resarry[count], pat, plen);
        strncpy(resarry[count] + plen, rp, slen);
        resarry[count][slen + plen] = '\0';
        ++count;
    }
#ifdef DVI$_ALT_HOST_TYPE
    lib$find_file_end(&context);    /* Only on V4 and later */
#endif
    if (status == RMS$_FNF) return(0);
    if (status == RMS$_NMF) return(count);
    return(-1);
}

