summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/thread/argv.c
diff options
context:
space:
mode:
Diffstat (limited to 'winpr/libwinpr/thread/argv.c')
-rw-r--r--winpr/libwinpr/thread/argv.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/winpr/libwinpr/thread/argv.c b/winpr/libwinpr/thread/argv.c
new file mode 100644
index 0000000..3eedc41
--- /dev/null
+++ b/winpr/libwinpr/thread/argv.c
@@ -0,0 +1,279 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Process Argument Vector Functions
+ *
+ * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/handle.h>
+
+#include <winpr/thread.h>
+
+#ifdef WINPR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "../log.h"
+#define TAG WINPR_TAG("thread")
+
+/**
+ * CommandLineToArgvW function:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391/
+ *
+ * CommandLineToArgvW has a special interpretation of backslash characters
+ * when they are followed by a quotation mark character ("), as follows:
+ *
+ * 2n backslashes followed by a quotation mark produce n backslashes followed by a quotation mark.
+ * (2n) + 1 backslashes followed by a quotation mark again produce n backslashes followed by a
+ * quotation mark. n backslashes not followed by a quotation mark simply produce n backslashes.
+ *
+ * The address returned by CommandLineToArgvW is the address of the first element in an array of
+ * LPWSTR values; the number of pointers in this array is indicated by pNumArgs. Each pointer to a
+ * null-terminated Unicode string represents an individual argument found on the command line.
+ *
+ * CommandLineToArgvW allocates a block of contiguous memory for pointers to the argument strings,
+ * and for the argument strings themselves; the calling application must free the memory used by the
+ * argument list when it is no longer needed. To free the memory, use a single call to the LocalFree
+ * function.
+ */
+
+/**
+ * Parsing C++ Command-Line Arguments:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft
+ *
+ * Microsoft C/C++ startup code uses the following rules when
+ * interpreting arguments given on the operating system command line:
+ *
+ * Arguments are delimited by white space, which is either a space or a tab.
+ *
+ * The caret character (^) is not recognized as an escape character or delimiter.
+ * The character is handled completely by the command-line parser in the operating
+ * system before being passed to the argv array in the program.
+ *
+ * A string surrounded by double quotation marks ("string") is interpreted as a
+ * single argument, regardless of white space contained within. A quoted string
+ * can be embedded in an argument.
+ *
+ * A double quotation mark preceded by a backslash (\") is interpreted as a
+ * literal double quotation mark character (").
+ *
+ * Backslashes are interpreted literally, unless they immediately
+ * precede a double quotation mark.
+ *
+ * If an even number of backslashes is followed by a double quotation mark,
+ * one backslash is placed in the argv array for every pair of backslashes,
+ * and the double quotation mark is interpreted as a string delimiter.
+ *
+ * If an odd number of backslashes is followed by a double quotation mark,
+ * one backslash is placed in the argv array for every pair of backslashes,
+ * and the double quotation mark is "escaped" by the remaining backslash,
+ * causing a literal double quotation mark (") to be placed in argv.
+ *
+ */
+
+LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs)
+{
+ const char* p = NULL;
+ size_t length = 0;
+ const char* pBeg = NULL;
+ const char* pEnd = NULL;
+ char* buffer = NULL;
+ char* pOutput = NULL;
+ int numArgs = 0;
+ LPSTR* pArgs = NULL;
+ size_t maxNumArgs = 0;
+ size_t maxBufferSize = 0;
+ size_t cmdLineLength = 0;
+ BOOL* lpEscapedChars = NULL;
+ LPSTR lpEscapedCmdLine = NULL;
+
+ if (!lpCmdLine)
+ return NULL;
+
+ if (!pNumArgs)
+ return NULL;
+
+ pArgs = NULL;
+ lpEscapedCmdLine = NULL;
+ cmdLineLength = strlen(lpCmdLine);
+ lpEscapedChars = (BOOL*)calloc(cmdLineLength + 1, sizeof(BOOL));
+
+ if (!lpEscapedChars)
+ return NULL;
+
+ if (strstr(lpCmdLine, "\\\""))
+ {
+ size_t n = 0;
+ const char* pLastEnd = NULL;
+ lpEscapedCmdLine = (char*)calloc(cmdLineLength + 1, sizeof(char));
+
+ if (!lpEscapedCmdLine)
+ {
+ free(lpEscapedChars);
+ return NULL;
+ }
+
+ p = (const char*)lpCmdLine;
+ pLastEnd = (const char*)lpCmdLine;
+ pOutput = (char*)lpEscapedCmdLine;
+
+ while (p < &lpCmdLine[cmdLineLength])
+ {
+ pBeg = strstr(p, "\\\"");
+
+ if (!pBeg)
+ {
+ length = strlen(p);
+ CopyMemory(pOutput, p, length);
+ pOutput += length;
+ break;
+ }
+
+ pEnd = pBeg + 2;
+
+ while (pBeg >= lpCmdLine)
+ {
+ if (*pBeg != '\\')
+ {
+ pBeg++;
+ break;
+ }
+
+ pBeg--;
+ }
+
+ n = ((pEnd - pBeg) - 1);
+ length = (pBeg - pLastEnd);
+ CopyMemory(pOutput, p, length);
+ pOutput += length;
+ p += length;
+
+ for (size_t i = 0; i < (n / 2); i++)
+ *pOutput++ = '\\';
+
+ p += n + 1;
+
+ if ((n % 2) != 0)
+ lpEscapedChars[pOutput - lpEscapedCmdLine] = TRUE;
+
+ *pOutput++ = '"';
+ pLastEnd = p;
+ }
+
+ *pOutput++ = '\0';
+ lpCmdLine = (LPCSTR)lpEscapedCmdLine;
+ cmdLineLength = strlen(lpCmdLine);
+ }
+
+ maxNumArgs = 2;
+ p = (const char*)lpCmdLine;
+
+ while (p < lpCmdLine + cmdLineLength)
+ {
+ p += strcspn(p, " \t");
+ p += strspn(p, " \t");
+ maxNumArgs++;
+ }
+
+ maxBufferSize = (maxNumArgs * (sizeof(char*))) + (cmdLineLength + 1);
+ buffer = calloc(maxBufferSize, sizeof(char));
+
+ if (!buffer)
+ {
+ free(lpEscapedCmdLine);
+ free(lpEscapedChars);
+ return NULL;
+ }
+
+ pArgs = (LPSTR*)buffer;
+ pOutput = (char*)&buffer[maxNumArgs * (sizeof(char*))];
+ p = (const char*)lpCmdLine;
+
+ while (p < lpCmdLine + cmdLineLength)
+ {
+ pBeg = p;
+
+ while (1)
+ {
+ p += strcspn(p, " \t\"\0");
+
+ if ((*p != '"') || !lpEscapedChars[p - lpCmdLine])
+ break;
+
+ p++;
+ }
+
+ if (*p != '"')
+ {
+ /* no whitespace escaped with double quotes */
+ length = (p - pBeg);
+ CopyMemory(pOutput, pBeg, length);
+ pOutput[length] = '\0';
+ pArgs[numArgs++] = pOutput;
+ pOutput += (length + 1);
+ }
+ else
+ {
+ p++;
+
+ while (1)
+ {
+ p += strcspn(p, "\"\0");
+
+ if ((*p != '"') || !lpEscapedChars[p - lpCmdLine])
+ break;
+
+ p++;
+ }
+
+ if (*p != '"')
+ WLog_ERR(TAG, "parsing error: uneven number of unescaped double quotes!");
+
+ if (*p && *(++p))
+ p += strcspn(p, " \t\0");
+
+ pArgs[numArgs++] = pOutput;
+
+ while (pBeg < p)
+ {
+ if (*pBeg != '"')
+ *pOutput++ = *pBeg;
+
+ pBeg++;
+ }
+
+ *pOutput++ = '\0';
+ }
+
+ p += strspn(p, " \t");
+ }
+
+ free(lpEscapedCmdLine);
+ free(lpEscapedChars);
+ *pNumArgs = numArgs;
+ return pArgs;
+}
+
+#ifndef _WIN32
+
+LPWSTR* CommandLineToArgvW(LPCWSTR lpCmdLine, int* pNumArgs)
+{
+ return NULL;
+}
+
+#endif