home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega CD-ROM 1
/
megacd_rom_1.zip
/
megacd_rom_1
/
GNUISH
/
GNULIB0.ZIP
/
_CWILD.C
next >
Wrap
C/C++ Source or Header
|
1990-09-20
|
10KB
|
372 lines
/* _cwild.c - (reasonable, i.e. **IX style) wildcard expansion and
passing of long commandlines for MSC
Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
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 1, 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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Header: e:/gnu/lib/RCS/_cwild.c 1.0 90/09/11 01:55:11 tho Exp $
*/
/* One of the major shortcomings of MS-DOS is the inability to pass long
commandlines. Commandlines are restricted to 126 characters in length
and may not contain newlines, etc.
Both of these restrictions make it impossible to put reasonably sized
`awk', `sed', `perl', etc. scripts into shell scripts. Also it's
impossible to put reasonably sized shell script fragments into
makefiles.
One way to overcome *some* of these problems is to let the user
commands perform their own globbing. The second (more satisfactory)
way is to invent a new scheme for argument passing.
One approach that presents itself, is to pass the arguments via the
environment. This is the approach adopted here. If this code is
compiled with `-DWANT_LONG_COMMANDLINES' (which is implied by
`-DSMART_SHELL_ONLY' and `-DSMART_SHELL'), the startup code looks for
"_argc" in the environment. If it is found, it is used as a argument
count and the commandline is taken from "_argv0", "_argv1", ... The
MS-DOS commandline is *ignored* in this case! This is of course only
useful if your Shell or Make supports this feature. (GNU make will do
in the next version.)
The other part of the code uses the GNU globbing library to perform
globbing of the MS-DOS commandline in a **IX compatible way.
This code has been developped to be used with the startup code of
Microsoft C. Compile with one of SMART_SHELL_ONLY, SMART_SHELL, or
DUMB_SHELL_ONLY. Link with the `setargv.obj' that came with the
compiler to ensure that _cwild () is called during startup.
IMPORTANT: Since we want this appraoch to become compiler independent,
feedback in form of patches for other compilers (Turbo C, Zortech,
etc.) is *greatly* appreciated. */
/* NOTE: Even though this approach is almost evident, I do *not* put it
in the public domain. I CLAIM A COPYRIGHT BOTH ON THIS CODE AND THE
UNDERLYING IDEAS. But you are welcome to redistribute, use and
improve it under the terms of the GNU GENERAL PUBLIC LICENSE.
This seems appropriate in the days of aggressive copyright lawsuits
to prevent someone from preventing YOU to use it. */
/* Configuration Section: */
/* Define this if you are exclusively using Bash, GNU make,
or other winning utilities which take the load of expanding
the commandline from your program and know how to pass
*long* commandlines. */
#ifdef SMART_SHELL_ONLY
#ifndef WANT_LONG_COMMANDLINES
#define WANT_LONG_COMMANDLINES
#endif
#ifdef WANT_GLOBBING
#undef WANT_GLOBBING
#endif
#endif /* SMART_SHELL_ONLY */
/* Define this if you are always use loosing Shells and Makes, that don't
know how to pass long commandlines. And if your program has to expand
the commandline itself. */
#ifdef DUMB_SHELL_ONLY
#ifdef WANT_LONG_COMMANDLINES
#undef WANT_LONG_COMMANDLINES
#endif
#ifndef WANT_GLOBBING
#define WANT_GLOBBING
#endif
#endif /* not DUMB_SHELL_ONLY */
#if !defined(SMART_SHELL) && !defined(SMART_SHELL_ONLY) \
&& !defined(DUMB_SHELL_ONLY)
#define SMART_SHELL
#endif
/* Define this if your program can expect long commandlines, but should
also be able to do some globbing. */
#ifdef SMART_SHELL
#ifndef WANT_LONG_COMMANDLINES
#define WANT_LONG_COMMANDLINES
#endif
#ifndef WANT_GLOBBING
#define WANT_GLOBBING
#endif
#endif /* SMART_SHELL */
/* This code relies on the standard GNU globbing library, which does
all the hard work. */
/* This wildcard expansion module is tailored for use with the Microsoft
C startup code and uses their conventions. It will probably not work
with the libraries of other compilers. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifdef WANT_LONG_COMMANDLINES
static int _cenv (void);
#define LONG_ARGS_PRESENT (getenv ("_argc") != NULL)
#else
#define _cenv() 1
#define LONG_ARGS_PRESENT 0
#endif
#ifdef WANT_GLOBBING
#include <gnulib.h>
static int compare (char **s1, char **s2);
static int _cglob (void);
#else
#define _cglob() 1
#endif
int _cwild (void);
/* The external argument vector: */
extern int __argc;
extern char ** __argv;
/* This is the main entry point, decide whether we have a smart shell
or have to do the globbing ourselves. */
int
_cwild (void)
{
return LONG_ARGS_PRESENT ? _cenv () : _cglob ();
}
#ifdef WANT_LONG_COMMANDLINES
/* We have been called by a smart shell, get arguments from the
environment entries "_argc", "_argv0", "_argv1", ... */
int
_cenv (void)
{
int ind = 0;
char **argv;
/* We know that "_argc" is there! */
__argc = atoi (getenv ("_argc"));
if (__argc == 0)
return -1;
argv = (char **) malloc ((__argc + 1) * sizeof (char *));
if (argv == NULL)
return -1;
while (ind < __argc)
{
char entry[10];
char *p;
sprintf (entry, "_argv%d", ind);
p = getenv (entry);
if (p != 0)
argv[ind] = strcpy (malloc (strlen (p) + 1), p);
else
argv[ind] = strcpy (malloc (1), "");
ind++;
}
/* Terminate */
argv[__argc] = NULL;
/* Install */
__argv = argv;
return 0;
}
#endif /* WANT_LONG_COMMANDLINES */
#ifdef WANT_GLOBBING
/* During startup, perform filename globbing of __ARGV. By Microsoft
convention, the first letter of each member of __ARGV marks wether
globbing is to be performed for this specific name. If it is '\"',
the string is left alone. One has to be careful, not to include
this character in the result. */
int
_cglob (void)
{
int argc = __argc;
char **argv = __argv;
int optind;
/* Vector of vectors of globbed filenames, terminated by NULL.
If GLOB_ARGV[N] == -1, or if *(GLOB_ARGV[N]) == NULL, no
globbing has been performed and the original __ARGV[N] will
be used. (Strictly speaking, GLOB_ARGVV[0] is never used,
but we don't care.) */
char ***glob_argvv = (char ***) malloc (argc * sizeof (char **));
if (glob_argvv == NULL)
return -1;
__argc = 2; /* program name and terminating NULL */
/* Pass 1: Find out how much storage we need and allocate it. */
for (optind = 1; optind < argc; optind++)
{
/* there's at least one (the original argv[optind]). */
__argc++;
if (*(argv[optind])++ == '\"')
{
/* Don't glob ARGV[OPTIND], but strip the leading quote marker */
glob_argvv[optind] = (char **) -1;
}
else
{
char **ptr = glob_argvv[optind] = glob_filename (argv[optind]);
size_t cnt = 0;
/* we will ignore errors from glob_filename () and pass the
unexpanded argument */
if (ptr != (char **) -1 && *ptr++ != NULL)
while (*ptr++ != NULL)
cnt++;
/* Sort the globbed filenames */
if (cnt > 0)
qsort (glob_argvv[optind], cnt + 1, sizeof (char *), compare);
__argc += cnt;
}
}
__argv = (char **) malloc ((__argc + 1) * sizeof (char *));
if (__argv == NULL)
{
__argv = argv; /* failed */
return -1;
}
/* Pass 2: Build the new commandline. */
__argc = 1;
__argv[0] = argv[0];
if (*(__argv[0])++ != '\"') /* Reformat the program name. */
msdos_format_filename (__argv[0]);
for (optind = 1; optind < argc; optind++)
{
char **ptr = glob_argvv[optind];
/* Did we perform globbing? */
if (ptr == (char **) -1 || *ptr == NULL)
__argv[__argc++] = argv[optind];
else
while (*ptr)
__argv[__argc++] = *ptr++;
}
__argv[__argc] = NULL; /* terminate */
free (glob_argvv); /* cleanup */
return 0;
}
/* This is for passing strcmp () to qsort (). */
int
compare (char **s1, char **s2)
{
return strcmp (*s1, *s2);
}
#endif /* WANT_GLOBBING */
/* Filenames returned by MS-DOS system calls are formatted very ugly:
all uppercase and backslashes. Perform some cosmetics. */
char *
msdos_format_filename (char *name)
{
char *p = name;
while (*p = (*p == '\\') ? '/' : tolower (*p))
p++;
return name;
}
#ifdef TEST
void
main (int argc, char **argv)
{
if (*++argv)
{
printf ("%s", *argv);
while (*++argv)
printf (" %s", *argv);
}
exit (0);
}
#endif /* TEST */
/*
* Local Variables:
* mode:C
* ChangeLog:ChangeLog
* compile-command:cl -DSMART_SHELL -DTEST _cwild.c glob msd_dir d:\ms\lib\setgarv -link /noe
* End:
*/