[comp.sys.ibm.pc] A Turbo C Question

greg@nmtsun.nmt.edu (Greg Lindhorst) (01/30/88)

I have a stupid question to ask.  How can one get Turbo C to expand
wild carded arguments on the command line?

I.E. Translate something like:    "doitto *.c"
     into somthing like:          "doitto first_file.c second_file.c ..."

You all know the scam, unix has been doing it for years...

Thanks a bunch,
greg                                  (...!lanl!unmvax!nmtsun!greg)

roper@june.cs.washington.edu (Michael Roper) (01/31/88)

greg@nmtsun.nmt.edu (Greg Lindhorst) writes:

> How can one get Turbo C to expand wild carded arguments on the command line?

Apparently you can't.  I don't own Turbo C, but according to the latest
issue of Turbo Technix, you must write your own module to do this (the
article gives you a complete step-by-step, including code).  

One point for Microsoft.  Although it would be nice if they included
a module to do Unix-style expansions, as well.

-- 
Mike Roper
                                      *  Ice Cream...
ARPA:  roper@june.cs.washington.edu   *
UUCP:  ihnp4!uw-beaver!uw-june!roper  *  ...it's not just for dessert anymore.

nelson@sun.soe.clarkson.edu (Russ Nelson) (01/31/88)

In article <1282@nmtsun.nmt.edu> greg@nmtsun.UUCP (Greg Lindhorst) writes:
>I have a stupid question to ask.  How can one get Turbo C to expand
>wild carded arguments on the command line?

Since you have Turbo C, you automatically get a free subscription to
Turbo Technix, Borland's captive magazine.  In the Jan/Feb 88 issue,
there is an article describing changes to the start-up code to expand
wildcards.  You might even have gotten it by the time you get this :-)
-russ

-- 
-russ
AT&T: (315)268-6591  BITNET: NELSON@CLUTX  Internet: nelson@clutx.clarkson.edu
GEnie: BH01  Compu$erve: 70441,205

dean@violet.berkeley.edu (Dean Pentcheff) (01/31/88)

In article <1282@nmtsun.nmt.edu> greg@nmtsun.UUCP (Greg Lindhorst) writes:
>I have a stupid question to ask.  How can one get Turbo C to expand
>wild carded arguments on the command line?

Well, there may be a better way to do it than the way I did it, but
I couldn't find it.  I did look at the assembly code for the C0x.c startup
routines, and there was no trace of an option to do filename expansion.
The elegant way to do things would be to rewrite those asm routines to
do it.  I'm lazy, though, so here's what I wrote: a routine which will
filename expand an argv-type list of strings.  Call it early on in your
program (before processing arguments).  It will allocate memory using 
malloc() as it sees fit.  See other documentation in the comments at the
top of the file.  Have fun.

Note: this is not a shar file, just text.

--------- cut here (and check for a .signature at the end) -------------------
/*
 * glob.c
 * N. Dean Pentcheff 1/88
 * dean@violet.berkeley.edu
 *
 * Do global filename expansion on an array of pointers to char.
 *
 * The Turbo startup routine groups any "double quoted" arguments together.
 * This routine does not filename expand any 'single quoted' argument or
 *     group of arguments.  It suppresses the single quotes.
 *
 * Prototype:  int  glob( char ** , char *** )
 *
 * Argument:  Expects an argv-like pointer to pointers to characters, and the
 *            address of another argv-like pointer for the new replacement
 *            globbed list.  Doesn't touch first arg, clobbers second.  The
 *            two arguments may, in fact, be the same.  For example:
 *                          argc = glob(argv, &argv);
 *            will just glob and replace the original argv and argc.
 *
 * Returns:  The number of (non-NULL) pointers in the new list.
 *
 * Limits:  May filename-expand up to a (silently enforced) limit of
 *          200 arguments.  Uses malloc() to get memory: if memory runs
 *          out, exit(1) is called after a perror() message is printed.
 * Note:	Compile using -DTESTPROG for a demo/test version including
 *          a main().  See end of this file.
 */

#include	<stdio.h>
#include	<dir.h>
#include	<string.h>
#include	<process.h>
#include	<alloc.h>
#include	<errno.h>
#include	<ctype.h>

#define		MAXARGS		200

void	docopy(char **, char *);
void	doglob(char ***, char *, char **);

int
glob(args, newlist)
	char	**args;		/* input pointer to pointers to characters */
	char	***newlist;	/* output pointer to pointer to pointers to char */
{
	char	**cpp;		/* used to step through the argument args */
	char	**new;		/* list to return to caller built on this */
	char	*cp;		/* general purpose character pointer      */
	int		inquote;	/* record if we're inside 'quoted' area   */

	/* Try to get memory for the new array of pointers to characters */
	if ((new=*newlist=(char **)malloc(sizeof(char *)*(MAXARGS+1))) == NULL) {
		perror("glob");
		exit(1);
	}

	/* Step through the argument array, globbing as required */
	inquote = 0;
	for (cpp = args;  (new-(*newlist)) < MAXARGS  &&  *cpp != NULL;  ++cpp) {
		if (inquote == 1) {			/* in quoted area */
			cp = *cpp;
			if (*cp  &&  *(cp=(cp+strlen(cp)-1))=='\'') {	/* ending? */
				*cp = '\0';		/* suppress quote */
				inquote = 0;
			}
			if (**cpp)			/* don't create 0-length arguments */
				docopy(new++, *cpp);
		} else {					/* not in quoted area */
			if (**cpp == '\'') {		/* starting quote? */
				for (cp=*cpp;  *cp;  ++cp)	/* suppress quote */
					*cp = *(cp+1);
				inquote = 1;
				cp = *cpp;
				if (*cp  &&  *(cp=(cp+strlen(cp)-1))=='\'') {	/* ending? */
					*cp = '\0';		/* suppress quote */
					inquote = 0;
				}
				if (**cpp)		/* don't create 0-length arguments */
					docopy(new++, *cpp);
			} else {					/* not quoted, so try globbing */
				doglob(&new, *cpp, *newlist);
			}
		}
	}
	*new = NULL;
	return((int) (new - (*newlist)));
}

static void
doglob(dest, str, base)
	char	***dest;	/* pointer to new array of pointers to characters */
	char	*str;		/* string to glob */
	char	**base;		/* beginning of new array of pointers to characters */
{
	struct	ffblk	ffb;	/* DOS file structure */
	char	*cp;			/* general purpose character pointer */

    if (findfirst(str, &ffb, 0) < 0) {
		docopy((*dest)++, str);			/* no glob matches, just copy arg */
	} else do {
		docopy(*dest, ffb.ff_name);		/* copy this globbed filename match */
		for (cp = **dest;  *cp;  ++cp)	/* lowercase it */
			*cp = tolower(*cp);
		++(*dest);						/* increment output array */
	} while ((*dest - base) < MAXARGS  &&  findnext(&ffb) == 0);
	return;
}

static void
docopy(cp1, cp2)
	char	**cp1;
	char	*cp2;
{
	if ((*cp1 = (char *)malloc(strlen(cp2)+1)) == NULL) {	/* get memory */
		perror("glob docopy");
		exit(1);
	} else {
		strcpy(*cp1, cp2);			/* copy the string into it */
	}
	return;
}

#ifdef 	TESTPROG
/*
 * Mainline test program.  To use, compile using:
 *    tcc -otryglob -DTESTPROG glob.c
 * NDP 1/88
 */

void
main(argc, argv)
	int		argc;
	char	**argv;
{
	int		nargc;
	char	**nargv;

	nargc = glob(argv, &nargv);
	printf("Originally, %d arguments.  Finally, %d arguments.\n\n",
			argc, nargc);
	while (*nargv != NULL) {
		printf("%s\n", *nargv++);
	}
}
#endif	TESTPROG
-----------------
Dean Pentcheff	(dean@violet.berkeley.edu)
-----------------
"A university is a place where people pay high prices for goods which they then
proceed to leave on the counter when they go out of the store."  Loren Eiseley

darrylo@hpsrlc.HP.COM (Darryl Okahata) (02/01/88)

In comp.sys.ibm.pc, greg@nmtsun.nmt.edu (Greg Lindhorst) writes:

> I have a stupid question to ask.  How can one get Turbo C to expand
> wild carded arguments on the command line?
     [ ... ]
> Thanks a bunch,
> greg                                  (...!lanl!unmvax!nmtsun!greg)

     I have a routine that does just that.  To use it, you simply compile
it and link it with your program; your program does NOT have to be
modified.  There is one possible problem with it (depending on your
application): it's copyrighted (I didn't write it -- I downloaded it from
Borland's SIG on Compuserve) and can be freely distributed as long as no
fee is charged.  If you or anyone else would like a copy, send Email.

     -- Darryl Okahata
	{hplabs!hpccc!, hpfcla!} hpsrla!darrylo
	CompuServe: 75206,3074

Disclaimer: the above is the author's personal opinion and is not the
opinion or policy of his employer or of the little green men that
have been following him all day.

wew@naucse.UUCP (Bill Wilson) (02/06/88)

In article <1282@nmtsun.nmt.edu>, greg@nmtsun.nmt.edu (Greg Lindhorst) writes:
> I have a stupid question to ask.  How can one get Turbo C to expand
> wild carded arguments on the command line?
> 
> I.E. Translate something like:    "doitto *.c"
>      into somthing like:          "doitto first_file.c second_file.c ..."

You will have to write your own routine that uses the findfirst
and findnext functions to expand it out for you.  Sorry...

Bill Wilson

nelson@sun.soe.clarkson.edu (Russ Nelson) (02/07/88)

In article <1282@nmtsun.nmt.edu>, greg@nmtsun.nmt.edu (Greg Lindhorst) writes:
> I have a stupid question to ask.  How can one get Turbo C to expand
> wild carded arguments on the command line?
> 
> I.E. Translate something like:    "doitto *.c"
>      into somthing like:          "doitto first_file.c second_file.c ..."

How's about this solution?  It's the best of all I've seen:

------------------------cut here, and remove .signature----------------------
/* setargv -- setup argv with wild card expansion                           */
/* copyright 1987  Michael M Rubenstein                                     */

/* This program may be freely distributed provided no fee is assessed.      */

/* This file implements wild card expansion in argv for Turbo C 1.5.        */
/* Strings of characters in either quotes (") or appostrophes (') on the    */
/* command line are considered a single argument.  However, backslash       */
/* escapes are not implemented.  A quote may be included in an argument     */
/* which is enclosed in appostrophes and an appostrophe may be included     */
/* in an argument enclosed in quotes.  Either may be included as an         */
/* in an argument starting with any other character.                        */

/* Any argument which is not enclosed in quotes or appostrophes, does not   */
/* begin with a hyphen (-), and which contains an asterisk (*) or question  */
/* mark (?) will be expanded.  It is NOT an error for an argument to have a */
/* null expansion (no matching files).  Only ordinary files (not            */
/* directories or hidden or system files) will be included in the           */
/* expansion.                                                               */

/* To use this function, simply compile it with the appropriate memory      */
/* model and include in the link.  This can be accomplished very simply     */
/* in the integrated environment by simply including this file in the       */
/* project file.  In the command line version, simply include this file     */
/* (or a precompiled .OBJ version) on the command line.                     */

#include <ctype.h>
#include <dir.h>
#include <dos.h>
#include <ctype.h>
#include <process.h>

#define FALSE           0
#define TRUE            1

void                    putarg(unsigned char far *, unsigned char far *);

extern int              _argc;
extern char             **_argv;
extern unsigned         _psp;
extern unsigned         _envseg;
extern unsigned         _envLng;
extern unsigned char    _osmajor;
extern void             _abort();
extern char             *sbrk(int);

void _setargv()
{
  unsigned char         far *cmdtail;
  unsigned char         *firstarg;
  unsigned char         far *cmdarg;
  int                   wild;
  int                   c;
  unsigned char         buffer[129];
  unsigned char         *p, *q;
  unsigned char         *lastdir;
  char                  **wargv;
  int                   i;
  struct ffblk          ffb;

  cmdtail = MK_FP(_psp, 0x81);
  cmdtail[cmdtail[-1]] = '\0';      /* make sure null at end */
  firstarg = (unsigned char *) sbrk(0);
  _argc = 1;

  while (*cmdtail != '\0')
  {
    /* skip white space */
    while (isascii(*cmdtail) && isspace(*cmdtail))
      ++cmdtail;

    /* done with command loop if end of command tail */
    if (*cmdtail == '\0')
      break;

    /* if quoted string, just save the argument */
    if ((c = *cmdtail) == '"' || c == '\'')
    {
      cmdarg = ++cmdtail;
      while (*cmdtail != c && *cmdtail != '\0')
        ++cmdtail;
      putarg(cmdarg, cmdtail);
      if (*cmdtail != '\0')
        ++cmdtail;
      continue;
    }

    /* find word */
    cmdarg = cmdtail;
    wild = FALSE;
    p = lastdir = buffer;
    while ((c = *cmdtail) != '\0'
        && (!isascii(c) || !isspace(c)))
    {
      /* wild is TRUE if word contains * or ? */
      wild |= (c == '*' || c == '?');
      *(p++) = c;

      /* lastdir points to the first character of the base file name */
      if (c == '\\' || c == ':')
        lastdir = p;
      ++cmdtail;
    }
    *p = '\0';

    if (wild && *cmdarg != '-')
      for (c = findfirst((char *) buffer, &ffb, 0);
           c == 0;
           c = findnext(&ffb))
      {
        /* use lower case for wild card expanded names (my prejudice) */
        for (p = lastdir, q = (unsigned char *) ffb.ff_name; *q != '\0';)
             *(p++) = tolower(*(q++));
          ;
        putarg(buffer, p);
      }
    else
      putarg(cmdarg, cmdtail);
  }

  /* allocate argv */
  if ((wargv = (char **) sbrk(sizeof(char *) * (_argc + 1))) == (char **) -1)
    abort();
  _argv = wargv;

  /* store program name */
  if (_osmajor < 3)
    *(wargv++) = "C";
  else
  {
      cmdtail = cmdarg = MK_FP(_envseg, _envLng + 2);
#   if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
      *(wargv++) = sbrk(0);
      while (*cmdtail != '\0')
        ++cmdtail;
      putarg(cmdarg, cmdtail);
      --_argc;
#   else
      *(wargv++) = (char *) cmdarg;
#   endif
  }

  /* store arguments */
  for (i = _argc; --i;)
  {
    *(wargv++) = (char *) firstarg;
    while(*++firstarg != '\0')
      ;
    ++firstarg;
  }
  *wargv = (char *) 0;
}

static void putarg(from, to)
  unsigned char         far *from, far *to;
{
  char                  *p;

  if ((p = sbrk(to - from + 1)) == (char *) -1)
    abort();
  while (from < to)
   *(p++) = *(from++);
  *p = '\0';
  ++_argc;
}
-- 
-russ
AT&T: (315)268-6591  BITNET: NELSON@CLUTX  Internet: nelson@clutx.clarkson.edu
GEnie: BH01  Compu$erve: 70441,205