about summary refs log tree commit diff stats
path: root/getopt/article.md
diff options
context:
space:
mode:
Diffstat (limited to 'getopt/article.md')
-rw-r--r--getopt/article.md224
1 files changed, 224 insertions, 0 deletions
diff --git a/getopt/article.md b/getopt/article.md
new file mode 100644
index 0000000..68c2c0d
--- /dev/null
+++ b/getopt/article.md
@@ -0,0 +1,224 @@
+Full getopt Port for Unicode and Multibyte Microsoft Visual C, C++, or MFC Projects
+===================================================================================
+
+Ludvik Jerabek, 15 Oct 2012
+
+Originally published at https://www.codeproject.com/Articles/157001/Full-getopt-Port-for-Unicode-and-Multibyte-Microso/
+
+
+Introduction
+------------
+
+This software was written after hours of searching for a robust Microsoft C and C++ implementation of getopt,
+which led to devoid results.
+
+This software is a modification of the Free Software Foundation, Inc. getopt library for parsing command line arguments
+and its purpose is to provide a Microsoft Visual C friendly derivative. The source code provides functionality for both
+Unicode and Multibyte builds and supports `getopt`, `getopt_long`, and `getopt_long_only`. Additionally the code supports the
+`POSIXLY_CORRECT` environment flag. The library uses the `_UNICODE` preprocessor directive when defining the `getopt`, `getopt_long`,
+and `getopt_long_only` functions. These functions are mapped back to `getopt_a`\`getopt_w`, `getopt_long_a`\`getopt_long_w`, and
+`getopt_long_only_a`\`getopt_long_only_w` respectively. This improvement was made to allow a single DLL to be used in both
+multibyte and Unicode projects.
+
+The original GNU code used several header and implementation files containing numerous preprocessor directives specific
+to Linux environments which have been removed. After removing unneeded dependencies, it was condensed into a single
+header and implementation file which can be compiled into a DLL, LIB, or directly included into any Visual C, C++, or MFC
+project. The getopt library can be used by proprietary software, however; certain measures need to be taken to ensure
+proprietary code adheres to the Lesser GNU Public License for non-derivative works. Please refer to the licensing section
+of this article for more details on how this software is licensed.
+
+For the sake of brevity, this article doesn't discuss how to use the `getopt` functions. Anyone new to using the `getopt`
+functions should refer to the GNU tutorial for using getopt.
+
+Licensing
+---------
+
+Since `getopt` is licensed under LGPL, it is free to use in proprietary software under some restrictions.
+When using this library as part of a proprietary software solution, it is important that the library is used as
+a dynamically linked library (DLL) and is not statically linked or directly compiled into proprietary source code.
+Static linkage requires that your software be released GPL. Therefore, by keeping the library separately referenced
+via Dynamic Link Library (DLL), allows the DLL to be modified and updated without changing the proprietary software
+which utilizes the library; under this condition proprietary software is said to "use" the library. Thus, it is not
+considered to be a derivative work and can be distributed freely under any license.
+
+Preprocessor Definitions
+------------------------
+
+Compiling `getopt` as a Dynamic Link Library (DLL) requires the preprocessor definition of `EXPORTS_GETOPT`.
+The definition of `EXPORTS_GETOPT` sets the internal preprocessor definition `_GETOPT_API` to the value `__declspec(dllexport)`.
+Compiling getopt as a Static Library (LIB) or directly including the source and header file within a project requires the
+preprocessor definition of `STATIC_GETOPT`. The definition of `STATIC_GETOPT` clears the value of the internal preprocessor definition
+of `_GETOPT_API`. Compiling software to use _getopt.dll_ requires that no library specific preprocessor definitions be used.
+When no library specific preprocessor definitions are used the value assigned to the internal preprocessor definition `_GETOPT_API` is `__declspec(dllimport)`.
+
+The code segment below demonstrates the logic outlined above:
+
+```c
+#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
+    #error "The preprocessor definitions of EXPORTS_GETOPT 
+        and STATIC_GETOPT can only be used individually"
+#elif defined(STATIC_GETOPT)
+#pragma message("Warning static builds of getopt violate the Lesser GNU Public License")
+    #define _GETOPT_API
+#elif defined(EXPORTS_GETOPT)
+    #pragma message("Exporting getopt library")
+    #define _GETOPT_API __declspec(dllexport)    
+#else
+    #pragma message("Importing getopt library")
+    #define _GETOPT_API __declspec(dllimport)
+#endif
+```
+
+The following code segment located in _getopt.h_ is responsible for mapping the correct version of the `getopt`, `getopt_long`,
+and `getopt_long_only` functions. The `getopt` functions appended with `_a` to denote ANSI characters using the char type and
+Unicode functions are appended with `_w` to denote wide characters using the `wchar_t` type.
+
+```c
+#ifdef _UNICODE
+    #define getopt getopt_w
+    #define getopt_long getopt_long_w
+    #define getopt_long_only getopt_long_only_w
+    #define option option_w
+    #define optarg optarg_w
+#else
+    #define getopt getopt_a
+    #define getopt_long getopt_long_a
+    #define getopt_long_only getopt_long_only_a
+    #define option option_a
+    #define optarg optarg_a
+#endif
+```
+
+Using the Code
+---------------
+
+The code is used identical to GNU `getopt`.
+
+```c
+#include <stdio.h>
+#include <stdlib.h>
+#include "tchar.h"
+#include "getopt.h"
+
+int _tmain(int argc, TCHAR** argv)
+{
+    static int verbose_flag;
+    int c;
+
+    while (1)
+    {        
+        static struct option long_options[] =
+        {
+            {_T("verbose"), ARG_NONE, &verbose_flag, 1},
+            {_T("brief"),   ARG_NONE, &verbose_flag, 0},
+            {_T("add"),     ARG_NONE, 0, _T('a')},
+            {_T("append"),  ARG_NONE, 0, _T('b')},
+            {_T("delete"),  ARG_REQ,  0, _T('d')},
+            {_T("create"),  ARG_REQ,  0, _T('c')},
+            {_T("file"),    ARG_REQ, 0 , _T('f')},
+            { ARG_NULL , ARG_NULL , ARG_NULL , ARG_NULL }
+        };
+
+        int option_index = 0;
+        c = getopt_long(argc, argv, _T("abc:d:f:"), long_options, &option_index);
+
+        // Check for end of operation or error
+        if (c == -1)
+            break;
+
+        // Handle options
+        switch (c)
+        {
+        case 0:
+            /* If this option set a flag, do nothing else now. */
+            if (long_options[option_index].flag != 0)
+                break;
+            _tprintf (_T("option %s"), long_options[option_index].name);
+            if (optarg)
+                _tprintf (_T(" with arg %s"), optarg);
+            _tprintf (_T("\n"));
+            break;
+
+        case _T('a'):
+            _tprintf(_T("option -a\n"));
+            break;
+
+        case _T('b'):
+            _tprintf(_T("option -b\n"));
+            break;
+
+        case _T('c'):
+            _tprintf (_T("option -c with value `%s'\n"), optarg);
+            break;
+
+        case _T('d'):
+            _tprintf (_T("option -d with value `%s'\n"), optarg);
+            break;
+
+        case _T('f'):
+            _tprintf (_T("option -f with value `%s'\n"), optarg);
+            break;
+
+        case '?':
+            /* getopt_long already printed an error message. */
+            break;
+
+        default:
+            abort();
+        }
+    }
+
+    if (verbose_flag)
+        _tprintf (_T("verbose flag is set\n"));
+
+
+    if (optind < argc)
+    {
+        _tprintf (_T("non-option ARGV-elements: "));
+        while (optind < argc) _tprintf (_T("%s "), argv[optind++]);
+        _tprintf (_T("\n"));
+    }
+    return 0;
+}
+```
+ 
+Using this Code with C++ Precompiled Headers
+--------------------------------------------
+
+When using this code statically within a C++ project with precompiled headers, it is necessary to rename `getopt.c`
+to `getopt.cpp` in order to circumvent the following compiler error:
+
+```
+"C1853 - Precompiled header file is from a previous version of the compiler, 
+or the precompiled header is C++ and you are using it from C (or vice versa)."
+```
+
+Additionally precompiled header file must be added as the first include of the `getopt.c` or `getopt.cpp` file.
+For example, if you are using _stdafx.h_ as the precompiled header, the following would be expected:
+
+```
+// File comments removed
+#include "stdafx.h"
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdlib.h>
+#include <stdio.h>
+#include "getopt.h"
+```
+
+History
+-------
+
+- 02/03/2011 - Initial release
+- 02/20/2011 - Fixed L4 compiler warnings
+- 07/05/2011 - Added no_argument, required_argument, optional_argument def
+- 08/05/2011 - Fixed non-argument runtime bug which caused runtime exception
+- 08/09/2011 - Added code to export functions for DLL and LIB
+- 02/15/2012 - Fixed _GETOPT_THROW definition missing in implementation file
+- 08/03/2012 - Created separate functions for char and wchar_t characters so single DLL can do both Unicode and ANSI
+- 10/15/2012 - Modified to match latest GNU features
+- 06/19/2015 - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
+
+License
+-------
+
+This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)
\ No newline at end of file