newlib/winsup/mingw/samples/fixargv/fixargv.c

291 lines
5.3 KiB
C

/*
* 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);
}