Merging MinGW changes

This commit is contained in:
Earnie Boyd
2002-05-28 13:13:45 +00:00
parent ad39fa8cb0
commit 4ad1e6fedb
46 changed files with 1877 additions and 1877 deletions

View File

@ -1,290 +1,290 @@
/*
* fixargv.c
*
* A special function which "fixes" an argv array by replacing arguments
* that need quoting with quoted versions.
*
* NOTE: In order to be reasonably consistent there is some misuse of the
* const keyword here-- which leads to compilation warnings. These
* should be ok to ignore.
*
* This is a sample distributed as part of the Mingw32 package.
*
* Contributors:
* Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAMED. This includes but is not limited to warrenties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Revision$
* $Author$
* $Date$
*
*/
#include <string.h>
#include "fixargv.h"
/*
* This takes a single string and fixes it, enclosing it in quotes if it
* contains any spaces and/or escaping the quotes it contains.
*/
char*
fix_arg (const char* szArg)
{
int nQuoteAll; /* Does the whole arg need quoting? */
int nBkSlRun; /* How may backslashes in a row? */
char* sz;
char* szNew;
size_t sizeLen;
nQuoteAll = 0;
nBkSlRun = 0;
sz = szArg;
sizeLen = 1;
/* First we figure out how much bigger the new string has to be
* than the old one. */
while (*sz != '\0')
{
/*
* Arguments containing whitespace of wildcards will be
* quoted to preserve tokenization and/or those special
* characters (i.e. wildcarding will NOT be done at the
* other end-- they will get the * and ? characters as is).
* TODO: Is this the best way? Do we want to enable wildcards?
* If so, when?
*/
if (!nQuoteAll &&
(*sz == ' ' || *sz == '\t' || *sz == '*' || *sz == '?'))
{
nQuoteAll = 1;
}
else if (*sz == '\\')
{
nBkSlRun++;
}
else
{
if (*sz == '\"')
{
sizeLen += nBkSlRun + 1;
}
nBkSlRun = 0;
}
sizeLen++;
sz++;
}
if (nQuoteAll)
{
sizeLen += 2;
}
/*
* Make a new string big enough.
*/
szNew = (char*) malloc (sizeLen);
if (!szNew)
{
return NULL;
}
sz = szNew;
/* First enclosing quote for fully quoted args. */
if (nQuoteAll)
{
*sz = '\"';
sz++;
}
/*
* Go through the string putting backslashes in front of quotes,
* and doubling all backslashes immediately in front of quotes.
*/
nBkSlRun = 0;
while (*szArg != '\0')
{
if (*szArg == '\\')
{
nBkSlRun++;
}
else
{
if (*szArg == '\"')
{
while (nBkSlRun > 0)
{
*sz = '\\';
sz++;
nBkSlRun--;
}
*sz = '\\';
sz++;
}
nBkSlRun = 0;
}
*sz = *szArg;
sz++;
szArg++;
}
/* Closing quote for fully quoted args. */
if (nQuoteAll)
{
*sz = '\"';
sz++;
}
*sz = '\0';
return szNew;
}
/*
* Takes argc and argv and returns a new argv with escaped members. Pass
* this fixed argv (along with the old one) to free_fixed_argv after
* you finish with it. Pass in an argc of -1 and make sure the argv vector
* ends with a null pointer to have fix_argv count the arguments for you.
*/
char* const*
fix_argv (int argc, char* const* szaArgv)
{
char** szaNew;
char* sz;
int i;
if (!szaArgv)
{
return NULL;
}
/*
* Count the arguments if asked.
*/
if (argc == -1)
{
for (i = 0; szaArgv[i]; i++)
;
argc = i;
}
/*
* If there are no args or only one arg then do no escaping.
*/
if (argc < 2)
{
return szaArgv;
}
for (i = 1, szaNew = NULL; i < argc; i++)
{
sz = szaArgv[i];
/*
* If an argument needs fixing, then fix it.
*/
if (strpbrk (sz, "\" \t*?"))
{
/*
* If we haven't created a new argv list already
* then make one.
*/
if (!szaNew)
{
szaNew = (char**) malloc ((argc + 1) *
sizeof (char*));
if (!szaNew)
{
return NULL;
}
/*
* Copy previous args from old to new.
*/
memcpy (szaNew, szaArgv, sizeof(char*) * i);
}
/*
* Now do the fixing.
*/
szaNew[i] = fix_arg (sz);
if (!szaNew[i])
{
/* Fixing failed, free up and return error. */
free_fixed_argv (szaNew, szaArgv);
return NULL;
}
}
else if (szaNew)
{
szaNew[i] = sz;
}
}
if (szaNew)
{
/* If we have created a new argv list then we might as well
* terminate it nicely. (And we depend on it in
* free_fixed_argv.) */
szaNew[argc] = NULL;
}
else
{
/* If we didn't create a new argv list then return the
* original. */
return szaArgv;
}
return szaNew;
}
void
free_fixed_argv (char* const* szaFixed, char* const* szaOld)
{
char* const* sza;
/*
* Check for error conditions. Also note that if no corrections
* were required the fixed argv will actually be the same as
* the old one, and we don't need to do anything.
*/
if (!szaFixed || !szaOld || szaFixed == szaOld)
{
return;
}
/*
* Go through all members of the argv list. If any of the
* members in the fixed list are different from the old
* list we free those members.
* NOTE: The first member is never modified, so we don't need to
* check.
*/
sza = szaFixed + 1;
szaOld++;
while (*sza)
{
if (*sza != *szaOld)
{
free (*sza);
}
sza++;
szaOld++;
}
/*
* Now we can free the array of char pointers itself.
*/
free (szaFixed);
}
/*
* fixargv.c
*
* A special function which "fixes" an argv array by replacing arguments
* that need quoting with quoted versions.
*
* NOTE: In order to be reasonably consistent there is some misuse of the
* const keyword here-- which leads to compilation warnings. These
* should be ok to ignore.
*
* This is a sample distributed as part of the Mingw32 package.
*
* Contributors:
* Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAMED. This includes but is not limited to warrenties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Revision$
* $Author$
* $Date$
*
*/
#include <string.h>
#include "fixargv.h"
/*
* This takes a single string and fixes it, enclosing it in quotes if it
* contains any spaces and/or escaping the quotes it contains.
*/
char*
fix_arg (const char* szArg)
{
int nQuoteAll; /* Does the whole arg need quoting? */
int nBkSlRun; /* How may backslashes in a row? */
char* sz;
char* szNew;
size_t sizeLen;
nQuoteAll = 0;
nBkSlRun = 0;
sz = szArg;
sizeLen = 1;
/* First we figure out how much bigger the new string has to be
* than the old one. */
while (*sz != '\0')
{
/*
* Arguments containing whitespace of wildcards will be
* quoted to preserve tokenization and/or those special
* characters (i.e. wildcarding will NOT be done at the
* other end-- they will get the * and ? characters as is).
* TODO: Is this the best way? Do we want to enable wildcards?
* If so, when?
*/
if (!nQuoteAll &&
(*sz == ' ' || *sz == '\t' || *sz == '*' || *sz == '?'))
{
nQuoteAll = 1;
}
else if (*sz == '\\')
{
nBkSlRun++;
}
else
{
if (*sz == '\"')
{
sizeLen += nBkSlRun + 1;
}
nBkSlRun = 0;
}
sizeLen++;
sz++;
}
if (nQuoteAll)
{
sizeLen += 2;
}
/*
* Make a new string big enough.
*/
szNew = (char*) malloc (sizeLen);
if (!szNew)
{
return NULL;
}
sz = szNew;
/* First enclosing quote for fully quoted args. */
if (nQuoteAll)
{
*sz = '\"';
sz++;
}
/*
* Go through the string putting backslashes in front of quotes,
* and doubling all backslashes immediately in front of quotes.
*/
nBkSlRun = 0;
while (*szArg != '\0')
{
if (*szArg == '\\')
{
nBkSlRun++;
}
else
{
if (*szArg == '\"')
{
while (nBkSlRun > 0)
{
*sz = '\\';
sz++;
nBkSlRun--;
}
*sz = '\\';
sz++;
}
nBkSlRun = 0;
}
*sz = *szArg;
sz++;
szArg++;
}
/* Closing quote for fully quoted args. */
if (nQuoteAll)
{
*sz = '\"';
sz++;
}
*sz = '\0';
return szNew;
}
/*
* Takes argc and argv and returns a new argv with escaped members. Pass
* this fixed argv (along with the old one) to free_fixed_argv after
* you finish with it. Pass in an argc of -1 and make sure the argv vector
* ends with a null pointer to have fix_argv count the arguments for you.
*/
char* const*
fix_argv (int argc, char* const* szaArgv)
{
char** szaNew;
char* sz;
int i;
if (!szaArgv)
{
return NULL;
}
/*
* Count the arguments if asked.
*/
if (argc == -1)
{
for (i = 0; szaArgv[i]; i++)
;
argc = i;
}
/*
* If there are no args or only one arg then do no escaping.
*/
if (argc < 2)
{
return szaArgv;
}
for (i = 1, szaNew = NULL; i < argc; i++)
{
sz = szaArgv[i];
/*
* If an argument needs fixing, then fix it.
*/
if (strpbrk (sz, "\" \t*?"))
{
/*
* If we haven't created a new argv list already
* then make one.
*/
if (!szaNew)
{
szaNew = (char**) malloc ((argc + 1) *
sizeof (char*));
if (!szaNew)
{
return NULL;
}
/*
* Copy previous args from old to new.
*/
memcpy (szaNew, szaArgv, sizeof(char*) * i);
}
/*
* Now do the fixing.
*/
szaNew[i] = fix_arg (sz);
if (!szaNew[i])
{
/* Fixing failed, free up and return error. */
free_fixed_argv (szaNew, szaArgv);
return NULL;
}
}
else if (szaNew)
{
szaNew[i] = sz;
}
}
if (szaNew)
{
/* If we have created a new argv list then we might as well
* terminate it nicely. (And we depend on it in
* free_fixed_argv.) */
szaNew[argc] = NULL;
}
else
{
/* If we didn't create a new argv list then return the
* original. */
return szaArgv;
}
return szaNew;
}
void
free_fixed_argv (char* const* szaFixed, char* const* szaOld)
{
char* const* sza;
/*
* Check for error conditions. Also note that if no corrections
* were required the fixed argv will actually be the same as
* the old one, and we don't need to do anything.
*/
if (!szaFixed || !szaOld || szaFixed == szaOld)
{
return;
}
/*
* Go through all members of the argv list. If any of the
* members in the fixed list are different from the old
* list we free those members.
* NOTE: The first member is never modified, so we don't need to
* check.
*/
sza = szaFixed + 1;
szaOld++;
while (*sza)
{
if (*sza != *szaOld)
{
free (*sza);
}
sza++;
szaOld++;
}
/*
* Now we can free the array of char pointers itself.
*/
free (szaFixed);
}

View File

@ -1,24 +1,24 @@
/*
* fixargv.h
*
* Prototypes of utility functions for 'properly' escaping argv vectors.
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* $Revision$
* $Author$
* $Date$
*
*/
#ifndef _FIXARGV_H_
#define _FIXARGV_H_
char* fix_arg (const char* szArg);
char* const* fix_argv (int argc, char* const* szaArgv);
void free_fixed_argv (char* const* szaFixed, char* const* szaOld);
#endif
/*
* fixargv.h
*
* Prototypes of utility functions for 'properly' escaping argv vectors.
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* $Revision$
* $Author$
* $Date$
*
*/
#ifndef _FIXARGV_H_
#define _FIXARGV_H_
char* fix_arg (const char* szArg);
char* const* fix_argv (int argc, char* const* szaArgv);
void free_fixed_argv (char* const* szaFixed, char* const* szaOld);
#endif

View File

@ -1,85 +1,85 @@
This code is a utility function I was considering adding to Mingw32. The
Microsoft versions of argc, argv construction use quotes and backslashes
to allow the user to pass arguments containing spaces (or quotes) to
programs they invoke. The rules are
- Arguments containing spaces must be enclosed in quotes.
- A quote can be passed by preceeding it with a backslash.
- Backslashes immediately preceeding a quote must be doubled to avoid
escaping the quote.
Thus an argument like:
-D="Foo Bar\\"
needs to be mangled as:
"-D\"Foo Bar\\\\\""
in order to get to the program as what was intended above.
The fix_argv set of functions is meant to be used with spawnv and the
like to allow a program to set up an argv array for the spawned program
and have that array duplicated *exactly* in the spawned program, no
matter what it contains (it also quotes 'globbing' characters like *
and ?, so it does not matter if the destination has globbing turned on
or not; it might be a reasonable extension to allow a flag to allow
globbing characters to pass through unmolested, but they would still
be quoted if the string contained whitespace).
The reason for writing this came up because of problems with arguments
like -DBLAH="Foo Bar" to GCC (define BLAH as a preprocessor constant
being the string "Foo Bar", including the quotes). Because GCC simply
passes the argument directly to CPP (the preprocessor) it had to be
escaped *twice*:
"-DBLAH=\"\\\"Foo Bar\\\"\""
This would reach GCC as
-DBLAH="\"Foo Bar\""
And that would reach CPP as the desired
-DBLAH="Foo Bar"
One level of quoting and escaping is to be expected (although MS's
standard is, arguably, not very good), but forcing the user to know
how many different programs the argument is going to pass through,
and perform double quoting and escaping, seems unreasonable. If
GCC and friends all used fix_argv (they use their own version of
it now) then the original argument could be
"-DBLAH=\"Foo Bar\""
And that would work fine, no matter how many different tools it
passed through.
The only basic limitation with this code is that it assumes that all
the spawned programs use Microsoft-type escaping when interpreting
their command line. Most programs on Win32 machines do (anything
compiled with Mingw32 will).
For now, this code has been relegated to 'sample' status. If you want
to use it, feel free (it is public domain after all).
Colin.
P.S. Just out of interest you might try writing your own little program
to look at the interaction of wildcards and quotes. Use the glob.exe
program in ../globbing and see what it does with
glob "foo*.txt"
even if there are files foo.txt and foobar.txt in the same directory.
Note that
del "My *.txt"
works (i.e. it deletes all files starting with My<space>). This could
not be done unless del does globbing *after* processing escapes and
quotes, which is not the way it seems to work normally (again see
the glob example).
This code is a utility function I was considering adding to Mingw32. The
Microsoft versions of argc, argv construction use quotes and backslashes
to allow the user to pass arguments containing spaces (or quotes) to
programs they invoke. The rules are
- Arguments containing spaces must be enclosed in quotes.
- A quote can be passed by preceeding it with a backslash.
- Backslashes immediately preceeding a quote must be doubled to avoid
escaping the quote.
Thus an argument like:
-D="Foo Bar\\"
needs to be mangled as:
"-D\"Foo Bar\\\\\""
in order to get to the program as what was intended above.
The fix_argv set of functions is meant to be used with spawnv and the
like to allow a program to set up an argv array for the spawned program
and have that array duplicated *exactly* in the spawned program, no
matter what it contains (it also quotes 'globbing' characters like *
and ?, so it does not matter if the destination has globbing turned on
or not; it might be a reasonable extension to allow a flag to allow
globbing characters to pass through unmolested, but they would still
be quoted if the string contained whitespace).
The reason for writing this came up because of problems with arguments
like -DBLAH="Foo Bar" to GCC (define BLAH as a preprocessor constant
being the string "Foo Bar", including the quotes). Because GCC simply
passes the argument directly to CPP (the preprocessor) it had to be
escaped *twice*:
"-DBLAH=\"\\\"Foo Bar\\\"\""
This would reach GCC as
-DBLAH="\"Foo Bar\""
And that would reach CPP as the desired
-DBLAH="Foo Bar"
One level of quoting and escaping is to be expected (although MS's
standard is, arguably, not very good), but forcing the user to know
how many different programs the argument is going to pass through,
and perform double quoting and escaping, seems unreasonable. If
GCC and friends all used fix_argv (they use their own version of
it now) then the original argument could be
"-DBLAH=\"Foo Bar\""
And that would work fine, no matter how many different tools it
passed through.
The only basic limitation with this code is that it assumes that all
the spawned programs use Microsoft-type escaping when interpreting
their command line. Most programs on Win32 machines do (anything
compiled with Mingw32 will).
For now, this code has been relegated to 'sample' status. If you want
to use it, feel free (it is public domain after all).
Colin.
P.S. Just out of interest you might try writing your own little program
to look at the interaction of wildcards and quotes. Use the glob.exe
program in ../globbing and see what it does with
glob "foo*.txt"
even if there are files foo.txt and foobar.txt in the same directory.
Note that
del "My *.txt"
works (i.e. it deletes all files starting with My<space>). This could
not be done unless del does globbing *after* processing escapes and
quotes, which is not the way it seems to work normally (again see
the glob example).