├── .gitignore ├── docs ├── config.py ├── inc │ └── menu.md ├── out │ ├── api.html │ ├── assets │ │ ├── code.js │ │ ├── fonts.css │ │ ├── fonts │ │ │ ├── CrimsonText-Bold.ttf │ │ │ ├── CrimsonText-Bold.woff2 │ │ │ ├── CrimsonText-BoldItalic.ttf │ │ │ ├── CrimsonText-BoldItalic.woff2 │ │ │ ├── CrimsonText-Italic.ttf │ │ │ ├── CrimsonText-Italic.woff2 │ │ │ ├── CrimsonText-Regular.ttf │ │ │ ├── CrimsonText-Regular.woff2 │ │ │ ├── CrimsonText-SemiBold.ttf │ │ │ ├── CrimsonText-SemiBold.woff2 │ │ │ ├── CrimsonText-SemiBoldItalic.ttf │ │ │ ├── CrimsonText-SemiBoldItalic.woff2 │ │ │ └── OFL.txt │ │ ├── graphite.css │ │ └── pygments.css │ ├── cli.html │ ├── index.html │ ├── license.html │ └── quickstart.html └── src │ ├── api.stx │ ├── cli.stx │ ├── index.stx │ ├── license.stx │ └── quickstart.stx ├── license.txt ├── makefile ├── readme.md └── src ├── args.cpp ├── args.h ├── example1.cpp ├── example2.cpp └── tests.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # C binary and object files. 2 | /bin/ 3 | /src/*.o 4 | -------------------------------------------------------------------------------- /docs/config.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # Site Configuration File 3 | # ------------------------------------------------------------------------------ 4 | 5 | title = "Args++" 6 | tagline = "A ridiculously simple argument-parsing library for C++." 7 | version = "Version 2.1.0" 8 | -------------------------------------------------------------------------------- /docs/inc/menu.md: -------------------------------------------------------------------------------- 1 | * [Home](@root/) 2 | * [Quickstart](@root/quickstart//) 3 | * [CLI](@root/cli//) 4 | * [API](@root/api//) 5 | * [License](@root/license//) 6 | * [Github](https://github.com/dmulholl/argspp) 7 | -------------------------------------------------------------------------------- /docs/out/api.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | API Reference 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |

Args++

25 | 26 |

A ridiculously simple argument-parsing library for C++.

27 | 28 | 29 |

Version 2.1.0

30 | 31 | 47 |
48 | 49 |
50 |
51 |

API Reference

52 | 53 |
54 |
55 | 72 |
73 |

74 | Setup 75 |

76 |

77 | This library is written in portable C++11. 78 | The header file exports an args::ArgParser class which provides the public interface to the library. 79 |

80 |
81 |
82 |
83 | ArgParser(string helptext = "", string version = "") 84 |
85 |
86 |

87 | Initialize an ArgParser instance. Supplying help text activates an automatic --help flag; supplying a version string activates an automatic --version flag. (Automatic -h and -v shortcuts are also activated unless registered by other options.) 88 |

89 |
90 |
91 |
92 |
93 | void .parse(int argc, char **argv) 94 |
95 |
96 |

97 | Parse the application's command line arguments. 98 | Arguments are assumed to be argc and argv as supplied to main(). 99 | Parsed option values can be retrieved from the parser instance itself. 100 |

101 |
102 |
103 |
104 |

105 | Flags and Options 106 |

107 |
108 |
109 |
110 | void .flag(string name) 111 |
112 |
113 |

114 | Registers a new flag. 115 | The name parameter accepts an unlimited number of space-separated aliases and single-character shortcuts. 116 |

117 |
118 |
119 |
120 |
121 | void .option(string name, string fallback = "") 122 |
123 |
124 |

125 | Registers a new option. 126 | The name parameter accepts an unlimited number of space-separated aliases and single-character shortcuts. 127 | A fallback value can be specified which will be used if the option is not found. 128 |

129 |
130 |
131 |
132 |

133 | Retrieving Values 134 |

135 |
136 |
137 |
138 | bool .found(string name) 139 |
140 |
141 |

142 | Returns true if the specified flag or option was found. 143 |

144 |
145 |
146 |
147 |
148 | int .count(string name) 149 |
150 |
151 |

152 | Returns the number of times the specified flag or option was found. 153 |

154 |
155 |
156 |
157 |
158 | string .value(string name) 159 |
160 |
161 |

162 | Returns the value of the specified option. Returns the fallback value if the option was not found. 163 |

164 |
165 |
166 |
167 |
168 | vector<string> .values(string name) 169 |
170 |
171 |

172 | Returns the specified option's list of values. 173 |

174 |
175 |
176 |
177 |

178 | Positional Arguments 179 |

180 |
181 |
182 |
183 | vector<string> .args 184 |
185 |
186 |

187 | Stores the positional arguments. 188 |

189 |
190 |
191 |
192 |

193 | Commands 194 |

195 |
196 |
197 |
198 | ArgParser& .command(string name, string helptext = "", callback = nullptr) 199 |
200 |
201 |

202 | Registers a new command. 203 | The name parameter accepts an unlimited number of space-separated aliases. 204 | Returns a reference to the command's ArgParser instance — you can register the command's flags and options on this parser using the standard methods listed above. 205 | If the command is found the callback function will be called with the command's name and ArgParser instance. 206 |

207 |
208 |
209 |
210 |
211 | bool .commandFound() 212 |
213 |
214 |

215 | Returns true if a command was found. 216 |

217 |
218 |
219 |
220 |
221 | string .commandName() 222 |
223 |
224 |

225 | Returns the command name if a command was found. 226 |

227 |
228 |
229 |
230 |
231 | ArgParser& .commandParser() 232 |
233 |
234 |

235 | Returns the command's parser instance if a command was found. 236 |

237 |
238 |
239 |
240 |
241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /docs/out/assets/code.js: -------------------------------------------------------------------------------- 1 | // Add a copy button to
 tags unless they have a 'no-copy' class.
 2 | document.addEventListener("DOMContentLoaded", function() {
 3 |     if (!navigator.clipboard) {
 4 |         return;
 5 |     }
 6 | 
 7 |     document.querySelectorAll("pre").forEach(node => {
 8 |         if (node.classList.contains("no-copy")) {
 9 |             return;
10 |         }
11 | 
12 |         var wrapper = document.createElement('div');
13 |         wrapper.classList.add("pre-copy-wrapper");
14 |         node.parentNode.insertBefore(wrapper, node);
15 |         wrapper.appendChild(node);
16 | 
17 |         let copyBtn = document.createElement("button");
18 |         copyBtn.innerText = "[COPY]";
19 |         wrapper.appendChild(copyBtn);
20 | 
21 |         copyBtn.addEventListener("click", async () => {
22 |             let text = node.innerText;
23 |             await navigator.clipboard.writeText(text);
24 |             copyBtn.innerText = "[COPIED]";
25 |             setTimeout(() => copyBtn.innerText = "[COPY]", 1000);
26 |         })
27 |     })
28 | });
29 | 


--------------------------------------------------------------------------------
/docs/out/assets/fonts.css:
--------------------------------------------------------------------------------
 1 | /**
 2 |  * -------------------------------------------------------------------------
 3 |  *  Google fonts served locally.
 4 |  * -------------------------------------------------------------------------
 5 |  */
 6 | 
 7 | @font-face {
 8 |   font-family: 'Crimson Text';
 9 |   font-style: normal;
10 |   font-weight: 400;
11 |   src: local('Crimson Text Regular'),
12 |        local('CrimsonText-Regular'),
13 |        url(fonts/CrimsonText-Regular.woff2) format('woff2'),
14 |        url(fonts/CrimsonText-Regular.ttf) format('truetype');
15 | }
16 | 
17 | @font-face {
18 |   font-family: 'Crimson Text';
19 |   font-style: italic;
20 |   font-weight: 400;
21 |   src: local('Crimson Text Italic'),
22 |        local('CrimsonText-Italic'),
23 |        url(fonts/CrimsonText-Italic.woff2) format('woff2'),
24 |        url(fonts/CrimsonText-Italic.ttf) format('truetype');
25 | }
26 | 
27 | @font-face {
28 |   font-family: 'Crimson Text';
29 |   font-style: normal;
30 |   font-weight: 700;
31 |   src: local('Crimson Text Bold'),
32 |        local('CrimsonText-Bold'),
33 |        url(fonts/CrimsonText-Bold.woff2) format('woff2'),
34 |        url(fonts/CrimsonText-Bold.ttf) format('truetype');
35 | }
36 | 
37 | /*
38 |     The fonts below are packaged with the theme and can be uncommented
39 |     if needed.
40 |  */
41 | 
42 | /*
43 | @font-face {
44 |   font-family: 'Crimson Text';
45 |   font-style: italic;
46 |   font-weight: 700;
47 |   src: local('Crimson Text Bold Italic'),
48 |        local('CrimsonText-BoldItalic'),
49 |        url(fonts/CrimsonText-BoldItalic.woff2) format('woff2'),
50 |        url(fonts/CrimsonText-BoldItalic.ttf) format('truetype');
51 | }
52 | 
53 | @font-face {
54 |   font-family: 'Crimson Text';
55 |   font-style: normal;
56 |   font-weight: 600;
57 |   src: local('Crimson Text SemiBold'),
58 |        local('CrimsonText-SemiBold'),
59 |        url(fonts/CrimsonText-SemiBold.woff2) format('woff2'),
60 |        url(fonts/CrimsonText-SemiBold.ttf) format('truetype');
61 | }
62 | 
63 | @font-face {
64 |   font-family: 'Crimson Text';
65 |   font-style: italic;
66 |   font-weight: 600;
67 |   src: local('Crimson Text SemiBold Italic'),
68 |        local('CrimsonText-SemiBoldItalic'),
69 |        url(fonts/CrimsonText-SemiBoldItalic.woff2) format('woff2'),
70 |        url(fonts/CrimsonText-SemiBoldItalic.ttf) format('truetype');
71 | }
72 | */
73 | 


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-Bold.ttf


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-Bold.woff2


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-BoldItalic.ttf


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-BoldItalic.woff2


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-Italic.ttf


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-Italic.woff2


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-Regular.ttf


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-Regular.woff2


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-SemiBold.ttf


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-SemiBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-SemiBold.woff2


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-SemiBoldItalic.ttf


--------------------------------------------------------------------------------
/docs/out/assets/fonts/CrimsonText-SemiBoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmulholl/argspp/b3b9423cfb40e2b9baa2953c1fe91027d2c05cc4/docs/out/assets/fonts/CrimsonText-SemiBoldItalic.woff2


--------------------------------------------------------------------------------
/docs/out/assets/fonts/OFL.txt:
--------------------------------------------------------------------------------
 1 | Copyright (c) 2010, Sebastian Kosch (sebastian@aldusleaf.org),
 2 | with Reserved Font Name "Crimson" and "Crimson Text".
 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
 4 | This license is copied below, and is also available with a FAQ at:
 5 | http://scripts.sil.org/OFL
 6 | 
 7 | 
 8 | -----------------------------------------------------------
 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 | 
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 | 
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded, 
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 | 
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 | 
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 | 
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 | 
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 | 
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 | 
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 | 
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 | 
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 | 
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 | 
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 | 
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 | 
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 | 
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 | 


--------------------------------------------------------------------------------
/docs/out/assets/graphite.css:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * -------------------------------------------------------------------------
  3 |  *  Micro Reset
  4 |  * -------------------------------------------------------------------------
  5 |  */
  6 | 
  7 | *, *:before, *:after {
  8 |     box-sizing: inherit;
  9 | }
 10 | 
 11 | html {
 12 |     box-sizing: border-box;
 13 |     font-size: 100%;
 14 |     -webkit-text-size-adjust: none;
 15 |             text-size-adjust: none;
 16 | }
 17 | 
 18 | body {
 19 |     margin: 0;
 20 |     padding: 0;
 21 | }
 22 | 
 23 | form, fieldset, legend {
 24 |     margin: 0;
 25 |     padding: 0;
 26 | }
 27 | 
 28 | button, input, select, textarea, label {
 29 |     margin: 0;
 30 |     padding: 0;
 31 |     font-family: inherit;
 32 |     font-size: inherit;
 33 | }
 34 | 
 35 | img {
 36 |     border: 0;
 37 |     max-width: 100%;
 38 | }
 39 | 
 40 | /**
 41 |  * -------------------------------------------------------------------------
 42 |  *  Typography
 43 |  * -------------------------------------------------------------------------
 44 |  */
 45 | 
 46 | body {
 47 |     font-size: 17px;
 48 |     color: black;
 49 |     font-family: 'Crimson Text', Georgia, serif;
 50 |     line-height: 1.75;
 51 | }
 52 | 
 53 | h1 {
 54 |     padding: 0;
 55 |     margin: 80px 0 30px;
 56 |     line-height: 1.25;
 57 |     text-align: center;
 58 |     font-size: 32px;
 59 |     font-weight: normal;
 60 | }
 61 | 
 62 | h2 {
 63 |     padding: 0;
 64 |     margin: 80px 0 30px;
 65 |     line-height: 1.25;
 66 |     text-align: center;
 67 |     font-size: 22px;
 68 |     font-weight: bold;
 69 | }
 70 | 
 71 | h2.underline {
 72 |     padding: 0;
 73 |     margin: 80px 0 35px;
 74 |     line-height: 1.25;
 75 |     text-align: left;
 76 |     font-size: 22px;
 77 |     font-weight: bold;
 78 |     padding-bottom: 5px;
 79 |     border-bottom: 1px solid #ccc;
 80 | }
 81 | 
 82 | h3, h4, h5, h6 {
 83 |     padding: 0;
 84 |     margin: 80px 0 30px;
 85 |     line-height: 1.25;
 86 |     text-align: left;
 87 |     font-size: 19px;
 88 |     font-weight: bold;
 89 | }
 90 | 
 91 | p {
 92 |     margin: 25px 0;
 93 |     padding: 0;
 94 |     overflow-wrap: break-word;
 95 | }
 96 | 
 97 | blockquote {
 98 |     margin: 40px 0px;
 99 |     padding: 0 20px;
100 |     border-left: 3px solid #ddd;
101 |     font-style: italic;
102 | }
103 | 
104 | .blockquote-caption {
105 |     margin: -10px 20px 40px;
106 |     text-align: right;
107 | }
108 | 
109 | abbr[title] {
110 |     border-bottom: 1px dotted;
111 |     cursor: help;
112 | }
113 | 
114 | sup, sub {
115 |     font-size: 75%;
116 |     line-height: 0;
117 |     position: relative;
118 |     vertical-align: baseline;
119 | }
120 | 
121 | sup {
122 |     bottom: 1.5ex;
123 |     padding: 0 0.5ex;
124 | }
125 | 
126 | sub {
127 |     top: .5ex;
128 | }
129 | 
130 | /**
131 |  * Code
132 |  */
133 | 
134 | pre, code {
135 |     font-size: 13px;
136 |     font-family: Courier, monospace;
137 | }
138 | 
139 | code {
140 |     margin: 0 2px;
141 |     padding: 1px 5px;
142 |     white-space: nowrap;
143 |     border: 1px solid #e8e8e8;
144 |     border-radius: 3px;
145 |     background-color: #f8f8f8;
146 | }
147 | 
148 | pre {
149 |     margin: 40px 0;
150 |     padding: 16px 20px;
151 |     border-top: 1px dotted #bbb;
152 |     border-bottom: 1px dotted #bbb;
153 |     background-color: #f8f8f8;
154 |     overflow: auto;
155 |     line-height: 1.4;
156 | }
157 | 
158 | /* Markdown renderers tend to wrap code blocks in 
 ... 
blocks. */ 159 | pre code { 160 | margin: 0; 161 | padding: 0; 162 | white-space: pre; 163 | border: none; 164 | border-radius: 0; 165 | background-color: #f8f8f8; 166 | } 167 | 168 | h1 code { 169 | font-size: 26px; 170 | } 171 | 172 | dt pre { 173 | margin: 0 2px; 174 | padding: 1px 5px; 175 | border: 1px solid #e8e8e8; 176 | border-radius: 3px; 177 | background-color: #f8f8f8; 178 | } 179 | 180 | .pre-copy-wrapper { 181 | position: relative; 182 | } 183 | 184 | .pre-copy-wrapper button { 185 | padding: 6px; 186 | background: transparent; 187 | border: none; 188 | position: absolute; 189 | top: 10px; 190 | right: 10px; 191 | opacity: 0.3; 192 | cursor: pointer; 193 | color: black; 194 | font-size: 12px; 195 | font-family: Consolas, monospace; 196 | display: none; 197 | } 198 | 199 | .pre-copy-wrapper:hover button { 200 | display: block;; 201 | } 202 | 203 | .pre-copy-wrapper button:hover { 204 | opacity: 0.6; 205 | } 206 | 207 | 208 | /** 209 | * Lists 210 | */ 211 | 212 | ul, ol { 213 | margin: 35px 0; 214 | padding: 0 0 0 20px; 215 | } 216 | 217 | ul ul, ol ol, ul ol, ol ul { 218 | margin: 10px 10px; 219 | } 220 | 221 | li { 222 | margin: 4px 0; 223 | padding: 0; 224 | } 225 | 226 | dl { 227 | margin: 40px 0; 228 | padding: 0; 229 | } 230 | 231 | dt { 232 | margin: 45px 0 25px; 233 | padding: 0; 234 | font-weight: bold; 235 | } 236 | 237 | dd { 238 | margin: 25px 0px; 239 | padding: 0 25px; 240 | border-left: 1px solid #ddd; 241 | } 242 | 243 | /** 244 | * Links 245 | */ 246 | 247 | a { 248 | color: black; 249 | text-decoration: none; 250 | padding-bottom: 2px; 251 | border-bottom: 1px solid; 252 | } 253 | 254 | sup a { 255 | border-bottom: none; 256 | } 257 | 258 | dt a { 259 | padding-bottom: 0; 260 | } 261 | 262 | 263 | /** 264 | * Miscellanea 265 | */ 266 | 267 | hr { 268 | display: block; 269 | height: 1px; 270 | border: 0; 271 | border-top: 1px solid; 272 | margin: 60px auto; 273 | padding: 0; 274 | max-width: 300px; 275 | } 276 | 277 | img { 278 | margin: 40px auto; 279 | display: block; 280 | } 281 | 282 | /** 283 | * ------------------------------------------------------------------------- 284 | * Layout 285 | * ------------------------------------------------------------------------- 286 | */ 287 | 288 | body { 289 | width: 960px; 290 | margin: 0 auto; 291 | padding: 40px 0; 292 | } 293 | 294 | .masthead { 295 | width: 360px; 296 | padding: 20px 50px; 297 | float: left; 298 | } 299 | 300 | .main { 301 | width: 600px; 302 | padding: 32px 50px 40px 50px; 303 | margin-left: 360px; 304 | border-left: 3px solid black; 305 | min-height: calc(100vh - 80px); 306 | } 307 | 308 | /** 309 | * ------------------------------------------------------------------------- 310 | * Masthead 311 | * ------------------------------------------------------------------------- 312 | */ 313 | 314 | .masthead h1 { 315 | margin-top: 0; 316 | margin-bottom: 34px; 317 | padding: 0; 318 | text-align: right; 319 | font-size: 46px; 320 | line-height: 58px; 321 | } 322 | 323 | .masthead h1 a { 324 | border-bottom: none; 325 | } 326 | 327 | .masthead .tagline { 328 | font-style: italic; 329 | text-align: right; 330 | } 331 | 332 | .masthead .version { 333 | font-style: italic; 334 | text-align: right; 335 | } 336 | 337 | .masthead .menu { 338 | margin-right: 20px; 339 | direction: rtl; 340 | } 341 | 342 | .masthead .menu a { 343 | direction: ltr; 344 | } 345 | 346 | .masthead .menu ul ul { 347 | list-style: none; 348 | margin-left: 10px; 349 | margin-right: 10px; 350 | } 351 | 352 | .masthead .menu li li::before { 353 | content: "•\00a\000a0\00a0" 354 | } 355 | 356 | #menu-check { 357 | display: none; 358 | } 359 | 360 | #menu-label { 361 | display: none; 362 | } 363 | 364 | /** 365 | * ------------------------------------------------------------------------- 366 | * Main 367 | * ------------------------------------------------------------------------- 368 | */ 369 | 370 | .main .title h1 { 371 | margin-top: 0; 372 | margin-bottom: 40px; 373 | } 374 | 375 | .main .title .subtitle { 376 | font-style: italic; 377 | text-align: center; 378 | width: 90%; 379 | margin-left: auto; 380 | margin-right: auto; 381 | } 382 | 383 | .main .title hr { 384 | margin: 50px auto 60px; 385 | } 386 | 387 | .main > :last-child { 388 | margin-bottom: 0; 389 | } 390 | 391 | /** 392 | * Info Boxes 393 | */ 394 | 395 | .infobox, .alertbox { 396 | margin: 40px 20px; 397 | border: 1px solid; 398 | padding: 0 25px; 399 | border-radius: 3px; 400 | border-color: #bbb; 401 | background-color: #f8f8f8; 402 | } 403 | 404 | .infobox.blue, .alertbox.info { 405 | border-color: #bac6d3; 406 | background-color: #e2eef9; 407 | } 408 | 409 | .infobox.yellow, .alertbox.warning { 410 | border-color: #dfd8c2; 411 | background-color: #fff9ea; 412 | } 413 | 414 | .infobox.red, .alertbox.error { 415 | border-color: #d2b2b2; 416 | background-color: #fcdede; 417 | } 418 | 419 | .infobox.green, .alertbox.success { 420 | border-color: #B2C2AB; 421 | background-color: #DEF2D6; 422 | } 423 | 424 | /** 425 | * Footnotes 426 | */ 427 | 428 | .footnote a::before { 429 | content: "["; 430 | } 431 | 432 | .footnote a::after { 433 | content: "]"; 434 | } 435 | 436 | .footnote a { 437 | border: none; 438 | } 439 | 440 | .footnotes dt { 441 | display: table-cell; 442 | width: 30px; 443 | text-align: right; 444 | font-weight: normal; 445 | } 446 | 447 | .footnotes dt a { 448 | padding: 0; 449 | border: none; 450 | } 451 | 452 | .footnotes dt a::before { 453 | content: "["; 454 | } 455 | 456 | .footnotes dt a::after { 457 | content: "]"; 458 | } 459 | 460 | .footnotes dd { 461 | display: table-cell; 462 | padding-left: 20px; 463 | padding-right: 0px; 464 | border: none 465 | } 466 | 467 | .footnotes dd :first-child { 468 | margin-top: 0; 469 | } 470 | 471 | .footnotes div:last-child dd :last-child { 472 | margin-bottom: 0; 473 | } 474 | 475 | .footnotes pre { 476 | margin: 30px 0; 477 | } 478 | 479 | /** 480 | * Tables 481 | */ 482 | 483 | table { 484 | font-size: 16px; 485 | border-collapse: collapse; 486 | border-spacing: 0; 487 | margin: 50px 0px; 488 | width: 100%; 489 | } 490 | 491 | thead, tfoot { 492 | background-color: #f8f8f8; 493 | } 494 | 495 | th, td { 496 | border: 1px solid #ccc; 497 | padding: 14px 20px; 498 | text-align: left; 499 | } 500 | 501 | /** 502 | * Utility Styles 503 | */ 504 | 505 | .small { 506 | font-size: 16px; 507 | } 508 | 509 | .left { 510 | text-align: left; 511 | } 512 | 513 | .right { 514 | text-align: right; 515 | } 516 | 517 | .center { 518 | text-align: center; 519 | } 520 | 521 | .justify { 522 | text-align: justify; 523 | } 524 | 525 | .bold { 526 | font-weight: bold; 527 | } 528 | 529 | .italic { 530 | font-style: italic; 531 | } 532 | 533 | .indent { 534 | padding-left: 30px; 535 | padding-right: 30px; 536 | } 537 | 538 | .unselectable { 539 | -webkit-user-select: none; 540 | -moz-user-select: none; 541 | -ms-user-select: none; 542 | user-select: none; 543 | } 544 | 545 | /** 546 | * Custom Classes 547 | */ 548 | 549 | body.extra-deflist-vspace dt { 550 | margin-top: 80px; 551 | } 552 | 553 | /** 554 | * ------------------------------------------------------------------------- 555 | * Media Queries 556 | * ------------------------------------------------------------------------- 557 | */ 558 | 559 | /* Tablet screens and smaller. */ 560 | 561 | @media screen and (max-width: 960px) { 562 | body { 563 | width: auto; 564 | max-width: 680px; 565 | padding-top: 60px; 566 | } 567 | 568 | .masthead { 569 | width: auto; 570 | float: none; 571 | padding: 60px 20px 60px 20px; 572 | text-align: center; 573 | margin-left: 40px; 574 | margin-right: 40px; 575 | border-top: 3px solid black; 576 | border-bottom: 3px solid black; 577 | } 578 | 579 | .main { 580 | width: auto; 581 | padding: 40px 40px; 582 | margin-left: 0; 583 | border-left: none; 584 | min-height: auto; 585 | } 586 | 587 | .masthead h1 { 588 | text-align: center; 589 | } 590 | 591 | .masthead .tagline { 592 | text-align: center; 593 | max-width: 450px; 594 | margin-left: auto; 595 | margin-right: auto; 596 | display: none; 597 | } 598 | 599 | .homepage .masthead .tagline { 600 | display: block; 601 | } 602 | 603 | .masthead .version { 604 | text-align: center; 605 | } 606 | 607 | .masthead .menu { 608 | direction: ltr; 609 | max-width: 300px; 610 | margin-left: auto; 611 | margin-right: auto; 612 | } 613 | 614 | .masthead .menu ul { 615 | text-align: left; 616 | margin: 0; 617 | padding: 0; 618 | } 619 | 620 | .masthead .menu ul ul { 621 | margin: 0; 622 | } 623 | 624 | .masthead .menu li { 625 | border-bottom: 1px solid; 626 | list-style: none; 627 | margin: 0; 628 | padding: 0; 629 | } 630 | 631 | .masthead .menu li:first-child { 632 | border-top: 1px solid; 633 | } 634 | 635 | .masthead .menu li li:last-child { 636 | border-bottom: none; 637 | } 638 | 639 | .masthead .menu a { 640 | display: block; 641 | padding: 15px 20px; 642 | border-bottom: none; 643 | } 644 | 645 | .masthead .menu li li a { 646 | padding-left: 30px; 647 | } 648 | 649 | .masthead .menu li li::before { 650 | content: none; 651 | } 652 | 653 | .masthead .menu li li a::before { 654 | content: "•\00a0\00a0\00a0"; 655 | } 656 | 657 | #menu-label { 658 | display: inline-block; 659 | padding: 0 20px; 660 | height: 50px; 661 | border: 1px solid #ddd; 662 | cursor: pointer; 663 | line-height: 50px; 664 | color: #333; 665 | font-size: 20px; 666 | margin-top: 10px; 667 | } 668 | 669 | #menu-label:hover, #menu-label:focus { 670 | border: 1px solid #888; 671 | } 672 | 673 | #menu-label .icon { 674 | padding-right: 8px; 675 | width: 30px; 676 | } 677 | 678 | #menu-check ~ label .close-icon { 679 | display: none; 680 | } 681 | 682 | #menu-check ~ label .open-icon { 683 | display: inline-block; 684 | } 685 | 686 | #menu-check:checked ~ label .close-icon { 687 | display: inline-block; 688 | } 689 | 690 | #menu-check:checked ~ label .open-icon { 691 | display: none; 692 | } 693 | 694 | #menu-check ~ ul { 695 | display: none; 696 | } 697 | 698 | #menu-check:checked ~ ul { 699 | display: block; 700 | margin-top: 50px; 701 | margin-bottom: 0; 702 | } 703 | } 704 | 705 | /* Landscape phone screens and smaller. */ 706 | 707 | @media screen and (max-width: 720px) { 708 | } 709 | 710 | /* Portrait phone screens. */ 711 | 712 | @media screen and (max-width: 480px) { 713 | body { 714 | font-size: 16px; 715 | padding-top: 40px; 716 | } 717 | 718 | h1 { 719 | font-size: 28px; 720 | } 721 | 722 | h2 { 723 | font-size: 18px; 724 | } 725 | 726 | h3, h4, h5, h6 { 727 | font-size: 16px; 728 | } 729 | 730 | h1 code { 731 | font-size: 24px; 732 | } 733 | 734 | pre, code { 735 | font-size: 12px; 736 | } 737 | 738 | .pre-copy-wrapper button { 739 | font-size: 11px; 740 | } 741 | 742 | .small { 743 | font-size: 15px; 744 | } 745 | 746 | .main .title .subtitle { 747 | width: auto; 748 | } 749 | } 750 | -------------------------------------------------------------------------------- /docs/out/assets/pygments.css: -------------------------------------------------------------------------------- 1 | /** 2 | * ------------------------------------------------------------------------- 3 | * Pygments Theme 4 | * ------------------------------------------------------------------------- 5 | */ 6 | 7 | pre .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ 8 | pre .c { color: #8f5902 } /* Comment */ 9 | pre .c1 { color: #8f5902 } /* Comment.Single */ 10 | pre .cm { color: #8f5902 } /* Comment.Multiline */ 11 | pre .cp { color: #540e8a; font-weight: bold } /* Comment.Preproc */ 12 | pre .cs { color: #8f5902 } /* Comment.Special */ 13 | pre .g { color: #222222 } /* Generic */ 14 | pre .gd { color: #a40000 } /* Generic.Deleted */ 15 | pre .ge { color: #222222 } /* Generic.Emph */ 16 | pre .gr { color: #ef2929 } /* Generic.Error */ 17 | pre .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 18 | pre .gi { color: #00A000 } /* Generic.Inserted */ 19 | pre .go { color: #222222 } /* Generic.Output */ 20 | pre .gp { color: #8f5902 } /* Generic.Prompt */ 21 | pre .gs { color: #222222; font-weight: bold } /* Generic.Strong */ 22 | pre .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 23 | pre .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ 24 | pre .il { color: #000088 } /* Literal.Number.Integer.Long */ 25 | pre .k { color: #204a87; font-weight: bold } /* Keyword */ 26 | pre .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ 27 | pre .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ 28 | pre .kn { color: #540e8a; font-weight: bold } /* Keyword.Namespace */ 29 | pre .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ 30 | pre .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ 31 | pre .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ 32 | pre .l { color: #222222 } /* Literal */ 33 | pre .ld { color: #222222 } /* Literal.Date */ 34 | pre .m { color: #000088 } /* Literal.Number */ 35 | pre .mf { color: #000088 } /* Literal.Number.Float */ 36 | pre .mh { color: #000088 } /* Literal.Number.Hex */ 37 | pre .mi { color: #000088 } /* Literal.Number.Integer */ 38 | pre .mo { color: #000088 } /* Literal.Number.Oct */ 39 | pre .mb { color: #000088 } /* Literal.Number.Bin */ 40 | pre .n { color: #222222 } /* Name */ 41 | pre .na { color: #8f5902 } /* Name.Attribute */ 42 | pre .nb { color: #204a87 } /* Name.Builtin */ 43 | pre .nc { color: #222222 } /* Name.Class */ 44 | pre .no { color: #222222 } /* Name.Constant */ 45 | pre .nd { color: #000088 } /* Name.Decorator */ 46 | pre .ni { color: #ce5c00 } /* Name.Entity */ 47 | pre .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ 48 | pre .nf { color: #222222 } /* Name.Function */ 49 | pre .nl { color: #880000 } /* Name.Label */ 50 | pre .nn { color: #222222 } /* Name.Namespace */ 51 | pre .nt { color: #204a87; font-weight: bold } /* Name.Tag */ 52 | pre .nv { color: #222222 } /* Name.Variable */ 53 | pre .nx { color: #222222 } /* Name.Other */ 54 | pre .o { color: #000088 } /* Operator */ 55 | pre .ow { color: #204a87; font-weight: bold } /* Operator.Word */ 56 | pre .p { color: #222222 } /* Punctuation */ 57 | pre .py { color: #222222 } /* Name.Property */ 58 | pre .s { color: #880000 } /* Literal.String */ 59 | pre .s1 { color: #880000 } /* Literal.String.Single */ 60 | pre .s2 { color: #880000 } /* Literal.String.Double */ 61 | pre .sb { color: #880000 } /* Literal.String.Backtick */ 62 | pre .sc { color: #880000 } /* Literal.String.Char */ 63 | pre .sd { color: #880000 } /* Literal.String.Doc */ 64 | pre .se { color: #880000 } /* Literal.String.Escape */ 65 | pre .sh { color: #880000 } /* Literal.String.Heredoc */ 66 | pre .si { color: #880000 } /* Literal.String.Interpol */ 67 | pre .sr { color: #880000 } /* Literal.String.Regex */ 68 | pre .ss { color: #880000 } /* Literal.String.Symbol */ 69 | pre .sx { color: #880000 } /* Literal.String.Other */ 70 | pre .vc { color: #222222 } /* Name.Variable.Class */ 71 | pre .vg { color: #222222 } /* Name.Variable.Global */ 72 | pre .vi { color: #222222 } /* Name.Variable.Instance */ 73 | pre .x { color: #222222 } /* Other */ 74 | 75 | pre .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ 76 | pre .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ 77 | -------------------------------------------------------------------------------- /docs/out/cli.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Command Line Interface 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |

Args++

25 | 26 |

A ridiculously simple argument-parsing library for C++.

27 | 28 | 29 |

Version 2.1.0

30 | 31 | 47 |
48 | 49 |
50 |
51 |

Command Line Interface

52 | 53 |
54 |
55 | 75 |
76 |

77 | Options 78 |

79 |

80 | An option can have an unlimited number of long-form aliases and single-character shortcuts: --option, -o. 81 |

82 |

83 | Option values can be separated by either a space, --opt 123, or an equals symbol, --opt=123. Either syntax can be used with shortcuts: -o 123, -o=123. 84 |

85 |

86 | Multiple shortcuts can be condensed into a single block, e.g. -abc foo bar. Trailing arguments are consumed in sequence as required by the options. 87 |

88 |

89 | Options are registered with default values which are used if the option is not found. If an option is found multiple times its value is the final value encountered. 90 |

91 |

92 | Multivalued Options 93 |

94 |

95 | Options can be treated as singular or multivalued as circumstances require. Each option maintains an internal list to which newly parsed values are appended; the (singular) value of the option is the final value in the list or the default value if the list is empty. 96 |

97 |

98 | For example, in the command below: 99 |

100 |
101 | $ myapp --foo abc --foo def
102 | 
103 |

104 | the value of the option foo is "def" but the array ["abc", "def"] is also available for use if required. 105 |

106 |

107 | Flags 108 |

109 |

110 | Flags are valueless options — they're either present or absent, but take no arguments. Like options, flags can have an unlimited number of long-form aliases and single-character shortcuts: --flag, -f. 111 |

112 |

113 | Positional Arguments 114 |

115 |

116 | Options and flags can be preceded by, followed by, or interspaced with positional arguments which are assembled by the parser into an array of strings. 117 |

118 |

119 | The parser supports the standard -- switch for turning off option-parsing. All arguments following a -- will be treated as positional arguments, even if they begin with a single or double dash. 120 |

121 |

122 | Commands 123 |

124 |

125 | This library supports git-style command interfaces with arbitrarily-nested commands. Commands have builtin support for an automatic --help flag and an automatic help <cmd> command, i.e. the commands 126 |

127 |
128 | $ myapp <cmd> --help
129 | 
130 |

131 | and 132 |

133 |
134 | $ myapp help <cmd>
135 | 
136 |

137 | are functionally identical and will both print the help text registered with the command. 138 |

139 |

140 | Negative Numbers 141 |

142 |

143 | Some argument-parsing libraries struggle with negative numbers — for example, they will try to parse -3 as a flag or option named 3. This library always treats arguments beginning with a dash and a digit as positional arguments or option values, never as flag or option names. 144 |

145 |
146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /docs/out/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Args++ — a ridiculously simple argument-parsing library for C++ 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |

Args++

25 | 26 |

A ridiculously simple argument-parsing library for C++.

27 | 28 | 29 |

Version 2.1.0

30 | 31 | 47 |
48 | 49 |
50 |
51 |

Home

52 | 53 |
54 |
55 |

56 | Args++ is a minimalist C++ library for parsing command line arguments. 57 |

58 |

59 | Features 60 |

61 | 81 | 84 | 95 |

96 | License 97 |

98 |

99 | Zero-Clause BSD (0BSD). 100 |

101 |
102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /docs/out/license.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | License 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |

Args++

25 | 26 |

A ridiculously simple argument-parsing library for C++.

27 | 28 | 29 |

Version 2.1.0

30 | 31 | 47 |
48 | 49 |
50 |
51 |

License

52 | 53 |
54 |
55 |

56 | This library is released under the Zero-Clause BSD licence (0BSD): 57 |

58 |
59 | Permission to use, copy, modify, and/or distribute this
60 | software for any purpose with or without fee is hereby
61 | granted.
62 | 
63 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
64 | ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
65 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
66 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
67 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
68 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
69 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
70 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
71 | USE OR PERFORMANCE OF THIS SOFTWARE.
72 | 
73 |

74 | Reference: https://opensource.org/licenses/0BSD. 75 |

76 |
77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/out/quickstart.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Quickstart Tutorial 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |

Args++

25 | 26 |

A ridiculously simple argument-parsing library for C++.

27 | 28 | 29 |

Version 2.1.0

30 | 31 | 47 |
48 | 49 |
50 |
51 |

Quickstart Tutorial

52 | 53 |
54 |
55 |

56 | Imagine we're building a utility for joining MP3 files, something like mp3cat. 57 | We want the user to supply the file names as a list of command line arguments. 58 | We also want to support an --out/-o option so the user can specify an output filename and a --quiet/-q flag for turning down the program's verbosity. 59 |

60 |

61 | First we need to create an ArgParser instance: 62 |

63 |
 64 | #include "args.h"
 65 | 
 66 | args::ArgParser parser;
 67 | parser.helptext = "Usage: mp3cat...";
 68 | parser.version = "1.0";
 69 | 
70 |

71 | Supplying a helptext string for the parser activates an automatic --help/-h flag; similarly, supplying a version string activates an automatic --version/-v flag. 72 |

73 |

74 | Now we can register our options and flags: 75 |

76 |
 77 | parser.option("out o", "default.mp3");
 78 | parser.flag("quiet q");
 79 | 
80 |

81 | That's it, we're done specifying our interface. Now we can parse the program's command line arguments, passing in argc and argv as supplied to main(): 82 |

83 |
 84 | parser.parse(argc, argv);
 85 | 
86 |

87 | This will exit with a suitable error message for the user if anything goes wrong. Now we can check if the --quiet flag was found: 88 |

89 |
 90 | if (parser.found("quiet")) {
 91 |     do_stuff();
 92 | }
 93 | 
94 |

95 | And determine our output filepath: 96 |

97 |
 98 | string filepath = parser.value("out");
 99 | 
100 |

101 | Positional aguments are collected up in the parser's .args list: 102 |

103 |
104 | for (string& filename: parser.args) {
105 |     do_stuff();
106 | }
107 | 
108 |
109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /docs/src/api.stx: -------------------------------------------------------------------------------- 1 | --- 2 | title: API Reference 3 | --- 4 | 5 | ::: insert toc 6 | ::: hr 7 | 8 | 9 | ### Setup 10 | 11 | This library is written in portable C++11. 12 | The header file exports an `args::ArgParser` class which provides the public interface to the library. 13 | 14 | 15 | [[ `ArgParser(string helptext = "", string version = "")` ]] 16 | 17 | Initialize an `ArgParser` instance. Supplying help text activates an automatic `--help` flag; supplying a version string activates an automatic `--version` flag. (Automatic `-h` and `-v` shortcuts are also activated unless registered by other options.) 18 | 19 | 20 | [[ `void .parse(int argc, char **argv)` ]] 21 | 22 | Parse the application's command line arguments. 23 | Arguments are assumed to be `argc` and `argv` as supplied to `main()`. 24 | Parsed option values can be retrieved from the parser instance itself. 25 | 26 | 27 | 28 | ### Flags and Options 29 | 30 | 31 | [[ `void .flag(string name)` ]] 32 | 33 | Registers a new flag. 34 | The `name` parameter accepts an unlimited number of space-separated aliases and single-character shortcuts. 35 | 36 | 37 | [[ `void .option(string name, string fallback = "")` ]] 38 | 39 | Registers a new option. 40 | The `name` parameter accepts an unlimited number of space-separated aliases and single-character shortcuts. 41 | A fallback value can be specified which will be used if the option is not found. 42 | 43 | 44 | 45 | ### Retrieving Values 46 | 47 | 48 | [[ `bool .found(string name)` ]] 49 | 50 | Returns true if the specified flag or option was found. 51 | 52 | 53 | [[ `int .count(string name)` ]] 54 | 55 | Returns the number of times the specified flag or option was found. 56 | 57 | 58 | [[ `string .value(string name)` ]] 59 | 60 | Returns the value of the specified option. Returns the fallback value if the option was not found. 61 | 62 | 63 | [[ `vector .values(string name)` ]] 64 | 65 | Returns the specified option's list of values. 66 | 67 | 68 | 69 | ### Positional Arguments 70 | 71 | 72 | [[ `vector .args` ]] 73 | 74 | Stores the positional arguments. 75 | 76 | 77 | 78 | ### Commands 79 | 80 | 81 | [[ `ArgParser& .command(string name, string helptext = "", callback = nullptr)` ]] 82 | 83 | Registers a new command. 84 | The `name` parameter accepts an unlimited number of space-separated aliases. 85 | Returns a reference to the command's `ArgParser` instance --- you can register the command's flags and options on this parser using the standard methods listed above. 86 | If the command is found the `callback` function will be called with the command's name and `ArgParser` instance. 87 | 88 | 89 | [[ `bool .commandFound()` ]] 90 | 91 | Returns true if a command was found. 92 | 93 | 94 | [[ `string .commandName()` ]] 95 | 96 | Returns the command name if a command was found. 97 | 98 | 99 | [[ `ArgParser& .commandParser()` ]] 100 | 101 | Returns the command's parser instance if a command was found. 102 | 103 | -------------------------------------------------------------------------------- /docs/src/cli.stx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Command Line Interface 3 | --- 4 | 5 | ::: insert toc 6 | ::: hr 7 | 8 | 9 | ### Options 10 | 11 | An option can have an unlimited number of long-form aliases and single-character shortcuts: `--option`, `-o`. 12 | 13 | Option values can be separated by either a space, `--opt 123`, or an equals symbol, `--opt=123`. Either syntax can be used with shortcuts: `-o 123`, `-o=123`. 14 | 15 | Multiple shortcuts can be condensed into a single block, e.g. `-abc foo bar`. Trailing arguments are consumed in sequence as required by the options. 16 | 17 | Options are registered with default values which are used if the option is not found. If an option is found multiple times its value is the final value encountered. 18 | 19 | 20 | 21 | ### Multivalued Options 22 | 23 | Options can be treated as singular or multivalued as circumstances require. Each option maintains an internal list to which newly parsed values are appended; the (singular) value of the option is the final value in the list or the default value if the list is empty. 24 | 25 | For example, in the command below: 26 | 27 | $ myapp --foo abc --foo def 28 | 29 | the value of the option `foo` is `"def"` but the array `["abc", "def"]` is also available for use if required. 30 | 31 | 32 | 33 | ### Flags 34 | 35 | Flags are valueless options --- they're either present or absent, but take no arguments. Like options, flags can have an unlimited number of long-form aliases and single-character shortcuts: `--flag`, `-f`. 36 | 37 | 38 | 39 | ### Positional Arguments 40 | 41 | Options and flags can be preceded by, followed by, or interspaced with positional arguments which are assembled by the parser into an array of strings. 42 | 43 | The parser supports the standard `--` switch for turning off option-parsing. All arguments following a `--` will be treated as positional arguments, even if they begin with a single or double dash. 44 | 45 | 46 | 47 | ### Commands 48 | 49 | This library supports git-style command interfaces with arbitrarily-nested commands. Commands have builtin support for an automatic `--help` flag and an automatic `help ` command, i.e. the commands 50 | 51 | $ myapp --help 52 | 53 | and 54 | 55 | $ myapp help 56 | 57 | are functionally identical and will both print the help text registered with the command. 58 | 59 | 60 | 61 | ### Negative Numbers 62 | 63 | Some argument-parsing libraries struggle with negative numbers --- for example, they will try to parse `-3` as a flag or option named `3`. This library always treats arguments beginning with a dash and a digit as positional arguments or option values, never as flag or option names. 64 | -------------------------------------------------------------------------------- /docs/src/index.stx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | meta title: Args++ — a ridiculously simple argument-parsing library for C++ 4 | --- 5 | 6 | Args++ is a minimalist C++ library for parsing command line arguments. 7 | 8 | 9 | 10 | ### Features 11 | 12 | * Long-form boolean flags with single-character shortcuts: `--flag`, `-f`. 13 | 14 | * Long-form string-valued options with single-character shortcuts: `--option `, `-o `. 15 | 16 | * Condensed short-form options: `-abc `. 17 | 18 | * Automatic `--help` and `--version` flags. 19 | 20 | * Support for multivalued options. 21 | 22 | * Support for git-style command interfaces with arbitrarily-nested commands. 23 | 24 | 25 | 26 | ### Links 27 | 28 | * [Github](https://github.com/dmulholl/argspp) 29 | * [Basic Example](https://github.com/dmulholl/argspp/blob/master/src/example1.cpp) 30 | * [Command Example](https://github.com/dmulholl/argspp/blob/master/src/example2.cpp) 31 | 32 | 33 | 34 | ### License 35 | 36 | Zero-Clause BSD (0BSD). 37 | -------------------------------------------------------------------------------- /docs/src/license.stx: -------------------------------------------------------------------------------- 1 | --- 2 | title: License 3 | --- 4 | 5 | This library is released under the Zero-Clause BSD licence (0BSD): 6 | 7 | Permission to use, copy, modify, and/or distribute this 8 | software for any purpose with or without fee is hereby 9 | granted. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS 12 | ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 13 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 14 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 15 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 17 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 18 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 19 | USE OR PERFORMANCE OF THIS SOFTWARE. 20 | 21 | Reference: . 22 | -------------------------------------------------------------------------------- /docs/src/quickstart.stx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Quickstart Tutorial 3 | --- 4 | 5 | Imagine we're building a utility for joining MP3 files, something like [mp3cat](https://github.com/dmulholl/mp3cat). 6 | We want the user to supply the file names as a list of command line arguments. 7 | We also want to support an `--out/-o` option so the user can specify an output filename and a `--quiet/-q` flag for turning down the program's verbosity. 8 | 9 | First we need to create an `ArgParser` instance: 10 | 11 | ::: code c++ 12 | #include "args.h" 13 | 14 | args::ArgParser parser; 15 | parser.helptext = "Usage: mp3cat..."; 16 | parser.version = "1.0"; 17 | 18 | Supplying a helptext string for the parser activates an automatic `--help/-h` flag; similarly, supplying a version string activates an automatic `--version/-v` flag. 19 | 20 | Now we can register our options and flags: 21 | 22 | ::: code c++ 23 | parser.option("out o", "default.mp3"); 24 | parser.flag("quiet q"); 25 | 26 | That's it, we're done specifying our interface. Now we can parse the program's command line arguments, passing in `argc` and `argv` as supplied to `main()`: 27 | 28 | ::: code c++ 29 | parser.parse(argc, argv); 30 | 31 | This will exit with a suitable error message for the user if anything goes wrong. Now we can check if the `--quiet` flag was found: 32 | 33 | ::: code c++ 34 | if (parser.found("quiet")) { 35 | do_stuff(); 36 | } 37 | 38 | And determine our output filepath: 39 | 40 | ::: code c++ 41 | string filepath = parser.value("out"); 42 | 43 | Positional aguments are collected up in the parser's `.args` list: 44 | 45 | ::: code c++ 46 | for (string& filename: parser.args) { 47 | do_stuff(); 48 | } 49 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Permission to use, copy, modify, and/or distribute this software for any purpose 2 | with or without fee is hereby granted. 3 | 4 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 5 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 6 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 7 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 8 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 9 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 10 | THIS SOFTWARE. 11 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # Make variables. 3 | # ------------------------------------------------------------------------------ 4 | 5 | CXXFLAGS = -Wall -Wextra -Wno-unused-parameter --stdlib=libc++ --std=c++11 6 | 7 | # ------------------------------------------------------------------------------ 8 | # Phony targets. 9 | # ------------------------------------------------------------------------------ 10 | 11 | all:: 12 | @make lib 13 | @make ex1 14 | @make ex2 15 | @make tests 16 | 17 | lib:: 18 | @mkdir -p bin 19 | $(CXX) $(CXXFLAGS) -c -o bin/args.o src/args.cpp 20 | 21 | ex1:: 22 | @mkdir -p bin 23 | $(CXX) $(CXXFLAGS) -o bin/ex1 src/example1.cpp src/args.cpp 24 | 25 | ex2:: 26 | @mkdir -p bin 27 | $(CXX) $(CXXFLAGS) -o bin/ex2 src/example2.cpp src/args.cpp 28 | 29 | tests:: 30 | @mkdir -p bin 31 | $(CXX) $(CXXFLAGS) -o bin/tests src/tests.cpp src/args.cpp 32 | 33 | check:: 34 | @make tests 35 | ./bin/tests 36 | 37 | clean:: 38 | rm -f ./bin/* 39 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Args++ 2 | 3 | An argument-parsing library for C++. 4 | 5 | * [Documentation](http://www.dmulholl.com/docs/argspp/master/) 6 | * [Basic Example](https://github.com/dmulholl/argspp/blob/master/src/example1.cpp) 7 | * [Command Example](https://github.com/dmulholl/argspp/blob/master/src/example2.cpp) 8 | -------------------------------------------------------------------------------- /src/args.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Args++: an argument-parsing library in portable C++11. 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include "args.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | using namespace args; 16 | 17 | 18 | // ----------------------------------------------------------------------------- 19 | // Flags and Options. 20 | // ----------------------------------------------------------------------------- 21 | 22 | 23 | struct args::Flag { 24 | int count = 0; 25 | }; 26 | 27 | 28 | struct args::Option { 29 | vector values; 30 | string fallback; 31 | }; 32 | 33 | 34 | // ----------------------------------------------------------------------------- 35 | // ArgStream. 36 | // ----------------------------------------------------------------------------- 37 | 38 | 39 | struct args::ArgStream { 40 | deque args; 41 | void append(string const& arg); 42 | string next(); 43 | bool hasNext(); 44 | }; 45 | 46 | 47 | void ArgStream::append(string const& arg) { 48 | args.push_back(arg); 49 | } 50 | 51 | 52 | string ArgStream::next() { 53 | string arg = args.front(); 54 | args.pop_front(); 55 | return arg; 56 | } 57 | 58 | 59 | bool ArgStream::hasNext() { 60 | return args.size() > 0; 61 | } 62 | 63 | 64 | // ----------------------------------------------------------------------------- 65 | // ArgParser: setup. 66 | // ----------------------------------------------------------------------------- 67 | 68 | 69 | void ArgParser::flag(string const& name) { 70 | Flag* flag = new Flag(); 71 | stringstream stream(name); 72 | string alias; 73 | while (stream >> alias) { 74 | flags[alias] = flag; 75 | } 76 | } 77 | 78 | 79 | void ArgParser::option(string const& name, string const& fallback) { 80 | Option* option = new Option(); 81 | option->fallback = fallback; 82 | stringstream stream(name); 83 | string alias; 84 | while (stream >> alias) { 85 | options[alias] = option; 86 | } 87 | } 88 | 89 | 90 | // ----------------------------------------------------------------------------- 91 | // ArgParser: retrieve values. 92 | // ----------------------------------------------------------------------------- 93 | 94 | 95 | bool ArgParser::found(string const& name) { 96 | if (flags.count(name) > 0) { 97 | return flags[name]->count > 0; 98 | } 99 | if (options.count(name) > 0) { 100 | return options[name]->values.size() > 0; 101 | } 102 | return false; 103 | } 104 | 105 | 106 | int ArgParser::count(string const& name) { 107 | if (flags.count(name) > 0) { 108 | return flags[name]->count; 109 | } 110 | if (options.count(name) > 0) { 111 | return options[name]->values.size(); 112 | } 113 | return 0; 114 | } 115 | 116 | 117 | string ArgParser::value(string const& name) { 118 | if (options.count(name) > 0) { 119 | if (options[name]->values.size() > 0) { 120 | return options[name]->values.back(); 121 | } 122 | return options[name]->fallback; 123 | } 124 | return string(); 125 | } 126 | 127 | 128 | vector ArgParser::values(string const& name) { 129 | if (options.count(name) > 0) { 130 | return options[name]->values; 131 | } 132 | return vector(); 133 | } 134 | 135 | 136 | // ----------------------------------------------------------------------------- 137 | // ArgParser: commands. 138 | // ----------------------------------------------------------------------------- 139 | 140 | 141 | ArgParser& ArgParser::command( 142 | string const& name, 143 | string const& helptext, 144 | void (*callback)(string cmd_name, ArgParser& cmd_parser)) { 145 | 146 | ArgParser *parser = new ArgParser(); 147 | parser->helptext = helptext; 148 | parser->callback = callback; 149 | 150 | stringstream stream(name); 151 | string alias; 152 | 153 | while (stream >> alias) { 154 | commands[alias] = parser; 155 | } 156 | 157 | return *parser; 158 | } 159 | 160 | 161 | bool ArgParser::commandFound() { 162 | return command_name != ""; 163 | } 164 | 165 | 166 | string ArgParser::commandName() { 167 | return command_name; 168 | } 169 | 170 | 171 | ArgParser& ArgParser::commandParser() { 172 | return *commands[command_name]; 173 | } 174 | 175 | 176 | // ----------------------------------------------------------------------------- 177 | // ArgParser: parse arguments. 178 | // ----------------------------------------------------------------------------- 179 | 180 | 181 | // Parse an option of the form --name=value or -n=value. 182 | void ArgParser::parseEqualsOption(string prefix, string name, string value) { 183 | if (options.count(name) > 0) { 184 | if (value.size() > 0) { 185 | options[name]->values.push_back(value); 186 | } else { 187 | cerr << "Error: missing value for " << prefix << name << ".\n"; 188 | exit(1); 189 | } 190 | } else { 191 | cerr << "Error: " << prefix << name << " is not a recognised option.\n"; 192 | exit(1); 193 | } 194 | } 195 | 196 | 197 | // Parse a long-form option, i.e. an option beginning with a double dash. 198 | void ArgParser::parseLongOption(string arg, ArgStream& stream) { 199 | size_t pos = arg.find("="); 200 | if (pos != string::npos) { 201 | parseEqualsOption("--", arg.substr(0, pos), arg.substr(pos + 1)); 202 | return; 203 | } 204 | 205 | if (flags.count(arg) > 0) { 206 | flags[arg]->count++; 207 | return; 208 | } 209 | 210 | if (options.count(arg) > 0) { 211 | if (stream.hasNext()) { 212 | options[arg]->values.push_back(stream.next()); 213 | return; 214 | } else { 215 | cerr << "Error: missing argument for --" << arg << ".\n"; 216 | exit(1); 217 | } 218 | } 219 | 220 | if (arg == "help" && this->helptext != "") { 221 | exitHelp(); 222 | } 223 | 224 | if (arg == "version" && this->version != "") { 225 | exitVersion(); 226 | } 227 | 228 | cerr << "Error: --" << arg << " is not a recognised flag or option.\n"; 229 | exit(1); 230 | } 231 | 232 | 233 | // Parse a short-form option, i.e. an option beginning with a single dash. 234 | void ArgParser::parseShortOption(string arg, ArgStream& stream) { 235 | size_t pos = arg.find("="); 236 | if (pos != string::npos) { 237 | parseEqualsOption("-", arg.substr(0, pos), arg.substr(pos + 1)); 238 | return; 239 | } 240 | 241 | for (char& c: arg) { 242 | string name = string(1, c); 243 | 244 | if (flags.count(name) > 0) { 245 | flags[name]->count++; 246 | continue; 247 | } 248 | 249 | if (options.count(name) > 0) { 250 | if (stream.hasNext()) { 251 | options[name]->values.push_back(stream.next()); 252 | continue; 253 | } else { 254 | if (arg.size() > 1) { 255 | cerr << "Error: missing argument for '" << c << "' in -" << arg << ".\n"; 256 | } else { 257 | cerr << "Error: missing argument for -" << c << ".\n"; 258 | } 259 | exit(1); 260 | } 261 | } 262 | 263 | if (c == 'h' && this->helptext != "") { 264 | exitHelp(); 265 | } 266 | 267 | if (c == 'v' && this->version != "") { 268 | exitVersion(); 269 | } 270 | 271 | if (arg.size() > 1) { 272 | cerr << "Error: '" << c << "' in -" << arg << " is not a recognised flag or option.\n"; 273 | } else { 274 | cerr << "Error: -" << c << " is not a recognised flag or option.\n"; 275 | } 276 | exit(1); 277 | } 278 | } 279 | 280 | 281 | // Parse a stream of string arguments. 282 | void ArgParser::parse(ArgStream& stream) { 283 | bool is_first_arg = true; 284 | 285 | while (stream.hasNext()) { 286 | string arg = stream.next(); 287 | 288 | // If we enounter a '--', turn off option parsing. 289 | if (arg == "--") { 290 | while (stream.hasNext()) { 291 | args.push_back(stream.next()); 292 | } 293 | continue; 294 | } 295 | 296 | // Is the argument a long-form option or flag? 297 | if (arg.compare(0, 2, "--") == 0) { 298 | parseLongOption(arg.substr(2), stream); 299 | continue; 300 | } 301 | 302 | // Is the argument a short-form option or flag? If the argument 303 | // consists of a single dash or a dash followed by a digit, we treat 304 | // it as a positional argument. 305 | if (arg[0] == '-') { 306 | if (arg.size() == 1 || isdigit(arg[1])) { 307 | args.push_back(arg); 308 | } else { 309 | parseShortOption(arg.substr(1), stream); 310 | } 311 | continue; 312 | } 313 | 314 | // Is the argument a registered command? 315 | if (is_first_arg && commands.count(arg) > 0) { 316 | ArgParser* command_parser = commands[arg]; 317 | command_name = arg; 318 | command_parser->parse(stream); 319 | if (command_parser->callback != nullptr) { 320 | command_parser->callback(arg, *command_parser); 321 | } 322 | continue; 323 | } 324 | 325 | // Is the argument the automatic 'help' command? 326 | if (is_first_arg && arg == "help" && commands.size() > 0) { 327 | if (stream.hasNext()) { 328 | string name = stream.next(); 329 | if (commands.find(name) == commands.end()) { 330 | cerr << "Error: '" << name << "' is not a recognised command.\n"; 331 | exit(1); 332 | } else { 333 | commands[name]->exitHelp(); 334 | } 335 | } else { 336 | cerr << "Error: the help command requires an argument.\n"; 337 | exit(1); 338 | } 339 | } 340 | 341 | // Otherwise add the argument to our list of positional arguments. 342 | args.push_back(arg); 343 | is_first_arg = false; 344 | } 345 | } 346 | 347 | 348 | // Parse an array of string arguments. We assume that [argc] and [argv] are the 349 | // original parameters passed to main() and skip the first element. In some 350 | // situations [argv] can be empty, i.e. [argc == 0]. This can lead to security 351 | // vulnerabilities if not handled explicitly. 352 | void ArgParser::parse(int argc, char **argv) { 353 | if (argc > 1) { 354 | ArgStream stream; 355 | for (int i = 1; i < argc; i++) { 356 | stream.append(argv[i]); 357 | } 358 | parse(stream); 359 | } 360 | } 361 | 362 | 363 | // Parse a vector of string arguments. 364 | void ArgParser::parse(vector args) { 365 | ArgStream stream; 366 | for (string& arg: args) { 367 | stream.append(arg); 368 | } 369 | parse(stream); 370 | } 371 | 372 | 373 | // ----------------------------------------------------------------------------- 374 | // ArgParser: utilities. 375 | // ----------------------------------------------------------------------------- 376 | 377 | 378 | // Override the << stream insertion operator to support vectors. This will 379 | // allow us to cout our lists of option values in the print() method. 380 | template 381 | static ostream& operator<<(ostream& stream, const vector& vec) { 382 | stream << "["; 383 | for(size_t i = 0; i < vec.size(); ++i) { 384 | if (i) cout << ", "; 385 | stream << vec[i]; 386 | } 387 | stream << "]"; 388 | return stream; 389 | } 390 | 391 | 392 | // Dump the parser's state to stdout. 393 | void ArgParser::print() { 394 | cout << "Options:\n"; 395 | if (options.size() > 0) { 396 | for (auto element: options) { 397 | cout << " " << element.first << ": "; 398 | Option *option = element.second; 399 | cout << "(" << option->fallback << ") "; 400 | cout << option->values; 401 | cout << "\n"; 402 | } 403 | } else { 404 | cout << " [none]\n"; 405 | } 406 | 407 | cout << "\nFlags:\n"; 408 | if (flags.size() > 0) { 409 | for (auto element: flags) { 410 | cout << " " << element.first << ": " << element.second->count << "\n"; 411 | } 412 | } else { 413 | cout << " [none]\n"; 414 | } 415 | 416 | cout << "\nArguments:\n"; 417 | if (args.size() > 0) { 418 | for (auto arg: args) { 419 | cout << " " << arg << "\n"; 420 | } 421 | } else { 422 | cout << " [none]\n"; 423 | } 424 | 425 | cout << "\nCommand:\n"; 426 | if (commandFound()) { 427 | cout << " " << command_name << "\n"; 428 | } else { 429 | cout << " [none]\n"; 430 | } 431 | } 432 | 433 | 434 | // Print the parser's help text and exit. 435 | void ArgParser::exitHelp() { 436 | cout << helptext << endl; 437 | exit(0); 438 | } 439 | 440 | 441 | // Print the parser's version string and exit. 442 | void ArgParser::exitVersion() { 443 | cout << version << endl; 444 | exit(0); 445 | } 446 | 447 | 448 | // ----------------------------------------------------------------------------- 449 | // ArgParser: cleanup. 450 | // ----------------------------------------------------------------------------- 451 | 452 | 453 | ArgParser::~ArgParser() { 454 | set unique_options; 455 | for (auto element: options) { 456 | unique_options.insert(element.second); 457 | } 458 | for (auto pointer: unique_options) { 459 | delete pointer; 460 | } 461 | 462 | set unique_flags; 463 | for (auto element: flags) { 464 | unique_flags.insert(element.second); 465 | } 466 | for (auto pointer: unique_flags) { 467 | delete pointer; 468 | } 469 | 470 | set unique_cmd_parsers; 471 | for (auto element: commands) { 472 | unique_cmd_parsers.insert(element.second); 473 | } 474 | for (auto pointer: unique_cmd_parsers) { 475 | delete pointer; 476 | } 477 | } 478 | -------------------------------------------------------------------------------- /src/args.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Args++: an argument-parsing library in portable C++11. 3 | // 4 | // Author: Darren Mulholland 5 | // License: Public Domain 6 | // Version: 2.1.0 7 | // ----------------------------------------------------------------------------- 8 | 9 | #ifndef args_h 10 | #define args_h 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace args { 17 | 18 | struct ArgStream; 19 | struct Option; 20 | struct Flag; 21 | 22 | class ArgParser { 23 | public: 24 | ArgParser( 25 | std::string const& helptext = "", 26 | std::string const& version = "" 27 | ) : helptext(helptext), version(version) {} 28 | 29 | ~ArgParser(); 30 | 31 | // Stores positional arguments. 32 | std::vector args; 33 | 34 | // Application/command help text and version strings. 35 | std::string helptext; 36 | std::string version; 37 | 38 | // Callback function for command parsers. 39 | void (*callback)(std::string cmd_name, ArgParser& cmd_parser); 40 | 41 | // Register flags and options. 42 | void flag(std::string const& name); 43 | void option(std::string const& name, std::string const& fallback = ""); 44 | 45 | // Parse the application's command line arguments. 46 | void parse(int argc, char **argv); 47 | void parse(std::vector args); 48 | 49 | // Retrieve flag and option values. 50 | bool found(std::string const& name); 51 | int count(std::string const& name); 52 | std::string value(std::string const& name); 53 | std::vector values(std::string const& name); 54 | 55 | // Register a command. Returns the command's ArgParser instance. 56 | ArgParser& command( 57 | std::string const& name, 58 | std::string const& helptext = "", 59 | void (*callback)(std::string cmd_name, ArgParser& cmd_parser) = nullptr 60 | ); 61 | 62 | // Utilities for handling commands manually. 63 | bool commandFound(); 64 | std::string commandName(); 65 | ArgParser& commandParser(); 66 | 67 | // Print a parser instance to stdout. 68 | void print(); 69 | 70 | private: 71 | std::map options; 72 | std::map flags; 73 | std::map commands; 74 | std::string command_name; 75 | 76 | void parse(ArgStream& args); 77 | void registerOption(std::string const& name, Option* option); 78 | void parseLongOption(std::string arg, ArgStream& stream); 79 | void parseShortOption(std::string arg, ArgStream& stream); 80 | void parseEqualsOption(std::string prefix, std::string name, std::string value); 81 | void exitHelp(); 82 | void exitVersion(); 83 | }; 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/example1.cpp: -------------------------------------------------------------------------------- 1 | #include "args.h" 2 | 3 | int main(int argc, char **argv) { 4 | args::ArgParser parser("Usage: example...", "1.0"); 5 | 6 | parser.flag("foo f"); 7 | parser.option("bar b", "default"); 8 | 9 | parser.parse(argc, argv); 10 | parser.print(); 11 | } 12 | -------------------------------------------------------------------------------- /src/example2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "args.h" 3 | 4 | using namespace args; 5 | using namespace std; 6 | 7 | void callback(string cmd_name, ArgParser& cmd_parser) { 8 | cout << "---------- boo! ----------\n"; 9 | cmd_parser.print(); 10 | cout << "--------------------------\n\n"; 11 | } 12 | 13 | int main(int argc, char **argv) { 14 | ArgParser parser("Usage: example...", "1.0"); 15 | 16 | ArgParser& cmd_parser = parser.command("boo", "Usage: example boo...", callback); 17 | cmd_parser.flag("foo f"); 18 | cmd_parser.option("bar b", "default"); 19 | 20 | parser.parse(argc, argv); 21 | parser.print(); 22 | } 23 | -------------------------------------------------------------------------------- /src/tests.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Unit test suite. 3 | // ----------------------------------------------------------------------------- 4 | 5 | #include 6 | #include 7 | #include 8 | #include "args.h" 9 | 10 | using namespace std; 11 | using namespace args; 12 | 13 | // ----------------------------------------------------------------------------- 14 | // 1. Flags. 15 | // ----------------------------------------------------------------------------- 16 | 17 | void test_flag_empty_input() { 18 | ArgParser parser; 19 | parser.flag("foo f"); 20 | parser.parse(vector()); 21 | assert(parser.found("foo") == false); 22 | assert(parser.count("foo") == 0); 23 | printf("."); 24 | } 25 | 26 | void test_flag_not_found() { 27 | ArgParser parser; 28 | parser.flag("foo f"); 29 | parser.parse(vector({"abc", "def"})); 30 | assert(parser.found("foo") == false); 31 | assert(parser.count("foo") == 0); 32 | printf("."); 33 | } 34 | 35 | void test_flag_long() { 36 | ArgParser parser; 37 | parser.flag("foo f"); 38 | parser.parse(vector({"--foo"})); 39 | assert(parser.found("foo") == true); 40 | assert(parser.count("foo") == 1); 41 | printf("."); 42 | } 43 | 44 | void test_flag_short() { 45 | ArgParser parser; 46 | parser.flag("foo f"); 47 | parser.parse(vector({"-f"})); 48 | assert(parser.found("foo") == true); 49 | assert(parser.count("foo") == 1); 50 | printf("."); 51 | } 52 | 53 | void test_flag_condensed() { 54 | ArgParser parser; 55 | parser.flag("foo f"); 56 | parser.parse(vector({"-fff"})); 57 | assert(parser.found("foo") == true); 58 | assert(parser.count("foo") == 3); 59 | printf("."); 60 | } 61 | 62 | void test_flag_multi() { 63 | ArgParser parser; 64 | parser.flag("foo f"); 65 | parser.parse(vector({"-fff", "--foo", "-f"})); 66 | assert(parser.found("foo") == true); 67 | assert(parser.count("foo") == 5); 68 | printf("."); 69 | } 70 | 71 | // ----------------------------------------------------------------------------- 72 | // 2. Options. 73 | // ----------------------------------------------------------------------------- 74 | 75 | void test_option_not_found() { 76 | ArgParser parser; 77 | parser.option("foo f", "default"); 78 | parser.parse(vector({"abc", "def"})); 79 | assert(parser.found("foo") == false); 80 | assert(parser.count("foo") == 0); 81 | assert(parser.value("foo") == "default"); 82 | printf("."); 83 | } 84 | 85 | void test_option_long() { 86 | ArgParser parser; 87 | parser.option("foo f", "default"); 88 | parser.parse(vector({"--foo", "bar"})); 89 | assert(parser.found("foo") == true); 90 | assert(parser.count("foo") == 1); 91 | assert(parser.value("foo") == "bar"); 92 | printf("."); 93 | } 94 | 95 | void test_option_short() { 96 | ArgParser parser; 97 | parser.option("foo f", "default"); 98 | parser.parse(vector({"-f", "bar"})); 99 | assert(parser.found("foo") == true); 100 | assert(parser.count("foo") == 1); 101 | assert(parser.value("foo") == "bar"); 102 | printf("."); 103 | } 104 | 105 | void test_option_condensed() { 106 | ArgParser parser; 107 | parser.option("foo f", "default"); 108 | parser.parse(vector({"-ff", "bar", "baz"})); 109 | assert(parser.found("foo") == true); 110 | assert(parser.count("foo") == 2); 111 | assert(parser.value("foo") == "baz"); 112 | printf("."); 113 | } 114 | 115 | void test_option_multi() { 116 | ArgParser parser; 117 | parser.option("foo f", "default"); 118 | parser.parse(vector({"-ff", "bar", "baz", "--foo", "bam"})); 119 | assert(parser.found("foo") == true); 120 | assert(parser.count("foo") == 3); 121 | assert(parser.value("foo") == "bam"); 122 | printf("."); 123 | } 124 | 125 | // ----------------------------------------------------------------------------- 126 | // 3. Positional arguments. 127 | // ----------------------------------------------------------------------------- 128 | 129 | void test_pos_args() { 130 | ArgParser parser; 131 | parser.parse(vector({"abc", "def"})); 132 | assert(parser.args.size() == 2); 133 | assert(parser.args[0] == "abc"); 134 | assert(parser.args[1] == "def"); 135 | printf("."); 136 | } 137 | 138 | // ----------------------------------------------------------------------------- 139 | // 4. Option parsing switch. 140 | // ----------------------------------------------------------------------------- 141 | 142 | void test_option_parsing_switch() { 143 | ArgParser parser; 144 | parser.parse(vector({"foo", "--", "--bar", "--baz"})); 145 | assert(parser.args.size() == 3); 146 | printf("."); 147 | } 148 | 149 | // ----------------------------------------------------------------------------- 150 | // 7. Commands. 151 | // ----------------------------------------------------------------------------- 152 | 153 | void test_command() { 154 | ArgParser parser; 155 | ArgParser& cmd_parser = parser.command("boo"); 156 | cmd_parser.flag("foo"); 157 | cmd_parser.option("bar", "default"); 158 | parser.parse(vector({"boo", "abc", "def", "--foo", "--bar", "baz"})); 159 | assert(parser.commandFound()); 160 | assert(parser.commandName() == "boo"); 161 | assert(cmd_parser.args.size() == 2); 162 | assert(cmd_parser.found("foo")); 163 | assert(cmd_parser.value("bar") == "baz"); 164 | printf("."); 165 | } 166 | 167 | // ----------------------------------------------------------------------------- 168 | // Test runner. 169 | // ----------------------------------------------------------------------------- 170 | 171 | void line() { 172 | for (int i = 0; i < 80; i++) { 173 | printf("-"); 174 | } 175 | printf("\n"); 176 | } 177 | 178 | int main() { 179 | setbuf(stdout, NULL); 180 | line(); 181 | 182 | printf("Tests: 1 "); 183 | test_flag_empty_input(); 184 | test_flag_not_found(); 185 | test_flag_long(); 186 | test_flag_short(); 187 | test_flag_condensed(); 188 | test_flag_multi(); 189 | 190 | printf(" 2 "); 191 | test_option_not_found(); 192 | test_option_long(); 193 | test_option_short(); 194 | test_option_condensed(); 195 | test_option_multi(); 196 | 197 | printf(" 3 "); 198 | test_pos_args(); 199 | 200 | printf(" 4 "); 201 | test_option_parsing_switch(); 202 | 203 | printf(" 5 "); 204 | test_command(); 205 | 206 | printf(" [ok]\n"); 207 | line(); 208 | } 209 | --------------------------------------------------------------------------------