OSDN Git Service

Enable to track git://github.com/monaka/binutils.git
[pf3gnuchains/pf3gnuchains3x.git] / winsup / mingw / samples / fixargv / fixargv.c
diff --git a/winsup/mingw/samples/fixargv/fixargv.c b/winsup/mingw/samples/fixargv/fixargv.c
new file mode 100644 (file)
index 0000000..c2e2a41
--- /dev/null
@@ -0,0 +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);
+}
+