Skip to content

Commit

Permalink
libwinpr-utils: started command-line parser
Browse files Browse the repository at this point in the history
  • Loading branch information
awakecoding committed Nov 2, 2012
1 parent fc1b789 commit f62180e
Show file tree
Hide file tree
Showing 6 changed files with 354 additions and 2 deletions.
65 changes: 65 additions & 0 deletions winpr/include/winpr/cmdline.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* WinPR: Windows Portable Runtime
* Command-Line Utils
*
* Copyright 2012 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.
*/

#ifndef WINPR_CMDLINE_H
#define WINPR_CMDLINE_H

#include <winpr/winpr.h>
#include <winpr/wtypes.h>

#define COMMAND_LINE_VALUE_FLAG 0x00000001
#define COMMAND_LINE_VALUE_REQUIRED 0x00000002
#define COMMAND_LINE_VALUE_OPTIONAL 0x00000004
#define COMMAND_LINE_VALUE_BOOLEAN 0x00000008

#define COMMAND_LINE_VALUE_PRESENT 0x80000001

struct _COMMAND_LINE_ARGUMENT_A
{
LPCSTR Name;
DWORD Flags;
LPSTR Value;
};
typedef struct _COMMAND_LINE_ARGUMENT_A COMMAND_LINE_ARGUMENT_A;

struct _COMMAND_LINE_ARGUMENT_W
{
LPCWSTR Name;
DWORD Flags;
LPWSTR Value;
};
typedef struct _COMMAND_LINE_ARGUMENT_W COMMAND_LINE_ARGUMENT_W;

#ifdef UNICODE
#define COMMAND_LINE_ARGUMENT COMMAND_LINE_ARGUMENT_W
#else
#define COMMAND_LINE_ARGUMENT COMMAND_LINE_ARGUMENT_A
#endif

WINPR_API int CommandLineParseArgumentsA(int argc, LPCSTR* argv, COMMAND_LINE_ARGUMENT_A* options, DWORD flags);
WINPR_API int CommandLineParseArgumentsW(int argc, LPCWSTR* argv, COMMAND_LINE_ARGUMENT_W* options, DWORD flags);

#ifdef UNICODE
#define CommandLineParseArguments CommandLineParseArgumentsW
#else
#define CommandLineParseArguments CommandLineParseArgumentsA
#endif

#endif /* WINPR_CMDLINE_H */

10 changes: 8 additions & 2 deletions winpr/libwinpr/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ set(MODULE_NAME "winpr-utils")
set(MODULE_PREFIX "WINPR_UTILS")

set(${MODULE_PREFIX}_SRCS
sam.c
ntlm.c
print.c
sam.c
stream.c)
stream.c
cmdline.c)

include_directories(${ZLIB_INCLUDE_DIRS})
include_directories(${OPENSSL_INCLUDE_DIR})
Expand Down Expand Up @@ -50,3 +51,8 @@ else()
endif()

set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")

if(BUILD_TESTING)
add_subdirectory(test)
endif()

190 changes: 190 additions & 0 deletions winpr/libwinpr/utils/cmdline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/**
* WinPR: Windows Portable Runtime
* Command-Line Utils
*
* Copyright 2012 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.
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <winpr/crt.h>

#include <winpr/cmdline.h>

/**
* Command-line syntax: some basic concepts:
* https://pythonconquerstheuniverse.wordpress.com/2010/07/25/command-line-syntax-some-basic-concepts/
*/

/**
* Remote Desktop Connection Usage
*
* mstsc [<connection file>] [/v:<server[:port]>] [/admin] [/f[ullscreen]]
* [/w:<width>] [/h:<height>] [/public] | [/span] [/multimon] [/migrate]
* [/edit "connection file"] [/?]
*
* "connection file" -- Specifies the name of an .RDP for the connection.
*
* /v:<server[:port]> -- Specifies the remote computer to which you want
* to connect.
*
* /admin -- Connects you to the session for administering a server.
*
* /f -- Starts Remote Desktop in full-screen mode.
*
* /w:<width> -- Specifies the width of the Remote Desktop window.
*
* /h:<height> -- Specifies the height of the Remote Desktop window.
*
* /public -- Runs Remote Desktop in public mode.
*
* /span -- Matches the remote desktop width and height with the local
* virtual desktop, spanning across multiple monitors if necessary. To
* span across monitors, the monitors must be arranged to form a
* rectangle.
*
* /multimon -- Configures the remote desktop session layout to
* be identical to the current client-side configuration.
*
* /edit -- Opens the specified .RDP connection file for editing.
*
* /migrate -- Migrates legacy connection files that were created with
* Client Connection Manager to new .RDP connection files.
*
* /? -- Lists these parameters.
*/

/**
* Command-Line Syntax:
*
* <sigil><keyword><separator><value>
*
* <sigil>: '/' or '-'
*
* <keyword>: option, named argument, flag
*
* <separator>: ':' or '='
*
* <value>: argument value
*
*/

int CommandLineParseArgumentsA(int argc, LPCSTR* argv, COMMAND_LINE_ARGUMENT_A* options, DWORD flags)
{
int i, j;
int length;
char* sigil;
int sigil_length;
int sigil_index;
char* keyword;
int keyword_length;
int keyword_index;
char* separator;
int separator_length;
int separator_index;
char* value;
int value_length;
int value_index;

for (i = 1; i < argc; i++)
{
sigil_index = 0;
sigil = (char*) &argv[i][sigil_index];
length = strlen(argv[i]);

if (sigil[sigil_index] == '/')
{
sigil_length = 1;

if (length < (sigil_length + 1))
return -1;

keyword_index = sigil_index + sigil_length;
keyword = (char*) &argv[i][keyword_index];

separator = strchr(keyword, ':');

if (separator)
{
separator_length = 1;
separator_index = (separator - argv[i]);

keyword_length = (separator - keyword);
printf("option: %.*s ", keyword_length, keyword);

value_index = separator_index + separator_length;
value = (char*) &argv[i][value_index];
value_length = (length - value_index);
}
else
{
separator_length = 0;
separator_index = -1;

keyword_length = (length - keyword_index);
printf("option: %.*s ", keyword_length, keyword);

value_index = -1;
value = NULL;
value_length = 0;
}

for (j = 0; options[j].Name != NULL; j++)
{
if (strncmp(options[j].Name, keyword, keyword_length) == 0)
{
if (strlen(options[j].Name) == keyword_length)
{
printf("option: %.*s", keyword_length, keyword);

if (value)
printf(" value: %s", value);

printf("\n");

if (value && (options[j].Flags & COMMAND_LINE_VALUE_FLAG))
return -1;

if (!value && (options[j].Flags & COMMAND_LINE_VALUE_REQUIRED))
return -1;

if (value)
{
options[j].Value = value;
options[j].Flags |= COMMAND_LINE_VALUE_PRESENT;
}
else
{
if (options[j].Flags & COMMAND_LINE_VALUE_FLAG)
{
options[j].Value = (LPSTR) 1;
options[j].Flags |= COMMAND_LINE_VALUE_PRESENT;
}
}
}
}
}
}
}

return 0;
}

int CommandLineParseArgumentsW(int argc, LPCWSTR* argv, COMMAND_LINE_ARGUMENT_W* options, DWORD flags)
{
return 0;
}
3 changes: 3 additions & 0 deletions winpr/libwinpr/utils/test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TestWinPRUtils
TestWinPRUtils.c

31 changes: 31 additions & 0 deletions winpr/libwinpr/utils/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

set(MODULE_NAME "TestWinPRUtils")
set(MODULE_PREFIX "TEST_WINPR_UTILS")

set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)

set(${MODULE_PREFIX}_TESTS
TestCmdLine.c)

create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
${${MODULE_PREFIX}_TESTS})

add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})

set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-utils)

target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")

foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()

set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

57 changes: 57 additions & 0 deletions winpr/libwinpr/utils/test/TestCmdLine.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/cmdline.h>

const char* testArgv[] =
{
"mstsc.exe",
"/w:1024",
"/h:768",
"/admin",
"/multimon",
"/v:localhost:3389"
};

COMMAND_LINE_ARGUMENT_A args[] =
{
{ "w", COMMAND_LINE_VALUE_REQUIRED },
{ "h", COMMAND_LINE_VALUE_REQUIRED },
{ "f", COMMAND_LINE_VALUE_FLAG },
{ "admin", COMMAND_LINE_VALUE_FLAG },
{ "multimon", COMMAND_LINE_VALUE_FLAG },
{ "v", COMMAND_LINE_VALUE_REQUIRED },
{ "?", COMMAND_LINE_VALUE_FLAG },
{ NULL, 0 }
};

#define testArgc (sizeof(testArgv) / sizeof(testArgv[0]))

int TestCmdLine(int argc, char* argv[])
{
if (CommandLineParseArgumentsA(testArgc, testArgv, args, 0) != 0)
return -1;

if (strcmp("1024", args[0].Value) != 0)
return -1;

if (strcmp("768", args[1].Value) != 0)
return -1;

if (args[2].Value)
return -1;

if (!args[3].Value)
return -1;

if (!args[4].Value)
return -1;

if (strcmp("localhost:3389", args[5].Value) != 0)
return -1;

if (args[6].Value)
return -1;

return 0;
}

0 comments on commit f62180e

Please sign in to comment.