├── .gitignore ├── CHANGELOG ├── CMakeLists.txt ├── LICENSE ├── README.md ├── optionparser.h ├── xbiso.cpp ├── xbisoConfig.h.in ├── xdvdfs.cpp └── xdvdfs.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 0.7.0: 2 | complete rewrite in C++ with Cmake 3 | no more xiso <= 1.10 compatibility 4 | no more integrated ftp support 5 | working Windows support 6 | 7 | 0.6.1: 8 | patched traversal bug 9 | 10 | 0.6.0: 11 | add mlib to configure 12 | support for extract-xiso optimized images - Rasmus Rohde 13 | support for big endian - Rasmus Rohde 14 | added make install/uninstall 15 | updated to compile on the following platforms/archs (thanks to sourceforge cf) 16 | x86-linux 17 | x86_64-linux 18 | x86-freebsd 19 | x86-netbsd 20 | ppc-osx 21 | alpha-linux 22 | sparc-solaris 23 | 24 | 0.5.9: 25 | realloc bugfix - Capelle Benoit 26 | 27 | 0.5.8: 28 | Support for images generated by xiso <=1.10. (see readme for more details) 29 | Bugfix for directories that don't contain files. 30 | Fix large memory leak as well as other minor ones. 31 | (note: no win32 binary included) 32 | 33 | 0.5.7: 34 | 35 | Merged 0.5.6-1 bugfix patch. 36 | Merged xbiso-ftp by, Stefan Alfredsson . 37 | configure script for detection of libftp etc. 38 | Other minor changes. 39 | 40 | 0.5.6: 41 | 42 | Fixed win32 support. 43 | Provided win32 binary. 44 | 45 | 0.5.5: 46 | 47 | First public release. 48 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | set (CMAKE_CXX_STANDARD 11) 3 | 4 | project (xbiso) 5 | 6 | set (XBISO_VERSION 0.7.1) 7 | set (XBISO_OS ${CMAKE_SYSTEM_NAME}) 8 | 9 | configure_file ( 10 | "${PROJECT_SOURCE_DIR}/xbisoConfig.h.in" 11 | "${PROJECT_BINARY_DIR}/xbisoConfig.h" 12 | ) 13 | 14 | include_directories("${PROJECT_BINARY_DIR}") 15 | 16 | add_executable(xbiso xbiso.cpp xdvdfs.cpp) 17 | 18 | install (TARGETS xbiso DESTINATION bin) 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xbiso 2 | xbiso is an ISO extraction and creation utillity for XDVDFS images. 3 | 4 | ## Old version 5 | This new version of xbiso is written in C++ and is NOT directly based on the old C-code written by Tonto Rostenfaust. I'd like to thank him and the other authors for their work, though, because it was their work that got me interested in writing this program. If you want to find out more about the old xbiso-version and it's authors, you can find all information in the history of this repository. 6 | 7 | 8 | ## FAQ ## 9 | ### How can I create an image? 10 | Unfortunately, you can't right now. Creating an image is more complicated than extracting one and thus isn't implemented yet. 11 | 12 | ### How do I extract an image? 13 | Simply call xbiso with the "-x" parameter. To see a list of options supported by xbiso, simply call it without any parameters or with the "-h" parameter. 14 | 15 | ### What operating systems are supported? 16 | I've been developing and testing this program on both Linux and Windows, both x86_64. 17 | Please not that big-endian architectures aren't supported right now (they were on the old version), I'm currently planning to readd support in a clean way. 18 | 19 | ### How can I build xbiso myself? 20 | I recommend the following procedure (on Linux): 21 | 1. Clone the Git-repository and enter the repository-folder 22 | 2. Create a directory in which to build the program and enter it: mkdir build && cd build 23 | 3. Run CMake: cmake ../ 24 | 4. Run make: make 25 | 5. Enjoy your very own "xbiso" binary! 26 | 27 | ### Why the rewrite? 28 | The old code wasn't very pretty and had no good Windows-support. The rewrite in C++ makes it easier to read, understand and extend the code. 29 | 30 | ### Why doesn't this version have FTP-support? 31 | FTP support would make the whole code more complex while being of little benefit. It isn't very complex or cumbersome to use an external FTP-client. "Do one thing and do it well." 32 | -------------------------------------------------------------------------------- /optionparser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The Lean Mean C++ Option Parser 3 | * 4 | * Copyright (C) 2012 Matthias S. Benkmann 5 | * Copyright (C) 2015 Stefan Schmidt 6 | * 7 | * The "Software" in the following 2 paragraphs refers to this file containing 8 | * the code to The Lean Mean C++ Option Parser. 9 | * The "Software" does NOT refer to any other files which you 10 | * may have received alongside this file (e.g. as part of a larger project that 11 | * incorporates The Lean Mean C++ Option Parser). 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software, to deal in the Software without restriction, including 15 | * without limitation the rights to use, copy, modify, merge, publish, 16 | * distribute, sublicense, and/or sell copies of the Software, and to permit 17 | * persons to whom the Software is furnished to do so, subject to the following 18 | * conditions: 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | */ 30 | 31 | /* 32 | * NOTE: It is recommended that you read the processed HTML doxygen documentation 33 | * rather than this source. If you don't know doxygen, it's like javadoc for C++. 34 | * If you don't want to install doxygen you can find a copy of the processed 35 | * documentation at 36 | * 37 | * http://optionparser.sourceforge.net/ 38 | * 39 | */ 40 | 41 | /** 42 | * @file 43 | * 44 | * @brief This is the only file required to use The Lean Mean C++ Option Parser. 45 | * Just \#include it and you're set. 46 | * 47 | * The Lean Mean C++ Option Parser handles the program's command line arguments 48 | * (argc, argv). 49 | * It supports the short and long option formats of getopt(), getopt_long() 50 | * and getopt_long_only() but has a more convenient interface. 51 | * The following features set it apart from other option parsers: 52 | * 53 | * @par Highlights: 54 | *
    55 | *
  • It is a header-only library. Just \#include "optionparser.h" and you're set. 56 | *
  • It is freestanding. There are no dependencies whatsoever, not even the 57 | * C or C++ standard library. 58 | *
  • It has a usage message formatter that supports column alignment and 59 | * line wrapping. This aids localization because it adapts to 60 | * translated strings that are shorter or longer (even if they contain 61 | * Asian wide characters). 62 | *
  • Unlike getopt() and derivatives it doesn't force you to loop through 63 | * options sequentially. Instead you can access options directly like this: 64 | *
      65 | *
    • Test for presence of a switch in the argument vector: 66 | * @code if ( options[QUIET] ) ... @endcode 67 | *
    • Evaluate --enable-foo/--disable-foo pair where the last one used wins: 68 | * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode 69 | *
    • Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): 70 | * @code int verbosity = options[VERBOSE].count(); @endcode 71 | *
    • Iterate over all --file=<fname> arguments: 72 | * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) 73 | * fname = opt->arg; ... @endcode 74 | *
    • If you really want to, you can still process all arguments in order: 75 | * @code 76 | * for (int i = 0; i < p.optionsCount(); ++i) { 77 | * Option& opt = buffer[i]; 78 | * switch(opt.index()) { 79 | * case HELP: ... 80 | * case VERBOSE: ... 81 | * case FILE: fname = opt.arg; ... 82 | * case UNKNOWN: ... 83 | * @endcode 84 | *
    85 | *
@n 86 | * Despite these features the code size remains tiny. 87 | * It is smaller than uClibc's GNU getopt() and just a 88 | * couple 100 bytes larger than uClibc's SUSv3 getopt(). @n 89 | * (This does not include the usage formatter, of course. But you don't have to use that.) 90 | * 91 | * @par Download: 92 | * Tarball with examples and test programs: 93 | * optionparser-1.3.tar.gz @n 94 | * Just the header (this is all you really need): 95 | * optionparser.h 96 | * 97 | * @par Changelog: 98 | * Version 1.3: Compatible with Microsoft Visual C++. @n 99 | * Version 1.2: Added @ref option::Option::namelen "Option::namelen" and removed the extraction 100 | * of short option characters into a special buffer. @n 101 | * Changed @ref option::Arg::Optional "Arg::Optional" to accept arguments if they are attached 102 | * rather than separate. This is what GNU getopt() does and how POSIX recommends 103 | * utilities should interpret their arguments.@n 104 | * Version 1.1: Optional mode with argument reordering as done by GNU getopt(), so that 105 | * options and non-options can be mixed. See 106 | * @ref option::Parser::parse() "Parser::parse()". 107 | * 108 | * @par Feedback: 109 | * Send questions, bug reports, feature requests etc. to: optionparser-feedback (a) lists.sourceforge.net 110 | * @htmlonly @endhtmlonly 111 | * 112 | * 113 | * @par Example program: 114 | * (Note: @c option::* identifiers are links that take you to their documentation.) 115 | * @code 116 | * #error EXAMPLE SHORTENED FOR READABILITY. BETTER EXAMPLES ARE IN THE .TAR.GZ! 117 | * #include 118 | * #include "optionparser.h" 119 | * 120 | * enum optionIndex { UNKNOWN, HELP, PLUS }; 121 | * const option::Descriptor usage[] = 122 | * { 123 | * {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n" 124 | * "Options:" }, 125 | * {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." }, 126 | * {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." }, 127 | * {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n" 128 | * " example --unknown -- --this_is_no_option\n" 129 | * " example -unk --plus -ppp file1 file2\n" }, 130 | * {0,0,0,0,0,0} 131 | * }; 132 | * 133 | * int main(int argc, char* argv[]) 134 | * { 135 | * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present 136 | * option::Stats stats(usage, argc, argv); 137 | * option::Option options[stats.options_max], buffer[stats.buffer_max]; 138 | * option::Parser parse(usage, argc, argv, options, buffer); 139 | * 140 | * if (parse.error()) 141 | * return 1; 142 | * 143 | * if (options[HELP] || argc == 0) { 144 | * option::printUsage(std::cout, usage); 145 | * return 0; 146 | * } 147 | * 148 | * std::cout << "--plus count: " << 149 | * options[PLUS].count() << "\n"; 150 | * 151 | * for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next()) 152 | * std::cout << "Unknown option: " << opt->name << "\n"; 153 | * 154 | * for (int i = 0; i < parse.nonOptionsCount(); ++i) 155 | * std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n"; 156 | * } 157 | * @endcode 158 | * 159 | * @par Option syntax: 160 | * @li The Lean Mean C++ Option Parser follows POSIX getopt() conventions and supports 161 | * GNU-style getopt_long() long options as well as Perl-style single-minus 162 | * long options (getopt_long_only()). 163 | * @li short options have the format @c -X where @c X is any character that fits in a char. 164 | * @li short options can be grouped, i.e. -X -Y is equivalent to @c -XY. 165 | * @li a short option may take an argument either separate (-X foo) or 166 | * attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by 167 | * registering @c X as a long option (in addition to being a short option) and 168 | * enabling single-minus long options. 169 | * @li an argument-taking short option may be grouped if it is the last in the group, e.g. 170 | * @c -ABCXfoo or -ABCX foo (@c foo is the argument to the @c -X option). 171 | * @li a lone minus character @c '-' is not treated as an option. It is customarily used where 172 | * a file name is expected to refer to stdin or stdout. 173 | * @li long options have the format @c --option-name. 174 | * @li the option-name of a long option can be anything and include any characters. 175 | * Even @c = characters will work, but don't do that. 176 | * @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous. 177 | * You can set a minimum length for abbreviations. 178 | * @li [optional] long options may begin with a single minus. The double minus form is always 179 | * accepted, too. 180 | * @li a long option may take an argument either separate ( --option arg ) or 181 | * attached ( --option=arg ). In the attached form the equals sign is mandatory. 182 | * @li an empty string can be passed as an attached long option argument: --option-name= . 183 | * Note the distinction between an empty string as argument and no argument at all. 184 | * @li an empty string is permitted as separate argument to both long and short options. 185 | * @li Arguments to both short and long options may start with a @c '-' character. E.g. 186 | * -X-X , -X -X or --long-X=-X . If @c -X 187 | * and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases. 188 | * @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must 189 | * be attached. 190 | * @li the special option @c -- (i.e. without a name) terminates the list of 191 | * options. Everything that follows is a non-option argument, even if it starts with 192 | * a @c '-' character. The @c -- itself will not appear in the parse results. 193 | * @li the first argument that doesn't start with @c '-' or @c '--' and does not belong to 194 | * a preceding argument-taking option, will terminate the option list and is the 195 | * first non-option argument. All following command line arguments are treated as 196 | * non-option arguments, even if they start with @c '-' . @n 197 | * NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is 198 | * explicitly requested (e.g. by setting POSIXLY_CORRECT). @n 199 | * You can enable the GNU behaviour by passing @c true as first argument to 200 | * e.g. @ref option::Parser::parse() "Parser::parse()". 201 | * @li Arguments that look like options (i.e. @c '-' followed by at least 1 character) but 202 | * aren't, are NOT treated as non-option arguments. They are treated as unknown options and 203 | * are collected into a list of unknown options for error reporting. @n 204 | * This means that in order to pass a first non-option 205 | * argument beginning with the minus character it is required to use the 206 | * @c -- special option, e.g. 207 | * @code 208 | * program -x -- --strange-filename 209 | * @endcode 210 | * In this example, @c --strange-filename is a non-option argument. If the @c -- 211 | * were omitted, it would be treated as an unknown option. @n 212 | * See @ref option::Descriptor::longopt for information on how to collect unknown options. 213 | * 214 | */ 215 | 216 | #ifndef OPTIONPARSER_H_ 217 | #define OPTIONPARSER_H_ 218 | 219 | /** @brief The namespace of The Lean Mean C++ Option Parser. */ 220 | namespace option 221 | { 222 | 223 | #ifdef _MSC_VER 224 | #include 225 | #pragma intrinsic(_BitScanReverse) 226 | struct MSC_Builtin_CLZ 227 | { 228 | static int builtin_clz(unsigned x) 229 | { 230 | unsigned long index; 231 | _BitScanReverse(&index, x); 232 | return 32-index; // int is always 32bit on Windows, even for target x64 233 | } 234 | }; 235 | #define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x) 236 | #endif 237 | 238 | class Option; 239 | 240 | /** 241 | * @brief Possible results when checking if an argument is valid for a certain option. 242 | * 243 | * In the case that no argument is provided for an option that takes an 244 | * optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent. 245 | */ 246 | enum ArgStatus 247 | { 248 | //! The option does not take an argument. 249 | ARG_NONE, 250 | //! The argument is acceptable for the option. 251 | ARG_OK, 252 | //! The argument is not acceptable but that's non-fatal because the option's argument is optional. 253 | ARG_IGNORE, 254 | //! The argument is not acceptable and that's fatal. 255 | ARG_ILLEGAL 256 | }; 257 | 258 | /** 259 | * @brief Signature of functions that check if an argument is valid for a certain type of option. 260 | * 261 | * Every Option has such a function assigned in its Descriptor. 262 | * @code 263 | * Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... }; 264 | * @endcode 265 | * 266 | * A CheckArg function has the following signature: 267 | * @code ArgStatus CheckArg(const Option& option, bool msg); @endcode 268 | * 269 | * It is used to check if a potential argument would be acceptable for the option. 270 | * It will even be called if there is no argument. In that case @c option.arg will be @c NULL. 271 | * 272 | * If @c msg is @c true and the function determines that an argument is not acceptable and 273 | * that this is a fatal error, it should output a message to the user before 274 | * returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you 275 | * will get duplicate messages). 276 | * 277 | * See @ref ArgStatus for the meaning of the return values. 278 | * 279 | * While you can provide your own functions, 280 | * often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice: 281 | * 282 | * @li @c Arg::None @copybrief Arg::None 283 | * @li @c Arg::Optional @copybrief Arg::Optional 284 | * 285 | */ 286 | typedef ArgStatus (*CheckArg)(const Option& option, bool msg); 287 | 288 | /** 289 | * @brief Describes an option, its help text (usage) and how it should be parsed. 290 | * 291 | * The main input when constructing an option::Parser is an array of Descriptors. 292 | 293 | * @par Example: 294 | * @code 295 | * enum OptionIndex {CREATE, ...}; 296 | * enum OptionType {DISABLE, ENABLE, OTHER}; 297 | * 298 | * const option::Descriptor usage[] = { 299 | * { CREATE, // index 300 | * OTHER, // type 301 | * "c", // shortopt 302 | * "create", // longopt 303 | * Arg::None, // check_arg 304 | * "--create Tells the program to create something." // help 305 | * } 306 | * , ... 307 | * }; 308 | * @endcode 309 | */ 310 | struct Descriptor 311 | { 312 | /** 313 | * @brief Index of this option's linked list in the array filled in by the parser. 314 | * 315 | * Command line options whose Descriptors have the same index will end up in the same 316 | * linked list in the order in which they appear on the command line. If you have 317 | * multiple long option aliases that refer to the same option, give their descriptors 318 | * the same @c index. 319 | * 320 | * If you have options that mean exactly opposite things 321 | * (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same 322 | * @c index, but distinguish them through different values for @ref type. 323 | * That way they end up in the same list and you can just take the last element of the 324 | * list and use its type. This way you get the usual behaviour where switches later 325 | * on the command line override earlier ones without having to code it manually. 326 | * 327 | * @par Tip: 328 | * Use an enum rather than plain ints for better readability, as shown in the example 329 | * at Descriptor. 330 | */ 331 | const unsigned index; 332 | 333 | /** 334 | * @brief Used to distinguish between options with the same @ref index. 335 | * See @ref index for details. 336 | * 337 | * It is recommended that you use an enum rather than a plain int to make your 338 | * code more readable. 339 | */ 340 | const int type; 341 | 342 | /** 343 | * @brief Each char in this string will be accepted as a short option character. 344 | * 345 | * The string must not include the minus character @c '-' or you'll get undefined 346 | * behaviour. 347 | * 348 | * If this Descriptor should not have short option characters, use the empty 349 | * string "". NULL is not permitted here! 350 | * 351 | * See @ref longopt for more information. 352 | */ 353 | const char* const shortopt; 354 | 355 | /** 356 | * @brief The long option name (without the leading @c -- ). 357 | * 358 | * If this Descriptor should not have a long option name, use the empty 359 | * string "". NULL is not permitted here! 360 | * 361 | * While @ref shortopt allows multiple short option characters, each 362 | * Descriptor can have only a single long option name. If you have multiple 363 | * long option names referring to the same option use separate Descriptors 364 | * that have the same @ref index and @ref type. You may repeat 365 | * short option characters in such an alias Descriptor but there's no need to. 366 | * 367 | * @par Dummy Descriptors: 368 | * You can use dummy Descriptors with an 369 | * empty string for both @ref shortopt and @ref longopt to add text to 370 | * the usage that is not related to a specific option. See @ref help. 371 | * The first dummy Descriptor will be used for unknown options (see below). 372 | * 373 | * @par Unknown Option Descriptor: 374 | * The first dummy Descriptor in the list of Descriptors, 375 | * whose @ref shortopt and @ref longopt are both the empty string, will be used 376 | * as the Descriptor for unknown options. An unknown option is a string in 377 | * the argument vector that is not a lone minus @c '-' but starts with a minus 378 | * character and does not match any Descriptor's @ref shortopt or @ref longopt. @n 379 | * Note that the dummy descriptor's @ref check_arg function @e will be called and 380 | * its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL 381 | * the parsing will be aborted with Parser::error()==true. @n 382 | * if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's 383 | * @ref index @e will be used to pick the linked list into which 384 | * to put the unknown option. @n 385 | * If there is no dummy descriptor, unknown options will be dropped silently. 386 | * 387 | */ 388 | const char* const longopt; 389 | 390 | /** 391 | * @brief For each option that matches @ref shortopt or @ref longopt this function 392 | * will be called to check a potential argument to the option. 393 | * 394 | * This function will be called even if there is no potential argument. In that case 395 | * it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty 396 | * string. 397 | * 398 | * See @ref CheckArg for more information. 399 | */ 400 | const CheckArg check_arg; 401 | 402 | /** 403 | * @brief The usage text associated with the options in this Descriptor. 404 | * 405 | * You can use option::printUsage() to format your usage message based on 406 | * the @c help texts. You can use dummy Descriptors where 407 | * @ref shortopt and @ref longopt are both the empty string to add text to 408 | * the usage that is not related to a specific option. 409 | * 410 | * See option::printUsage() for special formatting characters you can use in 411 | * @c help to get a column layout. 412 | * 413 | * @attention 414 | * Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8" 415 | * prefix to make sure string literals are properly encoded. 416 | */ 417 | const char* help; 418 | }; 419 | 420 | /** 421 | * @brief A parsed option from the command line together with its argument if it has one. 422 | * 423 | * The Parser chains all parsed options with the same Descriptor::index together 424 | * to form a linked list. This allows you to easily implement all of the common ways 425 | * of handling repeated options and enable/disable pairs. 426 | * 427 | * @li Test for presence of a switch in the argument vector: 428 | * @code if ( options[QUIET] ) ... @endcode 429 | * @li Evaluate --enable-foo/--disable-foo pair where the last one used wins: 430 | * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode 431 | * @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): 432 | * @code int verbosity = options[VERBOSE].count(); @endcode 433 | * @li Iterate over all --file=<fname> arguments: 434 | * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) 435 | * fname = opt->arg; ... @endcode 436 | */ 437 | class Option 438 | { 439 | Option* next_; 440 | Option* prev_; 441 | public: 442 | /** 443 | * @brief Pointer to this Option's Descriptor. 444 | * 445 | * Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used 446 | * for unknown options. 447 | * 448 | * @attention 449 | * @c desc==NULL signals that this Option is unused. This is the default state of 450 | * elements in the result array. You don't need to test @c desc explicitly. You 451 | * can simply write something like this: 452 | * @code 453 | * if (options[CREATE]) 454 | * { 455 | * ... 456 | * } 457 | * @endcode 458 | * This works because of operator const Option*() . 459 | */ 460 | const Descriptor* desc; 461 | 462 | /** 463 | * @brief The name of the option as used on the command line. 464 | * 465 | * The main purpose of this string is to be presented to the user in messages. 466 | * 467 | * In the case of a long option, this is the actual @c argv pointer, i.e. the first 468 | * character is a '-'. In the case of a short option this points to the option 469 | * character within the @c argv string. 470 | * 471 | * Note that in the case of a short option group or an attached option argument, this 472 | * string will contain additional characters following the actual name. Use @ref namelen 473 | * to filter out the actual option name only. 474 | * 475 | */ 476 | const char* name; 477 | 478 | /** 479 | * @brief Pointer to this Option's argument (if any). 480 | * 481 | * NULL if this option has no argument. Do not confuse this with the empty string which 482 | * is a valid argument. 483 | */ 484 | const char* arg; 485 | 486 | /** 487 | * @brief The length of the option @ref name. 488 | * 489 | * Because @ref name points into the actual @c argv string, the option name may be 490 | * followed by more characters (e.g. other short options in the same short option group). 491 | * This value is the number of bytes (not characters!) that are part of the actual name. 492 | * 493 | * For a short option, this length is always 1. For a long option this length is always 494 | * at least 2 if single minus long options are permitted and at least 3 if they are disabled. 495 | * 496 | * @note 497 | * In the pathological case of a minus within a short option group (e.g. @c -xf-z), this 498 | * length is incorrect, because this case will be misinterpreted as a long option and the 499 | * name will therefore extend to the string's 0-terminator or a following '=" character 500 | * if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you 501 | * really need to distinguish the case of a long and a short option, compare @ref name to 502 | * the @c argv pointers. A long option's @c name is always identical to one of them, 503 | * whereas a short option's is never. 504 | */ 505 | int namelen; 506 | 507 | /** 508 | * @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option 509 | * is invalid (unused). 510 | * 511 | * Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided 512 | * you arrange your types properly) switch on type() without testing validity first. 513 | * @code 514 | * enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 }; 515 | * enum OptionIndex { FOO }; 516 | * const Descriptor usage[] = { 517 | * { FOO, ENABLED, "", "enable-foo", Arg::None, 0 }, 518 | * { FOO, DISABLED, "", "disable-foo", Arg::None, 0 }, 519 | * { 0, 0, 0, 0, 0, 0 } }; 520 | * ... 521 | * switch(options[FOO].last()->type()) // no validity check required! 522 | * { 523 | * case ENABLED: ... 524 | * case DISABLED: ... // UNUSED==DISABLED ! 525 | * } 526 | * @endcode 527 | */ 528 | int type() const 529 | { 530 | return desc == 0 ? 0 : desc->type; 531 | } 532 | 533 | /** 534 | * @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option 535 | * is invalid (unused). 536 | */ 537 | int index() const 538 | { 539 | return desc == 0 ? -1 : static_cast(desc->index); 540 | } 541 | 542 | /** 543 | * @brief Returns the number of times this Option (or others with the same Descriptor::index) 544 | * occurs in the argument vector. 545 | * 546 | * This corresponds to the number of elements in the linked list this Option is part of. 547 | * It doesn't matter on which element you call count(). The return value is always the same. 548 | * 549 | * Use this to implement cumulative options, such as -v, -vv, -vvv for 550 | * different verbosity levels. 551 | * 552 | * Returns 0 when called for an unused/invalid option. 553 | */ 554 | int count() 555 | { 556 | int c = (desc == 0 ? 0 : 1); 557 | Option* p = first(); 558 | while (!p->isLast()) 559 | { 560 | ++c; 561 | p = p->next_; 562 | }; 563 | return c; 564 | } 565 | 566 | /** 567 | * @brief Returns true iff this is the first element of the linked list. 568 | * 569 | * The first element in the linked list is the first option on the command line 570 | * that has the respective Descriptor::index value. 571 | * 572 | * Returns true for an unused/invalid option. 573 | */ 574 | bool isFirst() const 575 | { 576 | return isTagged(prev_); 577 | } 578 | 579 | /** 580 | * @brief Returns true iff this is the last element of the linked list. 581 | * 582 | * The last element in the linked list is the last option on the command line 583 | * that has the respective Descriptor::index value. 584 | * 585 | * Returns true for an unused/invalid option. 586 | */ 587 | bool isLast() const 588 | { 589 | return isTagged(next_); 590 | } 591 | 592 | /** 593 | * @brief Returns a pointer to the first element of the linked list. 594 | * 595 | * Use this when you want the first occurrence of an option on the command line to 596 | * take precedence. Note that this is not the way most programs handle options. 597 | * You should probably be using last() instead. 598 | * 599 | * @note 600 | * This method may be called on an unused/invalid option and will return a pointer to the 601 | * option itself. 602 | */ 603 | Option* first() 604 | { 605 | Option* p = this; 606 | while (!p->isFirst()) 607 | p = p->prev_; 608 | return p; 609 | } 610 | 611 | /** 612 | * @brief Returns a pointer to the last element of the linked list. 613 | * 614 | * Use this when you want the last occurrence of an option on the command line to 615 | * take precedence. This is the most common way of handling conflicting options. 616 | * 617 | * @note 618 | * This method may be called on an unused/invalid option and will return a pointer to the 619 | * option itself. 620 | * 621 | * @par Tip: 622 | * If you have options with opposite meanings (e.g. @c --enable-foo and @c --disable-foo), you 623 | * can assign them the same Descriptor::index to get them into the same list. Distinguish them by 624 | * Descriptor::type and all you have to do is check last()->type() to get 625 | * the state listed last on the command line. 626 | */ 627 | Option* last() 628 | { 629 | return first()->prevwrap(); 630 | } 631 | 632 | /** 633 | * @brief Returns a pointer to the previous element of the linked list or NULL if 634 | * called on first(). 635 | * 636 | * If called on first() this method returns NULL. Otherwise it will return the 637 | * option with the same Descriptor::index that precedes this option on the command 638 | * line. 639 | */ 640 | Option* prev() 641 | { 642 | return isFirst() ? 0 : prev_; 643 | } 644 | 645 | /** 646 | * @brief Returns a pointer to the previous element of the linked list with wrap-around from 647 | * first() to last(). 648 | * 649 | * If called on first() this method returns last(). Otherwise it will return the 650 | * option with the same Descriptor::index that precedes this option on the command 651 | * line. 652 | */ 653 | Option* prevwrap() 654 | { 655 | return untag(prev_); 656 | } 657 | 658 | /** 659 | * @brief Returns a pointer to the next element of the linked list or NULL if called 660 | * on last(). 661 | * 662 | * If called on last() this method returns NULL. Otherwise it will return the 663 | * option with the same Descriptor::index that follows this option on the command 664 | * line. 665 | */ 666 | Option* next() 667 | { 668 | return isLast() ? 0 : next_; 669 | } 670 | 671 | /** 672 | * @brief Returns a pointer to the next element of the linked list with wrap-around from 673 | * last() to first(). 674 | * 675 | * If called on last() this method returns first(). Otherwise it will return the 676 | * option with the same Descriptor::index that follows this option on the command 677 | * line. 678 | */ 679 | Option* nextwrap() 680 | { 681 | return untag(next_); 682 | } 683 | 684 | /** 685 | * @brief Makes @c new_last the new last() by chaining it into the list after last(). 686 | * 687 | * It doesn't matter which element you call append() on. The new element will always 688 | * be appended to last(). 689 | * 690 | * @attention 691 | * @c new_last must not yet be part of a list, or that list will become corrupted, because 692 | * this method does not unchain @c new_last from an existing list. 693 | */ 694 | void append(Option* new_last) 695 | { 696 | Option* p = last(); 697 | Option* f = first(); 698 | p->next_ = new_last; 699 | new_last->prev_ = p; 700 | new_last->next_ = tag(f); 701 | f->prev_ = tag(new_last); 702 | } 703 | 704 | /** 705 | * @brief Casts from Option to const Option* but only if this Option is valid. 706 | * 707 | * If this Option is valid (i.e. @c desc!=NULL), returns this. 708 | * Otherwise returns NULL. This allows testing an Option directly 709 | * in an if-clause to see if it is used: 710 | * @code 711 | * if (options[CREATE]) 712 | * { 713 | * ... 714 | * } 715 | * @endcode 716 | * It also allows you to write loops like this: 717 | * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) 718 | * fname = opt->arg; ... @endcode 719 | */ 720 | operator const Option*() const 721 | { 722 | return desc ? this : 0; 723 | } 724 | 725 | /** 726 | * @brief Casts from Option to Option* but only if this Option is valid. 727 | * 728 | * If this Option is valid (i.e. @c desc!=NULL), returns this. 729 | * Otherwise returns NULL. This allows testing an Option directly 730 | * in an if-clause to see if it is used: 731 | * @code 732 | * if (options[CREATE]) 733 | * { 734 | * ... 735 | * } 736 | * @endcode 737 | * It also allows you to write loops like this: 738 | * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) 739 | * fname = opt->arg; ... @endcode 740 | */ 741 | operator Option*() 742 | { 743 | return desc ? this : 0; 744 | } 745 | 746 | /** 747 | * @brief Creates a new Option that is a one-element linked list and has NULL 748 | * @ref desc, @ref name, @ref arg and @ref namelen. 749 | */ 750 | Option() : 751 | desc(0), name(0), arg(0), namelen(0) 752 | { 753 | prev_ = tag(this); 754 | next_ = tag(this); 755 | } 756 | 757 | /** 758 | * @brief Creates a new Option that is a one-element linked list and has the given 759 | * values for @ref desc, @ref name and @ref arg. 760 | * 761 | * If @c name_ points at a character other than '-' it will be assumed to refer to a 762 | * short option and @ref namelen will be set to 1. Otherwise the length will extend to 763 | * the first '=' character or the string's 0-terminator. 764 | */ 765 | Option(const Descriptor* desc_, const char* name_, const char* arg_) 766 | { 767 | init(desc_, name_, arg_); 768 | } 769 | 770 | /** 771 | * @brief Makes @c *this a copy of @c orig except for the linked list pointers. 772 | * 773 | * After this operation @c *this will be a one-element linked list. 774 | */ 775 | void operator=(const Option& orig) 776 | { 777 | init(orig.desc, orig.name, orig.arg); 778 | } 779 | 780 | /** 781 | * @brief Makes @c *this a copy of @c orig except for the linked list pointers. 782 | * 783 | * After this operation @c *this will be a one-element linked list. 784 | */ 785 | Option(const Option& orig) 786 | { 787 | init(orig.desc, orig.name, orig.arg); 788 | } 789 | 790 | private: 791 | /** 792 | * @internal 793 | * @brief Sets the fields of this Option to the given values (extracting @c name if necessary). 794 | * 795 | * If @c name_ points at a character other than '-' it will be assumed to refer to a 796 | * short option and @ref namelen will be set to 1. Otherwise the length will extend to 797 | * the first '=' character or the string's 0-terminator. 798 | */ 799 | void init(const Descriptor* desc_, const char* name_, const char* arg_) 800 | { 801 | desc = desc_; 802 | name = name_; 803 | arg = arg_; 804 | prev_ = tag(this); 805 | next_ = tag(this); 806 | namelen = 0; 807 | if (name == 0) 808 | return; 809 | namelen = 1; 810 | if (name[0] != '-') 811 | return; 812 | while (name[namelen] != 0 && name[namelen] != '=') 813 | ++namelen; 814 | } 815 | 816 | static Option* tag(Option* ptr) 817 | { 818 | return reinterpret_cast(reinterpret_cast(ptr) | 1); 819 | } 820 | 821 | static Option* untag(Option* ptr) 822 | { 823 | return reinterpret_cast(reinterpret_cast(ptr) & ~1ull); 824 | } 825 | 826 | static bool isTagged(Option* ptr) 827 | { 828 | return (reinterpret_cast(ptr) & 1); 829 | } 830 | }; 831 | 832 | /** 833 | * @brief Functions for checking the validity of option arguments. 834 | * 835 | * @copydetails CheckArg 836 | * 837 | * The following example code 838 | * can serve as starting place for writing your own more complex CheckArg functions: 839 | * @code 840 | * struct Arg: public option::Arg 841 | * { 842 | * static void printError(const char* msg1, const option::Option& opt, const char* msg2) 843 | * { 844 | * fprintf(stderr, "ERROR: %s", msg1); 845 | * fwrite(opt.name, opt.namelen, 1, stderr); 846 | * fprintf(stderr, "%s", msg2); 847 | * } 848 | * 849 | * static option::ArgStatus Unknown(const option::Option& option, bool msg) 850 | * { 851 | * if (msg) printError("Unknown option '", option, "'\n"); 852 | * return option::ARG_ILLEGAL; 853 | * } 854 | * 855 | * static option::ArgStatus Required(const option::Option& option, bool msg) 856 | * { 857 | * if (option.arg != 0) 858 | * return option::ARG_OK; 859 | * 860 | * if (msg) printError("Option '", option, "' requires an argument\n"); 861 | * return option::ARG_ILLEGAL; 862 | * } 863 | * 864 | * static option::ArgStatus NonEmpty(const option::Option& option, bool msg) 865 | * { 866 | * if (option.arg != 0 && option.arg[0] != 0) 867 | * return option::ARG_OK; 868 | * 869 | * if (msg) printError("Option '", option, "' requires a non-empty argument\n"); 870 | * return option::ARG_ILLEGAL; 871 | * } 872 | * 873 | * static option::ArgStatus Numeric(const option::Option& option, bool msg) 874 | * { 875 | * char* endptr = 0; 876 | * if (option.arg != 0 && strtol(option.arg, &endptr, 10)){}; 877 | * if (endptr != option.arg && *endptr == 0) 878 | * return option::ARG_OK; 879 | * 880 | * if (msg) printError("Option '", option, "' requires a numeric argument\n"); 881 | * return option::ARG_ILLEGAL; 882 | * } 883 | * }; 884 | * @endcode 885 | */ 886 | struct Arg 887 | { 888 | //! @brief For options that don't take an argument: Returns ARG_NONE. 889 | static ArgStatus None(const Option&, bool) 890 | { 891 | return ARG_NONE; 892 | } 893 | 894 | //! @brief Returns ARG_OK if the argument is attached and ARG_IGNORE otherwise. 895 | static ArgStatus Optional(const Option& option, bool) 896 | { 897 | if (option.arg && option.name[option.namelen] != 0) 898 | return ARG_OK; 899 | else 900 | return ARG_IGNORE; 901 | } 902 | }; 903 | 904 | /** 905 | * @brief Determines the minimum lengths of the buffer and options arrays used for Parser. 906 | * 907 | * Because Parser doesn't use dynamic memory its output arrays have to be pre-allocated. 908 | * If you don't want to use fixed size arrays (which may turn out too small, causing 909 | * command line arguments to be dropped), you can use Stats to determine the correct sizes. 910 | * Stats work cumulative. You can first pass in your default options and then the real 911 | * options and afterwards the counts will reflect the union. 912 | */ 913 | struct Stats 914 | { 915 | /** 916 | * @brief Number of elements needed for a @c buffer[] array to be used for 917 | * @ref Parser::parse() "parsing" the same argument vectors that were fed 918 | * into this Stats object. 919 | * 920 | * @note 921 | * This number is always 1 greater than the actual number needed, to give 922 | * you a sentinel element. 923 | */ 924 | unsigned buffer_max; 925 | 926 | /** 927 | * @brief Number of elements needed for an @c options[] array to be used for 928 | * @ref Parser::parse() "parsing" the same argument vectors that were fed 929 | * into this Stats object. 930 | * 931 | * @note 932 | * @li This number is always 1 greater than the actual number needed, to give 933 | * you a sentinel element. 934 | * @li This number depends only on the @c usage, not the argument vectors, because 935 | * the @c options array needs exactly one slot for each possible Descriptor::index. 936 | */ 937 | unsigned options_max; 938 | 939 | /** 940 | * @brief Creates a Stats object with counts set to 1 (for the sentinel element). 941 | */ 942 | Stats() : 943 | buffer_max(1), options_max(1) // 1 more than necessary as sentinel 944 | { 945 | } 946 | 947 | /** 948 | * @brief Creates a new Stats object and immediately updates it for the 949 | * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, 950 | * if you just want to update @ref options_max. 951 | * 952 | * @note 953 | * The calls to Stats methods must match the later calls to Parser methods. 954 | * See Parser::parse() for the meaning of the arguments. 955 | */ 956 | Stats(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // 957 | bool single_minus_longopt = false) : 958 | buffer_max(1), options_max(1) // 1 more than necessary as sentinel 959 | { 960 | add(gnu, usage, argc, argv, min_abbr_len, single_minus_longopt); 961 | } 962 | 963 | //! @brief Stats(...) with non-const argv. 964 | Stats(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // 965 | bool single_minus_longopt = false) : 966 | buffer_max(1), options_max(1) // 1 more than necessary as sentinel 967 | { 968 | add(gnu, usage, argc, const_cast(argv), min_abbr_len, single_minus_longopt); 969 | } 970 | 971 | //! @brief POSIX Stats(...) (gnu==false). 972 | Stats(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // 973 | bool single_minus_longopt = false) : 974 | buffer_max(1), options_max(1) // 1 more than necessary as sentinel 975 | { 976 | add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); 977 | } 978 | 979 | //! @brief POSIX Stats(...) (gnu==false) with non-const argv. 980 | Stats(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // 981 | bool single_minus_longopt = false) : 982 | buffer_max(1), options_max(1) // 1 more than necessary as sentinel 983 | { 984 | add(false, usage, argc, const_cast(argv), min_abbr_len, single_minus_longopt); 985 | } 986 | 987 | /** 988 | * @brief Updates this Stats object for the 989 | * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, 990 | * if you just want to update @ref options_max. 991 | * 992 | * @note 993 | * The calls to Stats methods must match the later calls to Parser methods. 994 | * See Parser::parse() for the meaning of the arguments. 995 | */ 996 | void add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // 997 | bool single_minus_longopt = false); 998 | 999 | //! @brief add() with non-const argv. 1000 | void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // 1001 | bool single_minus_longopt = false) 1002 | { 1003 | add(gnu, usage, argc, const_cast(argv), min_abbr_len, single_minus_longopt); 1004 | } 1005 | 1006 | //! @brief POSIX add() (gnu==false). 1007 | void add(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // 1008 | bool single_minus_longopt = false) 1009 | { 1010 | add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); 1011 | } 1012 | 1013 | //! @brief POSIX add() (gnu==false) with non-const argv. 1014 | void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // 1015 | bool single_minus_longopt = false) 1016 | { 1017 | add(false, usage, argc, const_cast(argv), min_abbr_len, single_minus_longopt); 1018 | } 1019 | private: 1020 | class CountOptionsAction; 1021 | }; 1022 | 1023 | /** 1024 | * @brief Checks argument vectors for validity and parses them into data 1025 | * structures that are easier to work with. 1026 | * 1027 | * @par Example: 1028 | * @code 1029 | * int main(int argc, char* argv[]) 1030 | * { 1031 | * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present 1032 | * option::Stats stats(usage, argc, argv); 1033 | * option::Option options[stats.options_max], buffer[stats.buffer_max]; 1034 | * option::Parser parse(usage, argc, argv, options, buffer); 1035 | * 1036 | * if (parse.error()) 1037 | * return 1; 1038 | * 1039 | * if (options[HELP]) 1040 | * ... 1041 | * @endcode 1042 | */ 1043 | class Parser 1044 | { 1045 | int op_count; //!< @internal @brief see optionsCount() 1046 | int nonop_count; //!< @internal @brief see nonOptionsCount() 1047 | const char** nonop_args; //!< @internal @brief see nonOptions() 1048 | bool err; //!< @internal @brief see error() 1049 | public: 1050 | 1051 | /** 1052 | * @brief Creates a new Parser. 1053 | */ 1054 | Parser() : 1055 | op_count(0), nonop_count(0), nonop_args(0), err(false) 1056 | { 1057 | } 1058 | 1059 | /** 1060 | * @brief Creates a new Parser and immediately parses the given argument vector. 1061 | * @copydetails parse() 1062 | */ 1063 | Parser(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], 1064 | int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : 1065 | op_count(0), nonop_count(0), nonop_args(0), err(false) 1066 | { 1067 | parse(gnu, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); 1068 | } 1069 | 1070 | //! @brief Parser(...) with non-const argv. 1071 | Parser(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], 1072 | int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : 1073 | op_count(0), nonop_count(0), nonop_args(0), err(false) 1074 | { 1075 | parse(gnu, usage, argc, const_cast(argv), options, buffer, min_abbr_len, single_minus_longopt, bufmax); 1076 | } 1077 | 1078 | //! @brief POSIX Parser(...) (gnu==false). 1079 | Parser(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0, 1080 | bool single_minus_longopt = false, int bufmax = -1) : 1081 | op_count(0), nonop_count(0), nonop_args(0), err(false) 1082 | { 1083 | parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); 1084 | } 1085 | 1086 | //! @brief POSIX Parser(...) (gnu==false) with non-const argv. 1087 | Parser(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, 1088 | bool single_minus_longopt = false, int bufmax = -1) : 1089 | op_count(0), nonop_count(0), nonop_args(0), err(false) 1090 | { 1091 | parse(false, usage, argc, const_cast(argv), options, buffer, min_abbr_len, single_minus_longopt, bufmax); 1092 | } 1093 | 1094 | /** 1095 | * @brief Parses the given argument vector. 1096 | * 1097 | * @param gnu if true, parse() will not stop at the first non-option argument. Instead it will 1098 | * reorder arguments so that all non-options are at the end. This is the default behaviour 1099 | * of GNU getopt() but is not conforming to POSIX. @n 1100 | * Note, that once the argument vector has been reordered, the @c gnu flag will have 1101 | * no further effect on this argument vector. So it is enough to pass @c gnu==true when 1102 | * creating Stats. 1103 | * @param usage Array of Descriptor objects that describe the options to support. The last entry 1104 | * of this array must have 0 in all fields. 1105 | * @param argc The number of elements from @c argv that are to be parsed. If you pass -1, the number 1106 | * will be determined automatically. In that case the @c argv list must end with a NULL 1107 | * pointer. 1108 | * @param argv The arguments to be parsed. If you pass -1 as @c argc the last pointer in the @c argv 1109 | * list must be NULL to mark the end. 1110 | * @param options Each entry is the first element of a linked list of Options. Each new option 1111 | * that is parsed will be appended to the list specified by that Option's 1112 | * Descriptor::index. If an entry is not yet used (i.e. the Option is invalid), 1113 | * it will be replaced rather than appended to. @n 1114 | * The minimum length of this array is the greatest Descriptor::index value that 1115 | * occurs in @c usage @e PLUS ONE. 1116 | * @param buffer Each argument that is successfully parsed (including unknown arguments, if they 1117 | * have a Descriptor whose CheckArg does not return @ref ARG_ILLEGAL) will be stored in this 1118 | * array. parse() scans the array for the first invalid entry and begins writing at that 1119 | * index. You can pass @c bufmax to limit the number of options stored. 1120 | * @param min_abbr_len Passing a value min_abbr_len > 0 enables abbreviated long 1121 | * options. The parser will match a prefix of a long option as if it was 1122 | * the full long option (e.g. @c --foob=10 will be interpreted as if it was 1123 | * @c --foobar=10 ), as long as the prefix has at least @c min_abbr_len characters 1124 | * (not counting the @c -- ) and is unambiguous. 1125 | * @n Be careful if combining @c min_abbr_len=1 with @c single_minus_longopt=true 1126 | * because the ambiguity check does not consider short options and abbreviated 1127 | * single minus long options will take precedence over short options. 1128 | * @param single_minus_longopt Passing @c true for this option allows long options to begin with 1129 | * a single minus. The double minus form will still be recognized. Note that 1130 | * single minus long options take precedence over short options and short option 1131 | * groups. E.g. @c -file would be interpreted as @c --file and not as 1132 | * -f -i -l -e (assuming a long option named @c "file" exists). 1133 | * @param bufmax The greatest index in the @c buffer[] array that parse() will write to is 1134 | * @c bufmax-1. If there are more options, they will be processed (in particular 1135 | * their CheckArg will be called) but not stored. @n 1136 | * If you used Stats::buffer_max to dimension this array, you can pass 1137 | * -1 (or not pass @c bufmax at all) which tells parse() that the buffer is 1138 | * "large enough". 1139 | * @attention 1140 | * Remember that @c options and @c buffer store Option @e objects, not pointers. Therefore it 1141 | * is not possible for the same object to be in both arrays. For those options that are found in 1142 | * both @c buffer[] and @c options[] the respective objects are independent copies. And only the 1143 | * objects in @c options[] are properly linked via Option::next() and Option::prev(). 1144 | * You can iterate over @c buffer[] to 1145 | * process all options in the order they appear in the argument vector, but if you want access to 1146 | * the other Options with the same Descriptor::index, then you @e must access the linked list via 1147 | * @c options[]. You can get the linked list in options from a buffer object via something like 1148 | * @c options[buffer[i].index()]. 1149 | */ 1150 | void parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], 1151 | int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1); 1152 | 1153 | //! @brief parse() with non-const argv. 1154 | void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], 1155 | int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) 1156 | { 1157 | parse(gnu, usage, argc, const_cast(argv), options, buffer, min_abbr_len, single_minus_longopt, bufmax); 1158 | } 1159 | 1160 | //! @brief POSIX parse() (gnu==false). 1161 | void parse(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], 1162 | int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) 1163 | { 1164 | parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); 1165 | } 1166 | 1167 | //! @brief POSIX parse() (gnu==false) with non-const argv. 1168 | void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, 1169 | bool single_minus_longopt = false, int bufmax = -1) 1170 | { 1171 | parse(false, usage, argc, const_cast(argv), options, buffer, min_abbr_len, single_minus_longopt, bufmax); 1172 | } 1173 | 1174 | /** 1175 | * @brief Returns the number of valid Option objects in @c buffer[]. 1176 | * 1177 | * @note 1178 | * @li The returned value always reflects the number of Options in the buffer[] array used for 1179 | * the most recent call to parse(). 1180 | * @li The count (and the buffer[]) includes unknown options if they are collected 1181 | * (see Descriptor::longopt). 1182 | */ 1183 | int optionsCount() 1184 | { 1185 | return op_count; 1186 | } 1187 | 1188 | /** 1189 | * @brief Returns the number of non-option arguments that remained at the end of the 1190 | * most recent parse() that actually encountered non-option arguments. 1191 | * 1192 | * @note 1193 | * A parse() that does not encounter non-option arguments will leave this value 1194 | * as well as nonOptions() undisturbed. This means you can feed the Parser a 1195 | * default argument vector that contains non-option arguments (e.g. a default filename). 1196 | * Then you feed it the actual arguments from the user. If the user has supplied at 1197 | * least one non-option argument, all of the non-option arguments from the default 1198 | * disappear and are replaced by the user's non-option arguments. However, if the 1199 | * user does not supply any non-option arguments the defaults will still be in 1200 | * effect. 1201 | */ 1202 | int nonOptionsCount() 1203 | { 1204 | return nonop_count; 1205 | } 1206 | 1207 | /** 1208 | * @brief Returns a pointer to an array of non-option arguments (only valid 1209 | * if nonOptionsCount() >0 ). 1210 | * 1211 | * @note 1212 | * @li parse() does not copy arguments, so this pointer points into the actual argument 1213 | * vector as passed to parse(). 1214 | * @li As explained at nonOptionsCount() this pointer is only changed by parse() calls 1215 | * that actually encounter non-option arguments. A parse() call that encounters only 1216 | * options, will not change nonOptions(). 1217 | */ 1218 | const char** nonOptions() 1219 | { 1220 | return nonop_args; 1221 | } 1222 | 1223 | /** 1224 | * @brief Returns nonOptions()[i] (@e without checking if i is in range!). 1225 | */ 1226 | const char* nonOption(int i) 1227 | { 1228 | return nonOptions()[i]; 1229 | } 1230 | 1231 | /** 1232 | * @brief Returns @c true if an unrecoverable error occurred while parsing options. 1233 | * 1234 | * An illegal argument to an option (i.e. CheckArg returns @ref ARG_ILLEGAL) is an 1235 | * unrecoverable error that aborts the parse. Unknown options are only an error if 1236 | * their CheckArg function returns @ref ARG_ILLEGAL. Otherwise they are collected. 1237 | * In that case if you want to exit the program if either an illegal argument 1238 | * or an unknown option has been passed, use code like this 1239 | * 1240 | * @code 1241 | * if (parser.error() || options[UNKNOWN]) 1242 | * exit(1); 1243 | * @endcode 1244 | * 1245 | */ 1246 | bool error() 1247 | { 1248 | return err; 1249 | } 1250 | 1251 | private: 1252 | friend struct Stats; 1253 | class StoreOptionAction; 1254 | struct Action; 1255 | 1256 | /** 1257 | * @internal 1258 | * @brief This is the core function that does all the parsing. 1259 | * @retval false iff an unrecoverable error occurred. 1260 | */ 1261 | static bool workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, 1262 | bool single_minus_longopt, bool print_errors, int min_abbr_len); 1263 | 1264 | /** 1265 | * @internal 1266 | * @brief Returns true iff @c st1 is a prefix of @c st2 and 1267 | * in case @c st2 is longer than @c st1, then 1268 | * the first additional character is '='. 1269 | * 1270 | * @par Examples: 1271 | * @code 1272 | * streq("foo", "foo=bar") == true 1273 | * streq("foo", "foobar") == false 1274 | * streq("foo", "foo") == true 1275 | * streq("foo=bar", "foo") == false 1276 | * @endcode 1277 | */ 1278 | static bool streq(const char* st1, const char* st2) 1279 | { 1280 | while (*st1 != 0) 1281 | if (*st1++ != *st2++) 1282 | return false; 1283 | return (*st2 == 0 || *st2 == '='); 1284 | } 1285 | 1286 | /** 1287 | * @internal 1288 | * @brief Like streq() but handles abbreviations. 1289 | * 1290 | * Returns true iff @c st1 and @c st2 have a common 1291 | * prefix with the following properties: 1292 | * @li (if min > 0) its length is at least @c min characters or the same length as @c st1 (whichever is smaller). 1293 | * @li (if min <= 0) its length is the same as that of @c st1 1294 | * @li within @c st2 the character following the common prefix is either '=' or end-of-string. 1295 | * 1296 | * Examples: 1297 | * @code 1298 | * streqabbr("foo", "foo=bar",) == true 1299 | * streqabbr("foo", "fo=bar" , 2) == true 1300 | * streqabbr("foo", "fo" , 2) == true 1301 | * streqabbr("foo", "fo" , 0) == false 1302 | * streqabbr("foo", "f=bar" , 2) == false 1303 | * streqabbr("foo", "f" , 2) == false 1304 | * streqabbr("fo" , "foo=bar",) == false 1305 | * streqabbr("foo", "foobar" ,) == false 1306 | * streqabbr("foo", "fobar" ,) == false 1307 | * streqabbr("foo", "foo" ,) == true 1308 | * @endcode 1309 | */ 1310 | static bool streqabbr(const char* st1, const char* st2, long long min) 1311 | { 1312 | const char* st1start = st1; 1313 | while (*st1 != 0 && (*st1 == *st2)) 1314 | { 1315 | ++st1; 1316 | ++st2; 1317 | } 1318 | 1319 | return (*st1 == 0 || (min > 0 && (st1 - st1start) >= min)) && (*st2 == 0 || *st2 == '='); 1320 | } 1321 | 1322 | /** 1323 | * @internal 1324 | * @brief Returns true iff character @c ch is contained in the string @c st. 1325 | * 1326 | * Returns @c true for @c ch==0 . 1327 | */ 1328 | static bool instr(char ch, const char* st) 1329 | { 1330 | while (*st != 0 && *st != ch) 1331 | ++st; 1332 | return *st == ch; 1333 | } 1334 | 1335 | /** 1336 | * @internal 1337 | * @brief Rotates args[-count],...,args[-1],args[0] to become 1338 | * args[0],args[-count],...,args[-1]. 1339 | */ 1340 | static void shift(const char** args, int count) 1341 | { 1342 | for (int i = 0; i > -count; --i) 1343 | { 1344 | const char* temp = args[i]; 1345 | args[i] = args[i - 1]; 1346 | args[i - 1] = temp; 1347 | } 1348 | } 1349 | }; 1350 | 1351 | /** 1352 | * @internal 1353 | * @brief Interface for actions Parser::workhorse() should perform for each Option it 1354 | * parses. 1355 | */ 1356 | struct Parser::Action 1357 | { 1358 | /** 1359 | * @brief Called by Parser::workhorse() for each Option that has been successfully 1360 | * parsed (including unknown 1361 | * options if they have a Descriptor whose Descriptor::check_arg does not return 1362 | * @ref ARG_ILLEGAL. 1363 | * 1364 | * Returns @c false iff a fatal error has occured and the parse should be aborted. 1365 | */ 1366 | virtual bool perform(Option&) 1367 | { 1368 | return true; 1369 | } 1370 | 1371 | /** 1372 | * @brief Called by Parser::workhorse() after finishing the parse. 1373 | * @param numargs the number of non-option arguments remaining 1374 | * @param args pointer to the first remaining non-option argument (if numargs > 0). 1375 | * 1376 | * @return 1377 | * @c false iff a fatal error has occurred. 1378 | */ 1379 | virtual bool finished(int numargs, const char** args) 1380 | { 1381 | (void) numargs; 1382 | (void) args; 1383 | return true; 1384 | } 1385 | }; 1386 | 1387 | /** 1388 | * @internal 1389 | * @brief An Action to pass to Parser::workhorse() that will increment a counter for 1390 | * each parsed Option. 1391 | */ 1392 | class Stats::CountOptionsAction: public Parser::Action 1393 | { 1394 | unsigned* buffer_max; 1395 | public: 1396 | /** 1397 | * Creates a new CountOptionsAction that will increase @c *buffer_max_ for each 1398 | * parsed Option. 1399 | */ 1400 | CountOptionsAction(unsigned* buffer_max_) : 1401 | buffer_max(buffer_max_) 1402 | { 1403 | } 1404 | 1405 | bool perform(Option&) 1406 | { 1407 | if (*buffer_max == 0x7fffffff) 1408 | return false; // overflow protection: don't accept number of options that doesn't fit signed int 1409 | ++*buffer_max; 1410 | return true; 1411 | } 1412 | }; 1413 | 1414 | /** 1415 | * @internal 1416 | * @brief An Action to pass to Parser::workhorse() that will store each parsed Option in 1417 | * appropriate arrays (see Parser::parse()). 1418 | */ 1419 | class Parser::StoreOptionAction: public Parser::Action 1420 | { 1421 | Parser& parser; 1422 | Option* options; 1423 | Option* buffer; 1424 | int bufmax; //! Number of slots in @c buffer. @c -1 means "large enough". 1425 | public: 1426 | /** 1427 | * @brief Creates a new StoreOption action. 1428 | * @param parser_ the parser whose op_count should be updated. 1429 | * @param options_ each Option @c o is chained into the linked list @c options_[o.desc->index] 1430 | * @param buffer_ each Option is appended to this array as long as there's a free slot. 1431 | * @param bufmax_ number of slots in @c buffer_. @c -1 means "large enough". 1432 | */ 1433 | StoreOptionAction(Parser& parser_, Option options_[], Option buffer_[], int bufmax_) : 1434 | parser(parser_), options(options_), buffer(buffer_), bufmax(bufmax_) 1435 | { 1436 | // find first empty slot in buffer (if any) 1437 | int bufidx = 0; 1438 | while ((bufmax < 0 || bufidx < bufmax) && buffer[bufidx]) 1439 | ++bufidx; 1440 | 1441 | // set parser's optionCount 1442 | parser.op_count = bufidx; 1443 | } 1444 | 1445 | bool perform(Option& option) 1446 | { 1447 | if (bufmax < 0 || parser.op_count < bufmax) 1448 | { 1449 | if (parser.op_count == 0x7fffffff) 1450 | return false; // overflow protection: don't accept number of options that doesn't fit signed int 1451 | 1452 | buffer[parser.op_count] = option; 1453 | int idx = buffer[parser.op_count].desc->index; 1454 | if (options[idx]) 1455 | options[idx].append(buffer[parser.op_count]); 1456 | else 1457 | options[idx] = buffer[parser.op_count]; 1458 | ++parser.op_count; 1459 | } 1460 | return true; // NOTE: an option that is discarded because of a full buffer is not fatal 1461 | } 1462 | 1463 | bool finished(int numargs, const char** args) 1464 | { 1465 | // only overwrite non-option argument list if there's at least 1 1466 | // new non-option argument. Otherwise we keep the old list. This 1467 | // makes it easy to use default non-option arguments. 1468 | if (numargs > 0) 1469 | { 1470 | parser.nonop_count = numargs; 1471 | parser.nonop_args = args; 1472 | } 1473 | 1474 | return true; 1475 | } 1476 | }; 1477 | 1478 | inline void Parser::parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], 1479 | Option buffer[], int min_abbr_len, bool single_minus_longopt, int bufmax) 1480 | { 1481 | StoreOptionAction action(*this, options, buffer, bufmax); 1482 | err = !workhorse(gnu, usage, argc, argv, action, single_minus_longopt, true, min_abbr_len); 1483 | } 1484 | 1485 | inline void Stats::add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len, 1486 | bool single_minus_longopt) 1487 | { 1488 | // determine size of options array. This is the greatest index used in the usage + 1 1489 | int i = 0; 1490 | while (usage[i].shortopt != 0) 1491 | { 1492 | if (usage[i].index + 1 >= options_max) 1493 | options_max = (usage[i].index + 1) + 1; // 1 more than necessary as sentinel 1494 | 1495 | ++i; 1496 | } 1497 | 1498 | CountOptionsAction action(&buffer_max); 1499 | Parser::workhorse(gnu, usage, argc, argv, action, single_minus_longopt, false, min_abbr_len); 1500 | } 1501 | 1502 | inline bool Parser::workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, 1503 | bool single_minus_longopt, bool print_errors, int min_abbr_len) 1504 | { 1505 | // protect against NULL pointer 1506 | if (args == 0) 1507 | numargs = 0; 1508 | 1509 | int nonops = 0; 1510 | 1511 | while (numargs != 0 && *args != 0) 1512 | { 1513 | const char* param = *args; // param can be --long-option, -srto or non-option argument 1514 | 1515 | // in POSIX mode the first non-option argument terminates the option list 1516 | // a lone minus character is a non-option argument 1517 | if (param[0] != '-' || param[1] == 0) 1518 | { 1519 | if (gnu) 1520 | { 1521 | ++nonops; 1522 | ++args; 1523 | if (numargs > 0) 1524 | --numargs; 1525 | continue; 1526 | } 1527 | else 1528 | break; 1529 | } 1530 | 1531 | // -- terminates the option list. The -- itself is skipped. 1532 | if (param[1] == '-' && param[2] == 0) 1533 | { 1534 | shift(args, nonops); 1535 | ++args; 1536 | if (numargs > 0) 1537 | --numargs; 1538 | break; 1539 | } 1540 | 1541 | bool handle_short_options; 1542 | const char* longopt_name; 1543 | if (param[1] == '-') // if --long-option 1544 | { 1545 | handle_short_options = false; 1546 | longopt_name = param + 2; 1547 | } 1548 | else 1549 | { 1550 | handle_short_options = true; 1551 | longopt_name = param + 1; //for testing a potential -long-option 1552 | } 1553 | 1554 | bool try_single_minus_longopt = single_minus_longopt; 1555 | bool have_more_args = (numargs > 1 || numargs < 0); // is referencing argv[1] valid? 1556 | 1557 | do // loop over short options in group, for long options the body is executed only once 1558 | { 1559 | int idx; 1560 | 1561 | const char* optarg; 1562 | 1563 | /******************** long option **********************/ 1564 | if (handle_short_options == false || try_single_minus_longopt) 1565 | { 1566 | idx = 0; 1567 | while (usage[idx].longopt != 0 && !streq(usage[idx].longopt, longopt_name)) 1568 | ++idx; 1569 | 1570 | if (usage[idx].longopt == 0 && min_abbr_len > 0) // if we should try to match abbreviated long options 1571 | { 1572 | int i1 = 0; 1573 | while (usage[i1].longopt != 0 && !streqabbr(usage[i1].longopt, longopt_name, min_abbr_len)) 1574 | ++i1; 1575 | if (usage[i1].longopt != 0) 1576 | { // now test if the match is unambiguous by checking for another match 1577 | int i2 = i1 + 1; 1578 | while (usage[i2].longopt != 0 && !streqabbr(usage[i2].longopt, longopt_name, min_abbr_len)) 1579 | ++i2; 1580 | 1581 | if (usage[i2].longopt == 0) // if there was no second match it's unambiguous, so accept i1 as idx 1582 | idx = i1; 1583 | } 1584 | } 1585 | 1586 | // if we found something, disable handle_short_options (only relevant if single_minus_longopt) 1587 | if (usage[idx].longopt != 0) 1588 | handle_short_options = false; 1589 | 1590 | try_single_minus_longopt = false; // prevent looking for longopt in the middle of shortopt group 1591 | 1592 | optarg = longopt_name; 1593 | while (*optarg != 0 && *optarg != '=') 1594 | ++optarg; 1595 | if (*optarg == '=') // attached argument 1596 | ++optarg; 1597 | else 1598 | // possibly detached argument 1599 | optarg = (have_more_args ? args[1] : 0); 1600 | } 1601 | 1602 | /************************ short option ***********************************/ 1603 | if (handle_short_options) 1604 | { 1605 | if (*++param == 0) // point at the 1st/next option character 1606 | break; // end of short option group 1607 | 1608 | idx = 0; 1609 | while (usage[idx].shortopt != 0 && !instr(*param, usage[idx].shortopt)) 1610 | ++idx; 1611 | 1612 | if (param[1] == 0) // if the potential argument is separate 1613 | optarg = (have_more_args ? args[1] : 0); 1614 | else 1615 | // if the potential argument is attached 1616 | optarg = param + 1; 1617 | } 1618 | 1619 | const Descriptor* descriptor = &usage[idx]; 1620 | 1621 | if (descriptor->shortopt == 0) /************** unknown option ********************/ 1622 | { 1623 | // look for dummy entry (shortopt == "" and longopt == "") to use as Descriptor for unknown options 1624 | idx = 0; 1625 | while (usage[idx].shortopt != 0 && (usage[idx].shortopt[0] != 0 || usage[idx].longopt[0] != 0)) 1626 | ++idx; 1627 | descriptor = (usage[idx].shortopt == 0 ? 0 : &usage[idx]); 1628 | } 1629 | 1630 | if (descriptor != 0) 1631 | { 1632 | Option option(descriptor, param, optarg); 1633 | switch (descriptor->check_arg(option, print_errors)) 1634 | { 1635 | case ARG_ILLEGAL: 1636 | return false; // fatal 1637 | case ARG_OK: 1638 | // skip one element of the argument vector, if it's a separated argument 1639 | if (optarg != 0 && have_more_args && optarg == args[1]) 1640 | { 1641 | shift(args, nonops); 1642 | if (numargs > 0) 1643 | --numargs; 1644 | ++args; 1645 | } 1646 | 1647 | // No further short options are possible after an argument 1648 | handle_short_options = false; 1649 | 1650 | break; 1651 | case ARG_IGNORE: 1652 | case ARG_NONE: 1653 | option.arg = 0; 1654 | break; 1655 | } 1656 | 1657 | if (!action.perform(option)) 1658 | return false; 1659 | } 1660 | 1661 | } while (handle_short_options); 1662 | 1663 | shift(args, nonops); 1664 | ++args; 1665 | if (numargs > 0) 1666 | --numargs; 1667 | 1668 | } // while 1669 | 1670 | if (numargs > 0 && *args == 0) // It's a bug in the caller if numargs is greater than the actual number 1671 | numargs = 0; // of arguments, but as a service to the user we fix this if we spot it. 1672 | 1673 | if (numargs < 0) // if we don't know the number of remaining non-option arguments 1674 | { // we need to count them 1675 | numargs = 0; 1676 | while (args[numargs] != 0) 1677 | ++numargs; 1678 | } 1679 | 1680 | return action.finished(numargs + nonops, args - nonops); 1681 | } 1682 | 1683 | /** 1684 | * @internal 1685 | * @brief The implementation of option::printUsage(). 1686 | */ 1687 | struct PrintUsageImplementation 1688 | { 1689 | /** 1690 | * @internal 1691 | * @brief Interface for Functors that write (part of) a string somewhere. 1692 | */ 1693 | struct IStringWriter 1694 | { 1695 | /** 1696 | * @brief Writes the given number of chars beginning at the given pointer somewhere. 1697 | */ 1698 | virtual void operator()(const char*, int) 1699 | { 1700 | } 1701 | }; 1702 | 1703 | /** 1704 | * @internal 1705 | * @brief Encapsulates a function with signature func(string, size) where 1706 | * string can be initialized with a const char* and size with an int. 1707 | */ 1708 | template 1709 | struct FunctionWriter: public IStringWriter 1710 | { 1711 | Function* write; 1712 | 1713 | virtual void operator()(const char* str, int size) 1714 | { 1715 | (*write)(str, size); 1716 | } 1717 | 1718 | FunctionWriter(Function* w) : 1719 | write(w) 1720 | { 1721 | } 1722 | }; 1723 | 1724 | /** 1725 | * @internal 1726 | * @brief Encapsulates a reference to an object with a write(string, size) 1727 | * method like that of @c std::ostream. 1728 | */ 1729 | template 1730 | struct OStreamWriter: public IStringWriter 1731 | { 1732 | OStream& ostream; 1733 | 1734 | virtual void operator()(const char* str, int size) 1735 | { 1736 | ostream.write(str, size); 1737 | } 1738 | 1739 | OStreamWriter(OStream& o) : 1740 | ostream(o) 1741 | { 1742 | } 1743 | }; 1744 | 1745 | /** 1746 | * @internal 1747 | * @brief Like OStreamWriter but encapsulates a @c const reference, which is 1748 | * typically a temporary object of a user class. 1749 | */ 1750 | template 1751 | struct TemporaryWriter: public IStringWriter 1752 | { 1753 | const Temporary& userstream; 1754 | 1755 | virtual void operator()(const char* str, int size) 1756 | { 1757 | userstream.write(str, size); 1758 | } 1759 | 1760 | TemporaryWriter(const Temporary& u) : 1761 | userstream(u) 1762 | { 1763 | } 1764 | }; 1765 | 1766 | /** 1767 | * @internal 1768 | * @brief Encapsulates a function with the signature func(fd, string, size) (the 1769 | * signature of the @c write() system call) 1770 | * where fd can be initialized from an int, string from a const char* and size from an int. 1771 | */ 1772 | template 1773 | struct SyscallWriter: public IStringWriter 1774 | { 1775 | Syscall* write; 1776 | int fd; 1777 | 1778 | virtual void operator()(const char* str, int size) 1779 | { 1780 | (*write)(fd, str, size); 1781 | } 1782 | 1783 | SyscallWriter(Syscall* w, int f) : 1784 | write(w), fd(f) 1785 | { 1786 | } 1787 | }; 1788 | 1789 | /** 1790 | * @internal 1791 | * @brief Encapsulates a function with the same signature as @c std::fwrite(). 1792 | */ 1793 | template 1794 | struct StreamWriter: public IStringWriter 1795 | { 1796 | Function* fwrite; 1797 | Stream* stream; 1798 | 1799 | virtual void operator()(const char* str, int size) 1800 | { 1801 | (*fwrite)(str, size, 1, stream); 1802 | } 1803 | 1804 | StreamWriter(Function* w, Stream* s) : 1805 | fwrite(w), stream(s) 1806 | { 1807 | } 1808 | }; 1809 | 1810 | /** 1811 | * @internal 1812 | * @brief Sets i1 = max(i1, i2) 1813 | */ 1814 | static void upmax(int& i1, int i2) 1815 | { 1816 | i1 = (i1 >= i2 ? i1 : i2); 1817 | } 1818 | 1819 | /** 1820 | * @internal 1821 | * @brief Moves the "cursor" to column @c want_x assuming it is currently at column @c x 1822 | * and sets @c x=want_x . 1823 | * If x > want_x , a line break is output before indenting. 1824 | * 1825 | * @param write Spaces and possibly a line break are written via this functor to get 1826 | * the desired indentation @c want_x . 1827 | * @param[in,out] x the current indentation. Set to @c want_x by this method. 1828 | * @param want_x the desired indentation. 1829 | */ 1830 | static void indent(IStringWriter& write, int& x, int want_x) 1831 | { 1832 | int indent = want_x - x; 1833 | if (indent < 0) 1834 | { 1835 | write("\n", 1); 1836 | indent = want_x; 1837 | } 1838 | 1839 | if (indent > 0) 1840 | { 1841 | char space = ' '; 1842 | for (int i = 0; i < indent; ++i) 1843 | write(&space, 1); 1844 | x = want_x; 1845 | } 1846 | } 1847 | 1848 | /** 1849 | * @brief Returns true if ch is the unicode code point of a wide character. 1850 | * 1851 | * @note 1852 | * The following character ranges are treated as wide 1853 | * @code 1854 | * 1100..115F 1855 | * 2329..232A (just 2 characters!) 1856 | * 2E80..A4C6 except for 303F 1857 | * A960..A97C 1858 | * AC00..D7FB 1859 | * F900..FAFF 1860 | * FE10..FE6B 1861 | * FF01..FF60 1862 | * FFE0..FFE6 1863 | * 1B000...... 1864 | * @endcode 1865 | */ 1866 | static bool isWideChar(unsigned ch) 1867 | { 1868 | if (ch == 0x303F) 1869 | return false; 1870 | 1871 | return ((0x1100 <= ch && ch <= 0x115F) || (0x2329 <= ch && ch <= 0x232A) || (0x2E80 <= ch && ch <= 0xA4C6) 1872 | || (0xA960 <= ch && ch <= 0xA97C) || (0xAC00 <= ch && ch <= 0xD7FB) || (0xF900 <= ch && ch <= 0xFAFF) 1873 | || (0xFE10 <= ch && ch <= 0xFE6B) || (0xFF01 <= ch && ch <= 0xFF60) || (0xFFE0 <= ch && ch <= 0xFFE6) 1874 | || (0x1B000 <= ch)); 1875 | } 1876 | 1877 | /** 1878 | * @internal 1879 | * @brief Splits a @c Descriptor[] array into tables, rows, lines and columns and 1880 | * iterates over these components. 1881 | * 1882 | * The top-level organizational unit is the @e table. 1883 | * A table begins at a Descriptor with @c help!=NULL and extends up to 1884 | * a Descriptor with @c help==NULL. 1885 | * 1886 | * A table consists of @e rows. Due to line-wrapping and explicit breaks 1887 | * a row may take multiple lines on screen. Rows within the table are separated 1888 | * by \\n. They never cross Descriptor boundaries. This means a row ends either 1889 | * at \\n or the 0 at the end of the help string. 1890 | * 1891 | * A row consists of columns/cells. Columns/cells within a row are separated by \\t. 1892 | * Line breaks within a cell are marked by \\v. 1893 | * 1894 | * Rows in the same table need not have the same number of columns/cells. The 1895 | * extreme case are interjections, which are rows that contain neither \\t nor \\v. 1896 | * These are NOT treated specially by LinePartIterator, but they are treated 1897 | * specially by printUsage(). 1898 | * 1899 | * LinePartIterator iterates through the usage at 3 levels: table, row and part. 1900 | * Tables and rows are as described above. A @e part is a line within a cell. 1901 | * LinePartIterator iterates through 1st parts of all cells, then through the 2nd 1902 | * parts of all cells (if any),... @n 1903 | * Example: The row "1 \v 3 \t 2 \v 4" has 2 cells/columns and 4 parts. 1904 | * The parts will be returned in the order 1, 2, 3, 4. 1905 | * 1906 | * It is possible that some cells have fewer parts than others. In this case 1907 | * LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator 1908 | * always returns the same number of parts for each column. Note that this is different 1909 | * from the way rows and columns are handled. LinePartIterator does @e not guarantee that 1910 | * the same number of columns will be returned for each row. 1911 | * 1912 | */ 1913 | class LinePartIterator 1914 | { 1915 | const Descriptor* tablestart; //!< The 1st descriptor of the current table. 1916 | const Descriptor* rowdesc; //!< The Descriptor that contains the current row. 1917 | const char* rowstart; //!< Ptr to 1st character of current row within rowdesc->help. 1918 | const char* ptr; //!< Ptr to current part within the current row. 1919 | int col; //!< Index of current column. 1920 | int len; //!< Length of the current part (that ptr points at) in BYTES 1921 | int screenlen; //!< Length of the current part in screen columns (taking narrow/wide chars into account). 1922 | int max_line_in_block; //!< Greatest index of a line within the block. This is the number of \\v within the cell with the most \\vs. 1923 | int line_in_block; //!< Line index within the current cell of the current part. 1924 | int target_line_in_block; //!< Line index of the parts we should return to the user on this iteration. 1925 | bool hit_target_line; //!< Flag whether we encountered a part with line index target_line_in_block in the current cell. 1926 | 1927 | /** 1928 | * @brief Determines the byte and character lengths of the part at @ref ptr and 1929 | * stores them in @ref len and @ref screenlen respectively. 1930 | */ 1931 | void update_length() 1932 | { 1933 | screenlen = 0; 1934 | for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len) 1935 | { 1936 | ++screenlen; 1937 | unsigned ch = static_cast(ptr[len]); 1938 | if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte 1939 | { 1940 | // int __builtin_clz (unsigned int x) 1941 | // Returns the number of leading 0-bits in x, starting at the most significant bit 1942 | unsigned mask = static_cast(-1) >> __builtin_clz(ch ^ 0xff); 1943 | ch = ch & mask; // mask out length bits, we don't verify their correctness 1944 | while ((static_cast(ptr[len + 1]) ^ 0x80) <= 0x3F) // while next byte is continuation byte 1945 | { 1946 | ch = (ch << 6) ^ static_cast(ptr[len + 1]) ^ 0x80; // add continuation to char code 1947 | ++len; 1948 | } 1949 | // ch is the decoded unicode code point 1950 | if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case 1951 | ++screenlen; 1952 | } 1953 | } 1954 | } 1955 | 1956 | public: 1957 | //! @brief Creates an iterator for @c usage. 1958 | LinePartIterator(const Descriptor usage[]) : 1959 | tablestart(usage), rowdesc(0), rowstart(0), ptr(0), col(-1), len(0), max_line_in_block(0), line_in_block(0), 1960 | target_line_in_block(0), hit_target_line(true) 1961 | { 1962 | } 1963 | 1964 | /** 1965 | * @brief Moves iteration to the next table (if any). Has to be called once on a new 1966 | * LinePartIterator to move to the 1st table. 1967 | * @retval false if moving to next table failed because no further table exists. 1968 | */ 1969 | bool nextTable() 1970 | { 1971 | // If this is NOT the first time nextTable() is called after the constructor, 1972 | // then skip to the next table break (i.e. a Descriptor with help == 0) 1973 | if (rowdesc != 0) 1974 | { 1975 | while (tablestart->help != 0 && tablestart->shortopt != 0) 1976 | ++tablestart; 1977 | } 1978 | 1979 | // Find the next table after the break (if any) 1980 | while (tablestart->help == 0 && tablestart->shortopt != 0) 1981 | ++tablestart; 1982 | 1983 | restartTable(); 1984 | return rowstart != 0; 1985 | } 1986 | 1987 | /** 1988 | * @brief Reset iteration to the beginning of the current table. 1989 | */ 1990 | void restartTable() 1991 | { 1992 | rowdesc = tablestart; 1993 | rowstart = tablestart->help; 1994 | ptr = 0; 1995 | } 1996 | 1997 | /** 1998 | * @brief Moves iteration to the next row (if any). Has to be called once after each call to 1999 | * @ref nextTable() to move to the 1st row of the table. 2000 | * @retval false if moving to next row failed because no further row exists. 2001 | */ 2002 | bool nextRow() 2003 | { 2004 | if (ptr == 0) 2005 | { 2006 | restartRow(); 2007 | return rowstart != 0; 2008 | } 2009 | 2010 | while (*ptr != 0 && *ptr != '\n') 2011 | ++ptr; 2012 | 2013 | if (*ptr == 0) 2014 | { 2015 | if ((rowdesc + 1)->help == 0) // table break 2016 | return false; 2017 | 2018 | ++rowdesc; 2019 | rowstart = rowdesc->help; 2020 | } 2021 | else // if (*ptr == '\n') 2022 | { 2023 | rowstart = ptr + 1; 2024 | } 2025 | 2026 | restartRow(); 2027 | return true; 2028 | } 2029 | 2030 | /** 2031 | * @brief Reset iteration to the beginning of the current row. 2032 | */ 2033 | void restartRow() 2034 | { 2035 | ptr = rowstart; 2036 | col = -1; 2037 | len = 0; 2038 | screenlen = 0; 2039 | max_line_in_block = 0; 2040 | line_in_block = 0; 2041 | target_line_in_block = 0; 2042 | hit_target_line = true; 2043 | } 2044 | 2045 | /** 2046 | * @brief Moves iteration to the next part (if any). Has to be called once after each call to 2047 | * @ref nextRow() to move to the 1st part of the row. 2048 | * @retval false if moving to next part failed because no further part exists. 2049 | * 2050 | * See @ref LinePartIterator for details about the iteration. 2051 | */ 2052 | bool next() 2053 | { 2054 | if (ptr == 0) 2055 | return false; 2056 | 2057 | if (col == -1) 2058 | { 2059 | col = 0; 2060 | update_length(); 2061 | return true; 2062 | } 2063 | 2064 | ptr += len; 2065 | while (true) 2066 | { 2067 | switch (*ptr) 2068 | { 2069 | case '\v': 2070 | upmax(max_line_in_block, ++line_in_block); 2071 | ++ptr; 2072 | break; 2073 | case '\t': 2074 | if (!hit_target_line) // if previous column did not have the targetline 2075 | { // then "insert" a 0-length part 2076 | update_length(); 2077 | hit_target_line = true; 2078 | return true; 2079 | } 2080 | 2081 | hit_target_line = false; 2082 | line_in_block = 0; 2083 | ++col; 2084 | ++ptr; 2085 | break; 2086 | case 0: 2087 | case '\n': 2088 | if (!hit_target_line) // if previous column did not have the targetline 2089 | { // then "insert" a 0-length part 2090 | update_length(); 2091 | hit_target_line = true; 2092 | return true; 2093 | } 2094 | 2095 | if (++target_line_in_block > max_line_in_block) 2096 | { 2097 | update_length(); 2098 | return false; 2099 | } 2100 | 2101 | hit_target_line = false; 2102 | line_in_block = 0; 2103 | col = 0; 2104 | ptr = rowstart; 2105 | continue; 2106 | default: 2107 | ++ptr; 2108 | continue; 2109 | } // switch 2110 | 2111 | if (line_in_block == target_line_in_block) 2112 | { 2113 | update_length(); 2114 | hit_target_line = true; 2115 | return true; 2116 | } 2117 | } // while 2118 | } 2119 | 2120 | /** 2121 | * @brief Returns the index (counting from 0) of the column in which 2122 | * the part pointed to by @ref data() is located. 2123 | */ 2124 | int column() 2125 | { 2126 | return col; 2127 | } 2128 | 2129 | /** 2130 | * @brief Returns the index (counting from 0) of the line within the current column 2131 | * this part belongs to. 2132 | */ 2133 | int line() 2134 | { 2135 | return target_line_in_block; // NOT line_in_block !!! It would be wrong if !hit_target_line 2136 | } 2137 | 2138 | /** 2139 | * @brief Returns the length of the part pointed to by @ref data() in raw chars (not UTF-8 characters). 2140 | */ 2141 | int length() 2142 | { 2143 | return len; 2144 | } 2145 | 2146 | /** 2147 | * @brief Returns the width in screen columns of the part pointed to by @ref data(). 2148 | * Takes multi-byte UTF-8 sequences and wide characters into account. 2149 | */ 2150 | int screenLength() 2151 | { 2152 | return screenlen; 2153 | } 2154 | 2155 | /** 2156 | * @brief Returns the current part of the iteration. 2157 | */ 2158 | const char* data() 2159 | { 2160 | return ptr; 2161 | } 2162 | }; 2163 | 2164 | /** 2165 | * @internal 2166 | * @brief Takes input and line wraps it, writing out one line at a time so that 2167 | * it can be interleaved with output from other columns. 2168 | * 2169 | * The LineWrapper is used to handle the last column of each table as well as interjections. 2170 | * The LineWrapper is called once for each line of output. If the data given to it fits 2171 | * into the designated width of the last column it is simply written out. If there 2172 | * is too much data, an appropriate split point is located and only the data up to this 2173 | * split point is written out. The rest of the data is queued for the next line. 2174 | * That way the last column can be line wrapped and interleaved with data from 2175 | * other columns. The following example makes this clearer: 2176 | * @code 2177 | * Column 1,1 Column 2,1 This is a long text 2178 | * Column 1,2 Column 2,2 that does not fit into 2179 | * a single line. 2180 | * @endcode 2181 | * 2182 | * The difficulty in producing this output is that the whole string 2183 | * "This is a long text that does not fit into a single line" is the 2184 | * 1st and only part of column 3. In order to produce the above 2185 | * output the string must be output piecemeal, interleaved with 2186 | * the data from the other columns. 2187 | */ 2188 | class LineWrapper 2189 | { 2190 | static const int bufmask = 15; //!< Must be a power of 2 minus 1. 2191 | /** 2192 | * @brief Ring buffer for length component of pair (data, length). 2193 | */ 2194 | int lenbuf[bufmask + 1]; 2195 | /** 2196 | * @brief Ring buffer for data component of pair (data, length). 2197 | */ 2198 | const char* datbuf[bufmask + 1]; 2199 | /** 2200 | * @brief The indentation of the column to which the LineBuffer outputs. LineBuffer 2201 | * assumes that the indentation has already been written when @ref process() 2202 | * is called, so this value is only used when a buffer flush requires writing 2203 | * additional lines of output. 2204 | */ 2205 | int x; 2206 | /** 2207 | * @brief The width of the column to line wrap. 2208 | */ 2209 | int width; 2210 | int head; //!< @brief index for next write 2211 | int tail; //!< @brief index for next read - 1 (i.e. increment tail BEFORE read) 2212 | 2213 | /** 2214 | * @brief Multiple methods of LineWrapper may decide to flush part of the buffer to 2215 | * free up space. The contract of process() says that only 1 line is output. So 2216 | * this variable is used to track whether something has output a line. It is 2217 | * reset at the beginning of process() and checked at the end to decide if 2218 | * output has already occurred or is still needed. 2219 | */ 2220 | bool wrote_something; 2221 | 2222 | bool buf_empty() 2223 | { 2224 | return ((tail + 1) & bufmask) == head; 2225 | } 2226 | 2227 | bool buf_full() 2228 | { 2229 | return tail == head; 2230 | } 2231 | 2232 | void buf_store(const char* data, int len) 2233 | { 2234 | lenbuf[head] = len; 2235 | datbuf[head] = data; 2236 | head = (head + 1) & bufmask; 2237 | } 2238 | 2239 | //! @brief Call BEFORE reading ...buf[tail]. 2240 | void buf_next() 2241 | { 2242 | tail = (tail + 1) & bufmask; 2243 | } 2244 | 2245 | /** 2246 | * @brief Writes (data,len) into the ring buffer. If the buffer is full, a single line 2247 | * is flushed out of the buffer into @c write. 2248 | */ 2249 | void output(IStringWriter& write, const char* data, int len) 2250 | { 2251 | if (buf_full()) 2252 | write_one_line(write); 2253 | 2254 | buf_store(data, len); 2255 | } 2256 | 2257 | /** 2258 | * @brief Writes a single line of output from the buffer to @c write. 2259 | */ 2260 | void write_one_line(IStringWriter& write) 2261 | { 2262 | if (wrote_something) // if we already wrote something, we need to start a new line 2263 | { 2264 | write("\n", 1); 2265 | int _ = 0; 2266 | indent(write, _, x); 2267 | } 2268 | 2269 | if (!buf_empty()) 2270 | { 2271 | buf_next(); 2272 | write(datbuf[tail], lenbuf[tail]); 2273 | } 2274 | 2275 | wrote_something = true; 2276 | } 2277 | public: 2278 | 2279 | /** 2280 | * @brief Writes out all remaining data from the LineWrapper using @c write. 2281 | * Unlike @ref process() this method indents all lines including the first and 2282 | * will output a \\n at the end (but only if something has been written). 2283 | */ 2284 | void flush(IStringWriter& write) 2285 | { 2286 | if (buf_empty()) 2287 | return; 2288 | int _ = 0; 2289 | indent(write, _, x); 2290 | wrote_something = false; 2291 | while (!buf_empty()) 2292 | write_one_line(write); 2293 | write("\n", 1); 2294 | } 2295 | 2296 | /** 2297 | * @brief Process, wrap and output the next piece of data. 2298 | * 2299 | * process() will output at least one line of output. This is not necessarily 2300 | * the @c data passed in. It may be data queued from a prior call to process(). 2301 | * If the internal buffer is full, more than 1 line will be output. 2302 | * 2303 | * process() assumes that the a proper amount of indentation has already been 2304 | * output. It won't write any further indentation before the 1st line. If 2305 | * more than 1 line is written due to buffer constraints, the lines following 2306 | * the first will be indented by this method, though. 2307 | * 2308 | * No \\n is written by this method after the last line that is written. 2309 | * 2310 | * @param write where to write the data. 2311 | * @param data the new chunk of data to write. 2312 | * @param len the length of the chunk of data to write. 2313 | */ 2314 | void process(IStringWriter& write, const char* data, int len) 2315 | { 2316 | wrote_something = false; 2317 | 2318 | while (len > 0) 2319 | { 2320 | if (len <= width) // quick test that works because utf8width <= len (all wide chars have at least 2 bytes) 2321 | { 2322 | output(write, data, len); 2323 | len = 0; 2324 | } 2325 | else // if (len > width) it's possible (but not guaranteed) that utf8len > width 2326 | { 2327 | int utf8width = 0; 2328 | int maxi = 0; 2329 | while (maxi < len && utf8width < width) 2330 | { 2331 | int charbytes = 1; 2332 | unsigned ch = static_cast(data[maxi]); 2333 | if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte 2334 | { 2335 | // int __builtin_clz (unsigned int x) 2336 | // Returns the number of leading 0-bits in x, starting at the most significant bit 2337 | unsigned mask = static_cast(-1) >> __builtin_clz(ch ^ 0xff); 2338 | ch = ch & mask; // mask out length bits, we don't verify their correctness 2339 | while ((maxi + charbytes < len) && // 2340 | ((static_cast(data[maxi + charbytes]) ^ 0x80) <= 0x3F)) // while next byte is continuation byte 2341 | { 2342 | ch = (ch << 6) ^ static_cast(data[maxi + charbytes]) ^ 0x80; // add continuation to char code 2343 | ++charbytes; 2344 | } 2345 | // ch is the decoded unicode code point 2346 | if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case 2347 | { 2348 | if (utf8width + 2 > width) 2349 | break; 2350 | ++utf8width; 2351 | } 2352 | } 2353 | ++utf8width; 2354 | maxi += charbytes; 2355 | } 2356 | 2357 | // data[maxi-1] is the last byte of the UTF-8 sequence of the last character that fits 2358 | // onto the 1st line. If maxi == len, all characters fit on the line. 2359 | 2360 | if (maxi == len) 2361 | { 2362 | output(write, data, len); 2363 | len = 0; 2364 | } 2365 | else // if (maxi < len) at least 1 character (data[maxi] that is) doesn't fit on the line 2366 | { 2367 | int i; 2368 | for (i = maxi; i >= 0; --i) 2369 | if (data[i] == ' ') 2370 | break; 2371 | 2372 | if (i >= 0) 2373 | { 2374 | output(write, data, i); 2375 | data += i + 1; 2376 | len -= i + 1; 2377 | } 2378 | else // did not find a space to split at => split before data[maxi] 2379 | { // data[maxi] is always the beginning of a character, never a continuation byte 2380 | output(write, data, maxi); 2381 | data += maxi; 2382 | len -= maxi; 2383 | } 2384 | } 2385 | } 2386 | } 2387 | if (!wrote_something) // if we didn't already write something to make space in the buffer 2388 | write_one_line(write); // write at most one line of actual output 2389 | } 2390 | 2391 | /** 2392 | * @brief Constructs a LineWrapper that wraps its output to fit into 2393 | * screen columns @c x1 (incl.) to @c x2 (excl.). 2394 | * 2395 | * @c x1 gives the indentation LineWrapper uses if it needs to indent. 2396 | */ 2397 | LineWrapper(int x1, int x2) : 2398 | x(x1), width(x2 - x1), head(0), tail(bufmask) 2399 | { 2400 | if (width < 2) // because of wide characters we need at least width 2 or the code breaks 2401 | width = 2; 2402 | } 2403 | }; 2404 | 2405 | /** 2406 | * @internal 2407 | * @brief This is the implementation that is shared between all printUsage() templates. 2408 | * Because all printUsage() templates share this implementation, there is no template bloat. 2409 | */ 2410 | static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, // 2411 | int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) 2412 | { 2413 | if (width < 1) // protect against nonsense values 2414 | width = 80; 2415 | 2416 | if (width > 10000) // protect against overflow in the following computation 2417 | width = 10000; 2418 | 2419 | int last_column_min_width = ((width * last_column_min_percent) + 50) / 100; 2420 | int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100; 2421 | if (last_column_own_line_max_width == 0) 2422 | last_column_own_line_max_width = 1; 2423 | 2424 | LinePartIterator part(usage); 2425 | while (part.nextTable()) 2426 | { 2427 | 2428 | /***************** Determine column widths *******************************/ 2429 | 2430 | const int maxcolumns = 8; // 8 columns are enough for everyone 2431 | int col_width[maxcolumns]; 2432 | int lastcolumn; 2433 | int leftwidth; 2434 | int overlong_column_threshold = 10000; 2435 | do 2436 | { 2437 | lastcolumn = 0; 2438 | for (int i = 0; i < maxcolumns; ++i) 2439 | col_width[i] = 0; 2440 | 2441 | part.restartTable(); 2442 | while (part.nextRow()) 2443 | { 2444 | while (part.next()) 2445 | { 2446 | if (part.column() < maxcolumns) 2447 | { 2448 | upmax(lastcolumn, part.column()); 2449 | if (part.screenLength() < overlong_column_threshold) 2450 | // We don't let rows that don't use table separators (\t or \v) influence 2451 | // the width of column 0. This allows the user to interject section headers 2452 | // or explanatory paragraphs that do not participate in the table layout. 2453 | if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' 2454 | || part.data()[part.length()] == '\v') 2455 | upmax(col_width[part.column()], part.screenLength()); 2456 | } 2457 | } 2458 | } 2459 | 2460 | /* 2461 | * If the last column doesn't fit on the same 2462 | * line as the other columns, we can fix that by starting it on its own line. 2463 | * However we can't do this for any of the columns 0..lastcolumn-1. 2464 | * If their sum exceeds the maximum width we try to fix this by iteratively 2465 | * ignoring the widest line parts in the width determination until 2466 | * we arrive at a series of column widths that fit into one line. 2467 | * The result is a layout where everything is nicely formatted 2468 | * except for a few overlong fragments. 2469 | * */ 2470 | 2471 | leftwidth = 0; 2472 | overlong_column_threshold = 0; 2473 | for (int i = 0; i < lastcolumn; ++i) 2474 | { 2475 | leftwidth += col_width[i]; 2476 | upmax(overlong_column_threshold, col_width[i]); 2477 | } 2478 | 2479 | } while (leftwidth > width); 2480 | 2481 | /**************** Determine tab stops and last column handling **********************/ 2482 | 2483 | int tabstop[maxcolumns]; 2484 | tabstop[0] = 0; 2485 | for (int i = 1; i < maxcolumns; ++i) 2486 | tabstop[i] = tabstop[i - 1] + col_width[i - 1]; 2487 | 2488 | int rightwidth = width - tabstop[lastcolumn]; 2489 | bool print_last_column_on_own_line = false; 2490 | if (rightwidth < last_column_min_width && rightwidth < col_width[lastcolumn]) 2491 | { 2492 | print_last_column_on_own_line = true; 2493 | rightwidth = last_column_own_line_max_width; 2494 | } 2495 | 2496 | // If lastcolumn == 0 we must disable print_last_column_on_own_line because 2497 | // otherwise 2 copies of the last (and only) column would be output. 2498 | // Actually this is just defensive programming. It is currently not 2499 | // possible that lastcolumn==0 and print_last_column_on_own_line==true 2500 | // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 => 2501 | // rightwidth==width => rightwidth>=last_column_min_width (unless someone passes 2502 | // a bullshit value >100 for last_column_min_percent) => the above if condition 2503 | // is false => print_last_column_on_own_line==false 2504 | if (lastcolumn == 0) 2505 | print_last_column_on_own_line = false; 2506 | 2507 | LineWrapper lastColumnLineWrapper(width - rightwidth, width); 2508 | LineWrapper interjectionLineWrapper(0, width); 2509 | 2510 | part.restartTable(); 2511 | 2512 | /***************** Print out all rows of the table *************************************/ 2513 | 2514 | while (part.nextRow()) 2515 | { 2516 | int x = -1; 2517 | while (part.next()) 2518 | { 2519 | if (part.column() > lastcolumn) 2520 | continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1) 2521 | 2522 | if (part.column() == 0) 2523 | { 2524 | if (x >= 0) 2525 | write("\n", 1); 2526 | x = 0; 2527 | } 2528 | 2529 | indent(write, x, tabstop[part.column()]); 2530 | 2531 | if ((part.column() < lastcolumn) 2532 | && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' 2533 | || part.data()[part.length()] == '\v')) 2534 | { 2535 | write(part.data(), part.length()); 2536 | x += part.screenLength(); 2537 | } 2538 | else // either part.column() == lastcolumn or we are in the special case of 2539 | // an interjection that doesn't contain \v or \t 2540 | { 2541 | // NOTE: This code block is not necessarily executed for 2542 | // each line, because some rows may have fewer columns. 2543 | 2544 | LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper; 2545 | 2546 | if (!print_last_column_on_own_line) 2547 | lineWrapper.process(write, part.data(), part.length()); 2548 | } 2549 | } // while 2550 | 2551 | if (print_last_column_on_own_line) 2552 | { 2553 | part.restartRow(); 2554 | while (part.next()) 2555 | { 2556 | if (part.column() == lastcolumn) 2557 | { 2558 | write("\n", 1); 2559 | int _ = 0; 2560 | indent(write, _, width - rightwidth); 2561 | lastColumnLineWrapper.process(write, part.data(), part.length()); 2562 | } 2563 | } 2564 | } 2565 | 2566 | write("\n", 1); 2567 | lastColumnLineWrapper.flush(write); 2568 | interjectionLineWrapper.flush(write); 2569 | } 2570 | } 2571 | } 2572 | 2573 | } 2574 | ; 2575 | 2576 | /** 2577 | * @brief Outputs a nicely formatted usage string with support for multi-column formatting 2578 | * and line-wrapping. 2579 | * 2580 | * printUsage() takes the @c help texts of a Descriptor[] array and formats them into 2581 | * a usage message, wrapping lines to achieve the desired output width. 2582 | * 2583 | * Table formatting: 2584 | * 2585 | * Aside from plain strings which are simply line-wrapped, the usage may contain tables. Tables 2586 | * are used to align elements in the output. 2587 | * 2588 | * @code 2589 | * // Without a table. The explanatory texts are not aligned. 2590 | * -c, --create |Creates something. 2591 | * -k, --kill |Destroys something. 2592 | * 2593 | * // With table formatting. The explanatory texts are aligned. 2594 | * -c, --create |Creates something. 2595 | * -k, --kill |Destroys something. 2596 | * @endcode 2597 | * 2598 | * Table formatting removes the need to pad help texts manually with spaces to achieve 2599 | * alignment. To create a table, simply insert \\t (tab) characters to separate the cells 2600 | * within a row. 2601 | * 2602 | * @code 2603 | * const option::Descriptor usage[] = { 2604 | * {..., "-c, --create \tCreates something." }, 2605 | * {..., "-k, --kill \tDestroys something." }, ... 2606 | * @endcode 2607 | * 2608 | * Note that you must include the minimum amount of space desired between cells yourself. 2609 | * Table formatting will insert further spaces as needed to achieve alignment. 2610 | * 2611 | * You can insert line breaks within cells by using \\v (vertical tab). 2612 | * 2613 | * @code 2614 | * const option::Descriptor usage[] = { 2615 | * {..., "-c,\v--create \tCreates\vsomething." }, 2616 | * {..., "-k,\v--kill \tDestroys\vsomething." }, ... 2617 | * 2618 | * // results in 2619 | * 2620 | * -c, Creates 2621 | * --create something. 2622 | * -k, Destroys 2623 | * --kill something. 2624 | * @endcode 2625 | * 2626 | * You can mix lines that do not use \\t or \\v with those that do. The plain 2627 | * lines will not mess up the table layout. Alignment of the table columns will 2628 | * be maintained even across these interjections. 2629 | * 2630 | * @code 2631 | * const option::Descriptor usage[] = { 2632 | * {..., "-c, --create \tCreates something." }, 2633 | * {..., "----------------------------------" }, 2634 | * {..., "-k, --kill \tDestroys something." }, ... 2635 | * 2636 | * // results in 2637 | * 2638 | * -c, --create Creates something. 2639 | * ---------------------------------- 2640 | * -k, --kill Destroys something. 2641 | * @endcode 2642 | * 2643 | * You can have multiple tables within the same usage whose columns are 2644 | * aligned independently. Simply insert a dummy Descriptor with @c help==0. 2645 | * 2646 | * @code 2647 | * const option::Descriptor usage[] = { 2648 | * {..., "Long options:" }, 2649 | * {..., "--very-long-option \tDoes something long." }, 2650 | * {..., "--ultra-super-mega-long-option \tTakes forever to complete." }, 2651 | * {..., 0 }, // ---------- table break ----------- 2652 | * {..., "Short options:" }, 2653 | * {..., "-s \tShort." }, 2654 | * {..., "-q \tQuick." }, ... 2655 | * 2656 | * // results in 2657 | * 2658 | * Long options: 2659 | * --very-long-option Does something long. 2660 | * --ultra-super-mega-long-option Takes forever to complete. 2661 | * Short options: 2662 | * -s Short. 2663 | * -q Quick. 2664 | * 2665 | * // Without the table break it would be 2666 | * 2667 | * Long options: 2668 | * --very-long-option Does something long. 2669 | * --ultra-super-mega-long-option Takes forever to complete. 2670 | * Short options: 2671 | * -s Short. 2672 | * -q Quick. 2673 | * @endcode 2674 | * 2675 | * Output methods: 2676 | * 2677 | * Because TheLeanMeanC++Option parser is freestanding, you have to provide the means for 2678 | * output in the first argument(s) to printUsage(). Because printUsage() is implemented as 2679 | * a set of template functions, you have great flexibility in your choice of output 2680 | * method. The following example demonstrates typical uses. Anything that's similar enough 2681 | * will work. 2682 | * 2683 | * @code 2684 | * #include // write() 2685 | * #include // cout 2686 | * #include // ostringstream 2687 | * #include // fwrite() 2688 | * using namespace std; 2689 | * 2690 | * void my_write(const char* str, int size) { 2691 | * fwrite(str, size, 1, stdout); 2692 | * } 2693 | * 2694 | * struct MyWriter { 2695 | * void write(const char* buf, size_t size) const { 2696 | * fwrite(str, size, 1, stdout); 2697 | * } 2698 | * }; 2699 | * 2700 | * struct MyWriteFunctor { 2701 | * void operator()(const char* buf, size_t size) { 2702 | * fwrite(str, size, 1, stdout); 2703 | * } 2704 | * }; 2705 | * ... 2706 | * printUsage(my_write, usage); // custom write function 2707 | * printUsage(MyWriter(), usage); // temporary of a custom class 2708 | * MyWriter writer; 2709 | * printUsage(writer, usage); // custom class object 2710 | * MyWriteFunctor wfunctor; 2711 | * printUsage(&wfunctor, usage); // custom functor 2712 | * printUsage(write, 1, usage); // write() to file descriptor 1 2713 | * printUsage(cout, usage); // an ostream& 2714 | * printUsage(fwrite, stdout, usage); // fwrite() to stdout 2715 | * ostringstream sstr; 2716 | * printUsage(sstr, usage); // an ostringstream& 2717 | * 2718 | * @endcode 2719 | * 2720 | * @par Notes: 2721 | * @li the @c write() method of a class that is to be passed as a temporary 2722 | * as @c MyWriter() is in the example, must be a @c const method, because 2723 | * temporary objects are passed as const reference. This only applies to 2724 | * temporary objects that are created and destroyed in the same statement. 2725 | * If you create an object like @c writer in the example, this restriction 2726 | * does not apply. 2727 | * @li a functor like @c MyWriteFunctor in the example must be passed as a pointer. 2728 | * This differs from the way functors are passed to e.g. the STL algorithms. 2729 | * @li All printUsage() templates are tiny wrappers around a shared non-template implementation. 2730 | * So there's no penalty for using different versions in the same program. 2731 | * @li printUsage() always interprets Descriptor::help as UTF-8 and always produces UTF-8-encoded 2732 | * output. If your system uses a different charset, you must do your own conversion. You 2733 | * may also need to change the font of the console to see non-ASCII characters properly. 2734 | * This is particularly true for Windows. 2735 | * @li @b Security @b warning: Do not insert untrusted strings (such as user-supplied arguments) 2736 | * into the usage. printUsage() has no protection against malicious UTF-8 sequences. 2737 | * 2738 | * @param prn The output method to use. See the examples above. 2739 | * @param usage the Descriptor[] array whose @c help texts will be formatted. 2740 | * @param width the maximum number of characters per output line. Note that this number is 2741 | * in actual characters, not bytes. printUsage() supports UTF-8 in @c help and will 2742 | * count multi-byte UTF-8 sequences properly. Asian wide characters are counted 2743 | * as 2 characters. 2744 | * @param last_column_min_percent (0-100) The minimum percentage of @c width that should be available 2745 | * for the last column (which typically contains the textual explanation of an option). 2746 | * If less space is available, the last column will be printed on its own line, indented 2747 | * according to @c last_column_own_line_max_percent. 2748 | * @param last_column_own_line_max_percent (0-100) If the last column is printed on its own line due to 2749 | * less than @c last_column_min_percent of the width being available, then only 2750 | * @c last_column_own_line_max_percent of the extra line(s) will be used for the 2751 | * last column's text. This ensures an indentation. See example below. 2752 | * 2753 | * @code 2754 | * // width=20, last_column_min_percent=50 (i.e. last col. min. width=10) 2755 | * --3456789 1234567890 2756 | * 1234567890 2757 | * 2758 | * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) 2759 | * // last_column_own_line_max_percent=75 2760 | * --3456789 2761 | * 123456789012345 2762 | * 67890 2763 | * 2764 | * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) 2765 | * // last_column_own_line_max_percent=33 (i.e. max. 5) 2766 | * --3456789 2767 | * 12345 2768 | * 67890 2769 | * 12345 2770 | * 67890 2771 | * @endcode 2772 | */ 2773 | template 2774 | void printUsage(OStream& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, 2775 | int last_column_own_line_max_percent = 75) 2776 | { 2777 | PrintUsageImplementation::OStreamWriter write(prn); 2778 | PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); 2779 | } 2780 | 2781 | template 2782 | void printUsage(Function* prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, 2783 | int last_column_own_line_max_percent = 75) 2784 | { 2785 | PrintUsageImplementation::FunctionWriter write(prn); 2786 | PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); 2787 | } 2788 | 2789 | template 2790 | void printUsage(const Temporary& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, 2791 | int last_column_own_line_max_percent = 75) 2792 | { 2793 | PrintUsageImplementation::TemporaryWriter write(prn); 2794 | PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); 2795 | } 2796 | 2797 | template 2798 | void printUsage(Syscall* prn, int fd, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, 2799 | int last_column_own_line_max_percent = 75) 2800 | { 2801 | PrintUsageImplementation::SyscallWriter write(prn, fd); 2802 | PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); 2803 | } 2804 | 2805 | template 2806 | void printUsage(Function* prn, Stream* stream, const Descriptor usage[], int width = 80, int last_column_min_percent = 2807 | 50, 2808 | int last_column_own_line_max_percent = 75) 2809 | { 2810 | PrintUsageImplementation::StreamWriter write(prn, stream); 2811 | PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); 2812 | } 2813 | 2814 | } 2815 | // namespace option 2816 | 2817 | #endif /* OPTIONPARSER_H_ */ 2818 | -------------------------------------------------------------------------------- /xbiso.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * xbiso 3 | * Copyright (C) 2015 Stefan Schmidt 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see .*/ 17 | 18 | #include "xdvdfs.hpp" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "optionparser.h" 24 | #include 25 | 26 | #if defined _WIN32 27 | #include "direct.h" 28 | #define mkdir(a,b) _mkdir(a) 29 | #define chdir(a) _chdir(a) 30 | #else 31 | #include 32 | #include 33 | #endif 34 | 35 | void handleDirectoryEntry (std::ifstream& file, xdvdfs::DirectoryEntry& dirent); 36 | 37 | struct Arg: public option::Arg { 38 | static option::ArgStatus NonEmpty (const option::Option& option, bool msg) { 39 | if (option.arg) 40 | return option::ARG_OK; 41 | 42 | if (msg) 43 | std::cerr << "Option '" << option.name << "' requires an argument" << std::endl; 44 | 45 | return option::ARG_ILLEGAL; 46 | } 47 | }; 48 | 49 | enum optionIndex {UNKNOWN, HELP, VERBOSE, EXTRACT, DRYRUN, PROGRESS, DIRECTORY}; 50 | const option::Descriptor usage[] = { 51 | {UNKNOWN, 0, "", "", option::Arg::None, ""}, 52 | {HELP, 0, "h", "help", option::Arg::None, ""}, 53 | {VERBOSE, 0, "v", "verbose", option::Arg::None, ""}, 54 | {EXTRACT, 0, "x", "extract", option::Arg::None, ""}, 55 | {DRYRUN, 0, "n", "dry-run", option::Arg::None, ""}, 56 | {PROGRESS, 0, "p", "progress", option::Arg::None, ""}, 57 | {DIRECTORY, 0, "d", "directory", Arg::NonEmpty, ""}, 58 | {0,0,0,0,0,0} 59 | }; 60 | 61 | int verbosityLevel = 0; 62 | bool dryRun = false; 63 | 64 | void printUsage () 65 | { 66 | std::cout << "\n" 67 | << "xbiso " << XBISO_VERSION << "-" << XBISO_OS << ", Copyright (C) 2015 Stefan Schmidt\n\n" 68 | << "This program is free software: you can redistribute it and/or modify\n" 69 | << "it under the terms of the GNU General Public License as published by\n" 70 | << "the Free Software Foundation, either version 3 of the License, or\n" 71 | << "(at your option) any later version.\n\n" 72 | << "This program is distributed in the hope that it will be useful,\n" 73 | << "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 74 | << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 75 | << "GNU General Public License for more details.\n\n" 76 | << "You should have received a copy of the GNU General Public License\n" 77 | << "along with this program. If not, see ." 78 | << std::endl; 79 | 80 | std::cout << "\n" 81 | << "Usage: xbiso [options] file...\n" 82 | << "Options:\n" 83 | << " -h,--help Print this help message\n" 84 | << " -v,--verbose Be verbose\n" 85 | << " -x,--extract Extract the passed image files\n" 86 | << " -n,--dry-run Dry-run only, don't actually modify files\n" 87 | << " -p,--progress Show progress while extracting/creating\n" 88 | << " -d,--directory Extract into directory .\n" 89 | << " Only valid when passing a single file.\n" 90 | << std::endl; 91 | } 92 | 93 | int main (int argc, char* argv[]) 94 | { 95 | argc -= (argc>0); argv += (argc>0); 96 | 97 | option::Stats stats(usage, argc, argv); 98 | std::vector options(stats.options_max); 99 | std::vector buffer(stats.buffer_max); 100 | option::Parser parse(usage, argc, argv, &options[0], &buffer[0]); 101 | 102 | if (parse.error()) 103 | return 1; 104 | 105 | if (options[DIRECTORY] && parse.nonOptionsCount() > 1) { 106 | std::cerr << "ERROR: Specifying an extraction directory is not allowed when passing more than one image file." << std::endl; 107 | return 1; 108 | } 109 | 110 | if (options[HELP] || argc == 0) { 111 | printUsage(); 112 | return 0; 113 | } 114 | 115 | if (options[DRYRUN]) 116 | dryRun = true; 117 | 118 | if (options[EXTRACT]) { 119 | 120 | for (int i=0; i 4 | #include 5 | #include 6 | 7 | // TODO: support for big endian architectures 8 | 9 | void xdvdfs::VolumeDescriptor::readFromFile (std::ifstream& file) 10 | { 11 | std::vector buffer(2048); 12 | 13 | // read the whole sector 14 | file.seekg(VOLUME_DESCRIPTOR_SECTOR*SECTOR_SIZE, file.beg); 15 | file.read(buffer.data(), buffer.size()); 16 | 17 | // TODO: couldn't we use the stream operator instead? 18 | std::copy(buffer.begin(), buffer.begin()+0x14, this->magicNumber); 19 | std::copy(buffer.begin()+0x14, buffer.begin()+0x18, reinterpret_cast(&this->rootDirTableSector)); 20 | std::copy(buffer.begin()+0x18, buffer.begin()+0x1C, reinterpret_cast(&this->rootDirTableSize)); 21 | std::copy(buffer.begin()+0x1C, buffer.begin()+0x24, this->filetime); 22 | std::copy(buffer.begin()+0x7EC, buffer.end(), this->magicNumber2); 23 | 24 | // endianess conversion 25 | this->rootDirTableSector = le_to_host(this->rootDirTableSector); 26 | this->rootDirTableSize = le_to_host(this->rootDirTableSize); 27 | } 28 | 29 | void xdvdfs::VolumeDescriptor::validate () 30 | { 31 | if (std::memcmp(this->magicNumber, MAGIC_NUMBER, 0x14) != 0) 32 | throw new xdvdfs::Exception("First magic number incorrect"); 33 | 34 | if (this->rootDirTableSector == 0 || this->rootDirTableSize == 0) 35 | throw new xdvdfs::Exception("Root directory table is empty"); 36 | 37 | if (std::memcmp(this->magicNumber2, MAGIC_NUMBER, 0x14) != 0) 38 | throw new xdvdfs::Exception("Second magic number incorrect"); 39 | } 40 | 41 | xdvdfs::DirectoryEntry xdvdfs::VolumeDescriptor::getRootDirEntry (std::ifstream& file) 42 | { 43 | xdvdfs::DirectoryEntry dirent; 44 | 45 | dirent.readFromFile(file, rootDirTableSector); 46 | 47 | return dirent; 48 | } 49 | 50 | void xdvdfs::DirectoryEntry::readFromFile (std::ifstream& file, std::streampos sector, std::streampos offset) 51 | { 52 | std::vector buffer(2048); 53 | 54 | // read the whole sector 55 | file.seekg(sector*xdvdfs::SECTOR_SIZE + offset, file.beg); 56 | file.read(buffer.data(), buffer.size()); 57 | 58 | std::copy(buffer.begin(), buffer.begin()+0x02, reinterpret_cast(&this->leftSubTree)); 59 | std::copy(buffer.begin()+0x02, buffer.begin()+0x04, reinterpret_cast(&this->rightSubTree)); 60 | std::copy(buffer.begin()+0x04, buffer.begin()+0x08, reinterpret_cast(&this->startSector)); 61 | std::copy(buffer.begin()+0x08, buffer.begin()+0x0C, reinterpret_cast(&this->fileSize)); 62 | std::copy(buffer.begin()+0x0C, buffer.begin()+0x0D, reinterpret_cast(&this->attributes)); 63 | 64 | // reading the filename requires a bit more work 65 | uint8_t* filenameLength = reinterpret_cast(&buffer[0x0D]); 66 | this->filename = std::string(&buffer[0x0E], *filenameLength); 67 | 68 | this->sectorNumber = sector; 69 | 70 | // endianess conversion 71 | this->leftSubTree = le_to_host(this->leftSubTree); 72 | this->rightSubTree = le_to_host(this->rightSubTree); 73 | this->startSector = le_to_host(this->startSector); 74 | this->fileSize = le_to_host(this->fileSize); 75 | } 76 | 77 | std::string xdvdfs::DirectoryEntry::getFilename () 78 | { 79 | return this->filename; 80 | } 81 | 82 | std::streamsize xdvdfs::DirectoryEntry::getFileSize() 83 | { 84 | return this->fileSize; 85 | } 86 | 87 | void xdvdfs::DirectoryEntry::extractFile(std::ifstream& file, std::ofstream& ofile) 88 | { 89 | if (this->isDirectory()) 90 | throw new xdvdfs::Exception("Tried to access directory as a file"); 91 | 92 | std::vector buffer(4096); 93 | std::size_t filesize = this->fileSize; 94 | 95 | file.seekg(xdvdfs::SECTOR_SIZE * this->startSector); 96 | 97 | while (filesize > 0) 98 | { 99 | if (filesize > buffer.size()) 100 | { 101 | file.read(buffer.data(), buffer.size()); 102 | ofile.write(buffer.data(), buffer.size()); 103 | filesize -= buffer.size(); 104 | } 105 | else 106 | { 107 | file.read(buffer.data(), filesize); 108 | ofile.write(buffer.data(), filesize); 109 | filesize = 0; 110 | } 111 | } 112 | } 113 | 114 | bool xdvdfs::DirectoryEntry::isDirectory () 115 | { 116 | return ((this->attributes & xdvdfs::DirectoryEntry::FILE_DIRECTORY) != 0); 117 | } 118 | 119 | bool xdvdfs::DirectoryEntry::hasLeftChild () 120 | { 121 | return (this->leftSubTree != 0); 122 | } 123 | 124 | bool xdvdfs::DirectoryEntry::hasRightChild () 125 | { 126 | return (this->rightSubTree != 0); 127 | } 128 | 129 | xdvdfs::DirectoryEntry xdvdfs::DirectoryEntry::getLeftChild (std::ifstream& file) 130 | { 131 | xdvdfs::DirectoryEntry dirent; 132 | dirent.readFromFile(file, this->sectorNumber, static_cast(this->leftSubTree*4)); 133 | 134 | return dirent; 135 | } 136 | 137 | xdvdfs::DirectoryEntry xdvdfs::DirectoryEntry::getRightChild (std::ifstream& file) 138 | { 139 | xdvdfs::DirectoryEntry dirent; 140 | dirent.readFromFile(file, this->sectorNumber, static_cast(this->rightSubTree*4)); 141 | 142 | return dirent; 143 | } 144 | 145 | xdvdfs::DirectoryEntry xdvdfs::DirectoryEntry::getFirstEntry (std::ifstream& file) 146 | { 147 | if (!this->isDirectory()) 148 | throw new xdvdfs::Exception("Tried to access file as a directory"); 149 | 150 | xdvdfs::DirectoryEntry dirent; 151 | dirent.readFromFile(file, this->startSector); 152 | 153 | return dirent; 154 | } 155 | -------------------------------------------------------------------------------- /xdvdfs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace xdvdfs 7 | { 8 | static const int SECTOR_SIZE = 2048; 9 | static const int VOLUME_DESCRIPTOR_SECTOR = 32; 10 | 11 | static const char MAGIC_NUMBER[] = "MICROSOFT*XBOX*MEDIA"; 12 | 13 | class Exception : public std::exception 14 | { 15 | public: 16 | explicit Exception (const char * str) : sDetails(str) {} 17 | 18 | virtual const char* what() const throw () 19 | { 20 | return this->sDetails.c_str(); 21 | } 22 | private: 23 | std::string sDetails; 24 | }; 25 | 26 | template 27 | T le_to_host(T t) 28 | { 29 | uint8_t *bptr = reinterpret_cast(&t); 30 | T r = 0; 31 | 32 | for (std::size_t s=0; s