From 720c5a33b6a49cf328fdd7611f49153cf8f60247 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 8 Apr 2020 14:51:57 +0300 Subject: Separate tests and examples into individual packages Also make cli module to be explicitly enabled via the config.cli configuration variable. --- .gitignore | 20 - INSTALL | 92 +- NEWS | 73 - README | 15 - build/.gitignore | 3 - build/bootstrap.build | 18 - build/export.build | 9 - build/root.build | 37 - buildfile | 30 - cli-examples/.gitignore | 21 + cli-examples/LICENSE | 1 + cli-examples/README | 15 + cli-examples/build/.gitignore | 3 + cli-examples/build/bootstrap.build | 9 + cli-examples/build/root.build | 27 + cli-examples/buildfile | 4 + cli-examples/features/.gitignore | 1 + cli-examples/features/README | 20 + cli-examples/features/buildfile | 8 + cli-examples/features/driver.cxx | 61 + cli-examples/features/options.cli | 39 + cli-examples/file/.gitignore | 1 + cli-examples/file/README | 38 + cli-examples/file/buildfile | 11 + cli-examples/file/driver.cxx | 35 + cli-examples/file/options.cli | 7 + cli-examples/file/test.ops | 7 + cli-examples/hello/.gitignore | 1 + cli-examples/hello/README | 26 + cli-examples/hello/buildfile | 9 + cli-examples/hello/driver.cxx | 58 + cli-examples/hello/hello.cli | 18 + cli-examples/manifest | 15 + cli-tests/.gitignore | 22 + cli-tests/LICENSE | 1 + cli-tests/README | 8 + cli-tests/build/.gitignore | 3 + cli-tests/build/bootstrap.build | 9 + cli-tests/build/root.build | 27 + cli-tests/buildfile | 4 + cli-tests/combined/buildfile | 9 + cli-tests/combined/driver.cxx | 39 + cli-tests/combined/test.cli | 16 + cli-tests/combined/testscript | 108 ++ cli-tests/ctor/buildfile | 8 + cli-tests/ctor/driver.cxx | 60 + cli-tests/ctor/test.cli | 8 + cli-tests/erase/buildfile | 10 + cli-tests/erase/driver.cxx | 34 + cli-tests/erase/test.cli | 9 + cli-tests/file/buildfile | 9 + cli-tests/file/driver.cxx | 39 + cli-tests/file/test.cli | 7 + cli-tests/file/testscript | 286 ++++ cli-tests/group/buildfile | 9 + cli-tests/group/driver.cxx | 58 + cli-tests/group/test.cli | 7 + cli-tests/group/testscript | 140 ++ cli-tests/headings/buildfile | 6 + cli-tests/headings/testscript | 36 + cli-tests/inheritance/buildfile | 11 + cli-tests/inheritance/driver.cxx | 35 + cli-tests/inheritance/test.cli | 25 + cli-tests/inheritance/test.std | 4 + cli-tests/manifest | 15 + cli-tests/merge/buildfile | 9 + cli-tests/merge/driver.cxx | 55 + cli-tests/merge/test.cli | 18 + cli-tests/note/buildfile | 6 + cli-tests/note/testscript | 197 +++ cli-tests/specifier/buildfile | 10 + cli-tests/specifier/driver.cxx | 29 + cli-tests/specifier/test.cli | 12 + cli-tests/toc/buildfile | 6 + cli-tests/toc/testscript | 155 ++ cli/.gitignore | 21 +- cli/INSTALL | 6 + cli/LICENSE | 1 + cli/NEWS | 73 + cli/README | 15 + cli/build/.gitignore | 3 + cli/build/bootstrap.build | 10 + cli/build/export.build | 9 + cli/build/root.build | 60 + cli/buildfile | 55 +- cli/cli.cxx | 165 --- cli/cli/.gitignore | 7 + cli/cli/buildfile | 75 + cli/cli/cli.cxx | 165 +++ cli/cli/context.cxx | 2742 ++++++++++++++++++++++++++++++++++++ cli/cli/context.hxx | 295 ++++ cli/cli/generator.cxx | 584 ++++++++ cli/cli/generator.hxx | 28 + cli/cli/header.cxx | 383 +++++ cli/cli/header.hxx | 13 + cli/cli/html.cxx | 348 +++++ cli/cli/html.hxx | 13 + cli/cli/inline.cxx | 108 ++ cli/cli/inline.hxx | 13 + cli/cli/lexer.cxx | 604 ++++++++ cli/cli/lexer.hxx | 142 ++ cli/cli/lexer.ixx | 91 ++ cli/cli/lexer.test.cxx | 122 ++ cli/cli/lexer.test.testscript | 191 +++ cli/cli/man.cxx | 278 ++++ cli/cli/man.hxx | 13 + cli/cli/name-processor.cxx | 193 +++ cli/cli/name-processor.hxx | 13 + cli/cli/option-types.cxx | 43 + cli/cli/option-types.hxx | 33 + cli/cli/options.cli | 662 +++++++++ cli/cli/options.cxx | 2146 ++++++++++++++++++++++++++++ cli/cli/options.hxx | 1632 +++++++++++++++++++++ cli/cli/options.ixx | 2319 ++++++++++++++++++++++++++++++ cli/cli/parser.cxx | 1728 +++++++++++++++++++++++ cli/cli/parser.hxx | 91 ++ cli/cli/parser.test.cxx | 45 + cli/cli/parser.test.testscript | 242 ++++ cli/cli/runtime-header.cxx | 647 +++++++++ cli/cli/runtime-header.hxx | 13 + cli/cli/runtime-inline.cxx | 508 +++++++ cli/cli/runtime-inline.hxx | 13 + cli/cli/runtime-source.cxx | 1052 ++++++++++++++ cli/cli/runtime-source.hxx | 13 + cli/cli/semantics.hxx | 16 + cli/cli/semantics/class.cxx | 39 + cli/cli/semantics/class.hxx | 106 ++ cli/cli/semantics/doc.cxx | 27 + cli/cli/semantics/doc.hxx | 22 + cli/cli/semantics/elements.cxx | 129 ++ cli/cli/semantics/elements.hxx | 407 ++++++ cli/cli/semantics/expression.cxx | 27 + cli/cli/semantics/expression.hxx | 76 + cli/cli/semantics/namespace.cxx | 27 + cli/cli/semantics/namespace.hxx | 26 + cli/cli/semantics/option.cxx | 47 + cli/cli/semantics/option.hxx | 189 +++ cli/cli/semantics/unit.cxx | 63 + cli/cli/semantics/unit.hxx | 310 ++++ cli/cli/semantics/unit.txx | 108 ++ cli/cli/source.cxx | 1374 ++++++++++++++++++ cli/cli/source.hxx | 13 + cli/cli/token.hxx | 135 ++ cli/cli/token.ixx | 88 ++ cli/cli/traversal.hxx | 16 + cli/cli/traversal/class.cxx | 49 + cli/cli/traversal/class.hxx | 41 + cli/cli/traversal/doc.hxx | 16 + cli/cli/traversal/elements.cxx | 14 + cli/cli/traversal/elements.hxx | 142 ++ cli/cli/traversal/expression.hxx | 16 + cli/cli/traversal/namespace.cxx | 26 + cli/cli/traversal/namespace.hxx | 26 + cli/cli/traversal/option.cxx | 59 + cli/cli/traversal/option.hxx | 74 + cli/cli/traversal/unit.cxx | 46 + cli/cli/traversal/unit.hxx | 58 + cli/cli/txt.cxx | 301 ++++ cli/cli/txt.hxx | 46 + cli/cli/version.hxx.in | 45 + cli/context.cxx | 2742 ------------------------------------ cli/context.hxx | 295 ---- cli/doc/.gitignore | 2 + cli/doc/buildfile | 20 + cli/doc/cli-epilogue.1 | 21 + cli/doc/cli-epilogue.xhtml | 24 + cli/doc/cli-prologue.1 | 59 + cli/doc/cli-prologue.xhtml | 72 + cli/doc/default.css | 322 +++++ cli/doc/doc.sh | 78 + cli/doc/guide/.gitignore | 2 + cli/doc/guide/guide.html2ps | 63 + cli/doc/guide/index.xhtml | 1336 ++++++++++++++++++ cli/doc/language.txt | 128 ++ cli/generator.cxx | 584 -------- cli/generator.hxx | 28 - cli/header.cxx | 383 ----- cli/header.hxx | 13 - cli/html.cxx | 348 ----- cli/html.hxx | 13 - cli/inline.cxx | 108 -- cli/inline.hxx | 13 - cli/lexer.cxx | 604 -------- cli/lexer.hxx | 142 -- cli/lexer.ixx | 91 -- cli/man.cxx | 278 ---- cli/man.hxx | 13 - cli/manifest | 21 + cli/name-processor.cxx | 193 --- cli/name-processor.hxx | 13 - cli/option-types.cxx | 43 - cli/option-types.hxx | 33 - cli/options.cli | 662 --------- cli/options.cxx | 2146 ---------------------------- cli/options.hxx | 1632 --------------------- cli/options.ixx | 2319 ------------------------------ cli/parser.cxx | 1728 ----------------------- cli/parser.hxx | 91 -- cli/runtime-header.cxx | 647 --------- cli/runtime-header.hxx | 13 - cli/runtime-inline.cxx | 508 ------- cli/runtime-inline.hxx | 13 - cli/runtime-source.cxx | 1052 -------------- cli/runtime-source.hxx | 13 - cli/semantics.hxx | 16 - cli/semantics/class.cxx | 39 - cli/semantics/class.hxx | 106 -- cli/semantics/doc.cxx | 27 - cli/semantics/doc.hxx | 22 - cli/semantics/elements.cxx | 129 -- cli/semantics/elements.hxx | 407 ------ cli/semantics/expression.cxx | 27 - cli/semantics/expression.hxx | 76 - cli/semantics/namespace.cxx | 27 - cli/semantics/namespace.hxx | 26 - cli/semantics/option.cxx | 47 - cli/semantics/option.hxx | 189 --- cli/semantics/unit.cxx | 63 - cli/semantics/unit.hxx | 310 ---- cli/semantics/unit.txx | 108 -- cli/source.cxx | 1374 ------------------ cli/source.hxx | 13 - cli/token.hxx | 135 -- cli/token.ixx | 88 -- cli/traversal.hxx | 16 - cli/traversal/class.cxx | 49 - cli/traversal/class.hxx | 41 - cli/traversal/doc.hxx | 16 - cli/traversal/elements.cxx | 14 - cli/traversal/elements.hxx | 142 -- cli/traversal/expression.hxx | 16 - cli/traversal/namespace.cxx | 26 - cli/traversal/namespace.hxx | 26 - cli/traversal/option.cxx | 59 - cli/traversal/option.hxx | 74 - cli/traversal/unit.cxx | 46 - cli/traversal/unit.hxx | 58 - cli/txt.cxx | 301 ---- cli/txt.hxx | 46 - cli/version.hxx.in | 45 - doc/cli-epilogue.1 | 21 - doc/cli-epilogue.xhtml | 24 - doc/cli-prologue.1 | 59 - doc/cli-prologue.xhtml | 72 - doc/cli.1 | 412 ------ doc/cli.xhtml | 568 -------- doc/default.css | 322 ----- doc/doc.sh | 78 - doc/guide/.gitignore | 2 - doc/guide/guide.html2ps | 63 - doc/guide/index.xhtml | 1336 ------------------ doc/guide/makefile | 39 - doc/language.txt | 128 -- doc/makefile | 44 - examples/.gitignore | 1 - examples/README | 15 - examples/build/.gitignore | 3 - examples/build/bootstrap.build | 8 - examples/build/root.build | 36 - examples/buildfile | 4 - examples/features/.gitignore | 1 - examples/features/README | 20 - examples/features/buildfile | 8 - examples/features/driver.cxx | 61 - examples/features/options.cli | 39 - examples/file/.gitignore | 1 - examples/file/README | 38 - examples/file/buildfile | 11 - examples/file/driver.cxx | 35 - examples/file/options.cli | 7 - examples/file/test.ops | 7 - examples/hello/.gitignore | 1 - examples/hello/README | 26 - examples/hello/buildfile | 9 - examples/hello/driver.cxx | 58 - examples/hello/hello.cli | 18 - manifest | 19 - packages.manifest | 6 + tests/.gitignore | 2 - tests/build/.gitignore | 3 - tests/build/bootstrap.build | 8 - tests/build/root.build | 36 - tests/buildfile | 4 - tests/combined/buildfile | 9 - tests/combined/driver.cxx | 39 - tests/combined/test.cli | 16 - tests/combined/testscript | 108 -- tests/ctor/buildfile | 8 - tests/ctor/driver.cxx | 60 - tests/ctor/test.cli | 8 - tests/erase/buildfile | 10 - tests/erase/driver.cxx | 34 - tests/erase/test.cli | 9 - tests/file/buildfile | 9 - tests/file/driver.cxx | 39 - tests/file/test.cli | 7 - tests/file/testscript | 286 ---- tests/group/buildfile | 9 - tests/group/driver.cxx | 58 - tests/group/test.cli | 7 - tests/group/testscript | 140 -- tests/headings/buildfile | 4 - tests/headings/testscript | 38 - tests/inheritance/buildfile | 11 - tests/inheritance/driver.cxx | 35 - tests/inheritance/test.cli | 25 - tests/inheritance/test.std | 4 - tests/merge/buildfile | 9 - tests/merge/driver.cxx | 55 - tests/merge/test.cli | 18 - tests/note/buildfile | 4 - tests/note/testscript | 199 --- tests/specifier/buildfile | 10 - tests/specifier/driver.cxx | 29 - tests/specifier/test.cli | 12 - tests/toc/buildfile | 4 - tests/toc/testscript | 157 --- unit-tests/.gitignore | 1 - unit-tests/lexer/buildfile | 5 - unit-tests/lexer/driver.cxx | 122 -- unit-tests/lexer/testscript | 191 --- unit-tests/parser/buildfile | 5 - unit-tests/parser/driver.cxx | 45 - unit-tests/parser/testscript | 242 ---- 324 files changed, 26191 insertions(+), 27177 deletions(-) delete mode 100644 NEWS delete mode 100644 README delete mode 100644 build/.gitignore delete mode 100644 build/bootstrap.build delete mode 100644 build/export.build delete mode 100644 build/root.build delete mode 100644 buildfile create mode 100644 cli-examples/.gitignore create mode 120000 cli-examples/LICENSE create mode 100644 cli-examples/README create mode 100644 cli-examples/build/.gitignore create mode 100644 cli-examples/build/bootstrap.build create mode 100644 cli-examples/build/root.build create mode 100644 cli-examples/buildfile create mode 100644 cli-examples/features/.gitignore create mode 100644 cli-examples/features/README create mode 100644 cli-examples/features/buildfile create mode 100644 cli-examples/features/driver.cxx create mode 100644 cli-examples/features/options.cli create mode 100644 cli-examples/file/.gitignore create mode 100644 cli-examples/file/README create mode 100644 cli-examples/file/buildfile create mode 100644 cli-examples/file/driver.cxx create mode 100644 cli-examples/file/options.cli create mode 100644 cli-examples/file/test.ops create mode 100644 cli-examples/hello/.gitignore create mode 100644 cli-examples/hello/README create mode 100644 cli-examples/hello/buildfile create mode 100644 cli-examples/hello/driver.cxx create mode 100644 cli-examples/hello/hello.cli create mode 100644 cli-examples/manifest create mode 100644 cli-tests/.gitignore create mode 120000 cli-tests/LICENSE create mode 100644 cli-tests/README create mode 100644 cli-tests/build/.gitignore create mode 100644 cli-tests/build/bootstrap.build create mode 100644 cli-tests/build/root.build create mode 100644 cli-tests/buildfile create mode 100644 cli-tests/combined/buildfile create mode 100644 cli-tests/combined/driver.cxx create mode 100644 cli-tests/combined/test.cli create mode 100644 cli-tests/combined/testscript create mode 100644 cli-tests/ctor/buildfile create mode 100644 cli-tests/ctor/driver.cxx create mode 100644 cli-tests/ctor/test.cli create mode 100644 cli-tests/erase/buildfile create mode 100644 cli-tests/erase/driver.cxx create mode 100644 cli-tests/erase/test.cli create mode 100644 cli-tests/file/buildfile create mode 100644 cli-tests/file/driver.cxx create mode 100644 cli-tests/file/test.cli create mode 100644 cli-tests/file/testscript create mode 100644 cli-tests/group/buildfile create mode 100644 cli-tests/group/driver.cxx create mode 100644 cli-tests/group/test.cli create mode 100644 cli-tests/group/testscript create mode 100644 cli-tests/headings/buildfile create mode 100644 cli-tests/headings/testscript create mode 100644 cli-tests/inheritance/buildfile create mode 100644 cli-tests/inheritance/driver.cxx create mode 100644 cli-tests/inheritance/test.cli create mode 100644 cli-tests/inheritance/test.std create mode 100644 cli-tests/manifest create mode 100644 cli-tests/merge/buildfile create mode 100644 cli-tests/merge/driver.cxx create mode 100644 cli-tests/merge/test.cli create mode 100644 cli-tests/note/buildfile create mode 100644 cli-tests/note/testscript create mode 100644 cli-tests/specifier/buildfile create mode 100644 cli-tests/specifier/driver.cxx create mode 100644 cli-tests/specifier/test.cli create mode 100644 cli-tests/toc/buildfile create mode 100644 cli-tests/toc/testscript create mode 100644 cli/INSTALL create mode 120000 cli/LICENSE create mode 100644 cli/NEWS create mode 100644 cli/README create mode 100644 cli/build/.gitignore create mode 100644 cli/build/bootstrap.build create mode 100644 cli/build/export.build create mode 100644 cli/build/root.build delete mode 100644 cli/cli.cxx create mode 100644 cli/cli/.gitignore create mode 100644 cli/cli/buildfile create mode 100644 cli/cli/cli.cxx create mode 100644 cli/cli/context.cxx create mode 100644 cli/cli/context.hxx create mode 100644 cli/cli/generator.cxx create mode 100644 cli/cli/generator.hxx create mode 100644 cli/cli/header.cxx create mode 100644 cli/cli/header.hxx create mode 100644 cli/cli/html.cxx create mode 100644 cli/cli/html.hxx create mode 100644 cli/cli/inline.cxx create mode 100644 cli/cli/inline.hxx create mode 100644 cli/cli/lexer.cxx create mode 100644 cli/cli/lexer.hxx create mode 100644 cli/cli/lexer.ixx create mode 100644 cli/cli/lexer.test.cxx create mode 100644 cli/cli/lexer.test.testscript create mode 100644 cli/cli/man.cxx create mode 100644 cli/cli/man.hxx create mode 100644 cli/cli/name-processor.cxx create mode 100644 cli/cli/name-processor.hxx create mode 100644 cli/cli/option-types.cxx create mode 100644 cli/cli/option-types.hxx create mode 100644 cli/cli/options.cli create mode 100644 cli/cli/options.cxx create mode 100644 cli/cli/options.hxx create mode 100644 cli/cli/options.ixx create mode 100644 cli/cli/parser.cxx create mode 100644 cli/cli/parser.hxx create mode 100644 cli/cli/parser.test.cxx create mode 100644 cli/cli/parser.test.testscript create mode 100644 cli/cli/runtime-header.cxx create mode 100644 cli/cli/runtime-header.hxx create mode 100644 cli/cli/runtime-inline.cxx create mode 100644 cli/cli/runtime-inline.hxx create mode 100644 cli/cli/runtime-source.cxx create mode 100644 cli/cli/runtime-source.hxx create mode 100644 cli/cli/semantics.hxx create mode 100644 cli/cli/semantics/class.cxx create mode 100644 cli/cli/semantics/class.hxx create mode 100644 cli/cli/semantics/doc.cxx create mode 100644 cli/cli/semantics/doc.hxx create mode 100644 cli/cli/semantics/elements.cxx create mode 100644 cli/cli/semantics/elements.hxx create mode 100644 cli/cli/semantics/expression.cxx create mode 100644 cli/cli/semantics/expression.hxx create mode 100644 cli/cli/semantics/namespace.cxx create mode 100644 cli/cli/semantics/namespace.hxx create mode 100644 cli/cli/semantics/option.cxx create mode 100644 cli/cli/semantics/option.hxx create mode 100644 cli/cli/semantics/unit.cxx create mode 100644 cli/cli/semantics/unit.hxx create mode 100644 cli/cli/semantics/unit.txx create mode 100644 cli/cli/source.cxx create mode 100644 cli/cli/source.hxx create mode 100644 cli/cli/token.hxx create mode 100644 cli/cli/token.ixx create mode 100644 cli/cli/traversal.hxx create mode 100644 cli/cli/traversal/class.cxx create mode 100644 cli/cli/traversal/class.hxx create mode 100644 cli/cli/traversal/doc.hxx create mode 100644 cli/cli/traversal/elements.cxx create mode 100644 cli/cli/traversal/elements.hxx create mode 100644 cli/cli/traversal/expression.hxx create mode 100644 cli/cli/traversal/namespace.cxx create mode 100644 cli/cli/traversal/namespace.hxx create mode 100644 cli/cli/traversal/option.cxx create mode 100644 cli/cli/traversal/option.hxx create mode 100644 cli/cli/traversal/unit.cxx create mode 100644 cli/cli/traversal/unit.hxx create mode 100644 cli/cli/txt.cxx create mode 100644 cli/cli/txt.hxx create mode 100644 cli/cli/version.hxx.in delete mode 100644 cli/context.cxx delete mode 100644 cli/context.hxx create mode 100644 cli/doc/.gitignore create mode 100644 cli/doc/buildfile create mode 100644 cli/doc/cli-epilogue.1 create mode 100644 cli/doc/cli-epilogue.xhtml create mode 100644 cli/doc/cli-prologue.1 create mode 100644 cli/doc/cli-prologue.xhtml create mode 100644 cli/doc/default.css create mode 100755 cli/doc/doc.sh create mode 100644 cli/doc/guide/.gitignore create mode 100644 cli/doc/guide/guide.html2ps create mode 100644 cli/doc/guide/index.xhtml create mode 100644 cli/doc/language.txt delete mode 100644 cli/generator.cxx delete mode 100644 cli/generator.hxx delete mode 100644 cli/header.cxx delete mode 100644 cli/header.hxx delete mode 100644 cli/html.cxx delete mode 100644 cli/html.hxx delete mode 100644 cli/inline.cxx delete mode 100644 cli/inline.hxx delete mode 100644 cli/lexer.cxx delete mode 100644 cli/lexer.hxx delete mode 100644 cli/lexer.ixx delete mode 100644 cli/man.cxx delete mode 100644 cli/man.hxx create mode 100644 cli/manifest delete mode 100644 cli/name-processor.cxx delete mode 100644 cli/name-processor.hxx delete mode 100644 cli/option-types.cxx delete mode 100644 cli/option-types.hxx delete mode 100644 cli/options.cli delete mode 100644 cli/options.cxx delete mode 100644 cli/options.hxx delete mode 100644 cli/options.ixx delete mode 100644 cli/parser.cxx delete mode 100644 cli/parser.hxx delete mode 100644 cli/runtime-header.cxx delete mode 100644 cli/runtime-header.hxx delete mode 100644 cli/runtime-inline.cxx delete mode 100644 cli/runtime-inline.hxx delete mode 100644 cli/runtime-source.cxx delete mode 100644 cli/runtime-source.hxx delete mode 100644 cli/semantics.hxx delete mode 100644 cli/semantics/class.cxx delete mode 100644 cli/semantics/class.hxx delete mode 100644 cli/semantics/doc.cxx delete mode 100644 cli/semantics/doc.hxx delete mode 100644 cli/semantics/elements.cxx delete mode 100644 cli/semantics/elements.hxx delete mode 100644 cli/semantics/expression.cxx delete mode 100644 cli/semantics/expression.hxx delete mode 100644 cli/semantics/namespace.cxx delete mode 100644 cli/semantics/namespace.hxx delete mode 100644 cli/semantics/option.cxx delete mode 100644 cli/semantics/option.hxx delete mode 100644 cli/semantics/unit.cxx delete mode 100644 cli/semantics/unit.hxx delete mode 100644 cli/semantics/unit.txx delete mode 100644 cli/source.cxx delete mode 100644 cli/source.hxx delete mode 100644 cli/token.hxx delete mode 100644 cli/token.ixx delete mode 100644 cli/traversal.hxx delete mode 100644 cli/traversal/class.cxx delete mode 100644 cli/traversal/class.hxx delete mode 100644 cli/traversal/doc.hxx delete mode 100644 cli/traversal/elements.cxx delete mode 100644 cli/traversal/elements.hxx delete mode 100644 cli/traversal/expression.hxx delete mode 100644 cli/traversal/namespace.cxx delete mode 100644 cli/traversal/namespace.hxx delete mode 100644 cli/traversal/option.cxx delete mode 100644 cli/traversal/option.hxx delete mode 100644 cli/traversal/unit.cxx delete mode 100644 cli/traversal/unit.hxx delete mode 100644 cli/txt.cxx delete mode 100644 cli/txt.hxx delete mode 100644 cli/version.hxx.in delete mode 100644 doc/cli-epilogue.1 delete mode 100644 doc/cli-epilogue.xhtml delete mode 100644 doc/cli-prologue.1 delete mode 100644 doc/cli-prologue.xhtml delete mode 100644 doc/cli.1 delete mode 100644 doc/cli.xhtml delete mode 100644 doc/default.css delete mode 100755 doc/doc.sh delete mode 100644 doc/guide/.gitignore delete mode 100644 doc/guide/guide.html2ps delete mode 100644 doc/guide/index.xhtml delete mode 100644 doc/guide/makefile delete mode 100644 doc/language.txt delete mode 100644 doc/makefile delete mode 100644 examples/.gitignore delete mode 100644 examples/README delete mode 100644 examples/build/.gitignore delete mode 100644 examples/build/bootstrap.build delete mode 100644 examples/build/root.build delete mode 100644 examples/buildfile delete mode 100644 examples/features/.gitignore delete mode 100644 examples/features/README delete mode 100644 examples/features/buildfile delete mode 100644 examples/features/driver.cxx delete mode 100644 examples/features/options.cli delete mode 100644 examples/file/.gitignore delete mode 100644 examples/file/README delete mode 100644 examples/file/buildfile delete mode 100644 examples/file/driver.cxx delete mode 100644 examples/file/options.cli delete mode 100644 examples/file/test.ops delete mode 100644 examples/hello/.gitignore delete mode 100644 examples/hello/README delete mode 100644 examples/hello/buildfile delete mode 100644 examples/hello/driver.cxx delete mode 100644 examples/hello/hello.cli delete mode 100644 manifest create mode 100644 packages.manifest delete mode 100644 tests/.gitignore delete mode 100644 tests/build/.gitignore delete mode 100644 tests/build/bootstrap.build delete mode 100644 tests/build/root.build delete mode 100644 tests/buildfile delete mode 100644 tests/combined/buildfile delete mode 100644 tests/combined/driver.cxx delete mode 100644 tests/combined/test.cli delete mode 100644 tests/combined/testscript delete mode 100644 tests/ctor/buildfile delete mode 100644 tests/ctor/driver.cxx delete mode 100644 tests/ctor/test.cli delete mode 100644 tests/erase/buildfile delete mode 100644 tests/erase/driver.cxx delete mode 100644 tests/erase/test.cli delete mode 100644 tests/file/buildfile delete mode 100644 tests/file/driver.cxx delete mode 100644 tests/file/test.cli delete mode 100644 tests/file/testscript delete mode 100644 tests/group/buildfile delete mode 100644 tests/group/driver.cxx delete mode 100644 tests/group/test.cli delete mode 100644 tests/group/testscript delete mode 100644 tests/headings/buildfile delete mode 100644 tests/headings/testscript delete mode 100644 tests/inheritance/buildfile delete mode 100644 tests/inheritance/driver.cxx delete mode 100644 tests/inheritance/test.cli delete mode 100644 tests/inheritance/test.std delete mode 100644 tests/merge/buildfile delete mode 100644 tests/merge/driver.cxx delete mode 100644 tests/merge/test.cli delete mode 100644 tests/note/buildfile delete mode 100644 tests/note/testscript delete mode 100644 tests/specifier/buildfile delete mode 100644 tests/specifier/driver.cxx delete mode 100644 tests/specifier/test.cli delete mode 100644 tests/toc/buildfile delete mode 100644 tests/toc/testscript delete mode 100644 unit-tests/.gitignore delete mode 100644 unit-tests/lexer/buildfile delete mode 100644 unit-tests/lexer/driver.cxx delete mode 100644 unit-tests/lexer/testscript delete mode 100644 unit-tests/parser/buildfile delete mode 100644 unit-tests/parser/driver.cxx delete mode 100644 unit-tests/parser/testscript diff --git a/.gitignore b/.gitignore index c3de2e7..13d880b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1 @@ .bdep/ - -# Compiler/linker output. -# -*.d -*.t -*.i -*.ii -*.o -*.obj -*.so -*.dll -*.a -*.lib -*.exp -*.pdb -*.ilk -*.exe -*.exe.dlls/ -*.exe.manifest -*.pc diff --git a/INSTALL b/INSTALL index d4204a2..19bc883 100644 --- a/INSTALL +++ b/INSTALL @@ -1,62 +1,30 @@ -General -------- - -Unless you are using the cli+dep package, you will also need to install -the following dependencies: - - libcutl >= 1.1.0 http://www.codesynthesis.com/projects/libcutl/ - -Additionally, for UNIX-like operating systems: - - build >= 0.3.5 http://www.codesynthesis.com/projects/build/ - -The cli+dep package comes with the necessary dependencies bundled. - - -UNIX ----- - -Building on UNIX-like operating systems requires GNU make 3.81 or later. -Most recent GNU/Linux distributions should already have this version -installed. To check the GNU make version run make (or gmake) with the ---version option. - -To build the compiler, tests, and examples simply run make in the root -directory of the package. To run the automated test suite, run 'make test'. -To clean the object files, executables, etc., run 'make clean'. To de- -configure the package (that is, remove configuration files in addition -to objects, executables, etc.), run 'make disfigure'. - -To install the CLI compiler, examples, and documentation use the install -target, for example: - -$ make install_prefix=/usr install - -You can fine-tune the installation locations with the following make -variables: - -install_prefix default is /usr/local -install_data_prefix default is install_prefix -install_exec_prefix default is install_prefix - -install_bin_dir default is install_exec_prefix/bin -install_sbin_dir default is install_exec_prefix/sbin -install_lib_dir default is install_exec_prefix/lib - -install_data_dir default is install_data_prefix/share -install_inc_dir default is install_data_prefix/include - -install_doc_dir default is install_data_dir/doc -install_man_dir default is install_data_dir/man -install_info_dir default is install_data_dir/info - - -Windows -------- - -Project and solution files are provided for Visual C++ 8.0 (2005) and -9.0 (2008). To build the CLI compiler, open and build the corresponding -solution file in the cli\ directory. After the build is complete, the -compiler executable can be found in the cli\ directory. You can also -build examples by opening and building one of the solution files in the -examples\ directory. +CLI uses itself for command line options parsing which makes it a bit tricky +to develop. Below is one way to setup the development environment: + +$ git clone .../cli.git +$ cd cli +$ bdep init -C ../builds/main @main cc # Main build. +$ bdep update # Using pre-geneared code. +$ bdep init -d cli/ -C ../builds/save @save cc # "Saved" build. +$ bdep update @save + +# @@ This does not currently work because bdep (bpkg) will drop it on next +# sync (reconfigure). +# +#$ b configure: ../builds/main/cli/ \ +# config.cli="$(realpath ../builds/save/cli/cli/cli)" + +$ echo >>../builds/main/build/config.build \ + "cli/ config.cli=$(realpath ../builds/save/cli/cli/cli)" + +$ bdep update # Regenerate code. + +Then, when making changes that affect the generated code, perform the +following sequence of steps (the key thing to keep in mind is that the saved +configuration will use generated code from source directory that is +backlinked during the main build): + +$ b cli/ # Regenerate using old saved. +$ bdep update @save # Update saved. +$ b cli/ # Regenerate using new saved. +$ bdep update @save # Update saved. diff --git a/NEWS b/NEWS deleted file mode 100644 index a1fe25e..0000000 --- a/NEWS +++ /dev/null @@ -1,73 +0,0 @@ -Version 1.2.0 - - * New option, --generate-merge, triggers the generation of the merge() - function which can be used to merge several already parsed options class - instances, for example, to implement option appending/overriding. - - * New option, --generate-specifier, triggers the generation of functions - for determining whether the option was specified on the command line. - - * New option, --suppress-undocumented, suppresses the generation of - documentation entries for undocumented options. - - * New option, --cli-namespace, allows changing of the namespace for the - generated CLI support types. - - * The argv_file_scanner now supports double and single-quoting option - values in option files. This is useful to preserve leading and trailing - whitespaces as well as to specify empty values. - - * The argv_file_scanner now supports multiple file options as well as - file search callbacks. - -Version 1.1.0 - - * Support for option documentation. Option documentation is used to print - the usage information as well as to generate the program documentation in - the HTML and man page formats. For details, see Sections 2.5, "Adding - Documentation" and 3.3, "Option Documentation" in the Getting Started - Guide. New CLI compiler command line options related to this feature: - - --suppress-usage - --long-usage - --option-length - --generate-cxx - --generate-man - --generate-html - --man-prologue - --man-epilogue - --html-prologue - --html-epilogue - --man-suffix - --html-suffix - --class - --stdout - - The CLI compiler usage, HTML documentation, and man page are auto-generated - using this feature. - - * New option, --generate-modifier, triggers the generation of the option - value modifiers in addition to the accessors. - - * Support for erasing the parsed elements from the argc/argv array. See - Section 3.1, "Option Class Definition" in the Getting Started Guide for - more information. - - * New scanner interface. Starting with this version, the option class has - a new constructor which accepts an abstract scanner interface. See Section - 3.1, "Option Class Definition" in the Getting Started Guide for more - information. - - * New option, --generate-file-scanner, triggers the generation of the - argv_file_scanner scanner implementation which provides support for - reading command line arguments from the argv array as well as files - specified with command line options. For more information see Section - 3.1, "Option Class Definition" in the Getting Started Guide as well as - the 'file' example. - - * New option, --options-file, allows additional CLI command line options - to be provided in files (implemented using argv_file_scanner). - -Version 1.0.0 - - * First public release. diff --git a/README b/README deleted file mode 100644 index d2c6a02..0000000 --- a/README +++ /dev/null @@ -1,15 +0,0 @@ -CLI is a Command Line Interface definition language for C++. This package -contains the compiler implementation for this language. - -See the NEWS file for the user-visible changes from the previous release. - -See the LICENSE file for distribution conditions. - -See the INSTALL file for prerequisites and installation instructions. - -See the doc/ directory for documentation. - -The project page is at http://codesynthesis.com/projects/cli/. - -Send questions, bug reports, or any other feedback to -cli-users@codesynthesis.com. diff --git a/build/.gitignore b/build/.gitignore deleted file mode 100644 index e931f20..0000000 --- a/build/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -config.build -root/ -bootstrap/ \ No newline at end of file diff --git a/build/bootstrap.build b/build/bootstrap.build deleted file mode 100644 index cd43c15..0000000 --- a/build/bootstrap.build +++ /dev/null @@ -1,18 +0,0 @@ -# file : build/bootstrap.build -# license : MIT; see accompanying LICENSE file - -project = cli - -using version - -# By default leave the cli module unconfigured since we don't want to use some -# system-installed cli. Note that this value will be overridden if set either -# on the command line or in config.build. -# -config.cli = false - -using config - -using dist -using test -using install diff --git a/build/export.build b/build/export.build deleted file mode 100644 index 92c546c..0000000 --- a/build/export.build +++ /dev/null @@ -1,9 +0,0 @@ -# file : build/export.build -# license : MIT; see accompanying LICENSE file - -$out_root/ -{ - include cli/ -} - -export $out_root/cli/exe{cli} diff --git a/build/root.build b/build/root.build deleted file mode 100644 index 0a536ca..0000000 --- a/build/root.build +++ /dev/null @@ -1,37 +0,0 @@ -# file : build/root.build -# license : MIT; see accompanying LICENSE file - -cxx.std = latest - -using cxx - -hxx{*}: extension = hxx -ixx{*}: extension = ixx -txx{*}: extension = txx -cxx{*}: extension = cxx - -if ($cxx.target.system == 'win32-msvc') - cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS - -if ($cxx.class == 'msvc') - cxx.coptions += /wd4251 /wd4275 /wd4800 - -cxx.poptions =+ "-I$out_root" "-I$src_root" - -# Load the cli module but only if it's available. This way a distribution -# that includes pre-generated files can be built without installing cli. -# This is also the reason why we need to explicitly spell out individual -# source file prerequisites instead of using the cli.cxx{} group (it won't -# be there unless the module is configured). -# -using? cli - -# All exe{} in unit-tests/ are, well, tests. Also don't link whole archives -# by default there. -# -unit-tests/exe{*}: test = true -unit-tests/{libue libul}{*}: bin.whole = false - -# Specify the test target for cross-testing. -# -test.target = $cxx.target diff --git a/buildfile b/buildfile deleted file mode 100644 index 394230e..0000000 --- a/buildfile +++ /dev/null @@ -1,30 +0,0 @@ -# file : buildfile -# license : MIT; see accompanying LICENSE file - -d = cli/ unit-tests/ - -# Building examples/ and tests/ while bootstrapping the compiler is tricky. -# What we are going to do is omit these two directories if there is no cli -# compiler yet. Once it's built the user can reconfigure the project which -# will enable tests and examples. Alternatively, the user can install the -# compiler and test the installation with out-of-tree builds of tests/ and -# examples/. -# -# Note that to make sure we don't pick up some system-installed cli, we -# default (in bootstrap.build) to leaving the cli module unconfigured. -# -# Also note that creating distribution with the cli module unconfigured, you -# will end up with incomplete distribution directory (without tests, examples -# and options.cli file). -# -if $cli.configured - d += tests/ examples/ - -./: $d doc{INSTALL LICENSE NEWS README} manifest - -# Don't install examples, tests or the INSTALL file. -# -examples/: install = false -tests/: install = false -unit-tests/: install = false -doc{INSTALL}@./: install = false diff --git a/cli-examples/.gitignore b/cli-examples/.gitignore new file mode 100644 index 0000000..e1d6ab8 --- /dev/null +++ b/cli-examples/.gitignore @@ -0,0 +1,21 @@ +# Compiler/linker output. +# +*.d +*.t +*.i +*.ii +*.o +*.obj +*.so +*.dll +*.a +*.lib +*.exp +*.pdb +*.ilk +*.exe +*.exe.dlls/ +*.exe.manifest +*.pc + +driver diff --git a/cli-examples/LICENSE b/cli-examples/LICENSE new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/cli-examples/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/cli-examples/README b/cli-examples/README new file mode 100644 index 0000000..11589d2 --- /dev/null +++ b/cli-examples/README @@ -0,0 +1,15 @@ +This package contains a number of examples that show how to use the CLI +language and compiler to implement command line interface parsing in C++. +The following list gives an overview of each example. See the README files +in example directories for more information on each example. + +hello + A simple "Hello, world!" example that shows how to implement a very basic + command line interface using CLI. + +features + Shows how to use various features of the CLI language. + +file + Shows how to allow the users of your application to supply options in + files in addition to the command line. diff --git a/cli-examples/build/.gitignore b/cli-examples/build/.gitignore new file mode 100644 index 0000000..4a730a3 --- /dev/null +++ b/cli-examples/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ diff --git a/cli-examples/build/bootstrap.build b/cli-examples/build/bootstrap.build new file mode 100644 index 0000000..c50c6ac --- /dev/null +++ b/cli-examples/build/bootstrap.build @@ -0,0 +1,9 @@ +# file : build/bootstrap.build +# license : MIT; see accompanying LICENSE file + +project = cli-examples + +using version +using config +using dist +using test diff --git a/cli-examples/build/root.build b/cli-examples/build/root.build new file mode 100644 index 0000000..53bde39 --- /dev/null +++ b/cli-examples/build/root.build @@ -0,0 +1,27 @@ +# file : build/root.build +# license : MIT; see accompanying LICENSE file + +cxx.std = latest + +using cxx + +hxx{*}: extension = hxx +ixx{*}: extension = ixx +txx{*}: extension = txx +cxx{*}: extension = cxx + +if ($cxx.target.system == 'win32-msvc') + cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + +if ($cxx.class == 'msvc') + cxx.coptions += /wd4251 /wd4275 /wd4800 + +using cli + +# Every exe{} in this subproject is by default a test. +# +exe{*}: test = true + +# Specify the test target for cross-testing. +# +test.target = $cxx.target diff --git a/cli-examples/buildfile b/cli-examples/buildfile new file mode 100644 index 0000000..53d51dd --- /dev/null +++ b/cli-examples/buildfile @@ -0,0 +1,4 @@ +# file : buildfile +# license : MIT; see accompanying LICENSE file + +./: {*/ -build/} doc{LICENSE README} manifest diff --git a/cli-examples/features/.gitignore b/cli-examples/features/.gitignore new file mode 100644 index 0000000..c6e608b --- /dev/null +++ b/cli-examples/features/.gitignore @@ -0,0 +1 @@ +options.?xx diff --git a/cli-examples/features/README b/cli-examples/features/README new file mode 100644 index 0000000..9416320 --- /dev/null +++ b/cli-examples/features/README @@ -0,0 +1,20 @@ +This example shows how to use various features of the CLI language. + +The example consists of the following files: + +options.cli + Command line interface description in the CLI language. + +options.hxx +options.ixx +options.cxx + Command line interface implementation in C++. These files are generated + by the CLI compiler from hello.cli using the following command line: + + cli options.cli + +driver.cxx + Driver for the example. It first instantiates the option class which parses + the command line. The driver then examines and prints the option values. + +To run the example you can try various command lines suggested in options.cli. diff --git a/cli-examples/features/buildfile b/cli-examples/features/buildfile new file mode 100644 index 0000000..5051eae --- /dev/null +++ b/cli-examples/features/buildfile @@ -0,0 +1,8 @@ +# file : features/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -options} cli.cxx{options} doc{README} + +cxx.poptions =+ "-I$out_base" + +cli.cxx{options}: cli{options} diff --git a/cli-examples/features/driver.cxx b/cli-examples/features/driver.cxx new file mode 100644 index 0000000..c14b5c7 --- /dev/null +++ b/cli-examples/features/driver.cxx @@ -0,0 +1,61 @@ +// file : features/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include +#include +#include + +#include "options.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + features::options o (argc, argv); + + // --out-dir | -o + // + if (!o.out_dir ().empty ()) + cerr << "output dir: " << o.out_dir () << endl; + + // --first-name & --last-name + // + cerr << "first name: " << o.first_name () << endl + << "last name : " << o.last_name () << endl; + + // --vector | -v & --set | -s + // + if (!o.vector ().empty ()) + { + copy (o.vector ().begin (), o.vector ().end (), + ostream_iterator (cerr, " ")); + cerr << endl; + } + + if (!o.set ().empty ()) + { + copy (o.set ().begin (), o.set ().end (), + ostream_iterator (cerr, " ")); + cerr << endl; + } + + // --map | -m + // + typedef map str_map; + const str_map& m = o.map (); + str_map::const_iterator i (m.find ("a")); + + if (i != m.end ()) + cerr << "value for the 'a' key: " << i->second << endl; + + } + catch (const cli::exception& e) + { + cerr << e << endl; + return 1; + } +} diff --git a/cli-examples/features/options.cli b/cli-examples/features/options.cli new file mode 100644 index 0000000..ea055b3 --- /dev/null +++ b/cli-examples/features/options.cli @@ -0,0 +1,39 @@ +include ; +include ; +include ; +include ; + +// We can place the options classes into namespaces which mapped to C++ +// namespaces. +// +namespace features +{ + class options + { + // We can have several aliases for the same option. The first one is used + // to derive the accessor name. + // + std::string --out-dir | -o; + + // We can use both assignment and constructor notations to provide the + // default option value. + // + std::string --first-name = "John"; + std::string --last-name ("Mr John Doe", 8, 3); + + // We can use containers to to collect option value. If we have a command + // line like this: -v 1 -v 2 -v 1 -s 1 -s 2 -s 1 then the vector returned + // by the vector() accessor will contain three elements: 1, 2, and 1 while + // the set returned by the set() accessor will contain two elements: 1 and + // 2. + // + std::vector --vector | -v; + std::set --set | -s; + + // We can also use maps. In this case the option value is expected to have + // two parts: the key and the value, separated by '='. For example: -m a=A + // -m =B -m c= -m d (same as -m d=). + // + std::map --map | -m; + }; +} diff --git a/cli-examples/file/.gitignore b/cli-examples/file/.gitignore new file mode 100644 index 0000000..c6e608b --- /dev/null +++ b/cli-examples/file/.gitignore @@ -0,0 +1 @@ +options.?xx diff --git a/cli-examples/file/README b/cli-examples/file/README new file mode 100644 index 0000000..289fc64 --- /dev/null +++ b/cli-examples/file/README @@ -0,0 +1,38 @@ +This example shows how to allow the users of your application to supply +options in files in addition to the command line. + +The example consists of the following files: + +options.cli + Command line interface description in the CLI language. + +options.hxx +options.ixx +options.cxx + Command line interface implementation in C++. These files are generated + by the CLI compiler from options.cli using the following command line: + + cli --generate-file-scanner hello.cli + + We use the --generate-file-scanner CLI compiler option to include the + argv_file_scanner scanner implementation which provides support for + reading options from files in addition to the command line. + +driver.cxx + Driver for the example. It first creates the argv_file_scanner object + and indicates that the values for the --options-file option should be + recognized as files containing additional options. It then passes this + scanner object to the option class which parses the command line. The + driver then prints the option values. + +test.ops + Sample options file. + +To run this example you can try the following command line: + +$ ./driver --verbose 2 --val 1 --options-file test.ops --val 4 + +The output will be: + +verbosity: 5 +values: 1 2 3 4 diff --git a/cli-examples/file/buildfile b/cli-examples/file/buildfile new file mode 100644 index 0000000..89675d8 --- /dev/null +++ b/cli-examples/file/buildfile @@ -0,0 +1,11 @@ +# file : file/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -options} cli.cxx{options} doc{README} +exe{driver}: test.arguments = --options-file +exe{driver}: file{test.ops}: test.input = true # Added after test.arguments. + +cxx.poptions =+ "-I$out_base" + +cli.cxx{options}: cli{options} +cli.options = --generate-file-scanner diff --git a/cli-examples/file/driver.cxx b/cli-examples/file/driver.cxx new file mode 100644 index 0000000..b53574c --- /dev/null +++ b/cli-examples/file/driver.cxx @@ -0,0 +1,35 @@ +// file : file/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include +#include +#include + +#include "options.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + cli::argv_file_scanner s (argc, argv, "--options-file"); + options o (s); + + cout << "verbosity: " << o.verbose () << endl + << "values: "; + + copy (o.val ().begin (), + o.val ().end (), + ostream_iterator (cout, " ")); + + cerr << endl; + } + catch (const cli::exception& e) + { + cerr << e << endl; + return 1; + } +} diff --git a/cli-examples/file/options.cli b/cli-examples/file/options.cli new file mode 100644 index 0000000..3e6db5a --- /dev/null +++ b/cli-examples/file/options.cli @@ -0,0 +1,7 @@ +include ; + +class options +{ + int --verbose; + std::vector --val; +}; diff --git a/cli-examples/file/test.ops b/cli-examples/file/test.ops new file mode 100644 index 0000000..65fcf07 --- /dev/null +++ b/cli-examples/file/test.ops @@ -0,0 +1,7 @@ +# Sample options file. Empty lines and lines starting with '#' are +# ignored. +# +--verbose 5 + +--val 2 +--val=3 diff --git a/cli-examples/hello/.gitignore b/cli-examples/hello/.gitignore new file mode 100644 index 0000000..d73130a --- /dev/null +++ b/cli-examples/hello/.gitignore @@ -0,0 +1 @@ +hello.?xx diff --git a/cli-examples/hello/README b/cli-examples/hello/README new file mode 100644 index 0000000..dd14b01 --- /dev/null +++ b/cli-examples/hello/README @@ -0,0 +1,26 @@ +This is a "Hello, world!" example that shows how to implement a very basic +command line interface using CLI. + +The example consists of the following files: + +hello.cli + Command line interface description in the CLI language. + +hello.hxx +hello.ixx +hello.cxx + Command line interface implementation in C++. These files are generated + by the CLI compiler from hello.cli using the following command line: + + cli hello.cli + +driver.cxx + Driver for the example. It first instantiates the option class which parses + the command line. The driver then examines the options and prints the + greeting string for each name passed as an argument. + +To run the example you can try the following command lines: + +$ ./driver --help +$ ./driver John Jane +$ ./driver --greeting Hi --exclamations 3 John Jane diff --git a/cli-examples/hello/buildfile b/cli-examples/hello/buildfile new file mode 100644 index 0000000..8197d9e --- /dev/null +++ b/cli-examples/hello/buildfile @@ -0,0 +1,9 @@ +# file : hello/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -hello} cli.cxx{hello} doc{README} +exe{driver}: test.arguments = --greeting Hi John Jane + +cxx.poptions =+ "-I$out_base" + +cli.cxx{hello}: cli{hello} diff --git a/cli-examples/hello/driver.cxx b/cli-examples/hello/driver.cxx new file mode 100644 index 0000000..bc37564 --- /dev/null +++ b/cli-examples/hello/driver.cxx @@ -0,0 +1,58 @@ +// file : hello/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include + +#include "hello.hxx" + +using namespace std; + +void +usage (ostream& os) +{ + os << "usage: driver [options] " << endl + << "options:" << endl; + options::print_usage (os); +} + +int +main (int argc, char* argv[]) +{ + try + { + int end; // End of options. + options o (argc, argv, end); + + if (o.help ()) + { + usage (cout); + return 0; + } + + if (end == argc) + { + cerr << "no names provided" << endl; + usage (cerr); + return 1; + } + + // Print the greetings. + // + for (int i = end; i < argc; i++) + { + cout << o.greeting () << ", " << argv[i]; + + for (unsigned int j = 0; j < o.exclamations (); j++) + cout << '!'; + + cout << endl; + } + } + catch (const cli::exception& e) + { + cerr << e << endl; + usage (cerr); + return 1; + } +} diff --git a/cli-examples/hello/hello.cli b/cli-examples/hello/hello.cli new file mode 100644 index 0000000..b75e1b8 --- /dev/null +++ b/cli-examples/hello/hello.cli @@ -0,0 +1,18 @@ +include ; + +class options +{ + bool --help {"Print usage information and exit."}; + + std::string --greeting = "Hello" + { + "", + "Use as a greeting phrase instead of the default \"Hello\"." + }; + + unsigned int --exclamations = 1 + { + "", + "Print exclamation marks instead of 1 by default." + }; +}; diff --git a/cli-examples/manifest b/cli-examples/manifest new file mode 100644 index 0000000..9ef14f3 --- /dev/null +++ b/cli-examples/manifest @@ -0,0 +1,15 @@ +: 1 +name: cli-examples +version: 1.2.0-b.6.z +project: cli +summary: Examples of using the CLI language and compiler for C++ +license: MIT +description-file: README +url: https://www.codesynthesis.com/projects/cli/ +doc-url: https://www.codesynthesis.com/projects/cli/doc/guide/ +src-url: https://git.codesynthesis.com/cgit/cli/cli/tree/cli-examples +email: cli-users@codesynthesis.com ; Mailing list +build-email: builds@codesynthesis.com +requires: c++14 +depends: * build2 >= 0.13.0- +depends: * bpkg >= 0.13.0- diff --git a/cli-tests/.gitignore b/cli-tests/.gitignore new file mode 100644 index 0000000..0b99f39 --- /dev/null +++ b/cli-tests/.gitignore @@ -0,0 +1,22 @@ +# Compiler/linker output. +# +*.d +*.t +*.i +*.ii +*.o +*.obj +*.so +*.dll +*.a +*.lib +*.exp +*.pdb +*.ilk +*.exe +*.exe.dlls/ +*.exe.manifest +*.pc + +driver +test.?xx diff --git a/cli-tests/LICENSE b/cli-tests/LICENSE new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/cli-tests/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/cli-tests/README b/cli-tests/README new file mode 100644 index 0000000..28e7868 --- /dev/null +++ b/cli-tests/README @@ -0,0 +1,8 @@ +This package contains tests for the CLI compiler for C++. + +See the LICENSE file for distribution conditions. + +The project page is at http://codesynthesis.com/projects/cli/. + +Send questions, bug reports, or any other feedback to +cli-users@codesynthesis.com. diff --git a/cli-tests/build/.gitignore b/cli-tests/build/.gitignore new file mode 100644 index 0000000..4a730a3 --- /dev/null +++ b/cli-tests/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ diff --git a/cli-tests/build/bootstrap.build b/cli-tests/build/bootstrap.build new file mode 100644 index 0000000..f5c693e --- /dev/null +++ b/cli-tests/build/bootstrap.build @@ -0,0 +1,9 @@ +# file : build/bootstrap.build +# license : MIT; see accompanying LICENSE file + +project = cli-tests + +using version +using config +using dist +using test diff --git a/cli-tests/build/root.build b/cli-tests/build/root.build new file mode 100644 index 0000000..53bde39 --- /dev/null +++ b/cli-tests/build/root.build @@ -0,0 +1,27 @@ +# file : build/root.build +# license : MIT; see accompanying LICENSE file + +cxx.std = latest + +using cxx + +hxx{*}: extension = hxx +ixx{*}: extension = ixx +txx{*}: extension = txx +cxx{*}: extension = cxx + +if ($cxx.target.system == 'win32-msvc') + cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + +if ($cxx.class == 'msvc') + cxx.coptions += /wd4251 /wd4275 /wd4800 + +using cli + +# Every exe{} in this subproject is by default a test. +# +exe{*}: test = true + +# Specify the test target for cross-testing. +# +test.target = $cxx.target diff --git a/cli-tests/buildfile b/cli-tests/buildfile new file mode 100644 index 0000000..53d51dd --- /dev/null +++ b/cli-tests/buildfile @@ -0,0 +1,4 @@ +# file : buildfile +# license : MIT; see accompanying LICENSE file + +./: {*/ -build/} doc{LICENSE README} manifest diff --git a/cli-tests/combined/buildfile b/cli-tests/combined/buildfile new file mode 100644 index 0000000..943ca25 --- /dev/null +++ b/cli-tests/combined/buildfile @@ -0,0 +1,9 @@ +# file : combined/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -test} cli.cxx{test} testscript + +cxx.poptions =+ "-I$out_base" + +cli.cxx{test}: cli{test} +cli.options = --generate-specifier --generate-file-scanner diff --git a/cli-tests/combined/driver.cxx b/cli-tests/combined/driver.cxx new file mode 100644 index 0000000..dcbdd34 --- /dev/null +++ b/cli-tests/combined/driver.cxx @@ -0,0 +1,39 @@ +// file : combined/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// Test combined flags (-xyz vs -x -y -z) and option values (--foo=bar). +// + +#include + +#include "test.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + cli::argv_file_scanner s (argc, argv, "--file"); + options o (s); + + if (o.foo_specified ()) + cout << "--foo=" << o.foo () << endl; + + if (o.x () || o.y () || o.z ()) + cout << '-' + << (o.x () ? "x" : "") + << (o.y () ? "y" : "") + << (o.z () ? "z" : "") << endl; + + if (o.xyz ()) + cout << "--xyz" << endl; + } + catch (const cli::exception& e) + { + cerr << e << endl; + return 1; + } +} diff --git a/cli-tests/combined/test.cli b/cli-tests/combined/test.cli new file mode 100644 index 0000000..6377de8 --- /dev/null +++ b/cli-tests/combined/test.cli @@ -0,0 +1,16 @@ +// file : combined/test.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +include ; + +class options +{ + std::string --foo|-f; + + bool -x; + bool -y; + bool -z; + + bool --xyz; +}; diff --git a/cli-tests/combined/testscript b/cli-tests/combined/testscript new file mode 100644 index 0000000..d1f9830 --- /dev/null +++ b/cli-tests/combined/testscript @@ -0,0 +1,108 @@ +# file : combined/testscript +# license : MIT; see accompanying LICENSE file + +: values +: +{ + : long + : + $* --foo=123 >'--foo=123' + + : short + : + $* -f=123 >'--foo=123' + + : empty + : + $* --foo= >'--foo=' + + : unknown-option-long + : + $* --bar=123 2>>EOE != 0 + unknown option '--bar' + EOE + + : unknown-option-short + : + $* -b=123 2>>EOE != 0 + unknown option '-b' + EOE + + : unknown-value + : + $* --xyz=123 2>>EOE != 0 + invalid value '123' for option '--xyz' + EOE + + : options-file + : + { + : basics + : + cat <=options; + --foo=123 + EOI + $* --file=options >'--foo=123' + + : equal-in-value + : + cat <=options; + --foo bar=123 + EOI + $* --file=options >'--foo=bar=123' + + : space-in-value + : + cat <=options; + --foo= 123 + EOI + $* --file=options >'--foo= 123' + + : quoted-value + : + cat <=options; + --foo="'bar 123'" + EOI + $* --file=options >"--foo='bar 123'" + } +} + +: flags +: +{ + : basic + : + $* -zyx >'-xyz' + + : separate + : + $* -zx -y >'-xyz' + + : long + : + $* --xyz >'--xyz' + + : unknown-option + : + $* -xYz 2>>EOE != 0 + unknown option '-Y' + EOE + + : alnum-only + : + $* -xy+ 2>>EOE != 0 + unknown option '-xy+' + EOE + + : flags-only + : + $* -xyf 123 2>>EOE != 0 + missing value for option '-f' + EOE + + : flags-only-combined + : + $* -xyf=123 2>>EOE != 0 + missing value for option '-f' + EOE +} diff --git a/cli-tests/ctor/buildfile b/cli-tests/ctor/buildfile new file mode 100644 index 0000000..4144988 --- /dev/null +++ b/cli-tests/ctor/buildfile @@ -0,0 +1,8 @@ +# file : ctor/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -test} cli.cxx{test} + +cxx.poptions =+ "-I$out_base" + +cli.cxx{test}: cli{test} diff --git a/cli-tests/ctor/driver.cxx b/cli-tests/ctor/driver.cxx new file mode 100644 index 0000000..ed306f4 --- /dev/null +++ b/cli-tests/ctor/driver.cxx @@ -0,0 +1,60 @@ +// file : ctor/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include "test.hxx" + +int +main (int argc, char* argv[]) +{ + // Test that we can call all the c-tors unambiguously. + // + { + options o1 (argc, argv); + options o2 (argc, argv, true); + options o3 (argc, argv, true, + cli::unknown_mode::fail); + options o4 (argc, argv, true, + cli::unknown_mode::fail, + cli::unknown_mode::stop); + } + + { + options o1 (1, argc, argv); + options o2 (1, argc, argv, true); + options o3 (1, argc, argv, true, + cli::unknown_mode::fail); + options o4 (1, argc, argv, true, + cli::unknown_mode::fail, + cli::unknown_mode::stop); + } + + { + int end; + options o1 (argc, argv, end); + options o2 (argc, argv, end, true); + options o3 (argc, argv, end, true, + cli::unknown_mode::fail); + options o4 (argc, argv, end, true, + cli::unknown_mode::fail, + cli::unknown_mode::stop); + } + + { + int end; + options o1 (1, argc, argv, end); + options o2 (1, argc, argv, end, true); + options o3 (1, argc, argv, end, true, + cli::unknown_mode::fail); + options o4 (1, argc, argv, end, true, + cli::unknown_mode::fail, + cli::unknown_mode::stop); + } + + { + cli::argv_scanner s (argc, argv); + options o1 (s); + options o2 (s, cli::unknown_mode::fail); + options o3 (s, cli::unknown_mode::fail, cli::unknown_mode::stop); + } +} diff --git a/cli-tests/ctor/test.cli b/cli-tests/ctor/test.cli new file mode 100644 index 0000000..94797fb --- /dev/null +++ b/cli-tests/ctor/test.cli @@ -0,0 +1,8 @@ +// file : ctor/test.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +class options +{ + bool --help; +}; diff --git a/cli-tests/erase/buildfile b/cli-tests/erase/buildfile new file mode 100644 index 0000000..024e021 --- /dev/null +++ b/cli-tests/erase/buildfile @@ -0,0 +1,10 @@ +# file : erase/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -test} cli.cxx{test} +exe{driver}: test.arguments = foo -a bar -b 123 --arg -- -b 234 + +cxx.poptions =+ "-I$out_base" + +cli.cxx{test}: cli{test} +cli.options = --no-combined-flags # Can't be used with the skip unknown mode. diff --git a/cli-tests/erase/driver.cxx b/cli-tests/erase/driver.cxx new file mode 100644 index 0000000..af35836 --- /dev/null +++ b/cli-tests/erase/driver.cxx @@ -0,0 +1,34 @@ +// file : erase/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// Test argument erasing. +// + +#include +#include + +#include "test.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + options o (argc, argv, true, + cli::unknown_mode::skip, + cli::unknown_mode::skip); + + assert (o.a ()); + assert (o.b () == 123); + + // We should have 'foo bar --arg -- -b 234'. + // + assert (argc == 7); + assert (argv[1] == string ("foo")); + assert (argv[2] == string ("bar")); + assert (argv[3] == string ("--arg")); + assert (argv[4] == string ("--")); + assert (argv[5] == string ("-b")); + assert (argv[6] == string ("234")); +} diff --git a/cli-tests/erase/test.cli b/cli-tests/erase/test.cli new file mode 100644 index 0000000..a5d7672 --- /dev/null +++ b/cli-tests/erase/test.cli @@ -0,0 +1,9 @@ +// file : erase/test.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +class options +{ + bool -a; + int -b; +}; diff --git a/cli-tests/file/buildfile b/cli-tests/file/buildfile new file mode 100644 index 0000000..793d2a9 --- /dev/null +++ b/cli-tests/file/buildfile @@ -0,0 +1,9 @@ +# file : file/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -test} cli.cxx{test} testscript + +cxx.poptions =+ "-I$out_base" + +cli.cxx{test}: cli{test} +cli.options = --generate-file-scanner diff --git a/cli-tests/file/driver.cxx b/cli-tests/file/driver.cxx new file mode 100644 index 0000000..eef7ef1 --- /dev/null +++ b/cli-tests/file/driver.cxx @@ -0,0 +1,39 @@ +// file : file/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// Test argv_file_scanner. +// +#include +#include +#include + +#include "test.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + string a (argc > 1 ? argv[1] : ""); + + // Special modes. + // + // ---- + // --- + // + unique_ptr s ( + a == "----" ? new cli::argv_file_scanner (argv[2], "--file") : + a == "---" ? new cli::argv_file_scanner (argv[2]) : + new cli::argv_file_scanner (argc, argv, "--file")); + + while (s->more ()) + cout << s->next () << endl; + } + catch (const cli::exception& e) + { + cerr << e << endl; + } +} diff --git a/cli-tests/file/test.cli b/cli-tests/file/test.cli new file mode 100644 index 0000000..c72a495 --- /dev/null +++ b/cli-tests/file/test.cli @@ -0,0 +1,7 @@ +// file : file/test.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +class options +{ +}; diff --git a/cli-tests/file/testscript b/cli-tests/file/testscript new file mode 100644 index 0000000..d86ec1d --- /dev/null +++ b/cli-tests/file/testscript @@ -0,0 +1,286 @@ +# file : file/testscript +# license : MIT; see accompanying LICENSE file + +# End-of-line marker. Place its expansion in here-documents after the trailing +# spaces to prevent them from being stripped by editors and to improve +# readability. +# +eol = "" + ++cat <=empty.ops +# Empty options file. +# + +EOI ++cat <=base.ops +-a 21 +-b 21 +EOI + +# @@ Give tests some meaningfull descriptions. +# + +: 000 +: +cat <=test.ops; +-a 11 +-b 11 + -a 12 + + -b 12 +a +EOI +$* -a 1 --file ../empty.ops -b 1 --file ../base.ops --file test.ops b >>EOO +-a +1 +-b +1 +-a +21 +-b +21 +-a +11 +-b +11 +-a +12 +-b +12 +a +b +EOO + +: 001 +: +cat <=test.ops; +# Empty options file. +# + +EOI +$* -a 1 -- --file test.ops b >>EOO +-a +1 +-- +--file +test.ops +b +EOO + +: 002 +: +cat <=test.ops; +-a 11 +-b 11 +-- +--file ../base.ops +-a 12 +-b 12 +a +EOI +$* -a 1 --file test.ops --file ../empty.ops b >>EOO +-a +1 +-a +11 +-b +11 +-- +--file +../base.ops +-a +12 +-b +12 +a +--file +../empty.ops +b +EOO + +: 003 +: +$* -a 1 --file ../base.ops --file test.ops b >>EOO 2>>EOE +-a +1 +-a +21 +-b +21 +EOO +unable to open file 'test.ops' or read failure +EOE + +: 004 +: +cat <=test.ops; +-a a"b"c +-a "abc" +-a "a"b" +-a "" +-a " abc " +-a " " +-a """ +-a "'" + +-a a'b'c +-a 'abc' +-a 'a'b' +-a '' +-a ' abc ' +-a ' ' +-a ''' +-a '"' +EOI +$* --file test.ops >>"EOO" +-a +a"b"c +-a +abc +-a +a"b +-a + +-a + abc $eol +-a + $eol +-a +" +-a +' +-a +a'b'c +-a +abc +-a +a'b +-a + +-a + abc $eol +-a + $eol +-a +' +-a +" +EOO + +: 005 +: +cat <=test.ops; +-a " +EOI +$* --file test.ops 2>>EOE +unmatched quote in argument '"' +EOE + +: 006 +: +cat <=test.ops; +-a "abc +EOI +$* --file test.ops 2>>EOE +unmatched quote in argument '"abc' +EOE + +: 007 +: +cat <=test.ops; +-a abc" +EOI +$* --file test.ops 2>>EOE +unmatched quote in argument 'abc"' +EOE + +: 008 +: +cat <=test.ops; +-a ' +EOI +$* --file test.ops 2>>EOE +unmatched quote in argument ''' +EOE + +: 009 +: +cat <=test.ops; +-a 'abc +EOI +$* --file test.ops 2>>EOE +unmatched quote in argument ''abc' +EOE + +: 010 +: +cat <=test.ops; +-a abc' +EOI +$* --file test.ops 2>>EOE +unmatched quote in argument 'abc'' +EOE + +: 011 +: +cat <=test.ops; +-a "abc' +EOI +$* --file test.ops 2>>EOE +unmatched quote in argument '"abc'' +EOE + +: 012 +: +cat <=test.ops; +-a 'abc" +EOI +$* --file test.ops 2>>EOE +unmatched quote in argument ''abc"' +EOE + +: quoted-argument +: +cat <=test.ops; +"'foo bar'" +'"foo bar"' +EOI +$* --file test.ops >>EOO +'foo bar' +"foo bar" +EOO + +: direct-file-load +: +cat <=test.ops; +-f +-a 123 +EOI +$* --- test.ops >>EOO +-f +-a +123 +EOO + +: direct-file-empty +: +cat <=test.ops; +EOI +$* --- test.ops + +: direct-file-load-nested +: +cat <=test.ops; +-f +--file ../base.ops +-a 123 +EOI +$* ---- test.ops >>EOO +-f +-a +21 +-b +21 +-a +123 +EOO diff --git a/cli-tests/group/buildfile b/cli-tests/group/buildfile new file mode 100644 index 0000000..30327e0 --- /dev/null +++ b/cli-tests/group/buildfile @@ -0,0 +1,9 @@ +# file : group/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -test} cli.cxx{test} testscript + +cxx.poptions =+ "-I$out_base" + +cli.cxx{test}: cli{test} +cli.options = --generate-group-scanner diff --git a/cli-tests/group/driver.cxx b/cli-tests/group/driver.cxx new file mode 100644 index 0000000..68f6107 --- /dev/null +++ b/cli-tests/group/driver.cxx @@ -0,0 +1,58 @@ +// file : group/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// Test group_scanner. +// + +#include + +#include "test.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + try + { + using namespace cli; + + // Mode flags. + // + // 'g' -- don't handle groups. + // 's' -- skip arguments. + // + string m (argv[1]); + + argv_scanner as (--argc, ++argv); + group_scanner s (as); + + while (s.more ()) + { + if (m.find ('s') == string::npos) + { + const char* a (s.next ()); + cout << "'" << a << "'"; + } + else + s.skip (); + + if (m.find ('g') == string::npos) + { + scanner& gs (s.group ()); + while (gs.more ()) + cout << " '" << gs.next () << "'"; + } + + cout << endl; + } + + return 0; + } + catch (const cli::exception& e) + { + cerr << e << endl; + return 1; + } +} diff --git a/cli-tests/group/test.cli b/cli-tests/group/test.cli new file mode 100644 index 0000000..8725791 --- /dev/null +++ b/cli-tests/group/test.cli @@ -0,0 +1,7 @@ +// file : group/test.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +class options +{ +}; diff --git a/cli-tests/group/testscript b/cli-tests/group/testscript new file mode 100644 index 0000000..6269ca2 --- /dev/null +++ b/cli-tests/group/testscript @@ -0,0 +1,140 @@ +# file : group/testscript +# license : MIT; see accompanying LICENSE file + +: no-args +: +$* '' + +: no-groups +: +$* '' --foo arg >>EOO +'--foo' +'arg' +EOO + +: group-pre +: +$* '' { --foo --bar }+ arg1 arg2 >>EOO +'arg1' '--foo' '--bar' +'arg2' +EOO + +: group-pre-multi +: +$* '' { --foo }+ { --bar }+ arg1 arg2 >>EOO +'arg1' '--foo' '--bar' +'arg2' +EOO + +: group-post +: +$* '' arg1 arg2 +{ foo bar } >>EOO +'arg1' +'arg2' 'foo' 'bar' +EOO + +: group-post-multi +: +$* '' arg1 arg2 +{ foo } +{ bar } >>EOO +'arg1' +'arg2' 'foo' 'bar' +EOO + +: group-both +: +$* '' arg1 { --foo --bar }+ arg2 +{ foo bar } arg3 >>EOO +'arg1' +'arg2' '--foo' '--bar' 'foo' 'bar' +'arg3' +EOO + +: group-both-multi +: +$* '' arg1 { --foo }+ { --bar }+ arg2 +{ foo } +{ bar } arg3 >>EOO +'arg1' +'arg2' '--foo' '--bar' 'foo' 'bar' +'arg3' +EOO + +: multi-group +: +$* '' { --foo }+ arg1 arg2 +{ bar } >>EOO +'arg1' '--foo' +'arg2' 'bar' +EOO + +: empty-group +: +$* '' { }+ arg1 arg2 +{ } >>EOO +'arg1' +'arg2' +EOO + +: escape-arg +: +$* '' '\{' '\}' '\+{' '\}+' '{x' '}x' >>EOO +'{' +'}' +'+{' +'}+' +'{x' +'}x' +EOO + +: escape-group +: +$* '' { '\{' '\}' '\+{' '\}+' '{x' '}x' }+ arg >>EOO +'arg' '{' '}' '+{' '}+' '{x' '}x' +EOO + +: not-group +: +$* '' { --foo } 2>>EOE != 0 +expected group separator '}+' instead of '}', use '\}' to escape +EOE + +: no-arg-pre +: +$* '' { --foo }+ 2>>EOE != 0 +unexpected group separator '{', use '\{' to escape +EOE + +: no-arg-pre-empty +: +$* '' { }+ 2>>EOE != 0 +unexpected group separator '{', use '\{' to escape +EOE + +: no-arg-post +: +$* '' +{ --foo } 2>>EOE != 0 +unexpected group separator '+{', use '\+{' to escape +EOE + +: no-arg-post-empty +: +$* '' +{ } 2>>EOE != 0 +unexpected group separator '+{', use '\+{' to escape +EOE + +: unhandled-group-pre +: +$* 'g' { --foo }+ arg >>EOO 2>>EOE != 0 +'arg' +EOO +unexpected grouped argument '--foo' for argument 'arg' +EOE + +: unhandled-group-post +: +$* 'g' arg +{ bar } >>EOO 2>>EOE != 0 +'arg' +EOO +unexpected grouped argument 'bar' for argument 'arg' +EOE + +: unhandled-group-skip +: +$* 'sg' { --foo }+ arg +{ bar } >>EOO + +EOO diff --git a/cli-tests/headings/buildfile b/cli-tests/headings/buildfile new file mode 100644 index 0000000..af3ae75 --- /dev/null +++ b/cli-tests/headings/buildfile @@ -0,0 +1,6 @@ +# file : headings/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $cli + +testscript{*}: test = $cli diff --git a/cli-tests/headings/testscript b/cli-tests/headings/testscript new file mode 100644 index 0000000..0efb7ae --- /dev/null +++ b/cli-tests/headings/testscript @@ -0,0 +1,36 @@ +# file : headings/testscript +# license : MIT; see accompanying LICENSE file + +: auto-headings +: +: Note that auto-headings break if we split into multiple doc strings. +: +cat <=map.cli; +" +\h1|Heading 1| + +\h|Heading 1.1| + +\h2|Heading 1.1.1| + +\h|Heading 1.2| + +\h2|Heading 1.2.1| + +\h1|Heading 2| +" +EOI +$* --generate-html --stdout map.cli >>EOO +

Heading 1

+ +

Heading 1.1

+ +

Heading 1.1.1

+ +

Heading 1.2

+ +

Heading 1.2.1

+ +

Heading 2

+ +EOO diff --git a/cli-tests/inheritance/buildfile b/cli-tests/inheritance/buildfile new file mode 100644 index 0000000..6fe1ecc --- /dev/null +++ b/cli-tests/inheritance/buildfile @@ -0,0 +1,11 @@ +# file : inheritance/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -test} cli.cxx{test} +exe{driver}: file{test.std}: test.stdout = true +exe{driver}: test.arguments = --very-long-flag -s short -i 123 --string long + +cxx.poptions =+ "-I$out_base" + +cli.cxx{test}: cli{test} +cli.options = --generate-description --option-length 17 diff --git a/cli-tests/inheritance/driver.cxx b/cli-tests/inheritance/driver.cxx new file mode 100644 index 0000000..4acab0d --- /dev/null +++ b/cli-tests/inheritance/driver.cxx @@ -0,0 +1,35 @@ +// file : inheritance/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// Test option class inheritance. +// + +#include +#include +#include + +#include "test.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + const cli::options& d (options::description ()); + + assert (d.size () == 4); + assert (d[0].name () == "--very-long-flag"); + assert (d[1].name () == "-i"); + assert (d[2].name () == "-s"); + assert (d[3].name () == "--string"); + + options o (argc, argv); + + assert (o.very_long_flag ()); + assert (o.s () == "short"); + assert (o.i () == 123); + assert (o.string () == "long"); + + options::print_usage (cout); +} diff --git a/cli-tests/inheritance/test.cli b/cli-tests/inheritance/test.cli new file mode 100644 index 0000000..3b73848 --- /dev/null +++ b/cli-tests/inheritance/test.cli @@ -0,0 +1,25 @@ +// file : inheritance/test.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +include ; + +class base1 = 0 +{ + bool --very-long-flag {"Long flag."}; +}; + +class base2 +{ + std::string -s {"", "Short string."}; +}; + +class interm: base1 +{ + int -i = 1 {"", "Integer."}; +}; + +class options: interm, base2 +{ + std::string --string {"", "Long string."}; +}; diff --git a/cli-tests/inheritance/test.std b/cli-tests/inheritance/test.std new file mode 100644 index 0000000..4c93225 --- /dev/null +++ b/cli-tests/inheritance/test.std @@ -0,0 +1,4 @@ +--very-long-flag Long flag. +-i Integer. +-s Short string. +--string Long string. diff --git a/cli-tests/manifest b/cli-tests/manifest new file mode 100644 index 0000000..a7898ce --- /dev/null +++ b/cli-tests/manifest @@ -0,0 +1,15 @@ +: 1 +name: cli-tests +version: 1.2.0-b.6.z +project: cli +summary: Tests for the CLI compiler for C++ +license: MIT +description-file: README +url: https://www.codesynthesis.com/projects/cli/ +doc-url: https://www.codesynthesis.com/projects/cli/doc/guide/ +src-url: https://git.codesynthesis.com/cgit/cli/cli/tree/cli-tests +email: cli-users@codesynthesis.com ; Mailing list +build-email: builds@codesynthesis.com +requires: c++14 +depends: * build2 >= 0.13.0- +depends: * bpkg >= 0.13.0- diff --git a/cli-tests/merge/buildfile b/cli-tests/merge/buildfile new file mode 100644 index 0000000..ed93cda --- /dev/null +++ b/cli-tests/merge/buildfile @@ -0,0 +1,9 @@ +# file : merge/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -test} cli.cxx{test} + +cxx.poptions =+ "-I$out_base" + +cli.cxx{test}: cli{test} +cli.options = --generate-merge diff --git a/cli-tests/merge/driver.cxx b/cli-tests/merge/driver.cxx new file mode 100644 index 0000000..43b1c59 --- /dev/null +++ b/cli-tests/merge/driver.cxx @@ -0,0 +1,55 @@ +// file : merge/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// Test parsed options merging. +// + +#include +#include + +#include "test.hxx" + +using namespace std; + +template +static T +merge (const char* (&av1)[N1], const char* (&av2)[N2]) +{ + int ac1 (N1); + int ac2 (N2); + T o1 (ac1, const_cast (av1)); + T o2 (ac2, const_cast (av2)); + o1.merge (o2); + return o1; +} + +int +main () +{ + // Basics. + // + { + const char* a1[] = {"", "-i=123", "-v=1", "-v=2"}; + const char* a2[] = {"", "-b", "-i=456", "-s=xyz", "-v=3", "-v=4"}; + derived r (merge (a1, a2)); + + assert (r.b ()); + assert (r.i_specified () && r.i () == 456); + assert (r.s_specified () && r.s () == "xyz"); + assert (r.v_specified () && r.v ().size () == 4 && + r.v ()[0] == 1 && + r.v ()[1] == 2 && + r.v ()[2] == 3 && + r.v ()[3] == 4); + } + + // Default value does not override. + // + { + const char* a1[] = {"", "-i=456"}; + const char* a2[] = {"" }; + derived r (merge (a1, a2)); + assert (r.i_specified () && r.i () == 456); + } +} diff --git a/cli-tests/merge/test.cli b/cli-tests/merge/test.cli new file mode 100644 index 0000000..67f50c6 --- /dev/null +++ b/cli-tests/merge/test.cli @@ -0,0 +1,18 @@ +// file : merge/test.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +include ; +include ; + +class base +{ + bool -b; + int -i = -1; + std::string -s; +}; + +class derived: base +{ + std::vector -v; +}; diff --git a/cli-tests/note/buildfile b/cli-tests/note/buildfile new file mode 100644 index 0000000..c8cf49b --- /dev/null +++ b/cli-tests/note/buildfile @@ -0,0 +1,6 @@ +# file : note/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $cli + +testscript{*}: test = $cli diff --git a/cli-tests/note/testscript b/cli-tests/note/testscript new file mode 100644 index 0000000..9f00811 --- /dev/null +++ b/cli-tests/note/testscript @@ -0,0 +1,197 @@ +# file : note/testscript +# license : MIT; see accompanying LICENSE file + +: block-basics +: +cat <=test.cli; +" +Leading paragraph. + +\N|This is a note block one.| + +Interleaving paragraph that is quite long and therefore it may span many +lines in order to make text easy to read. + +\N|This is a note block two that is quite long and therefore it may span many +lines in order to make text easy to read.| + +Trailing paragraph. +" +EOI +$* --generate-html --stdout test.cli >>EOO; +

Leading paragraph.

+ +
+

This is a note block one.

+
+ +

Interleaving paragraph that is quite long and therefore it may span many + lines in order to make text easy to read.

+ +
+

This is a note block two that is quite long and therefore it may span + many lines in order to make text easy to read.

+
+ +

Trailing paragraph.

+ +EOO + $* --generate-txt --stdout test.cli >>EOO +Leading paragraph. + +| This is a note block one. + +Interleaving paragraph that is quite long and therefore it may span many lines +in order to make text easy to read. + +| This is a note block two that is quite long and therefore it may span many +| lines in order to make text easy to read. + +Trailing paragraph. +EOO + + +: block-multi-para +: +cat <=test.cli; +" +\N| +This is a note para one that is quite long and therefore it may span many +lines in order to make text easy to read. + +This is a note para two. +| +" +EOI +$* --generate-html --stdout test.cli >>EOO; +
+

This is a note para one that is quite long and therefore it may span many + lines in order to make text easy to read.

+ +

This is a note para two.

+
+ +EOO +$* --generate-txt --stdout test.cli >>EOO +| This is a note para one that is quite long and therefore it may span many +| lines in order to make text easy to read. +| +| This is a note para two. +EOO + +: block-pre +: +cat <=test.cli; +" + +\N| +This is a note para one. + +\ +And this is a +pre-formatter text fragment. +\ + +| +" +EOI +$* --generate-html --stdout test.cli >>EOO; +
+

This is a note para one.

+ +
And this is a
+pre-formatter text fragment.
+
+ +EOO +$* --generate-txt --stdout test.cli >>EOO +| This is a note para one. +| +| And this is a +| pre-formatter text fragment. +EOO + +# This is not yet supported (see txt_wrap_lines()). +# +#\ +: block-list +: +cat <=test.cli; +" +\N|This is a note para one followed by a list. + +\ul| + +\li|This is a list item that is quite long and therefore it may span many +lines in order to make text easy to read.||| +" +EOI +$* --generate-html --stdout test.cli >>EOO; +EOO +$* --generate-txt --stdout test.cli >>EOO +EOO +#\ + +: block-in-list +: +cat <=test.cli; +" +\ul| + +\li|Normal text para. + +\N|This is a note para one that is quite long and therefore it may span many +lines in order to make text easy to read.||| +" +EOI +$* --generate-html --stdout test.cli >>EOO; +
    +
  • Normal text para. + +
    +

    This is a note para one that is quite long and therefore it may span many + lines in order to make text easy to read.

    +
  • +
+ +EOO +$* --generate-txt --stdout test.cli >>EOO +* Normal text para. + + | This is a note para one that is quite long and therefore it may span many + | lines in order to make text easy to read. +EOO + + +: span-basics +: +cat <=test.cli; +" +This is normal text. \N{This is a note.} And this is normal text again. +" +EOI +$* --generate-html --stdout test.cli >>EOO; +

This is normal text. This is a note. And this + is normal text again.

+ +EOO + $* --generate-txt --stdout test.cli >>EOO +This is normal text. [Note: This is a note.] And this is normal text again. +EOO + + +: span-nested-link +: +cat <=test.cli; +" +\N{This is a note with a \l{https://example.com link} inside.} +" +EOI +$* --generate-html --stdout test.cli >>EOO; +

This is a note with a link inside.

+ +EOO +$* --generate-txt --stdout test.cli >>EOO +[Note: This is a note with a link (https://example.com) inside.] +EOO diff --git a/cli-tests/specifier/buildfile b/cli-tests/specifier/buildfile new file mode 100644 index 0000000..935a002 --- /dev/null +++ b/cli-tests/specifier/buildfile @@ -0,0 +1,10 @@ +# file : specifier/buildfile +# license : MIT; see accompanying LICENSE file + +exe{driver}: {hxx cxx}{* -test} cli.cxx{test} +exe{driver}: test.arguments = -a -c foo + +cxx.poptions =+ "-I$out_base" + +cli.cxx{test}: cli{test} +cli.options = --generate-specifier --generate-modifier diff --git a/cli-tests/specifier/driver.cxx b/cli-tests/specifier/driver.cxx new file mode 100644 index 0000000..50b9cf5 --- /dev/null +++ b/cli-tests/specifier/driver.cxx @@ -0,0 +1,29 @@ +// file : specifier/driver.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// Test specifier functions. +// + +#include +#include + +#include "test.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + options o (argc, argv); + + assert (o.a ()); + assert (o.b () == 1 && !o.b_specified ()); + assert (o.c () == "foo" && o.c_specified ()); + + o.b_specified (true); + o.c_specified (false); + + assert (o.b_specified ()); + assert (!o.c_specified ()); +} diff --git a/cli-tests/specifier/test.cli b/cli-tests/specifier/test.cli new file mode 100644 index 0000000..c11ebb7 --- /dev/null +++ b/cli-tests/specifier/test.cli @@ -0,0 +1,12 @@ +// file : specifier/test.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +include ; + +class options +{ + bool -a; + int -b = 1; + std::string -c; +}; diff --git a/cli-tests/toc/buildfile b/cli-tests/toc/buildfile new file mode 100644 index 0000000..3be6359 --- /dev/null +++ b/cli-tests/toc/buildfile @@ -0,0 +1,6 @@ +# file : toc/buildfile +# license : MIT; see accompanying LICENSE file + +./: testscript $cli + +testscript{*}: test = $cli diff --git a/cli-tests/toc/testscript b/cli-tests/toc/testscript new file mode 100644 index 0000000..70e9065 --- /dev/null +++ b/cli-tests/toc/testscript @@ -0,0 +1,155 @@ +# file : toc/testscript +# license : MIT; see accompanying LICENSE file + +: toc +: +cat <=toc.cli; +"\h1|Table of Contents|" +"\$TOC$" + +" +\h0#preface|Preface| + +This document describes something awesome. + +\h#about-document|About This Document| + +And this document is also awesome. + +\h#more-information|More Information| + +It is so awesome that no further information will be required." + +" +\H#part1|PART I| + +Start of part one. + +\h1#intro|Introduction| + +Beginning of the first chapter. + +\h#arch-flow|Architecture and Workflow| + +Some basics. + +\h#benefits|Benefits| + +You will like them. + +\h1#hello|Hello World| + +Beginning of the second chapter. + +\h#hell-setup|Setup| + +More basics. + +\h#hello-compile|Compiling| + +How to build the example + +\h2#hello-compile-gcc|Compiling with GCC| + +GCC. For Clang see \l{#hello-compile-clang Compiling with Clang}. + +\h2#hello-compile-clang|Compiling with Clang| + +Clang. For GCC see \l{#hello-compile-gcc Compiling with GCC}. + +\h#hello-conclusion|Conclusion| + +Some remarks. +" +EOI +$* --generate-html --stdout toc.cli >>EOO +

Table of Contents

+ + + + + + +
Preface + + + +
About +This Document
More +Information
+
PART I
1Introduction + + + +
1.1Architecture and +Workflow
1.2Benefits
+
2Hello World + + + + +
2.1Setup
2.2Compiling + + + +
2.2.1Compiling with +GCC
2.2.2Compiling +with Clang
+
2.3Conclusion
+
+ +

Preface

+ +

This document describes something awesome.

+ +

About This Document

+ +

And this document is also awesome.

+ +

More Information

+ +

It is so awesome that no further information will be required.

+ +

PART I

+ +

Start of part one.

+ +

1 Introduction

+ +

Beginning of the first chapter.

+ +

1.1 Architecture and Workflow

+ +

Some basics.

+ +

1.2 Benefits

+ +

You will like them.

+ +

2 Hello World

+ +

Beginning of the second chapter.

+ +

2.1 Setup

+ +

More basics.

+ +

2.2 Compiling

+ +

How to build the example

+ +

2.2.1 Compiling with GCC

+ +

GCC. For Clang see Compiling with + Clang.

+ +

2.2.2 Compiling with Clang

+ +

Clang. For GCC see Compiling with + GCC.

+ +

2.3 Conclusion

+ +

Some remarks.

+ +EOO diff --git a/cli/.gitignore b/cli/.gitignore index bb4f521..cece09c 100644 --- a/cli/.gitignore +++ b/cli/.gitignore @@ -1,2 +1,19 @@ -cli -version.hxx +# Compiler/linker output. +# +*.d +*.t +*.i +*.ii +*.o +*.obj +*.so +*.dll +*.a +*.lib +*.exp +*.pdb +*.ilk +*.exe +*.exe.dlls/ +*.exe.manifest +*.pc diff --git a/cli/INSTALL b/cli/INSTALL new file mode 100644 index 0000000..abb0f51 --- /dev/null +++ b/cli/INSTALL @@ -0,0 +1,6 @@ +The easiest way to build this package is with the bpkg package manager: + +$ bpkg build cli + +But if you don't want to use the package manager, then you can also build it +manually using the standard build2 build system. diff --git a/cli/LICENSE b/cli/LICENSE new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/cli/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/cli/NEWS b/cli/NEWS new file mode 100644 index 0000000..a1fe25e --- /dev/null +++ b/cli/NEWS @@ -0,0 +1,73 @@ +Version 1.2.0 + + * New option, --generate-merge, triggers the generation of the merge() + function which can be used to merge several already parsed options class + instances, for example, to implement option appending/overriding. + + * New option, --generate-specifier, triggers the generation of functions + for determining whether the option was specified on the command line. + + * New option, --suppress-undocumented, suppresses the generation of + documentation entries for undocumented options. + + * New option, --cli-namespace, allows changing of the namespace for the + generated CLI support types. + + * The argv_file_scanner now supports double and single-quoting option + values in option files. This is useful to preserve leading and trailing + whitespaces as well as to specify empty values. + + * The argv_file_scanner now supports multiple file options as well as + file search callbacks. + +Version 1.1.0 + + * Support for option documentation. Option documentation is used to print + the usage information as well as to generate the program documentation in + the HTML and man page formats. For details, see Sections 2.5, "Adding + Documentation" and 3.3, "Option Documentation" in the Getting Started + Guide. New CLI compiler command line options related to this feature: + + --suppress-usage + --long-usage + --option-length + --generate-cxx + --generate-man + --generate-html + --man-prologue + --man-epilogue + --html-prologue + --html-epilogue + --man-suffix + --html-suffix + --class + --stdout + + The CLI compiler usage, HTML documentation, and man page are auto-generated + using this feature. + + * New option, --generate-modifier, triggers the generation of the option + value modifiers in addition to the accessors. + + * Support for erasing the parsed elements from the argc/argv array. See + Section 3.1, "Option Class Definition" in the Getting Started Guide for + more information. + + * New scanner interface. Starting with this version, the option class has + a new constructor which accepts an abstract scanner interface. See Section + 3.1, "Option Class Definition" in the Getting Started Guide for more + information. + + * New option, --generate-file-scanner, triggers the generation of the + argv_file_scanner scanner implementation which provides support for + reading command line arguments from the argv array as well as files + specified with command line options. For more information see Section + 3.1, "Option Class Definition" in the Getting Started Guide as well as + the 'file' example. + + * New option, --options-file, allows additional CLI command line options + to be provided in files (implemented using argv_file_scanner). + +Version 1.0.0 + + * First public release. diff --git a/cli/README b/cli/README new file mode 100644 index 0000000..d2c6a02 --- /dev/null +++ b/cli/README @@ -0,0 +1,15 @@ +CLI is a Command Line Interface definition language for C++. This package +contains the compiler implementation for this language. + +See the NEWS file for the user-visible changes from the previous release. + +See the LICENSE file for distribution conditions. + +See the INSTALL file for prerequisites and installation instructions. + +See the doc/ directory for documentation. + +The project page is at http://codesynthesis.com/projects/cli/. + +Send questions, bug reports, or any other feedback to +cli-users@codesynthesis.com. diff --git a/cli/build/.gitignore b/cli/build/.gitignore new file mode 100644 index 0000000..e931f20 --- /dev/null +++ b/cli/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ \ No newline at end of file diff --git a/cli/build/bootstrap.build b/cli/build/bootstrap.build new file mode 100644 index 0000000..1e5c8a4 --- /dev/null +++ b/cli/build/bootstrap.build @@ -0,0 +1,10 @@ +# file : build/bootstrap.build +# license : MIT; see accompanying LICENSE file + +project = cli + +using version +using config +using dist +using test +using install diff --git a/cli/build/export.build b/cli/build/export.build new file mode 100644 index 0000000..92c546c --- /dev/null +++ b/cli/build/export.build @@ -0,0 +1,9 @@ +# file : build/export.build +# license : MIT; see accompanying LICENSE file + +$out_root/ +{ + include cli/ +} + +export $out_root/cli/exe{cli} diff --git a/cli/build/root.build b/cli/build/root.build new file mode 100644 index 0000000..c611c4f --- /dev/null +++ b/cli/build/root.build @@ -0,0 +1,60 @@ +# file : build/root.build +# license : MIT; see accompanying LICENSE file + +# Regenerate the options parsing code (included into the repository). +# +# Note that this is the same variable as what's used by the import machinery +# when we import cli%exe{cli}. Here, however, we require it to be explicitly +# specified (i.e., no default search in PATH) in order for the regeneration +# to be enabled. +# +# Normally, in the development build, this variable will be set only in the +# cli package configuration to point to its own binary (or a binary in another +# build configuration if you want to play it safe). +# +# Note, though, that currently referring to the cli target in the project +# itself ends up with the 'dependency cycle detected' error. In the future we +# will fix that by using an ad hoc recipe instead of the cli module. But for +# now you can workaround this issue by pointing to a binary in another +# configuration. +# +config [path] config.cli + +cxx.std = latest + +using cxx + +hxx{*}: extension = hxx +ixx{*}: extension = ixx +txx{*}: extension = txx +cxx{*}: extension = cxx + +if ($cxx.target.system == 'win32-msvc') + cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + +if ($cxx.class == 'msvc') + cxx.coptions += /wd4251 /wd4275 /wd4800 + +cxx.poptions =+ "-I$out_root" "-I$src_root" + +# Load the cli module only if explicitly requested. This way a distribution +# that includes pre-generated files can be built without installing cli. This +# is also the reason why we need to explicitly spell out individual source +# file prerequisites instead of using the cli.cxx{} group (it won't be there +# unless the module is configured). +# +# @@ Replace with import when the parsing code regenerating is implemented +# via an ad hoc recipe. +# +if ($config.cli != [null] && $config.cli != false) + using cli + +# All exe{} in unit-tests/ are, well, tests. Also don't link whole archives +# by default there. +# +unit-tests/exe{*}: test = true +unit-tests/{libue libul}{*}: bin.whole = false + +# Specify the test target for cross-testing. +# +test.target = $cxx.target diff --git a/cli/buildfile b/cli/buildfile index d6723d0..832328a 100644 --- a/cli/buildfile +++ b/cli/buildfile @@ -1,54 +1,9 @@ -# file : cli/buildfile +# file : buildfile # license : MIT; see accompanying LICENSE file -import libs = libcutl%lib{cutl} +./: {*/ -build/} doc{INSTALL LICENSE NEWS README} manifest -exe{cli}: cxx{cli} libue{cli} -{ - # Target metadata, see also --build2-metadata in cli.cxx. - # - cli.version = $version.project_id - cli.checksum = $version -} - -libue{cli}: {hxx ixx txx cxx}{** -cli -version -options} \ - {hxx}{version} {hxx ixx cxx}{options} \ - $libs - -hxx{version}: in{version} $src_root/manifest - -# Build options. -# -# Pass the copyright notice extracted from the LICENSE file. -# -copyright = $process.run_regex(cat $src_root/LICENSE, \ - 'Copyright \(c\) (.+)\.', \ - '\1') - -obj{cli}: cxx.poptions += -DCLI_COPYRIGHT=\"$copyright\" - -# Generated options parser. +# Don't install unit tests or the INSTALL file. # -if $cli.configured -{ - cli.cxx{options}: cli{options} - - cli.options += --include-with-brackets --include-prefix cli \ ---guard-prefix CLI --generate-file-scanner --generate-specifier \ ---generate-modifier --reserved-name stdout - - cli.cxx{*}: - { - # Include the generated cli files into the distribution and don't remove - # them when cleaning in src (so that clean results in a state identical to - # distributed). - # - dist = true - clean = ($src_root != $out_root) - - # We keep the generated code in the repository so copy it back to src - # in case of a forwarded configuration. - # - backlink = overwrite - } -} +unit-tests/: install = false +doc{INSTALL}@./: install = false diff --git a/cli/cli.cxx b/cli/cli.cxx deleted file mode 100644 index c57caee..0000000 --- a/cli/cli.cxx +++ /dev/null @@ -1,165 +0,0 @@ -// file : cli/cli.cxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#include -#include -#include // unique_ptr -#include -#include - -#include - -#include - -#include -#include -#include - -#include - -using namespace std; -using namespace cutl; - -int -main (int argc, char* argv[]) -{ - ostream& e (cerr); - const char* file (0); - - try - { - cli::argv_file_scanner scan (argc, argv, "--options-file"); - options ops (scan); - - // Handle --build2-metadata (see also buildfile). - // - if (ops.build2_metadata ()) - { - ostream& o (cout); - - o << "# build2 buildfile cli" << endl - << "cli.version = '" << CLI_VERSION_ID << '\'' << endl - << "cli.checksum = '" << CLI_CHECKSUM << '\'' << endl; - - return 0; - } - - // Handle --version - // - if (ops.version ()) - { - ostream& o (cout); - - o << "CLI (command line interface compiler) " << CLI_VERSION_ID << endl - << "Copyright (c) " << CLI_COPYRIGHT << "." << endl; - - o << "This is free software; see the source for copying conditions. " - << "There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS " - << "FOR A PARTICULAR PURPOSE." << endl; - - return 0; - } - - // Handle --help - // - if (ops.help ()) - { - ostream& o (cout); - - o << "Usage: " << argv[0] << " [options] file" << endl - << "Options:" << endl; - - options::print_usage (o); - - return 0; - } - - if (!scan.more ()) - { - e << "error: no input file specified" << endl - << "info: try '" << argv[0] << " --help' for more information" << endl; - - return 1; - } - - // Extract include search paths. - // - parser::paths include_paths; - for (vector::const_iterator i (ops.include_path ().begin ()); - i != ops.include_path ().end (); ++i) - { - // Invalid path exception is handled below. - // - include_paths.push_back (semantics::path (*i)); - } - - // Open the input file. - // - file = scan.next (); - semantics::path path (file); - - ifstream ifs (path.string ().c_str ()); - if (!ifs.is_open ()) - { - e << path << ": error: unable to open in read mode" << endl; - return 1; - } - - ifs.exceptions (ifstream::failbit | ifstream::badbit); - - // Parse and generate. - // - parser p (include_paths); - unique_ptr unit (p.parse (ifs, path)); - - // Merge documentation variables from the command line. - // - for (map::const_iterator i (ops.docvar ().begin ()); - i != ops.docvar ().end (); - ++i) - { - using semantics::doc; - - // Values specified in the .cli file override command line. - // - if (unit->lookup ("", "var: " + i->first) != 0) - continue; - - doc& d (unit->new_node (semantics::path (""), 0, 0)); - unit->new_edge (*unit, d, "var: " + i->first); - d.push_back (i->second); - } - - generator g; - g.generate (ops, *unit, path); - } - catch (cli::exception const& ex) - { - e << ex << endl; - return 1; - } - catch (semantics::invalid_path const& ex) - { - e << "error: '" << ex.path () << "' is not a valid filesystem path" - << endl; - return 1; - } - catch (std::ios_base::failure const&) - { - e << file << ": error: read failure" << endl; - return 1; - } - catch (parser::invalid_input const&) - { - // Diagnostics has already been issued by the parser. - // - return 1; - } - catch (generator::failed const&) - { - // Diagnostics has already been issued by the generator. - // - return 1; - } -} diff --git a/cli/cli/.gitignore b/cli/cli/.gitignore new file mode 100644 index 0000000..903d015 --- /dev/null +++ b/cli/cli/.gitignore @@ -0,0 +1,7 @@ +cli +version.hxx + +# Unit test executables and Testscript output directories (can be symlinks). +# +*.test +test-*.test diff --git a/cli/cli/buildfile b/cli/cli/buildfile new file mode 100644 index 0000000..ff562c2 --- /dev/null +++ b/cli/cli/buildfile @@ -0,0 +1,75 @@ +# file : cli/buildfile +# license : MIT; see accompanying LICENSE file + +import libs = libcutl%lib{cutl} + +./: exe{cli}: cxx{cli} libue{cli} + +# Target metadata, see also --build2-metadata in cli.cxx. +# +exe{cli}: +{ + cli.version = $version.project_id + cli.checksum = $version +} + +libue{cli}: {hxx ixx txx cxx}{** -cli -version -options -**.test...} \ + {hxx}{version} {hxx ixx cxx}{options} \ + $libs + +hxx{version}: in{version} $src_root/manifest + +# Unit tests. +# +exe{*.test}: +{ + test = true + install = false +} + +for t: cxx{**.test...} +{ + d = $directory($t) + n = $name($t)... + + ./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n} + $d/exe{$n}: libue{cli}: bin.whole = false +} + +# Build options. +# +# Pass the copyright notice extracted from the LICENSE file. +# +copyright = $process.run_regex(cat $src_root/LICENSE, \ + 'Copyright \(c\) (.+)\.', \ + '\1') + +obj{cli}: cxx.poptions += -DCLI_COPYRIGHT=\"$copyright\" + +# Generated options parsing code. +# +# @@ This will eventually be replaced with an ah hoc recipe. +# +if ($config.cli != [null] && $config.cli != false) +{ + cli.cxx{options}: cli{options} + + cli.options += --include-with-brackets --include-prefix cli \ +--guard-prefix CLI --generate-file-scanner --generate-specifier \ +--generate-modifier --reserved-name stdout + + cli.cxx{*}: + { + # Include the generated cli files into the distribution and don't remove + # them when cleaning in src (so that clean results in a state identical to + # distributed). + # + dist = true + clean = ($src_root != $out_root) + + # We keep the generated code in the repository so copy it back to src + # in case of a forwarded configuration. + # + backlink = overwrite + } +} diff --git a/cli/cli/cli.cxx b/cli/cli/cli.cxx new file mode 100644 index 0000000..c57caee --- /dev/null +++ b/cli/cli/cli.cxx @@ -0,0 +1,165 @@ +// file : cli/cli.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include +#include +#include // unique_ptr +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +using namespace std; +using namespace cutl; + +int +main (int argc, char* argv[]) +{ + ostream& e (cerr); + const char* file (0); + + try + { + cli::argv_file_scanner scan (argc, argv, "--options-file"); + options ops (scan); + + // Handle --build2-metadata (see also buildfile). + // + if (ops.build2_metadata ()) + { + ostream& o (cout); + + o << "# build2 buildfile cli" << endl + << "cli.version = '" << CLI_VERSION_ID << '\'' << endl + << "cli.checksum = '" << CLI_CHECKSUM << '\'' << endl; + + return 0; + } + + // Handle --version + // + if (ops.version ()) + { + ostream& o (cout); + + o << "CLI (command line interface compiler) " << CLI_VERSION_ID << endl + << "Copyright (c) " << CLI_COPYRIGHT << "." << endl; + + o << "This is free software; see the source for copying conditions. " + << "There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS " + << "FOR A PARTICULAR PURPOSE." << endl; + + return 0; + } + + // Handle --help + // + if (ops.help ()) + { + ostream& o (cout); + + o << "Usage: " << argv[0] << " [options] file" << endl + << "Options:" << endl; + + options::print_usage (o); + + return 0; + } + + if (!scan.more ()) + { + e << "error: no input file specified" << endl + << "info: try '" << argv[0] << " --help' for more information" << endl; + + return 1; + } + + // Extract include search paths. + // + parser::paths include_paths; + for (vector::const_iterator i (ops.include_path ().begin ()); + i != ops.include_path ().end (); ++i) + { + // Invalid path exception is handled below. + // + include_paths.push_back (semantics::path (*i)); + } + + // Open the input file. + // + file = scan.next (); + semantics::path path (file); + + ifstream ifs (path.string ().c_str ()); + if (!ifs.is_open ()) + { + e << path << ": error: unable to open in read mode" << endl; + return 1; + } + + ifs.exceptions (ifstream::failbit | ifstream::badbit); + + // Parse and generate. + // + parser p (include_paths); + unique_ptr unit (p.parse (ifs, path)); + + // Merge documentation variables from the command line. + // + for (map::const_iterator i (ops.docvar ().begin ()); + i != ops.docvar ().end (); + ++i) + { + using semantics::doc; + + // Values specified in the .cli file override command line. + // + if (unit->lookup ("", "var: " + i->first) != 0) + continue; + + doc& d (unit->new_node (semantics::path (""), 0, 0)); + unit->new_edge (*unit, d, "var: " + i->first); + d.push_back (i->second); + } + + generator g; + g.generate (ops, *unit, path); + } + catch (cli::exception const& ex) + { + e << ex << endl; + return 1; + } + catch (semantics::invalid_path const& ex) + { + e << "error: '" << ex.path () << "' is not a valid filesystem path" + << endl; + return 1; + } + catch (std::ios_base::failure const&) + { + e << file << ": error: read failure" << endl; + return 1; + } + catch (parser::invalid_input const&) + { + // Diagnostics has already been issued by the parser. + // + return 1; + } + catch (generator::failed const&) + { + // Diagnostics has already been issued by the generator. + // + return 1; + } +} diff --git a/cli/cli/context.cxx b/cli/cli/context.cxx new file mode 100644 index 0000000..54bb988 --- /dev/null +++ b/cli/cli/context.cxx @@ -0,0 +1,2742 @@ +// file : cli/context.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include +#include +#include // strncmp() +#include +#include +#include + +#include + +using namespace std; + +namespace +{ + char const* keywords[] = + { + "NULL", + "and", + "asm", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "class", + "compl", + "const", + "const_cast", + "continue", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "end_eq", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "not", + "not_eq", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "return", + "short", + "signed", + "sizeof", + "static", + "static_cast", + "struct", + "switch", + "template", + "this", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq" + }; +} + +context:: +context (ostream& os_, + output_type ot_, + semantics::cli_unit& unit_, + options_type const& ops) + : data_ (new (shared) data), + os (os_), + unit (unit_), + options (ops), + ot (ot_), + gen_modifier (options.generate_modifier ()), + gen_specifier (options.generate_specifier () || + options.generate_merge ()), + gen_parse (options.generate_parse ()), + gen_merge (options.generate_merge ()), + inl (data_->inl_), + opt_prefix (options.option_prefix ()), + opt_sep (options.option_separator ()), + cli (data_->cli_), + reserved_name_map (options.reserved_name ()), + keyword_set (data_->keyword_set_), + link_regex (data_->link_regex_), + id_set (data_->id_set_), + ref_set (data_->ref_set_), + heading_map (data_->heading_map_), + toc (data_->toc_), + tocs (data_->tocs_) +{ + if (options.suppress_usage ()) + gen_usage = ut_none; + else + { + if (options.long_usage ()) + gen_usage = options.short_usage () ? ut_both : ut_long; + else + gen_usage = ut_short; + } + + if (!options.suppress_inline ()) + data_->inl_ = "inline "; + + data_->cli_ = options.cli_namespace (); + + if (!cli.empty () && cli[0] != ':') + data_->cli_ = "::" + data_->cli_; + + for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i) + data_->keyword_set_.insert (keywords[i]); + + // Link regex. + // + for (vector::const_iterator i (ops.link_regex ().begin ()); + i != ops.link_regex ().end (); ++i) + { + try + { + data_->link_regex_.push_back (regexsub (*i)); + } + catch (const regex_format& e) + { + cerr << "error: invalid regex '" << *i << "': " << e.what () << endl; + throw generation_failed (); + } + } + + toc = 0; +} + +context:: +context (context& c) + : data_ (c.data_), + os (c.os), + unit (c.unit), + options (c.options), + ot (c.ot), + gen_modifier (c.gen_modifier), + gen_specifier (c.gen_specifier), + gen_parse (c.gen_parse), + gen_merge (c.gen_merge), + gen_usage (c.gen_usage), + inl (c.inl), + opt_prefix (c.opt_prefix), + opt_sep (c.opt_sep), + cli (c.cli), + reserved_name_map (c.reserved_name_map), + keyword_set (c.keyword_set), + link_regex (c.link_regex), + id_set (c.id_set), + ref_set (c.ref_set), + heading_map (c.heading_map), + toc (c.toc), + tocs (c.tocs) +{ +} + +string context:: +escape (string const& name) const +{ + typedef string::size_type size; + + string r; + size n (name.size ()); + + // In most common cases we will have that many characters. + // + r.reserve (n); + + for (size i (0); i < n; ++i) + { + char c (name[i]); + + if (i == 0) + { + if (!((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c == '_')) + r = (c >= '0' && c <= '9') ? "cxx_" : "cxx"; + } + + if (!((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_')) + r += '_'; + else + r += c; + } + + if (r.empty ()) + r = "cxx"; + + // Custom reserved words. + // + reserved_name_map_type::const_iterator i (reserved_name_map.find (r)); + + if (i != reserved_name_map.end ()) + { + if (!i->second.empty ()) + return i->second; + else + r += L'_'; + } + + // Keywords + // + if (keyword_set.find (r) != keyword_set.end ()) + { + r += '_'; + + // Re-run custom words. + // + i = reserved_name_map.find (r); + + if (i != reserved_name_map.end ()) + { + if (!i->second.empty ()) + return i->second; + else + r += L'_'; + } + } + + return r; +} + +string context:: +process_link_target (const string& tg) +{ + bool t (options.link_regex_trace ()); + + if (t) + cerr << "link: '" << tg << "'" << endl; + + string r; + bool found (false); + + for (regex_mapping::const_iterator i (link_regex.begin ()); + i != link_regex.end (); ++i) + { + if (t) + cerr << "try: '" << i->regex () << "' : "; + + if (i->match (tg)) + { + r = i->replace (tg); + found = true; + + if (t) + cerr << "'" << r << "' : "; + } + + if (t) + cerr << (found ? '+' : '-') << endl; + + if (found) + break; + } + + return found ? r : tg; +} + + +string context:: +translate_arg (string const& s, std::set& set) +{ + string r; + r.reserve (s.size ()); + set.clear (); + + size_t p (string::npos); + + for (size_t i (0), n (s.size ()); i < n; ++i) + { + if (p == string::npos && s[i] == '<') + { + p = i; + r += "\\ci{"; + continue; + } + + if (p != string::npos && s[i] == '>') + { + set.insert (string (s, p + 1, i - p - 1)); + r += '}'; + p = string::npos; + continue; + } + + if (p != string::npos && s[i] == '}' && s[i - 1] != '\\') + { + r += "\\}"; + continue; + } + + r += s[i]; + } + + return r; +} + +string context:: +translate (string const& s, std::set const& set) +{ + string r; + r.reserve (s.size ()); + + bool pre (false); + size_t p (string::npos); + + for (size_t i (0), n (s.size ()); i < n; ++i) + { + char c (s[i]); + + // Skip pre-formatted fragments. + // + if (c == (pre ? 0x03 : 0x02)) + { + pre = !pre; + + if (p != string::npos) + { + assert (pre); + r.append (s, p, i - p); + p = string::npos; + } + } + else if (!pre) + { + if (p == string::npos && c == '<') + { + p = i; + continue; + } + + if (p != string::npos) + { + if (c == '>') + { + string a (s, p + 1, i - p - 1); + + if (set.find (a) != set.end ()) + { + r += "\\ci{"; + + for (size_t j (0), n (a.size ()); j < n; ++j) + { + if (a[j] == '}' && (j == 0 || a[j - 1] != '\\')) + r += "\\}"; + else + r += a[j]; + } + + r += '}'; + } + else + { + r += '<'; + r += a; + r += '>'; + } + p = string::npos; + } + continue; + } + } + + r += c; + } + + // If we found the opening '<' but no closing '>', add the rest. + // + if (p != string::npos) + r.append (s, p, string::npos); + + return r; +} + +void context:: +format_line (output_type ot, string& r, const char* l, size_t n) +{ + bool color (options.ansi_color ()); + + typedef unsigned char span; // Mask. + + const span code = 1; + const span itlc = 2; + const span bold = 4; + const span link = 8; + const span note = 16; + + vector spans; + + string link_target; + string link_section; // If not empty, man section; target is man name. + bool link_empty (false); // Link has no text. + + bool escape (false); + for (size_t i (0); i < n; ++i) + { + char c (l[i]); + + if (escape) + { + bool new_span (false); + + switch (c) + { + case ' ': + { + // Non-ignorable space. + // + switch (ot) + { + case ot_plain: + { + r += ' '; + break; + } + case ot_html: + { + r += " "; + break; + } + case ot_man: + { + r += "\\ "; + break; + } + } + + break; + } + case '-': + { + // N-dash. If someone wants m-dash, can use \-- with \-{}- as + // a way to "escape" an n-dash followed by hyphen. + // + switch (ot) + { + case ot_plain: + { + r += "--"; + break; + } + case ot_html: + { + r += "–"; + break; + } + case ot_man: + { + r += "\\(en"; + break; + } + } + + break; + } + case 'n': + { + switch (ot) + { + case ot_plain: + { + r += '\n'; + break; + } + case ot_html: + { + if (!r.empty () && r[r.size () - 1] != '\n') + r += '\n'; + + r += "
"; + break; + } + case ot_man: + { + if (!r.empty () && r[r.size () - 1] != '\n') + r += '\n'; + + // Note that if we have several consecutive breaks, they + // will be collapsed into a single one. No, .sp doesn't + // work (or, more exactly, will only work for two breaks). + // + r += ".br"; + break; + } + } + + // Skip following spaces. + // + for (; i + 1 < n && l[i + 1] == ' '; ++i) ; + + switch (ot) + { + case ot_plain: break; + case ot_html: + case ot_man: + { + if (i + 1 < n) // More text in this paragraph? + r += "\n"; + + break; + } + } + + break; + } + case 'c': + { + span s (code); + size_t j (i + 1); + + if (j < n) + { + if (l[j] == 'i') + { + s |= itlc; + j++; + + if (j < n && l[j] == 'b') + { + s |= bold; + j++; + } + } + else if (l[j] == 'b') + { + s |= bold; + j++; + + if (j < n && l[j] == 'i') + { + s |= itlc; + j++; + } + } + } + + if (j < n && l[j] == '{') + { + i = j; + spans.push_back (s); + new_span = true; + break; + } + + r += 'c'; + break; + } + case 'i': + { + span s (itlc); + size_t j (i + 1); + + if (j < n) + { + if (l[j] == 'c') + { + s |= code; + j++; + + if (j < n && l[j] == 'b') + { + s |= bold; + j++; + } + } + else if (l[j] == 'b') + { + s |= bold; + j++; + + if (j < n && l[j] == 'c') + { + s |= code; + j++; + } + } + } + + if (j < n && l[j] == '{') + { + i = j; + spans.push_back (s); + new_span = true; + break; + } + + r += 'i'; + break; + } + case 'b': + { + span s (bold); + size_t j (i + 1); + + if (j < n) + { + if (l[j] == 'c') + { + s |= code; + j++; + + if (j < n && l[j] == 'i') + { + s |= itlc; + j++; + } + } + else if (l[j] == 'i') + { + s |= itlc; + j++; + + if (j < n && l[j] == 'c') + { + s |= code; + j++; + } + } + } + + if (j < n && l[j] == '{') + { + i = j; + spans.push_back (s); + new_span = true; + break; + } + + r += 'b'; + break; + } + case 'l': + { + if (i + 1 < n && l[i + 1] == '{') + { + string& t (link_target); + + if (!t.empty ()) + { + cerr << "error: nested links in documentation paragraph '" + << string (l, 0, n) << "'" << endl; + throw generation_failed (); + } + + // Find the end of the link target. + // + size_t b (++i + 1), e (b); + for (; i + 1 < n; ++i) + { + char c (l[i + 1]); + + if (c == ' ' || c == '}') + { + e = i + 1; + + if (c == ' ') // Skip spaces. + for (++i; i + 1 < n && l[i + 1] == ' '; ++i) ; + + break; + } + } + + // Run the link target through format_line(ot_plain) to handle + // escaping (e.g., \\$). + // + format_line (ot_plain, t, l + b, e - b); + + if (t.empty ()) + { + cerr << "error: missing link target in documentation paragraph '" + << string (l, 0, n) << "'" << endl; + throw generation_failed (); + } + + // See if link_target is a man page name/section. + // + size_t o (t.find ('(')); + + if (o != string::npos) + { + link_section.assign (t, o + 1, t.size () - o - 2); + + if (t[t.size () - 1] != ')' || link_section.empty ()) + { + cerr << "error: missing man section in '" << t << "'" << endl; + throw generation_failed (); + } + + string n (t, 0, o); + + if (n.empty ()) + { + cerr << "error: missing man page in '" << t << "'" << endl; + throw generation_failed (); + } + + t = n; + } + else + link_section.clear (); + + // If this is a local fragment reference, add it to the set to be + // verified at the end. + // + if (t[0] == '#') + { + assert (link_section.empty ()); // Not a man page. + ref_set.insert (string (t, 1, string::npos)); + } + + link_empty = i + 1 < n && l[i + 1] == '}'; + + spans.push_back (link); + new_span = true; + break; + } + + r += 'l'; + break; + } + case 'N': + { + if (i + 1 < n && l[i + 1] == '{') + { + ++i; + spans.push_back (note); + new_span = true; + break; + } + + r += 'N'; + break; + } + case '\\': + { + switch (ot) + { + case ot_man: + { + r += "\\e"; + break; + } + default: + { + r += '\\'; + break; + } + } + break; + } + case '"': + { + r += '"'; + break; + } + case '\'': + { + r += '\''; + break; + } + case '}': + { + r += '}'; + break; + } + case '|': + { + r += '|'; + break; + } + default: + { + cerr << "error: unknown escape sequence '\\" << c << "' in " + << "documentation paragraph '" << string (l, 0, n) << "'" + << endl; + throw generation_failed (); + } + } + + // If we just added a new span, add corresponding output markup. + // + if (new_span) + { + span s (spans.back ()); + + span es (0); // Effective span. + for (vector::iterator i (spans.begin ()); + i != spans.end (); + ++i) + es |= *i & (code | itlc | bold); + + switch (ot) + { + case ot_plain: + { + if ((s & note) != 0) + { + r += "[Note: "; + } + else if ((s & link) == 0) + { + if (color) + { + if (s & bold) + r += "\033[1m"; + + if (s & itlc) + r += "\033[4m"; + } + } + + break; + } + case ot_html: + { + if (s & note) + { + r += ""; + } + else if (s & link) + { + r += ""; + } + else + { + if (s & code) + r += ""; + + if (s & itlc) + r += ""; + + if (s & bold) + r += ""; + } + + break; + } + case ot_man: + { + if ((s & note) != 0) + { + cerr << "error: \\N{} in man output not yet supported" << endl; + throw generation_failed (); + } + + if ((s & link) == 0) + { + if ((es & itlc) && (es & bold)) + r += "\\f(BI"; + else if (es & itlc) + r += "\\fI"; + else if (es & bold) + r += "\\fB"; + } + + break; + } + } + } + + escape = false; + } + else // Not escape. + { + switch (c) + { + case '\\': + { + escape = true; + break; + } + case '.': + { + if (ot == ot_man) + r += "\\."; + else + r += '.'; + break; + } + case '}': + { + if (!spans.empty ()) + { + span s (spans.back ()); + spans.pop_back (); + + span es (0); // New effective span. + for (vector::iterator i (spans.begin ()); + i != spans.end (); + ++i) + es |= *i & (code | itlc | bold); + + switch (ot) + { + case ot_plain: + { + if ((s & note) != 0) + { + r += ']'; + } + else if ((s & link) != 0) + { + string t (link_section.empty () + ? link_target + : link_target + "(" + link_section + ")"); + + string pt (process_link_target (t)); + + if (pt.empty ()) + { + if (link_empty) + { + cerr << "error: link target '" << t << "' became empty " + << "and link text is also empty" << endl; + throw generation_failed (); + } + } + else + { + if (!link_empty) + r += " ("; + + if (link_section.empty ()) + r += pt; + else + { + if (color) + r += "\033[1m"; + + r += pt; + + if (color) + r += "\033[0m"; + } + + if (!link_empty) + r += ")"; + } + } + else + { + if (color) + { + // While there are codes to turn off bold (22) and + // underline (24), it is not clear how widely they + // are supported. + // + r += "\033[0m"; // Clear all. + + if (es & bold) + r += "\033[1m"; + + if (es & itlc) + r += "\033[4m"; + } + } + + break; + } + case ot_html: + { + if ((s & note) != 0) + { + r += ""; + } + else if ((s & link) != 0) + { + if (link_empty) + { + if (link_section.empty ()) + r += link_target; + else + { + r += ""; + r += link_target + "(" + link_section + ")"; + r += ""; + } + } + + r += ""; + } + else + { + if (s & bold) + r += ""; + + if (s & itlc) + r += ""; + + if (s & code) + r += ""; + } + + break; + } + case ot_man: + { + assert ((s & note) == 0); + + if ((s & link) != 0) + { + string t (link_section.empty () + ? link_target + : link_target + "(" + link_section + ")"); + + string pt (process_link_target (t)); + + if (pt.empty ()) + { + if (link_empty) + { + cerr << "error: link target '" << t << "' became empty " + << "and link text is also empty" << endl; + throw generation_failed (); + } + } + else + { + if (!link_empty) + r += " ("; + + if (link_section.empty ()) + r += pt; + else + r += "\\fB" + pt + "\\fP"; + + if (!link_empty) + r += ")"; + } + } + else + { + // At first sight, \fP (select previous font) looks like + // exactly what we need here. However, it doesn't quite + // have the stack semantics that we need. + // + if ((es & itlc) && (es & bold)) + r += "\\f(BI"; + else if (es & itlc) + r += "\\fI"; + else if (es & bold) + r += "\\fB"; + else + r += "\\fR"; + } + + break; + } + } + + if (s & link) + link_target.clear (); + + break; + } + } + // Fall through. + default: + r += c; + break; + } + } + } + + if (escape) + { + cerr << "error: unterminated escape sequence in documentation " + << "paragraph '" << string (l, 0, n) << "'" << endl; + throw generation_failed (); + } + + if (!spans.empty ()) + { + unsigned char b (spans.back ()); + string bs; + + if (b & code) bs += 'c'; + if (b & itlc) bs += 'i'; + if (b & bold) bs += 'b'; + if (b & link) bs = 'l'; + if (b & note) bs = 'N'; + + + cerr << "error: unterminated formatting span '\\" << bs << "' " + << "in documentation paragraph '" << string (l, 0, n) << "'" << endl; + throw generation_failed (); + } +} + +struct block +{ + // The semantic meaning of \hN and their mapping to HTML is as follows: + // + // \h0 - preface

+ // \H - part

+ // \h1 - chapter

+ // \h - section

or

+ // \h2 - sub-section

+ // + // In HTML, if \h0 or \h1 was seen, then \h is automatically mappend to + //

. Otherwise it is

. + // + // The specifier (0, H, 1, h, 2) is stored in header. + // + enum kind_type {h, ul, ol, dl, li, note, text, pre}; + + kind_type kind; + bool para; // True if first text fragment should be in own paragraph. + + string id; + string header; + string value; + string trailer; + + block (kind_type k, bool p, const string& i, const string& h = "") + : kind (k), para (p), id (i), header (h) {} +}; + +static const char* block_kind_str[] = { + "\\h", "\\ul", "\\ol", "\\dl", "\\li", "\\N", "text", "preformatted text"}; + +inline ostream& +operator<< (ostream& os, block::kind_type k) +{ + return os << block_kind_str[k]; +} + +// Given the contents of a block element, convert any leading/trailing
+// elements to top/bottom margins. While conceptually it would seem better to +// translate them to padding, margins actually give better practical results +// since they overlap with container's margins. +// +static string +html_margin (string& v) +{ + size_t top (0), bot (0); + + const char* b (v.c_str ()); + const char* e (v.c_str () + v.size ()); + + for (; e - b >= 5 && strncmp (b, "
", 5) == 0; ++top) + { + b += 5; + + if (b != e && *b == '\n') // Remove following newline, if any. + ++b; + } + + for (; e - b >= 5 && strncmp (e - 5, "
", 5) == 0; ++bot) + { + e -= 5; + + if (e != b && *(e - 1) == '\n') // Remove preceding newline, if any. + --e; + } + + if (top == 0 && bot == 0) + return ""; + + string t; + t.swap (v); + v.assign (b, e - b); + + ostringstream os; + + if (top != 0) + os << "margin-top:" << top << "em"; + + if (bot != 0) + os << (top != 0 ? ";" : "") << "margin-bottom:" << bot << "em"; + + return os.str (); +} + +// The same idea except there are no margins. So we just strip .br. +// +static void +man_margin (string& v) +{ + size_t top (0), bot (0); + + const char* b (v.c_str ()); + const char* e (v.c_str () + v.size ()); + + for (; e - b >= 3 && strncmp (b, ".br", 3) == 0; ++top) + { + b += 3; + + if (b != e && *b == '\n') // Remove following newline, if any. + ++b; + } + + for (; e - b >= 3 && strncmp (e - 3, ".br", 3) == 0; ++bot) + { + e -= 3; + + if (e != b && *(e - 1) == '\n') // Remove preceding newline, if any. + --e; + } + + if (top != 0 || bot != 0) + { + string t; + t.swap (v); + v.assign (b, e - b); + } +} + +string context:: +format (semantics::scope& scope, string const& s, bool para) +{ + stack blocks; + blocks.push (block (block::text, para, "")); // Top-level. + + // Number of li in ol. Since we don't support nested lists, we don't + // need to push it into the stack. + // + size_t ol_count (0); + + // Mapping of \h to HTML tag. By default it is

until we encounter + // \h0 or \h1 at which point we change it to

. + // + char html_h ('1'); + + bool last (false); + for (size_t b (0), e; !last; b = e + 1) + { + bool pre (s[b] == 0x02); + + const char* l; + size_t n; + string subst; // Variable-substituted. + + if (pre) + { + ++b; // Skip 0x02. + + e = s.find (0x03, b); + assert (e != string::npos); + + l = s.c_str () + b; + n = e - b; + + ++e; // Skip newline that follows 0x03. + last = (e == s.size ()); + } + else + { + e = s.find ('\n', b); + last = (e == string::npos); + + l = s.c_str () + b; + n = (last ? s.size () : e) - b; + + // Perform variable expansions (\$var$). Also detect the switch + // to/from TOC mode. + // + unsigned short t (toc); + if (substitute (scope, l, n, subst)) + { + if (subst.empty ()) + continue; + + if (t != toc) + { + // This is a TOC prologue/epilogue (returned by start/end_toc()) and + // we shouldn't be formatting it. + // + assert (blocks.size () == 1); + string& v (blocks.top ().value); + + // Require that \$TOC$ appears in its own doc string. Failed this + // it is tricky to get indentation right. + // + if (!v.empty () || !last) + { + cerr << "error: TOC variable should be in its own documentation " + << "string" << endl; + throw generation_failed (); + } + + switch (ot) + { + case ot_plain: break; + case ot_html: + { + // Different "newline protocol" inside TOC. + // + v += subst; + + if (toc) + v += '\n'; + } + case ot_man: break; + } + + continue; + } + + l = subst.c_str (); + n = subst.size (); + } + } + + // If this is TOC phase 2, then we simply ignore everything. + // + if (toc == 2) + continue; + + const char* ol (l); // Original, full line for diagnostics. + size_t on (n); + + // First determine what kind of paragraph block this is. + // + block::kind_type k (block::h); + string id; + string header; + string trailer; + + size_t pop (0); // Pop count. + + if (pre) + { + k = block::pre; + } + else + { + // \h \H + // + if (n >= 3 && + l[0] == '\\' && + (l[1] == 'h' || l[1] == 'H') && + (l[2] == '|' || l[2] == '#')) + { + k = block::h; + header = l[1]; + l += 3; + n -= 3; + } + // + // \h0 \h1 \h2 + // + else if (n >= 4 && + l[0] == '\\' && + l[1] == 'h' && + (l[3] == '|' || l[3] == '#')) + { + if (l[2] != '0' && l[2] != '1' && l[2] != '2') + { + cerr << "error: '0', '1', or '2' expected in \\hN| in '" + << string (ol, 0, on) << "'" << endl; + throw generation_failed (); + } + + k = block::h; + header = l[2]; + l += 4; + n -= 4; + } + // + // \ul \ol \dl + // + else if (n >= 4 && + l[0] == '\\' && + (l[1] == 'u' || l[1] == 'o' || l[1] == 'd') && + l[2] == 'l' && + (l[3] == '|' || l[3] == '#')) + { + switch (l[1]) + { + case 'u': k = block::ul; break; + case 'o': k = block::ol; break; + case 'd': k = block::dl; break; + } + + l += 4; + n -= 4; + } + // + // \li + // + else if (n >= 4 && + l[0] == '\\' && + l[1] == 'l' && + l[2] == 'i' && + (l[3] == '|' || l[3] == '#')) + { + k = block::li; + l += 4; + n -= 4; + } + // + // \N (note) + // + else if (n >= 3 && + l[0] == '\\' && + l[1] == 'N' && + (l[2] == '|' || l[2] == '#')) + { + k = block::note; + l += 3; + n -= 3; + } + else + k = block::text; + + // Get the id, if present. + // + if (k != block::text && *(l - 1) == '#') + { + for (; n != 0 && *l != '|'; ++l, --n) + id += *l; + + if (n == 0) + { + cerr << "error: paragraph begin '|' expected after id in '" + << string (ol, 0, on) << "'" << endl; + throw generation_failed (); + } + + ++l; --n; // Skip '|'. + } + + // Skip leading spaces after opening '|'. + // + if (k != block::text) + while (n != 0 && (*l == 0x20 || *l == 0x0D || *l == 0x09)) {++l; --n;} + + // Next figure out how many blocks we need to pop at the end of this + // paragraph. Things get a bit complicated since '|' could be escaped. + // + for (; n - pop > 0 && l[n - pop - 1] == '|'; ++pop) ; + if (pop != 0) + { + // To determine whether the first '|' is part of an escape sequence + // we have to find the first non-backslash character and then figure + // out who escapes whom. + // + size_t ec (0); // Escape count. + for (; n - pop - ec > 0 && l[n - pop - ec - 1] == '\\'; ++ec) ; + + // If we have an odd number of backslashes, then the last '|' is + // escaped. + // + if (ec % 2 != 0) + --pop; + + n -= pop; // Number of special '|' at the end. + + // Skip trailing spaces before closing '|'. + // + while (n != 0 && (l[n - 1] == 0x20 || + l[n - 1] == 0x0D || + l[n - 1] == 0x09)) n--; + } + } + + // Outer block kind. + // + block::kind_type ok (blocks.top ().kind); + + // Verify that this block type is valid in this context. Ignore + // empty text blocks (can happen if we just have '|'). + // + if (k != block::text || n != 0) + { + bool good (true); + + switch (ok) + { + case block::h: good = false; break; + case block::ul: + case block::ol: + case block::dl: good = (k == block::li); break; + case block::li: good = (k == block::note || + k == block::text || + k == block::pre ); break; + case block::note: good = (k == block::text || + k == block::pre || + (ot == ot_html && (k == block::ul || + k == block::ol || + k == block::dl))); break; + case block::text: good = (k != block::li); break; + case block::pre: assert (false); + } + + if (!good) + { + cerr << "error: " << k << " inside " << ok << " " + << "in documentation string '" << s << "'" << endl; + throw generation_failed (); + } + } + + // Check id for duplicates. Do it only on the non-TOC pass. + // + if (!toc && !id.empty ()) + { + if (!id_set.insert (id).second) + { + cerr << "error: duplicate id '" << id << "' in documentation " + << "string '" << s << "'" << endl; + throw generation_failed (); + } + } + + // Verify the block itself. + // + switch (k) + { + case block::h: + { + // \h blocks are only valid if we are required to start a new + // paragraph (first_para is true). + // + if (!para) + { + cerr << "error: paragraph '" << string (ol, 0, on) << "' " + << "not allowed in '" << s << "'" << endl; + throw generation_failed (); + } + + // \h must be single-paragraph. + // + if (pop == 0) + { + cerr << "error: '|' expected at the end of paragraph '" + << string (ol, 0, on) << "'" << endl; + throw generation_failed (); + } + + // \h must not be empty. + // + if (n == 0) + { + cerr << "error: empty paragraph '" << string (ol, 0, on) << "' " + << "in documentation string '" << s << "'" << endl; + throw generation_failed (); + } + + break; + } + case block::ul: + case block::ol: + case block::dl: + { + if (pop != 0) + { + cerr << "error: empty list '" << string (ol, 0, on) << "' " + << "in documentation string '" << s << "'" << endl; + throw generation_failed (); + } + + if (n != 0) + { + cerr << "error: unexpected text after " << k << "| " + << "in paragraph '" << string (ol, 0, on) << "'" << endl; + throw generation_failed (); + } + + break; + } + case block::li: + { + if (ok == block::dl) + { + if (n == 0) + { + cerr << "error: term text missing in paragraph '" + << string (ol, 0, on) << "'" << endl; + throw generation_failed (); + } + } + + break; + } + case block::note: + case block::text: + case block::pre: + break; + } + + // Push the block into the stack. + // + switch (k) + { + case block::h: blocks.push (block (k, false, id, header)); break; + case block::ul: + case block::ol: ol_count = 0; // Fall through. + case block::dl: blocks.push (block (k, true, id)); break; + case block::li: + { + switch (blocks.top ().kind) + { + case block::ol: + { + ostringstream os; + os << ++ol_count; + header = os.str (); + break; + } + case block::dl: + { + format_line (ot, header, l, n); + n = 0; + break; + } + default: + break; + } + + blocks.push (block (k, false, id, header)); + break; + } + case block::note: + { + blocks.push (block (k, true, id, header)); + break; + } + case block::text: break; // No push. + case block::pre: break; // No push. + } + + // Output paragraph text. If we are in TOC mode and this is a top-level + // block, then pretend we don't have anything to write. For non-top-level + // blocks, we handle this below, when we pop them. + // + if (toc && blocks.size () == 1) + n = 0; + + if (n != 0) + { + block& b (blocks.top ()); + string& v (b.value); + bool first (v.empty ()); + + switch (ot) + { + case ot_plain: + { + // Separate paragraphs with a blank line. + // + if (!first) + v += "\n\n"; + + if (k == block::pre) + v.append (l, n); + else + { + /* + // Strip a single "\n" at the beginning of the paragraph since we + // already wrote one newline as part of starting the paragraph. An + // example where this might be useful: + // + // li| + // + // \ + // ... + // \ + // + // \n| + // + if (n >= 2 && l[0] == '\\' && l[1] == 'n') + { + l += 2; + n -= 2; + } + + if (n != 0) + */ + + format_line (ot, v, l, n); + } + + break; + } + case ot_html: + { + // Separate paragraphs with a blank line. + // + if (!first) + v += "\n\n"; + + if (k == block::pre) + { + v += "
";
+            v.append (l, n);
+            v += "
"; + } + else + { + if (!first || b.para) + { + string t; + format_line (ot, t, l, n); + string s (html_margin (t)); + + // If the entire paragraph is wrapped in then signal this + // fact via the "code" class. This can be used, for example, to + // change alignment from "justify" to "left" in order to support + // custom alignments (in combination with non-ignorable space + // escaping; think multi-line synopsis in man pages). + // + // While at it also cleanup nested fragments (we + // may end up with quite a few of them due to the + // translation). + // + string c; + { + size_t n (t.size ()); + + if (n >= 13 && + t.compare (0, 6, "") == 0 && + t.compare (n - 7, 7, "") == 0) + { + string tt; + + // Make sure this is one contigous . + // + size_t b (1); // / balance. + for (size_t i (6), j (0); + i != n && (i = t.find ("code>", i)) != string::npos; + j = i = i + 5) + { + if (t[i - 1] == '<') b++; + else if (t[i - 1] == '/' && t[i - 2] == '<') b--; + else continue; + + // Append previous chunk. + // + tt.append (t, j, i - j - (t[i - 1] == '<' ? 1 : 2)); + + if (b == 0) + { + if (i + 5 == n) + { + tt.append (t, i - 2, 7); // Closing . + t = move (tt); + c = "code"; + } + + break; + } + } + } + } + + v += "= blocks.size ()) // >= to account for top-level. + { + cerr << "error: extraneous '|' at the end of paragraph '" + << string (ol, 0, on) << "'" << endl; + throw generation_failed (); + } + + for (; pop != 0; --pop) + { + block pb (blocks.top ()); // move + string& pi (pb.id); + string& ph (pb.header); + string& pv (pb.value); + + blocks.pop (); + + block& b (blocks.top ()); + string& v (b.value); + + // Handle poping into top-level block in TOC mode. + // + if (toc && blocks.size () == 1) + { + if (pb.kind == block::h) + { + switch (ot) + { + case ot_plain: break; + case ot_html: + { + char t (ph[0]); + + if (pi.empty ()) + { + cerr << "error: TOC heading '" << pv << "' has no id" << endl; + throw generation_failed (); + } + + pv = "" + pv + ""; + + // Unwind heading levels that are deeper ("more sub") than us. + // + for (; tocs.size () != 1; tocs.pop_back ()) + { + toc_entry const& e (tocs.back ()); + + bool pop (true); + + switch (t) + { + case '0': + case 'H': + case '1': break; // Always unwind. + case 'h': + { + pop = html_h == '1' || e.type == 'h' || e.type == '2'; + break; + } + case '2': pop = e.type == '2'; break; + } + + if (!pop) + break; + + // If we have sub-headings, then we need to close the table. + // + if (e.count != 0) + { + size_t l (tocs.size ()); + + v += string (l * 4 - 2, ' ') + "\n"; + v += string (l * 4 - 4, ' ') + "\n"; + } + else + // Otherwise it is inline. + // + v += "\n"; + } + + size_t l (tocs.size ()); + toc_entry& e (tocs.back ()); + + // If this is a first sub-entry, then we need to open the + // sub-table. + // + string in ((l * 4) - 2, ' '); + + if (l > 1 && e.count == 0) + { + v += "\n"; + v += in + "\n"; + } + + in += " "; + + switch (t) + { + case 'H': + { + v += in + "\n"; + break; + } + case '0': + case '1': + case 'h': + case '2': + { + // Calculate Chapter(X)/Section(X.Y)/Subsection(X.Y.Z) unless + // it is the preface (or a subsection thereof). + // + string n; + if (t != '0') + { + ++e.count; + + for (toc_stack::const_iterator i (tocs.begin ()); + i != tocs.end (); + ++i) + { + if (i->type == '0') + { + n.clear (); + break; + } + + if (!n.empty ()) + n += '.'; + + ostringstream os; + os << i->count; + n += os.str (); + } + } + + v += in + ""; + + if (!n.empty ()) + { + v += "\n"; + } + else + // Otherwise it is inline. + // + v += "\n"; + } + + v += "
" + pv + "
" + n + ""; + heading_map[pi] = n; // Save it for later. + } + else + v += ""; + + v += pv; // No newline + tocs.push_back (toc_entry (t)); + break; + } + } + + // Same as in non-TOC mode below. + // + // @@ This only works for a single string fragment. + // + if (t == '0' || t == '1') + html_h = '2'; + + break; + } + case ot_man: break; + } + } + + continue; + } + + switch (ot) + { + case ot_plain: + { + const char* sn (v.empty () ? "" : "\n"); + const char* dn (v.empty () ? "" : "\n\n"); + + switch (pb.kind) + { + case block::h: + { + v += dn; + + if (options.ansi_color ()) + v += "\033[1m"; // Bold. + + v += pv; + + if (options.ansi_color ()) + v += "\033[0m"; + + break; + } + case block::ul: + case block::ol: + case block::dl: v += dn + pv; break; + case block::li: + { + v += sn; + size_t ind (0), vn (pv.size ()); + + switch (b.kind) + { + case block::ul: + v += "* "; + ind = 2; + break; + case block::ol: + v += ph + ". "; + ind = ph.size () + 2; + break; + case block::dl: + v += ph + "\n" + (vn != 0 && pv[0] != '\n' ? " " : ""); + ind = 4; + break; + default: + break; + } + + // Add value with indentation for subsequent paragraphs. + // + char c, p ('\0'); // Current and previous characters. + for (size_t i (0); i != vn; p = c, ++i) + { + c = pv[i]; + + if (p == '\n' && c != '\n') // Don't indent blanks. + v += string (ind, ' '); + + v += c; + } + + break; + } + case block::note: + { + v += dn; + + // Add a special character (bell) plus space in front of every + // line (including blanks). The bell is recognized and + // translated by txt_wrap_lines() to '|'. + // + char p ('\n'); // Previous character. + for (size_t i (0), n (pv.size ()); i != n; ++i) + { + char c (pv[i]); + + if (p == '\n') + v += (c != '\n' ? "\x07 " : "\x07"); + + v += c; + p = c; + } + + break; + } + case block::text: + case block::pre: assert (false); + } + + break; + } + case ot_html: + { + if (!v.empty ()) + v += "\n\n"; + + switch (pb.kind) + { + case block::h: + { + char t (ph[0]); + + string h; + string c; + + typedef map map; + const map& hm (options.html_heading_map ()); + map::const_iterator mi (hm.find (t)); + + if (mi == hm.end ()) + { + switch (t) + { + case '0': h = "h1"; c = "preface"; break; + case 'H': h = "h1"; c = "part"; break; + case '1': h = "h1"; break; + case 'h': h = html_h == '1' ? "h1" : "h2"; break; + case '2': h = "h3"; break; + } + } + else + h = mi->second; + + v += '<' + h; + if (!pi.empty ()) v += " id=\"" + pi + '"'; + if (!c.empty ()) v += " class=\"" + c + '"'; + v += '>'; + + // See if we have a heading number (assigned by TOC). + // + if (!pi.empty ()) + { + heading_map_type::const_iterator i (heading_map.find (pi)); + + if (i != heading_map.end ()) + v += i->second + ' '; + } + + v += pv; + + v += "'; + + // @@ This only works for a single string fragment. + // + if (t == '0' || t == '1') + html_h = '2'; + + break; + } + case block::ul: v += "
    \n" + pv + "\n
"; break; + case block::ol: v += "
    \n" + pv + "\n
"; break; + case block::dl: v += "
\n" + pv + "\n
"; break; + case block::li: + { + string pvs (html_margin (pv)); + + if (b.kind == block::dl) + { + string phs (html_margin (ph)); + + v += (phs.empty () ? "
" : "
") + + ph + "
\n"; + + v += (pvs.empty () ? "
" : "
") + + pv + "
"; + } + else + v += (pvs.empty () ? "
  • " : "
  • ") + + pv + "
  • "; + + break; + } + case block::note: + { + v += "
    \n"; + v += pv; + v += "\n
    "; + + break; + } + case block::text: + case block::pre: assert (false); + } + + break; + } + case ot_man: + { + // Seeing that we always write a macro, one newline is enough. + // + if (!v.empty ()) + v += "\n"; + + switch (pb.kind) + { + case block::h: v += ".SH \"" + pv + "\""; break; + case block::ul: + case block::ol: + case block::dl: + { + if (!b.para) // First list inside .IP. + { + // .IP within .IP? Just shoot me in the head already! We + // have to manually indent it with .RS/.RE *and* everything + // that comes after it (since .PP resets the indent). Why + // not just indent the whole list content? Because then the + // first line will never start on the same line as the term. + // + v += ".RS\n"; + b.trailer = "\n.RE"; + b.para = true; // Start emitting .PP from now on. + } + + v += pv; + break; + } + case block::li: + { + man_margin (ph); // Strip leading/trailing .br. + + switch (b.kind) + { + case block::ul: v += ".IP \\(bu 2em\n" + pv; break; + case block::ol: v += ".IP " + ph + ". 4em\n" + pv; break; + // + // Add .br to force the definition to start on the new line. + // + case block::dl: v += ".IP \"" + ph + "\"\n.br\n" + pv; break; + default: break; + } + + break; + } + case block::note: + { + cerr << "error: " << pb.kind << "| in man output not yet " + << "supported" << endl; + throw generation_failed (); + } + case block::text: + case block::pre: assert (false); + } + + break; + } + } + } + } + + assert (!blocks.empty ()); // Should have top-level. + + if (blocks.size () > 1) + { + cerr << "error: unterminated paragraph " << blocks.top ().kind << " " + << "in documentation string '" << s << "'" << endl; + throw generation_failed (); + } + + block& b (blocks.top ()); + + switch (ot) + { + case ot_man: return b.value + b.trailer; + default: return b.value; + } +} + +string context:: +start_toc () +{ + switch (ot) + { + case ot_plain: break; + case ot_html: + { + tocs.push_back (toc_entry ('\0')); + return " "; + } + case ot_man: break; + } + + return string (); +} + +string context:: +end_toc () +{ + switch (ot) + { + case ot_plain: break; + case ot_html: + { + string v; + + // Unwind the TOC stack until we reach top level. Same code as in + // format(). + // + for (; tocs.size () != 1; tocs.pop_back ()) + { + toc_entry const& e (tocs.back ()); + + // If we have sub-headings, then we need to close the table. + // + if (e.count != 0) + { + size_t l (tocs.size ()); + + v += string (l * 4 - 2, ' ') + "
    \n"; + v += string (l * 4 - 4, ' ') + "
    "; + return v; + } + case ot_man: break; + } + + return string (); +} + +void context:: +verify_id_ref () +{ + if (!options.omit_link_check ()) + { + bool f (false); + + for (id_set_type::const_iterator i (ref_set.begin ()); + i != ref_set.end (); + ++i) + { + if (id_set.find (*i) == id_set.end ()) + { + cerr << "error: no id for fragment link '#" << *i << "'" << endl; + f = true; + } + } + + if (f) + throw generation_failed (); + } + + id_set.clear (); + ref_set.clear (); + heading_map.clear (); +} + +string context:: +substitute (const string& s, const path* d) +{ + string r; + + // Scan the string looking for variables ($var$) or paths. + // + size_t b (0), e (b); + for (size_t n (s.size ()); e != n; ++e) + { + if (s[e] == '$' && e + 1 != n) + { + if (s[e + 1] == '$') // Escape. + { + r.append (s, b, ++e - b); // Keep one, skip the other. + b = e + 1; + continue; + } + + bool file (false); + + // Scan for as long as it is a C identifier or a file. + // + size_t p (e + 1); // Position of the second '$'. + for (; p != n; ++p) + { + char c (s[p]); + bool f (p == e + 1); // First. + + if (d != 0 && f && c == '.' && p + 1 != n && + (s[p + 1] == '/' || // "./" + (s[p + 1] == '.' && p + 2 != n && s[p + 2] == '/'))) // "../" + file = true; + + if (file) + { + if (c == '$') + break; + } + else + { + if (!(c == '_' || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + (!f && '0' <= c && c <= '9'))) + break; + } + } + + // Note: check that the second '$' is not escaped. + // + if (p != n && s[p] == '$' && (p + 1 == n || s[p + 1] != '$')) + { + r.append (s, b, e - b); // Save what came before the expansion. + + // Var/file name. + // + ++e; + string v (s, e, p - e); + + if (file) + { + path p (*d / path (v)); + p.normalize (); // Apply '.' and '..'. + + ifstream ifs (p.string ().c_str (), ifstream::in | ifstream::binary); + if (!ifs.is_open ()) + { + cerr << p << ": error: unable to open in read mode" << endl; + throw generation_failed (); + } + + // We don't expect our file to contain '\0' so use that as the + // delimiter to read the entire file with getline(). + // + string s; + getline (ifs, s, '\0'); + r += s; + } + else + { + // Handle special variables. + // + if (v == "TOC") + { + if (!r.empty () || p + 1 != n) + { + cerr << "error: TOC variable should be on its own line" << endl; + throw generation_failed (); + } + + // Invert the TOC mode. + // + if ((toc = toc ? 0 : 1)) + r = start_toc (); + else + r = end_toc (); + + return r; + } + + // Lookup and substiute the variable. + // + using semantics::doc; + + if (doc* d = unit.lookup ("", "var: " + v)) + r += d->front (); + else + { + cerr << "error: undefined variable '" << v << "' in '" << s << "'" + << endl; + throw generation_failed (); + } + } + + e = p; + b = e + 1; + } + } + } + + r.append (s, b, e - b); // Last chunk. + return r; +} + +bool context:: +substitute (semantics::scope& scope, const char* s, size_t n, string& result) +{ + bool sub (false); + result.clear (); + + // Scan the string looking for variables (\$var$). + // + size_t b (0), e (b); + for (char p ('\0'); e != n; ++e) + { + char c (s[e]); + + if (p == '\\') + { + if (c == '\\') // Escape sequence. + { + p = '\0'; + continue; + } + + if (c == '$') + { + // Variable expansion. + // + sub = true; + + // Find the closing '$'. + // + size_t p (e + 1); // Position of the second '$'. + for (; p != n && s[p] != '$'; ++p) ; + + if (p == n) + { + cerr << "error: missing closing '$' in '" << string (s, n) << "'" + << endl; + throw generation_failed (); + } + + result.append (s, b, e - b - 1); // Save what came before. + + // Var name. + // + ++e; + string v (s, e, p - e); + + // Handle special variables. + // + if (v == "TOC") + { + if (!result.empty () || p + 1 != n) + { + cerr << "error: TOC variable should be its own paragraph" << endl; + throw generation_failed (); + } + + // Invert the TOC mode. + // + if ((toc = toc ? 0 : 1)) + result = start_toc (); + else + result = end_toc (); + + return true; + } + + // Lookup and substiute. + // + using semantics::doc; + + if (doc* d = unit.lookup (scope.fq_name (), "var: " + v)) + result += d->front (); + else + { + cerr << "error: undefined variable '" << v << "' in '" + << string (s, n) << "'" << endl; + throw generation_failed (); + } + + e = p; + b = e + 1; + } + } + + p = s[e]; + } + + if (sub) + result.append (s, b, e - b); // Last chunk. + + return sub; +} + +string context:: +fq_name (semantics::nameable& n, bool cxx_name) +{ + using namespace semantics; + + string r; + + if (dynamic_cast (&n)) + { + return ""; // Map to global namespace. + } + else + { + r = fq_name (n.scope ()); + r += "::"; + r += cxx_name ? escape (n.name ()) : n.name (); + } + + return r; +} + +string context:: +ns_open (const string& qn, bool last) +{ + string::size_type b (0), e; + + do + { + e = qn.find ("::", b); + string n (qn, b, e == string::npos ? e : e - b); + + if (!n.empty () && (last || e != string::npos)) + os << "namespace " << n << "{"; + + b = e; + + if (b == string::npos) + return n; + + b += 2; + + } while (true); +} + +void context:: +ns_close (const string& qn, bool last) +{ + string::size_type b (0), e; + + do + { + e = qn.find ("::", b); + string n (qn, b, e == string::npos ? e : e - b); + + if (!n.empty () && (last || e != string::npos)) + os << "}"; + + b = e; + + if (b == string::npos) + return; + + b += 2; + + } while (true); +} + +class_doc context:: +class_doc (semantics::class_& c) +{ + typedef map map; + const map& m (options.class_doc ()); + + string n (c.fq_name ()); + + map::const_iterator i (m.find (n)); + + if (i == m.end ()) + { + n = string (n, 2, string::npos); // Try without leading '::'. + i = m.find (n); + } + + if (i == m.end ()) + return cd_default; + + const string& k (i->second); + + if (k == "exclude") + return cd_exclude; + if (k == "exclude-base") + return cd_exclude_base; + else if (k == "short") + return cd_short; + else if (k == "long") + return cd_long; + else + { + cerr << "error: unknown --class-doc kind value '" << k << "'" << endl; + throw generation_failed (); + } +} + +string context:: +first_sentence (string const& s) +{ + size_t p (s.find ('.')); + + // Add some heuristics here: check that there is a space + // (or end of text) after the period. + // + while (p != string::npos && + p + 1 <= s.size () && + s[p + 1] != ' ' && + s[p + 1] != '\n') + p = s.find ('.', p + 1); + + return p == string::npos ? s : string (s, 0, p + 1); +} + +// namespace +// + +void namespace_:: +pre (type& ns) +{ + string name (ns.name ()); + + if (!name.empty ()) + os << "namespace " << escape (name) + << "{"; +} + +void namespace_:: +post (type& ns) +{ + if (!ns.name ().empty ()) + os << "}"; +} diff --git a/cli/cli/context.hxx b/cli/cli/context.hxx new file mode 100644 index 0000000..633b8ad --- /dev/null +++ b/cli/cli/context.hxx @@ -0,0 +1,295 @@ +// file : cli/context.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_CONTEXT_HXX +#define CLI_CONTEXT_HXX + +#include +#include +#include +#include +#include +#include // std::size_t + +#include +#include +#include + +#include +#include +#include + +using std::endl; + +class generation_failed {}; + +enum usage +{ + ut_none, + ut_short, + ut_long, + ut_both +}; + +enum class_doc +{ + cd_default, + cd_exclude, + cd_exclude_base, + cd_short, + cd_long +}; + +class context +{ +public: + typedef std::size_t size_t; + typedef std::string string; + + typedef cutl::fs::path path; + typedef cutl::fs::invalid_path invalid_path; + + typedef ::options options_type; + typedef ::usage usage_type; + typedef ::class_doc class_doc_type; + + // Regex. + // + typedef cutl::re::regex regex; + typedef cutl::re::regexsub regexsub; + typedef cutl::re::format regex_format; + + typedef std::vector regex_mapping; + +private: + struct data; + cutl::shared_ptr data_; + +public: + std::ostream& os; + semantics::cli_unit& unit; + options_type const& options; + + // Documentation output type. + // + enum output_type + { + ot_plain, + ot_html, + ot_man + }; + + output_type ot; + + bool gen_modifier; + bool gen_specifier; + bool gen_parse; + bool gen_merge; + usage_type gen_usage; + + string const& inl; + string const& opt_prefix; + string const& opt_sep; + string const& cli; + + typedef std::map reserved_name_map_type; + reserved_name_map_type const& reserved_name_map; + + typedef std::set keyword_set_type; + keyword_set_type const& keyword_set; + + regex_mapping const& link_regex; + + typedef std::set id_set_type; + id_set_type& id_set; + id_set_type& ref_set; + + // Map of heading ids to heading number (assigned during TOC generation) + // + typedef std::map heading_map_type; + heading_map_type& heading_map; + + // TOC phase. + // + // 0 - non-TOC + // 1 - generating TOC after seeing expansion but before restart + // 2 - generating TOC after restart + // 0 - non-TOC after seeing expansion after restart + // + unsigned short& toc; + + struct toc_entry + { + toc_entry (char t = '\0', size_t c = 0): type (t), count (c) {} + + char type; // Entry type (output type-specific, usually X from \hX). + size_t count; // Number of sub-entries so far. + }; + + typedef std::vector toc_stack; + toc_stack& tocs; + +private: + struct data + { + string inl_; + string cli_; + keyword_set_type keyword_set_; + regex_mapping link_regex_; + id_set_type id_set_; + id_set_type ref_set_; + heading_map_type heading_map_; + unsigned short toc_; + toc_stack tocs_; + }; + +public: + // Escape C++ keywords, reserved names, and illegal characters. + // + string + escape (string const&) const; + + string + process_link_target (const string&); + + // Translate and format the documentation string. Translate converts + // the -style constructs to \i{arg}. Format converts the string + // to the output format. + // + static string + translate_arg (string const&, std::set&); + + static string + translate (string const&, std::set const&); + + // If para is true, start a new paragraph. + // + string + format (semantics::scope&, string const&, bool para); + + void + format_line (output_type, string&, const char*, size_t); + + // Called when we switch to the TOC mode and when we exit it, + // respectively. + // + string + start_toc (); + + string + end_toc (); + + // Make sure each local fragment reference has the corresponding id. Issue + // diagnostics and throw generation_failed if fails. Otherwise clear the + // id and ref sets. + // + void + verify_id_ref (); + + // Substitute doc variable expansions ($var$). Var must be a C identifier. + // If the path is not NULL, then also recognize names that start with either + // ./ or ../ and treat them as files relative to path. Such file expansions + // are substituted with the file contents. + // + string + substitute (const string&, const path* = 0); + + // Substitute doc variable expansions (\$var$). Note that it leaves escapes + // (\\$) as is. Return true if any substitutions have been made, in which + // case result will contain the expansion result. + // + bool + substitute (semantics::scope&, const char* s, size_t n, string& result); + +public: + static string const& + ename (semantics::nameable& n) + { + return n.context ().get ("name"); + } + + static string const& + especifier (semantics::nameable& n) + { + return n.context ().get ("specifier"); + } + + static string const& + emember (semantics::nameable& n) + { + return n.context ().get ("member"); + } + + static string const& + especifier_member (semantics::nameable& n) + { + return n.context ().get ("specifier-member"); + } + +public: + // Return fully-qualified C++ or CLI name. + // + string + fq_name (semantics::nameable& n, bool cxx_name = true); + + // Open/close namespace. If last is false, then the last name + // component is not treated as a namespace. The open function + // also returns the last name component. + // +public: + string + ns_open (const string& name, bool last = true); + + void + ns_close (const string& name, bool last = true); + +public: + class_doc_type + class_doc (semantics::class_&); + +public: + string + first_sentence (string const&); + +public: + context (std::ostream&, + output_type, + semantics::cli_unit&, + options_type const&); + + context (context&); + +private: + context& + operator= (context const&); +}; + +// Checks if scope Y names any of X. +// +template +bool +has (Y& y) +{ + for (semantics::scope::names_iterator i (y.names_begin ()), + e (y.names_end ()); i != e; ++i) + if (i->named (). template is_a ()) + return true; + + return false; +} + +// Standard namespace traverser. +// +struct namespace_: traversal::namespace_, context +{ + namespace_ (context& c) : context (c) {} + + virtual void + pre (type&); + + virtual void + post (type&); +}; + +#endif // CLI_CONTEXT_HXX diff --git a/cli/cli/generator.cxx b/cli/cli/generator.cxx new file mode 100644 index 0000000..df1b99e --- /dev/null +++ b/cli/cli/generator.cxx @@ -0,0 +1,584 @@ +// file : cli/generator.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include // std::toupper, std::is{alpha,upper,lower} +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace cutl; + +using semantics::path; + +namespace +{ + static char const cxx_header[] = + "// -*- C++ -*-\n" + "//\n" + "// This file was generated by CLI, a command line interface\n" + "// compiler for C++.\n" + "//\n\n"; + + string + make_guard (string const& file, context& ctx) + { + string g (file); + + // Split words, e.g., "FooBar" to "Foo_Bar" and convert everything + // to upper case. + // + string r; + for (string::size_type i (0), n (g.size ()); i < n - 1; ++i) + { + char c1 (g[i]); + char c2 (g[i + 1]); + + r += toupper (c1); + + if (isalpha (c1) && isalpha (c2) && islower (c1) && isupper (c2)) + r += "_"; + } + r += toupper (g[g.size () - 1]); + + return ctx.escape (r); + } + + void + open (ifstream& ifs, string const& path) + { + ifs.open (path.c_str (), ios_base::in | ios_base::binary); + + if (!ifs.is_open ()) + { + cerr << path << ": error: unable to open in read mode" << endl; + throw generator::failed (); + } + } + + void + append (context& ctx, string const& s, const path* d = 0) + { + // Detect the switch to/from TOC mode. + // + unsigned short t (ctx.toc); + string const& r (ctx.substitute (s, d)); + + if (t != ctx.toc) + { + if (!r.empty ()) // TOC prologue/epilogue (returned by start/end_toc()). + ctx.os << r << endl; + } + // Skip it if we are in the TOC mode. + // + else if (!t) + ctx.os << r << endl; + } + + void + append (context& ctx, vector const& text, string const& file) + { + for (vector::const_iterator i (text.begin ()); + i != text.end (); ++i) + { + append (ctx, *i); + } + + if (!file.empty ()) + { + ifstream ifs; + open (ifs, file); + + path d (path (file).directory ()); + + // getline() will set the failbit if it failed to extract anything, + // not even the delimiter and eofbit if it reached eof before seeing + // the delimiter. + // + for (string s; getline (ifs, s); ) + append (ctx, s, &d); + } + } +} + +generator:: +generator () +{ +} + +void generator:: +generate (options& ops, semantics::cli_unit& unit, path const& p) +{ + if (ops.generate_group_scanner ()) + ops.generate_vector_scanner (true); + + try + { + path file (p.leaf ()); + string base (file.base ().string ()); + + const string& pfx (ops.output_prefix ()); + const string& sfx (ops.output_suffix ()); + + bool gen_cxx (ops.generate_cxx ()); + bool gen_man (ops.generate_man ()); + bool gen_html (ops.generate_html ()); + bool gen_txt (ops.generate_txt ()); + + if (!gen_cxx && !gen_man && !gen_html && !gen_txt) + gen_cxx = true; + + if (ops.stdout_ ()) + { + if (gen_cxx) + { + cerr << "error: --stdout cannot be used with C++ output" << endl; + throw failed (); + } + + if ((gen_man && gen_html) || + (gen_man && gen_txt) || + (gen_html && gen_txt)) + { + cerr << "error: --stdout cannot only be used with one output format" + << endl; + throw failed (); + } + } + + fs::auto_removes auto_rm; + + // C++ output. + // + if (gen_cxx) + { + bool inl (!ops.suppress_inline ()); + + string hxx_name (pfx + base + sfx + ops.hxx_suffix ()); + string ixx_name (pfx + base + sfx + ops.ixx_suffix ()); + string cxx_name (pfx + base + sfx + ops.cxx_suffix ()); + + path hxx_path (hxx_name); + path ixx_path (ixx_name); + path cxx_path (cxx_name); + + if (!ops.output_dir ().empty ()) + { + path dir (ops.output_dir ()); + + hxx_path = dir / hxx_path; + ixx_path = dir / ixx_path; + cxx_path = dir / cxx_path; + } + + // Process names. + // + { + context ctx (cerr, context::ot_plain, unit, ops); + process_names (ctx); + } + + // Check if we need to generate the runtime code. If we include + // another options file, then we assume the runtime is generated + // there. However, to reduce the number of standard headers we + // have to include in the generated header file, we will still + // need to generate some template code in the source file. + // + bool runtime (!ops.suppress_cli ()); + + if (runtime) + { + for (semantics::cli_unit::includes_iterator i (unit.includes_begin ()); + i != unit.includes_end (); + ++i) + { + if (i->is_a ()) + { + runtime = false; + break; + } + } + } + + // + // + ofstream hxx (hxx_path.string ().c_str ()); + + if (!hxx.is_open ()) + { + cerr << "error: unable to open '" << hxx_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (hxx_path); + + // + // + ofstream ixx; + + if (inl) + { + ixx.open (ixx_path.string ().c_str (), ios_base::out); + + if (!ixx.is_open ()) + { + cerr << "error: unable to open '" << ixx_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (ixx_path); + } + + // + // + ofstream cxx (cxx_path.string ().c_str ()); + + if (!cxx.is_open ()) + { + cerr << "error: unable to open '" << cxx_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (cxx_path); + + // Print headers. + // + hxx << cxx_header; + if (inl) + ixx << cxx_header; + cxx << cxx_header; + + typedef + compiler::ostream_filter + cxx_filter; + + // Include settings. + // + bool br (ops.include_with_brackets ()); + string ip (ops.include_prefix ()); + string gp (ops.guard_prefix ()); + + if (!ip.empty () && ip[ip.size () - 1] != '/') + ip.append ("/"); + + if (!gp.empty () && gp[gp.size () - 1] != '_') + gp.append ("_"); + + // HXX + // + { + context ctx (hxx, context::ot_plain, unit, ops); + + string guard (make_guard (gp + hxx_name, ctx)); + + hxx << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + hxx << "// Begin prologue." << endl + << "//" << endl; + append (ctx, ops.hxx_prologue (), ops.hxx_prologue_file ()); + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // We don't want to indent prologues/epilogues. + // + cxx_filter filt (ctx.os); + + if (runtime) + generate_runtime_header (ctx); + + generate_header (ctx); + } + + if (inl) + { + hxx << "#include " << (br ? '<' : '"') << ip << ixx_name << + (br ? '>' : '"') << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + append (ctx, ops.hxx_epilogue (), ops.hxx_epilogue_file ()); + hxx << "//" << endl + << "// End epilogue." << endl + << endl; + + hxx << "#endif // " << guard << endl; + } + + // IXX + // + if (inl) + { + context ctx (ixx, context::ot_plain, unit, ops); + + // Copy prologue. + // + ixx << "// Begin prologue." << endl + << "//" << endl; + append (ctx, ops.ixx_prologue (), ops.ixx_prologue_file ()); + ixx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // We don't want to indent prologues/epilogues. + // + cxx_filter filt (ctx.os); + + if (runtime) + generate_runtime_inline (ctx); + + generate_inline (ctx); + } + + // Copy epilogue. + // + ixx << "// Begin epilogue." << endl + << "//" << endl; + append (ctx, ops.ixx_epilogue (), ops.ixx_epilogue_file ()); + ixx << "//" << endl + << "// End epilogue." << endl; + } + + // CXX + // + { + context ctx (cxx, context::ot_plain, unit, ops); + + // Copy prologue. + // + cxx << "// Begin prologue." << endl + << "//" << endl; + append (ctx, ops.cxx_prologue (), ops.cxx_prologue_file ()); + cxx << "//" << endl + << "// End prologue." << endl + << endl; + + cxx << "#include " << (br ? '<' : '"') << ip << hxx_name << + (br ? '>' : '"') << endl + << endl; + + { + // We don't want to indent prologues/epilogues. + // + cxx_filter filt (ctx.os); + + if (runtime && !inl) + generate_runtime_inline (ctx); + + if (!ops.suppress_cli ()) + generate_runtime_source (ctx, runtime); + + if (!inl) + generate_inline (ctx); + + generate_source (ctx); + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + append (ctx, ops.cxx_epilogue (), ops.cxx_epilogue_file ()); + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + } + } + + // man output + // + if (gen_man) + { + ofstream man; + + if (!ops.stdout_ ()) + { + path man_path (pfx + base + sfx + ops.man_suffix ()); + + if (!ops.output_dir ().empty ()) + man_path = path (ops.output_dir ()) / man_path; + + man.open (man_path.string ().c_str ()); + + if (!man.is_open ()) + { + cerr << "error: unable to open '" << man_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (man_path); + } + + // The explicit cast helps VC++ 8.0 overcome its issues. + // + ostream& os (ops.stdout_ () ? cout : static_cast (man)); + context ctx (os, context::ot_man, unit, ops); + + for (bool first (true); first || ctx.toc; first = false) + { + append (ctx, ops.man_prologue (), ops.man_prologue_file ()); + generate_man (ctx); + append (ctx, ops.man_epilogue (), ops.man_epilogue_file ()); + + if (ctx.toc) + { + assert (first); // Second run should end in non-TOC mode. + ctx.toc++; // TOC phase after restart. + } + } + + ctx.verify_id_ref (); + } + + // HTML output + // + if (gen_html) + { + ofstream html; + + if (!ops.stdout_ ()) + { + // May have to update link derivation in format_line() if changing + // this. + // + path html_path (pfx + base + sfx + ops.html_suffix ()); + + if (!ops.output_dir ().empty ()) + html_path = path (ops.output_dir ()) / html_path; + + html.open (html_path.string ().c_str ()); + + if (!html.is_open ()) + { + cerr << "error: unable to open '" << html_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (html_path); + } + + // The explicit cast helps VC++ 8.0 overcome its issues. + // + ostream& os (ops.stdout_ () ? cout : static_cast (html)); + context ctx (os, context::ot_html, unit, ops); + + for (bool first (true); first || ctx.toc; first = false) + { + append (ctx, ops.html_prologue (), ops.html_prologue_file ()); + generate_html (ctx); + append (ctx, ops.html_epilogue (), ops.html_epilogue_file ()); + + if (ctx.toc) + { + assert (first); // Second run should end in non-TOC mode. + ctx.toc++; // TOC phase after restart. + } + } + + ctx.verify_id_ref (); + } + + // txt output + // + if (gen_txt) + { + ofstream txt; + + if (!ops.stdout_ ()) + { + path txt_path (pfx + base + sfx + ops.txt_suffix ()); + + if (!ops.output_dir ().empty ()) + txt_path = path (ops.output_dir ()) / txt_path; + + txt.open (txt_path.string ().c_str ()); + + if (!txt.is_open ()) + { + cerr << "error: unable to open '" << txt_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (txt_path); + } + + // The explicit cast helps VC++ 8.0 overcome its issues. + // + ostream& os (ops.stdout_ () ? cout : static_cast (txt)); + context ctx (os, context::ot_plain, unit, ops); + + for (bool first (true); first || ctx.toc; first = false) + { + append (ctx, ops.txt_prologue (), ops.txt_prologue_file ()); + generate_txt (ctx); + append (ctx, ops.txt_epilogue (), ops.txt_epilogue_file ()); + + if (ctx.toc) + { + assert (first); // Second run should end in non-TOC mode. + ctx.toc++; // TOC phase after restart. + } + } + + ctx.verify_id_ref (); + } + + auto_rm.cancel (); + } + catch (const generation_failed&) + { + // Code generation failed. Diagnostics has already been issued. + // + throw failed (); + } + catch (semantics::invalid_path const& e) + { + cerr << "error: '" << e.path () << "' is not a valid filesystem path" + << endl; + throw failed (); + } + catch (fs::error const&) + { + // Auto-removal of generated files failed. Ignore it. + // + throw failed (); + } +} diff --git a/cli/cli/generator.hxx b/cli/cli/generator.hxx new file mode 100644 index 0000000..f567528 --- /dev/null +++ b/cli/cli/generator.hxx @@ -0,0 +1,28 @@ +// file : cli/generator.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_GENERATOR_HXX +#define CLI_GENERATOR_HXX + +#include +#include + +class generator +{ +public: + generator (); + + class failed {}; + + void + generate (options&, semantics::cli_unit&, semantics::path const&); + +private: + generator (generator const&); + + generator& + operator= (generator const&); +}; + +#endif // CLI_GENERATOR_HXX diff --git a/cli/cli/header.cxx b/cli/cli/header.cxx new file mode 100644 index 0000000..a2a3ccd --- /dev/null +++ b/cli/cli/header.cxx @@ -0,0 +1,383 @@ +// file : cli/header.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include + +using namespace std; + +namespace +{ + // + // + struct option: traversal::option, context + { + option (context& c) : context (c) {} + + virtual void + traverse (type& o) + { + string name (ename (o)); + string type (o.type ().name ()); + + os << "const " << type << "&" << endl + << name << " () const;" + << endl; + + if (gen_modifier) + { + os << type << "&" << endl + << name << " ();" + << endl; + + os << "void" << endl + << name << " (const " << type << "&);" + << endl; + } + + if (gen_specifier && type != "bool") + { + string spec (especifier (o)); + + os << "bool" << endl + << spec << " () const;" + << endl; + + if (gen_modifier) + os << "void" << endl + << spec << " (bool);" + << endl; + } + } + }; + + // + // + struct option_data: traversal::option, context + { + option_data (context& c) : context (c) {} + + virtual void + traverse (type& o) + { + string member (emember (o)); + string type (o.type ().name ()); + + os << type << " " << member << ";"; + + if (gen_specifier && type != "bool") + os << "bool " << especifier_member (o) << ";"; + } + }; + + // + // + struct base: traversal::class_, context + { + base (context& c): context (c), first_ (true) {} + + virtual void + traverse (type& c) + { + if (first_) + { + os << ": "; + first_ = false; + } + else + os << "," << endl + << " "; + + os << "public " << fq_name (c); + } + + private: + bool first_; + }; + + // + // + struct class_: traversal::class_, context + { + class_ (context& c) + : context (c), + option_ (c), + option_data_ (c) + { + names_option_ >> option_; + names_option_data_ >> option_data_; + } + + virtual void + traverse (type& c) + { + bool abst (c.abstract ()); + string name (escape (c.name ())); + string um (cli + "::unknown_mode"); + + os << "class " << name; + + { + base b (*this); + traversal::inherits i (b); + inherits (c, i); + } + + os << "{" + << "public:" << endl; + + // c-tors + // + if (!abst) + { + os << name << " ();" + << endl; + + // Are we generating parsing constructors or parse() functions? + // + string n; + if (gen_parse) + { + os << "// Return true if anything has been parsed." << endl + << "//" << endl; + + n = string ("bool\n") + (name != "parse" ? "parse" : "parse_"); + } + else + n = name; + + os << n << " (int& argc," << endl + << "char** argv," << endl + << "bool erase = false," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + + os << n << " (int start," << endl + << "int& argc," << endl + << "char** argv," << endl + << "bool erase = false," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + + os << n << " (int& argc," << endl + << "char** argv," << endl + << "int& end," << endl + << "bool erase = false," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + + os << n << " (int start," << endl + << "int& argc," << endl + << "char** argv," << endl + << "int& end," << endl + << "bool erase = false," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + + os << n << " (" << cli << "::scanner&," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + } + + + // Note that we are generating public merge() function even for abstract + // classes; theoretically, one may want to merge options only starting + // form a specific point in the inheritance hierarchy (e.g., only common + // options or some such). + // + if (gen_merge) + os << "// Merge options from the specified instance appending/overriding" << endl + << "// them as if they appeared after options in this instance." << endl + << "//" << endl + << "void" << endl + << "merge (const " << name << "&);" + << endl; + + // + // + os << "// Option accessors" << (gen_modifier ? " and modifiers." : ".") << endl + << "//" << endl; + + names (c, names_option_); + + // Usage. + // + if (gen_usage != ut_none) + { + string up (cli + "::usage_para"); + string const& ost (options.ostream_type ()); + + os << "// Print usage information." << endl + << "//" << endl; + + os << "static " << up << endl + << "print_usage (" << ost << "&," << endl + << up << " = " << up << "::none);" + << endl; + + if (gen_usage == ut_both) + os << "static " << up << endl + << "print_long_usage (" << ost << "&," << endl + << up << " = " << up << "::none);" + << endl; + } + + // Description. + // + if (options.generate_description ()) + { + os << "// Option description." << endl + << "//" << endl + << "static const " << cli << "::options&" << endl + << "description ();" + << endl; + } + + os << "// Implementation details." << endl + << "//" << endl + << "protected:" << endl; + + // default c-tor (abstract) + // + if (abst) + os << name << " ();" + << endl; + + // fill () + // + if (options.generate_description ()) + os << "friend struct _cli_" + name + "_desc_type;" + << endl + << "static void" << endl + << "fill (" << cli << "::options&);" + << endl; + + // _parse () + // + os << "bool" << endl + << "_parse (const char*, " << cli << "::scanner&);" + << endl; + + // _parse () + // + if (!abst) + os << "private:" << endl + << "bool" << endl + << "_parse (" << cli << "::scanner&," << endl + << um << " option," << endl + << um << " argument);" + << endl; + + // Data members. + // + os << "public:" << endl; //@@ tmp + + names (c, names_option_data_); + + os << "};"; + } + + private: + option option_; + traversal::names names_option_; + + option_data option_data_; + traversal::names names_option_data_; + }; + + // + // + struct includes_: traversal::cxx_includes, + traversal::cli_includes, + context + { + includes_ (context& c) : context (c) {} + + virtual void + traverse (semantics::cxx_includes& i) + { + generate (i.kind (), i.file ().string ()); + } + + virtual void + traverse (semantics::cli_includes& i) + { + generate (i.kind (), + (options.output_prefix () + + i.file ().base ().string () + + options.output_suffix () + + options.hxx_suffix ())); + } + + void + generate (semantics::includes::kind_type k, string const& f) + { + char b, e; + if (k == semantics::includes::quote) + b = e = '"'; + else + { + b = '<'; + e = '>'; + } + + os << "#include " << b << f << e << endl + << endl; + } + }; +} + +void +generate_header (context& ctx) +{ + ostream& os (ctx.os); + + traversal::cli_unit unit; + includes_ includes (ctx); + traversal::names unit_names; + namespace_ ns (ctx); + class_ cl (ctx); + + unit >> includes; + unit >> unit_names >> ns; + unit_names >> cl; + + traversal::names ns_names; + + ns >> ns_names >> ns; + ns_names >> cl; + + unit.dispatch (ctx.unit); + + // Entire page usage. + // + if (ctx.gen_usage != ut_none && ctx.options.page_usage_specified ()) + { + os << "// Print page usage information." << endl + << "//" << endl; + + const string& qn (ctx.options.page_usage ()); + string n (ctx.escape (ctx.substitute (ctx.ns_open (qn, false)))); + + string up (ctx.cli + "::usage_para"); + string const& ost (ctx.options.ostream_type ()); + + os << up << endl + << n << "usage (" << ost << "&," << endl + << up << " = " << up << "::none);" + << endl; + + if (ctx.gen_usage == ut_both) + os << up << endl + << n << "long_usage (" << ost << "&," << endl + << up << " = " << up << "::none);" + << endl; + + ctx.ns_close (qn, false); + } +} diff --git a/cli/cli/header.hxx b/cli/cli/header.hxx new file mode 100644 index 0000000..e6e68ee --- /dev/null +++ b/cli/cli/header.hxx @@ -0,0 +1,13 @@ +// file : cli/header.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_HEADER_HXX +#define CLI_HEADER_HXX + +#include + +void +generate_header (context&); + +#endif // CLI_HEADER_HXX diff --git a/cli/cli/html.cxx b/cli/cli/html.cxx new file mode 100644 index 0000000..b374b91 --- /dev/null +++ b/cli/cli/html.cxx @@ -0,0 +1,348 @@ +// file : cli/html.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include +#include + +#include + +using namespace std; + +namespace +{ + static string + escape_html (string const& s) + { + string r; + r.reserve (s.size ()); + + for (size_t i (0), n (s.size ()); i < n; ++i) + { + switch (s[i]) + { + case '<': + { + r += "<"; + break; + } + case '&': + { + r += "&"; + break; + } + default: + { + r += s[i]; + break; + } + } + } + + return r; + } + + static void + wrap_lines (ostream& os, const string& d, size_t indent) + { + size_t lim (78 - indent); + string ind (indent, ' '); + + bool nl (true); // True if last written to os character is a newline. + + size_t b (0), e (0), i (0); + for (size_t n (d.size ()); i < n; ++i) + { + // First handle
    .
    +      //
    +      if (d.compare (i, 5, "
    ") == 0)
    +      {
    +        // Write what might have already accumulated.
    +        //
    +        if (b != i)
    +        {
    +          if (nl)
    +            os << ind;
    +
    +          os << string (d, b, i - b);
    +          nl = false;
    +        }
    +
    +        // Output everything until (and including) closing 
    as is. + // + e = d.find ("
    ", i + 5); + assert (e != string::npos); + e += 6; // Now points past '>'. + + if (nl) + os << ind; + + os << string (d, i, e - i); + + b = e; + i = e - 1; // For ++i in loop header. + nl = false; + continue; + } + + if (d[i] == ' ' || d[i] == '\n') + e = i; + + if (d[i] == '\n' || (i - b >= lim && e != b)) + { + if (nl && b != e) + os << ind; + + os << string (d, b, e - b) << endl; + + b = e = e + 1; + nl = true; + } + } + + // Write the last line. + // + if (b != i) + { + if (nl) + os << ind; + + os << string (d, b, i - b); + } + } + + struct doc: traversal::doc, context + { + doc (context& c, class_doc_type cd, bool& l) + : context (c), cd_ (cd), list_ (l) {} + + virtual void + traverse (type& ds) + { + if (ds.name ().compare (0, 3, "doc") != 0) // Ignore doc variables. + return; + + // n = 1 - common doc string + // n = 2 - arg string, common doc string + // n > 2 - arg string, short string, long string + // + size_t n (ds.size ()); + const string& d ( + n == 1 + ? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0]) + : (n == 2 + ? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1]) + : ds[cd_ == cd_short ? 1 : 2])); + + std::set arg_set; + if (n > 1) + translate_arg (ds[0], arg_set); + + unsigned short t (toc); // Detect the switch to/from TOC mode. + + string s ( + format (ds.scope (), escape_html (translate (d, arg_set)), true)); + + if (s.empty ()) + return; + + if (list_) + { + os << " " << endl + << endl; + list_ = false; + } + + wrap_lines (os, s, (t || toc) ? 0 : 2); // TOC mode does its own thing. + + if (!toc) // TOC mode does its own thing. + os << endl + << endl; + } + + private: + class_doc_type cd_; + bool& list_; // True if we are currently in
    . + }; + + struct option: traversal::option, context + { + option (context& c, class_doc_type cd, bool& l) + : context (c), cd_ (cd), list_ (l) {} + + virtual void + traverse (type& o) + { + using semantics::names; + + semantics::doc_strings const& doc (o.doc ()); + + if (options.suppress_undocumented () && doc.empty ()) + return; + + if (toc) + return; // No option documentation in the TOC mode. + + if (!list_) + { + os << "
    " << endl; + list_ = true; + } + else + os << endl; // Separate from the previous
    . + + names& n (o.named ()); + + os << "
    "; + + for (names::name_iterator i (n.name_begin ()); i != n.name_end (); ++i) + { + if (i != n.name_begin ()) + os << "|"; + + os << escape_html (*i); + } + + os << ""; + + string type (o.type ().name ()); + + std::set arg_set; + + if (type != "bool" || doc.size () >= 3) + { + string s ( + translate_arg ( + doc.size () > 0 ? doc[0] : string (""), arg_set)); + + os << ' ' << format (o.scope (), escape_html (s), false); + } + + os << "
    " << endl; + + string d; + if (type == "bool" && doc.size () < 3) + { + if (doc.size () > 1) + d = doc[cd_ == cd_short ? 0 : 1]; + else if (doc.size () > 0) + d = (cd_ == cd_short ? first_sentence (doc[0]) : doc[0]); + } + else + { + if (doc.size () > 2) + d = doc[cd_ == cd_short ? 1 : 2]; + else if (doc.size () > 1) + d = (cd_ == cd_short ? first_sentence (doc[1]) : doc[1]); + } + + // Format the documentation string. + // + d = format (o.scope (), escape_html (translate (d, arg_set)), false); + + wrap_lines (os, "
    " + d + "
    ", 4); + os << endl; + } + + private: + class_doc_type cd_; + bool& list_; // True if we are currently in
    . + }; + + // + // + struct class_: traversal::class_, context + { + class_ (context& c, bool& l): context (c), list_ (l), base_ (false) + { + *this >> inherits_ >> *this; + } + + virtual void + traverse (type& c) + { + class_doc_type cd (class_doc (c)); + + if (cd == cd_exclude || (base_ && cd == cd_exclude_base)) + return; + + if (!options.exclude_base () && !options.include_base_last ()) + { + bool ob (base_); + base_ = true; + inherits (c); + base_ = ob; + } + + doc dc (*this, cd, list_); + option op (*this, cd, list_); + traversal::names n; + n >> dc; + n >> op; + names (c, n); + + if (!options.exclude_base () && options.include_base_last ()) + { + bool ob (base_); + base_ = true; + inherits (c); + base_ = ob; + } + } + + private: + bool& list_; + bool base_; + traversal::inherits inherits_; + }; +} + +void +generate_html (context& ctx) +{ + bool list (false); + + traversal::cli_unit unit; + traversal::names unit_names; + traversal::namespace_ ns; + doc dc (ctx, cd_default, list); + class_ cl (ctx, list); + unit >> unit_names; + unit_names >> dc; + unit_names >> ns; + unit_names >> cl; + + traversal::names ns_names; + ns >> ns_names; + ns_names >> dc; + ns_names >> ns; + ns_names >> cl; + + if (ctx.options.class_ ().empty ()) + unit.dispatch (ctx.unit); + else + { + for (vector::const_iterator i (ctx.options.class_ ().begin ()); + i != ctx.options.class_ ().end (); ++i) + { + string n (*i); + + // Strip leading :: if present. + // + if (n.size () > 2 && n[0] == ':' && n[1] == ':') + n = string (n, 2, string::npos); + + if (semantics::class_* c = ctx.unit.lookup ("", n)) + cl.traverse (*c); + else + { + cerr << "error: class '" << *i << "' not found" << endl; + throw generation_failed (); + } + } + } + + if (list) + ctx.os << "
    " << endl + << endl; +} diff --git a/cli/cli/html.hxx b/cli/cli/html.hxx new file mode 100644 index 0000000..4ba5a41 --- /dev/null +++ b/cli/cli/html.hxx @@ -0,0 +1,13 @@ +// file : cli/html.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_HTML_HXX +#define CLI_HTML_HXX + +#include + +void +generate_html (context&); + +#endif // CLI_HTML_HXX diff --git a/cli/cli/inline.cxx b/cli/cli/inline.cxx new file mode 100644 index 0000000..05b83db --- /dev/null +++ b/cli/cli/inline.cxx @@ -0,0 +1,108 @@ +// file : cli/inline.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include + +namespace +{ + // + // + struct option: traversal::option, context + { + option (context& c) : context (c) {} + + virtual void + traverse (type& o) + { + string name (ename (o)); + string type (o.type ().name ()); + string scope (escape (o.scope ().name ())); + + os << inl << "const " << type << "& " << scope << "::" << endl + << name << " () const" + << "{" + << "return this->" << emember (o) << ";" + << "}"; + + if (gen_modifier) + { + os << inl << type << "& " << scope << "::" << endl + << name << " ()" + << "{" + << "return this->" << emember (o) << ";" + << "}"; + + os << inl << "void " << scope << "::" << endl + << name << "(const " << type << "& x)" + << "{" + << "this->" << emember (o) << " = x;" + << "}"; + } + + if (gen_specifier && type != "bool") + { + string spec (especifier (o)); + + os << inl << "bool " << scope << "::" << endl + << spec << " () const" + << "{" + << "return this->" << especifier_member (o) << ";" + << "}"; + + if (gen_modifier) + os << inl << "void " << scope << "::" << endl + << spec << "(bool x)" + << "{" + << "this->" << especifier_member (o) << " = x;" + << "}"; + } + } + }; + + // + // + struct class_: traversal::class_, context + { + class_ (context& c) + : context (c), option_ (c) + { + names_option_ >> option_; + } + + virtual void + traverse (type& c) + { + string name (escape (c.name ())); + + os << "// " << name << endl + << "//" << endl + << endl; + + names (c, names_option_); + } + + private: + option option_; + traversal::names names_option_; + }; +} + +void +generate_inline (context& ctx) +{ + traversal::cli_unit unit; + traversal::names unit_names; + namespace_ ns (ctx); + class_ cl (ctx); + + unit >> unit_names >> ns; + unit_names >> cl; + + traversal::names ns_names; + + ns >> ns_names >> ns; + ns_names >> cl; + + unit.dispatch (ctx.unit); +} diff --git a/cli/cli/inline.hxx b/cli/cli/inline.hxx new file mode 100644 index 0000000..38e7768 --- /dev/null +++ b/cli/cli/inline.hxx @@ -0,0 +1,13 @@ +// file : cli/inline.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_INLINE_HXX +#define CLI_INLINE_HXX + +#include + +void +generate_inline (context&); + +#endif // CLI_INLINE_HXX diff --git a/cli/cli/lexer.cxx b/cli/cli/lexer.cxx new file mode 100644 index 0000000..573c76b --- /dev/null +++ b/cli/cli/lexer.cxx @@ -0,0 +1,604 @@ +// file : cli/lexer.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include + +#include + +using namespace std; + +lexer:: +lexer (istream& is, string const& id) + : loc_ ("C"), + is_ (is), + id_ (id), + l_ (1), + c_(1), + eos_ (false), + include_ (false), + valid_ (true), + buf_ (0, 0, 0), + unget_ (false) +{ + keyword_map_["source"] = token::k_source; + keyword_map_["include"] = token::k_include; + keyword_map_["namespace"] = token::k_namespace; + keyword_map_["class"] = token::k_class; + keyword_map_["signed"] = token::k_signed; + keyword_map_["unsigned"] = token::k_unsigned; + keyword_map_["bool"] = token::k_bool; + keyword_map_["char"] = token::k_char; + keyword_map_["wchar_t"] = token::k_wchar; + keyword_map_["short"] = token::k_short; + keyword_map_["int"] = token::k_int; + keyword_map_["long"] = token::k_long; + keyword_map_["float"] = token::k_float; + keyword_map_["double"] = token::k_double; +} + +lexer::xchar lexer:: +peek () +{ + if (unget_) + return buf_; + else + { + if (eos_) + return xchar (xchar::traits_type::eof (), l_, c_); + else + { + xchar::int_type i (is_.peek ()); + + if (i == xchar::traits_type::eof ()) + eos_ = true; + + return xchar (i, l_, c_); + } + } +} + +lexer::xchar lexer:: +get () +{ + if (unget_) + { + unget_ = false; + return buf_; + } + else + { + // When is_.get () returns eof, the failbit is also set (stupid, + // isn't?) which may trigger an exception. To work around this + // we will call peek() first and only call get() if it is not + // eof. But we can only call peek() on eof once; any subsequent + // calls will spoil the failbit (even more stupid). + // + xchar c (peek ()); + + if (!is_eos (c)) + { + is_.get (); + + if (c == '\n') + { + l_++; + c_ = 1; + } + else + c_++; + } + + return c; + } +} + +void lexer:: +unget (xchar c) +{ + // Because iostream::unget cannot work once eos is reached, + // we have to provide our own implementation. + // + buf_ = c; + unget_ = true; +} + +token lexer:: +next () +{ + while (true) // Recovery loop. + { + bool include (include_); + include_ = false; + + skip_spaces (); + + xchar c (get ()); + + if (is_eos (c)) + return token (c.line (), c.column ()); + + try + { + switch (c) + { + case '\'': + { + return char_literal (c); + } + case '\"': + { + if (include) + return path_literal (c); + else + return string_literal (c); + } + case '<': + { + if (include) + return path_literal (c); + else + return template_expression (c); + } + case ';': + { + return token (token::p_semi, c.line (), c.column ()); + } + case ',': + { + return token (token::p_comma, c.line (), c.column ()); + } + case ':': + { + if (peek () == ':') + { + get (); + return token (token::p_dcolon, c.line (), c.column ()); + } + + return token (token::p_colon, c.line (), c.column ()); + } + case '{': + { + return token (token::p_lcbrace, c.line (), c.column ()); + } + case '}': + { + return token (token::p_rcbrace, c.line (), c.column ()); + } + case '(': + { + return call_expression (c); + } + case '=': + { + return token (token::p_eq, c.line (), c.column ()); + } + case '|': + { + return token (token::p_or, c.line (), c.column ()); + } + case '-': + { + // This can be a beginning of an identifier or a an integer + // literal. Figure out which one it is. + // + xchar p (peek ()); + + if (is_dec_digit (p)) + return int_literal (get (), true, c.line (), c.column ()); + else if (is_space (p)) + { + skip_spaces (); + p = peek (); + + if (is_dec_digit (p)) + return int_literal (get (), true, c.line (), c.column ()); + + // Stray '-'. + // + cerr << id_ << ':' << c.line () << ':' << c.column () + << ": error: unexpected character '-'" << endl; + throw invalid_input (); + } + + break; + } + } + + if (is_alpha (c) || c == '_' || c == '-' || c == '/') + { + return identifier (c); + } + + if (is_dec_digit (c)) + { + return int_literal (c); + } + + cerr << id_ << ':' << c.line () << ':' << c.column () + << ": error: unexpected character '" << c << "'" << endl; + throw invalid_input (); + } + catch (invalid_input const&) + { + valid_ = false; + } + + // Try to recover. + // + do + { + c = get (); + + if (is_eos (c)) + return token (c.line (), c.column ()); + } while (c != ';'); + } +} + +void lexer:: +skip_spaces () +{ + for (xchar c (peek ());; c = peek ()) + { + if (is_eos (c)) + break; + + if (c == '/') + { + c = get (); + xchar p (peek ()); + + if (p == '/') + { + get (); + + // C++ comment. Read until newline or eos. + // + for (c = get (); !is_eos (c) && c != '\n'; c = get ()) ; + continue; + } + else if (p == '*') + { + get (); + + // C comment. + // + for (c = get ();; c = get ()) + { + if (is_eos (c)) + { + cerr << id_ << ':' << c.line () << ':' << c.column () + << ": error: end of stream reached while reading " + << "C-style comment" << endl; + throw invalid_input (); + } + + if (c == '*') + { + c = peek (); + if (c == '/') + { + get (); + break; + } + } + } + continue; + } + else + { + unget (c); + break; + } + } + + if (!is_space (c)) + break; + + get (); + } +} + +token lexer:: +identifier (xchar c) +{ + size_t ln (c.line ()), cl (c.column ()); + string lexeme; + lexeme += c; + + bool check (c == '-' || c == '/'); + + for (c = peek (); + !is_eos (c) && (is_alnum (c) || c == '_' || c == '-'); + c = peek ()) + { + get (); + lexeme += c; + } + + // Check for invalid identifiers. + // + if (check) + { + size_t i (1); + + for (; i < lexeme.size (); ++i) + if (is_alnum (lexeme[i]) || lexeme[i] == '_') + break; + + if (i == lexeme.size ()) + { + cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " + << "invalid character sequence '" << lexeme << "'" << endl; + throw invalid_input (); + } + } + + keyword_map::const_iterator i (keyword_map_.find (lexeme)); + + if (i != keyword_map_.end ()) + { + if (i->second == token::k_include || i->second == token::k_source) + include_ = true; + + return token (i->second, ln, cl); + } + + if (lexeme == "true" || lexeme == "false") + return token (token::t_bool_lit, lexeme, ln, cl); + + return token (token::t_identifier, lexeme, ln, cl); +} + +token lexer:: +int_literal (xchar c, bool neg, size_t ml, size_t mc) +{ + size_t ln (neg ? ml : c.line ()), cl (neg ? mc : c.column ()); + string lexeme; + + if (neg) + lexeme += '-'; + + lexeme += c; + + for (c = peek (); !is_eos (c) && is_dec_digit (c); c = peek ()) + { + get (); + lexeme += c; + } + + return token (token::t_int_lit, lexeme, ln, cl); +} + +token lexer:: +char_literal (xchar c) +{ + size_t ln (c.line ()), cl (c.column ()); + string lexeme; + lexeme += c; + + char p (c); + + while (true) + { + c = get (); + + if (is_eos (c)) + { + cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " + << "end of stream reached while reading character literal" << endl; + throw invalid_input (); + } + + lexeme += c; + + if (c == '\'' && p != '\\') + break; + + // We need to keep track of \\ escapings so we don't confuse + // them with \', as in '\\'. + // + if (c == '\\' && p == '\\') + p = '\0'; + else + p = c; + } + + return token (token::t_char_lit, lexeme, ln, cl); +} + +token lexer:: +string_literal (xchar c) +{ + size_t ln (c.line ()), cl (c.column ()); + string lexeme; + lexeme += c; + + while (true) + { + lexeme += string_literal_trailer (); + + // Check if there are more strings. + // + skip_spaces (); + + c = peek (); + + if (is_eos (c) || c != '"') + break; + + get (); + lexeme += "\""; + } + + return token (token::t_string_lit, lexeme, ln, cl); +} + +string lexer:: +string_literal_trailer () +{ + string r; + char p ('\0'); + + while (true) + { + xchar c = get (); + + if (is_eos (c)) + { + cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " + << "end of stream reached while reading string literal" << endl; + throw invalid_input (); + } + + r += c; + + if (c == '"' && p != '\\') + break; + + // We need to keep track of \\ escapings so we don't confuse + // them with \", as in "\\". + // + if (c == '\\' && p == '\\') + p = '\0'; + else + p = c; + } + + return r; +} + +token lexer:: +path_literal (xchar c) +{ + size_t ln (c.line ()), cl (c.column ()); + string lexeme; + lexeme += c; + + char end (c == '<' ? '>' : '"'); + + while (true) + { + c = get (); + + if (is_eos (c)) + { + cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " + << "end of stream reached while reading path literal" << endl; + throw invalid_input (); + } + + lexeme += c; + + if (c == end) + break; + } + + token::token_type tt; + + if (lexeme.compare (1, 4, "c++:") == 0) + { + tt = token::t_cxx_path_lit; + lexeme = lexeme[0] + string (lexeme, 5, string::npos); + } + else if (lexeme.compare (1, 4, "cli:") == 0) + { + tt = token::t_cli_path_lit; + lexeme = lexeme[0] + string (lexeme, 5, string::npos); + } + else + { + // See if the path ends with .cli. If not, then we assume this is + // a C++ inclusion. + // + size_t n (lexeme.size ()); + + if (n > 5 && lexeme.compare (n - 5, 4, ".cli") == 0) + tt = token::t_cli_path_lit; + else + tt = token::t_cxx_path_lit; + } + + return token (tt, lexeme, ln, cl); +} + +token lexer:: +call_expression (xchar c) +{ + size_t ln (c.line ()), cl (c.column ()); + string lexeme; + lexeme += c; + size_t balance (1); + + while (balance != 0) + { + c = get (); + + if (is_eos (c)) + { + cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " + << "end of stream reached while reading call expression" << endl; + throw invalid_input (); + } + + lexeme += c; + + switch (c) + { + case '(': + { + balance++; + break; + } + case ')': + { + balance--; + break; + } + } + } + + return token (token::t_call_expr, lexeme, ln, cl); +} + +token lexer:: +template_expression (xchar c) +{ + size_t ln (c.line ()), cl (c.column ()); + string lexeme; + lexeme += c; + size_t balance (1); + + while (balance != 0) + { + c = get (); + + if (is_eos (c)) + { + cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " + << "end of stream reached while reading template expression" + << endl; + throw invalid_input (); + } + + lexeme += c; + + switch (c) + { + case '<': + { + balance++; + break; + } + case '>': + { + balance--; + break; + } + } + } + + return token (token::t_template_expr, lexeme, ln, cl); +} diff --git a/cli/cli/lexer.hxx b/cli/cli/lexer.hxx new file mode 100644 index 0000000..bd7b0c9 --- /dev/null +++ b/cli/cli/lexer.hxx @@ -0,0 +1,142 @@ +// file : cli/lexer.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_LEXER_HXX +#define CLI_LEXER_HXX + +#include +#include +#include +#include // std::size_t +#include + +#include + +class lexer +{ +public: + lexer (std::istream& is, std::string const& id); + + token + next (); + + bool + valid () const; + +protected: + class xchar + { + public: + typedef std::char_traits traits_type; + typedef traits_type::int_type int_type; + typedef traits_type::char_type char_type; + + xchar (int_type v, std::size_t l, std::size_t c); + + operator char_type () const; + + int_type + value () const; + + std::size_t + line () const; + + std::size_t + column () const; + + private: + int_type v_; + std::size_t l_; + std::size_t c_; + }; + + xchar + peek (); + + xchar + get (); + + void + unget (xchar); + +protected: + class invalid_input {}; + + void + skip_spaces (); + + token + identifier (xchar); + + token + int_literal (xchar, + bool neg = false, + std::size_t ml = 0, + std::size_t mc = 0); + + token + char_literal (xchar); + + token + string_literal (xchar); + + std::string + string_literal_trailer (); + + token + path_literal (xchar); + + token + call_expression (xchar); + + token + template_expression (xchar); + +protected: + bool + is_alpha (char c) const; + + bool + is_oct_digit (char c) const; + + bool + is_dec_digit (char c) const; + + bool + is_hex_digit (char c) const; + + bool + is_alnum (char c) const; + + bool + is_space (char c) const; + + bool + is_eos (xchar const& c) const; + + char + to_upper (char c) const; + +private: + typedef std::map keyword_map; + + std::locale loc_; + std::istream& is_; + std::string id_; + std::size_t l_; + std::size_t c_; + + keyword_map keyword_map_; + + bool eos_; + bool include_; // Literal in include or source. + bool valid_; + + xchar buf_; + bool unget_; +}; + +#include + +#endif // CLI_LEXER_HXX diff --git a/cli/cli/lexer.ixx b/cli/cli/lexer.ixx new file mode 100644 index 0000000..1c4c42e --- /dev/null +++ b/cli/cli/lexer.ixx @@ -0,0 +1,91 @@ +// file : cli/lexer.ixx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// lexer::xchar +// +inline lexer::xchar:: +xchar (int_type v, std::size_t l, std::size_t c) + : v_ (v), l_ (l), c_ (c) +{ +} + +inline lexer::xchar:: +operator char_type () const +{ + return traits_type::to_char_type (v_); +} + +inline lexer::xchar::int_type lexer::xchar:: +value () const +{ + return v_; +} + +inline std::size_t lexer::xchar:: +line () const +{ + return l_; +} + +inline std::size_t lexer::xchar:: +column () const +{ + return c_; +} + +// lexer +// +inline bool lexer:: +valid () const +{ + return valid_; +} + +inline bool lexer:: +is_alpha (char c) const +{ + return std::isalpha (c, loc_); +} + +inline bool lexer:: +is_oct_digit (char c) const +{ + return std::isdigit (c, loc_) && c != '8' && c != '9'; +} + +inline bool lexer:: +is_dec_digit (char c) const +{ + return std::isdigit (c, loc_); +} + +inline bool lexer:: +is_hex_digit (char c) const +{ + return std::isxdigit (c, loc_); +} + +inline bool lexer:: +is_alnum (char c) const +{ + return std::isalnum (c, loc_); +} + +inline bool lexer:: +is_space (char c) const +{ + return std::isspace (c, loc_); +} + +inline bool lexer:: +is_eos (xchar const& c) const +{ + return c.value () == xchar::traits_type::eof (); +} + +inline char lexer:: +to_upper (char c) const +{ + return std::toupper (c, loc_); +} diff --git a/cli/cli/lexer.test.cxx b/cli/cli/lexer.test.cxx new file mode 100644 index 0000000..0eb4dcb --- /dev/null +++ b/cli/cli/lexer.test.cxx @@ -0,0 +1,122 @@ +// file : cli/lexer.test.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include +#include + +#include +#include + +using namespace std; + +const char* keywords[] = +{ + "source", + "include", + "namespace", + "class", + "signed", + "unsigned", + "bool", + "char", + "wchar_t", + "short", + "int", + "long", + "float", + "double" +}; + +const char* punctuation[] = { + ";", ",", ":", "::", "{", "}", /*"(", ")",*/ "=", "|"}; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " file.cli" << endl; + return 1; + } + + ifstream ifs; + ifs.exceptions (ifstream::failbit | ifstream::badbit); + ifs.open (argv[1]); + + lexer l (ifs, argv[1]); + + while (true) + { + token t (l.next ()); + + switch (t.type ()) + { + case token::t_eos: + { + cout << "" << endl; + return 0; + } + case token::t_keyword: + { + cout << "keyword: " << keywords[t.keyword ()] << endl; + break; + } + case token::t_identifier: + { + cout << "identifier: " << t.identifier () << endl; + break; + } + case token::t_punctuation: + { + cout << punctuation[t.punctuation ()] << endl; + break; + } + case token::t_cxx_path_lit: + { + cout << "c++ path: " << t.literal () << endl; + break; + } + case token::t_cli_path_lit: + { + cout << "cli path: " << t.literal () << endl; + break; + } + case token::t_string_lit: + { + cout << t.literal () << endl; + break; + } + case token::t_char_lit: + { + cout << t.literal () << endl; + break; + } + case token::t_bool_lit: + { + cout << t.literal () << endl; + break; + } + case token::t_int_lit: + { + cout << t.literal () << endl; + break; + } + case token::t_float_lit: + { + cout << t.literal () << endl; + break; + } + case token::t_call_expr: + { + cout << t.expression () << endl; + break; + } + case token::t_template_expr: + { + cout << t.expression () << endl; + break; + } + } + } +} diff --git a/cli/cli/lexer.test.testscript b/cli/cli/lexer.test.testscript new file mode 100644 index 0000000..e2df5f6 --- /dev/null +++ b/cli/cli/lexer.test.testscript @@ -0,0 +1,191 @@ +# file : cli/lexer.test.testscript +# license : MIT; see accompanying LICENSE file + +# @@ Give tests some meaningfull descriptions. +# + +: 000 +: +cat <=test.cli; +help +help-me +-h +--help +--help-me +--help-me- +/h +/help-me +/help/me +--_ + +EOI +$* test.cli >>EOO +identifier: help +identifier: help-me +identifier: -h +identifier: --help +identifier: --help-me +identifier: --help-me- +identifier: /h +identifier: /help-me +identifier: /help +identifier: /me +identifier: --_ + +EOO + +: 001 +: +cat <=test.cli; +5 +123456 +-12345 +- 1 +- +123 +EOI +$* test.cli >>EOO +5 +123456 +-12345 +-1 +-123 + +EOO + +: 002 +: +cat <=test.cli; +'a' +'\n' +'\\' +'\0' +'\'' +'\xaf' +'\111' +EOI +$* test.cli >>EOO +'a' +'\n' +'\\' +'\0' +'\'' +'\xaf' +'\111' + +EOO + +: 003 +: +cat <=test.cli; +"abc"; +"a\nb"; +"abc\\"; +"aaa\0"; +"\""; +"a\xaf"; +"a\111"; +"abc""def"; +"abc" "def"; +"abc + def + + xyz"; +EOI +$* test.cli >>EOO +"abc" +; +"a\nb" +; +"abc\\" +; +"aaa\0" +; +"\"" +; +"a\xaf" +; +"a\111" +; +"abc""def" +; +"abc""def" +; +"abc + def + + xyz" +; + +EOO + +: 004 +: +cat <=test.cli; +include "foo/abc.hxx"; +include ; +include "c++:map"; +include ; +include "map.cli" +EOI +$* test.cli >>EOO +keyword: include +c++ path: "foo/abc.hxx" +; +keyword: include +c++ path: +; +keyword: include +c++ path: "map" +; +keyword: include +cli path: +; +keyword: include +cli path: "map.cli" + +EOO + +: 005 +: +cat <=test.cli; +(abc, 123 - 345, 12.34) + +EOI +$* test.cli >>EOO +(abc, 123 - 345, 12.34) + + +EOO + +: 006 +: +cat <=test.cli; +// c++ comment ; +/* c comment ; */ +; +"a" // foo +"b" +"a" /* foo +bar +baz */ "b"; +- // aaa +5; +- /* a +a +a*/ 5 +// eos +: +:: +EOI +$* test.cli >>EOO +; +"a""b""a""b" +; +-5 +; +-5 +: +:: + +EOO diff --git a/cli/cli/man.cxx b/cli/cli/man.cxx new file mode 100644 index 0000000..df703e8 --- /dev/null +++ b/cli/cli/man.cxx @@ -0,0 +1,278 @@ +// file : cli/man.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include +#include + +#include + +using namespace std; + +namespace +{ + // According to groff_mdoc(7), groff may have issues with any of the + // following characters at the beginning of the line: + // + // {}+-/*%<>=,&`'" + // + // Plus, escaping leading '.' with '\' is not sufficient. + // + static const string escape ("{}+-/*%<>=,&`'\""); + + static string + escape_line (const string& s, size_t b, size_t e) + { + string r; + size_t n (e - b); + + + if (escape.find (s[b]) != string::npos || + (n > 1 && s[b] == '\\' && s[b + 1] == '.')) + r = "\\&"; + + r.append (s, b, n); + return r; + } + + static void + wrap_lines (ostream& os, const string& d) + { + size_t b (0), e (0), i (0); + for (size_t n (d.size ()); i < n; ++i) + { + // First handle preformatted text (.nf/.fi). + // + if (d.compare (i, 4, ".nf\n") == 0 && (i == 0 || d[i - 1] == '\n')) + { + assert (b == i); // We should have nothing accumulated. + + // Output everything until (and including) closing .fi as is. + // + e = d.find ("\n.fi", i + 4); + assert (e != string::npos); + e += 4; // Now points past 'i'. + + os << string (d, i, e - i); + + b = e; + i = e - 1; // For ++i in loop header. + continue; + } + + if (d[i] == ' ' || d[i] == '\n') + e = i; + + if (d[i] == '\n' || (i - b >= 78 && e != b)) + { + os << escape_line (d, b, e) << endl; + b = e = e + 1; + } + } + + // Flush the last line. + // + if (b != i) + os << escape_line (d, b, i); + } + + struct doc: traversal::doc, context + { + doc (context& c, class_doc_type cd): context (c), cd_ (cd) {} + + virtual void + traverse (type& ds) + { + if (ds.name ().compare (0, 3, "doc") != 0) // Ignore doc variables. + return; + + // n = 1 - common doc string + // n = 2 - arg string, common doc string + // n > 2 - arg string, short string, long string + // + size_t n (ds.size ()); + const string& d ( + n == 1 + ? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0]) + : (n == 2 + ? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1]) + : ds[cd_ == cd_short ? 1 : 2])); + + std::set arg_set; + if (n > 1) + translate_arg (ds[0], arg_set); + + string s (format (ds.scope (), translate (d, arg_set), true)); + + if (s.empty ()) + return; + + wrap_lines (os, s); + os << endl; + } + + private: + class_doc_type cd_; + }; + + struct option: traversal::option, context + { + option (context& c, class_doc_type cd) : context (c), cd_ (cd) {} + + virtual void + traverse (type& o) + { + using semantics::names; + + semantics::doc_strings const& doc (o.doc ()); + + if (options.suppress_undocumented () && doc.empty ()) + return; + + names& n (o.named ()); + + os << ".IP \"\\fB"; + + for (names::name_iterator i (n.name_begin ()); i != n.name_end (); ++i) + { + if (i != n.name_begin ()) + os << "\\fR|\\fB"; + + os << *i; + } + + os << "\\fR"; + + string type (o.type ().name ()); + + std::set arg_set; + + if (type != "bool" || doc.size () >= 3) + { + string s ( + translate_arg ( + doc.size () > 0 ? doc[0] : string (""), arg_set)); + + os << ' ' << format (o.scope (), s, false); + } + + os << "\"" << endl; + + string d; + if (type == "bool" && doc.size () < 3) + { + if (doc.size () > 1) + d = doc[cd_ == cd_short ? 0 : 1]; + else if (doc.size () > 0) + d = (cd_ == cd_short ? first_sentence (doc[0]) : doc[0]); + } + else + { + if (doc.size () > 2) + d = doc[cd_ == cd_short ? 1 : 2]; + else if (doc.size () > 1) + d = (cd_ == cd_short ? first_sentence (doc[1]) : doc[1]); + } + + // Format the documentation string. + // + d = format (o.scope (), translate (d, arg_set), false); + + wrap_lines (os, d); + os << endl; + } + + private: + class_doc_type cd_; + }; + + // + // + struct class_: traversal::class_, context + { + class_ (context& c): context (c), base_ (false) + { + *this >> inherits_ >> *this; + } + + virtual void + traverse (type& c) + { + class_doc_type cd (class_doc (c)); + + if (cd == cd_exclude || (base_ && cd == cd_exclude_base)) + return; + + if (!options.exclude_base () && !options.include_base_last ()) + { + bool ob (base_); + base_ = true; + inherits (c); + base_ = ob; + } + + doc dc (*this, cd); + option op (*this, cd); + traversal::names n; + n >> dc; + n >> op; + names (c, n); + + if (!options.exclude_base () && options.include_base_last ()) + { + bool ob (base_); + base_ = true; + inherits (c); + base_ = ob; + } + } + + private: + bool base_; + traversal::inherits inherits_; + }; +} + +void +generate_man (context& ctx) +{ + traversal::cli_unit unit; + traversal::names unit_names; + traversal::namespace_ ns; + doc dc (ctx, cd_default); + class_ cl (ctx); + unit >> unit_names; + unit_names >> ns; + unit_names >> dc; + unit_names >> cl; + + traversal::names ns_names; + ns >> ns_names; + ns_names >> ns; + ns_names >> dc; + ns_names >> cl; + + if (ctx.options.class_ ().empty ()) + unit.dispatch (ctx.unit); + else + { + for (vector::const_iterator i (ctx.options.class_ ().begin ()); + i != ctx.options.class_ ().end (); ++i) + { + string n (*i); + + // Strip leading :: if present. + // + if (n.size () > 2 && n[0] == ':' && n[1] == ':') + n = string (n, 2, string::npos); + + if (semantics::class_* c = ctx.unit.lookup ("", n)) + cl.traverse (*c); + else + { + cerr << "error: class '" << *i << "' not found" << endl; + throw generation_failed (); + } + } + } +} diff --git a/cli/cli/man.hxx b/cli/cli/man.hxx new file mode 100644 index 0000000..0825305 --- /dev/null +++ b/cli/cli/man.hxx @@ -0,0 +1,13 @@ +// file : cli/man.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_MAN_HXX +#define CLI_MAN_HXX + +#include + +void +generate_man (context&); + +#endif // CLI_MAN_HXX diff --git a/cli/cli/name-processor.cxx b/cli/cli/name-processor.cxx new file mode 100644 index 0000000..ab125bc --- /dev/null +++ b/cli/cli/name-processor.cxx @@ -0,0 +1,193 @@ +// file : cli/name-processor.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include +#include + +#include +#include + +using namespace std; + +namespace +{ + typedef set name_set; + typedef ::context context_base; + + struct context: context_base + { + context (context_base& c): context_base (c) {} + context (context& c): context_base (c) {} + + public: + string + find_name (string const& n, string const& suffix, name_set& set) + { + string name (escape (n + suffix)); + + for (size_t i (1); set.find (name) != set.end (); ++i) + { + ostringstream os; + os << i; + name = escape (n + os.str () + suffix); + } + + set.insert (name); + return name; + } + + string + find_name (string const& n, name_set& set) + { + return find_name (n, "", set); + } + }; + + struct primary_option: traversal::option, context + { + primary_option (context& c, name_set& set) + : context (c), set_ (set) + { + } + + virtual void + traverse (type& o) + { + string n (o.name ()), name; + + // Get rid of leading special characters, e.f., -, --, /, etc. + // + for (size_t i (0); i < n.size (); ++i) + { + if (isalpha (n[i]) || n[i] == '_') + { + name.assign (n.c_str (), i, n.size () - i); + break; + } + } + + o.context ().set ("name", find_name (name, set_)); + } + + private: + name_set& set_; + }; + + struct intermediate_option: traversal::option, context + { + intermediate_option (context& c, name_set& set) + : context (c), set_ (set) + { + } + + virtual void + traverse (type& o) + { + if (gen_specifier && o.type ().name () != "bool") + { + semantics::context& oc (o.context ()); + string const& base (oc.get ("name")); + oc.set ("specifier", find_name (base + "_specified", set_)); + } + } + + private: + name_set& set_; + }; + + struct secondary_option: traversal::option, context + { + secondary_option (context& c, name_set& set) + : context (c), set_ (set) + { + } + + virtual void + traverse (type& o) + { + semantics::context& oc (o.context ()); + string const& base (oc.get ("name")); + oc.set ("member", find_name (base + "_", set_)); + + if (gen_specifier && o.type ().name () != "bool") + { + string const& base (oc.get ("specifier")); + oc.set ("specifier-member", find_name (base + "_", set_)); + } + } + + private: + name_set& set_; + }; + + struct class_: traversal::class_, context + { + class_ (context& c) : context (c) {} + + virtual void + traverse (type& c) + { + semantics::context& cc (c.context ()); + + cc.set ("member-name-set", name_set ()); + name_set& member_set (cc.get ("member-name-set")); + + member_set.insert (escape (c.name ())); + + // First assign primary names. + // + { + primary_option option (*this, member_set); + traversal::names names (option); + + class_::names (c, names); + } + + // Then assign intermediate names. + // + { + intermediate_option option (*this, member_set); + traversal::names names (option); + + class_::names (c, names); + } + + // Finally assign secondary names. + // + { + secondary_option option (*this, member_set); + traversal::names names (option); + + class_::names (c, names); + } + } + }; + + void + process_names_ (context_base& c) + { + context ctx (c); + + traversal::cli_unit unit; + traversal::names unit_names; + traversal::namespace_ ns; + class_ cl (ctx); + + unit >> unit_names >> ns; + unit_names >> cl; + + traversal::names ns_names; + + ns >> ns_names >> ns; + ns_names >> cl; + + unit.dispatch (ctx.unit); + } +} + +void +process_names (context_base& c) +{ + process_names_ (c); +} diff --git a/cli/cli/name-processor.hxx b/cli/cli/name-processor.hxx new file mode 100644 index 0000000..c21561b --- /dev/null +++ b/cli/cli/name-processor.hxx @@ -0,0 +1,13 @@ +// file : cli/name-processor.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_NAME_PROCESSOR_HXX +#define CLI_NAME_PROCESSOR_HXX + +#include + +void +process_names (context&); + +#endif // CLI_NAME_PROCESSOR_HXX diff --git a/cli/cli/option-types.cxx b/cli/cli/option-types.cxx new file mode 100644 index 0000000..da1f434 --- /dev/null +++ b/cli/cli/option-types.cxx @@ -0,0 +1,43 @@ +// file : cli/option-types.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include + +#include + +using namespace std; + +static const char* cxx_version_[] = +{ + "c++98", + "c++11" + "c++14" +}; + +string cxx_version:: +string () const +{ + return cxx_version_[v_]; +} + +istream& +operator>> (istream& is, cxx_version& v) +{ + string s; + is >> s; + + if (!is.fail ()) + { + if (s == "c++98") + v = cxx_version::cxx98; + else if (s == "c++11") + v = cxx_version::cxx11; + else if (s == "c++14") + v = cxx_version::cxx14; + else + is.setstate (istream::failbit); + } + + return is; +} diff --git a/cli/cli/option-types.hxx b/cli/cli/option-types.hxx new file mode 100644 index 0000000..02d9ede --- /dev/null +++ b/cli/cli/option-types.hxx @@ -0,0 +1,33 @@ +// file : cli/option-types.hxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef CLI_OPTION_TYPES_HXX +#define CLI_OPTION_TYPES_HXX + +#include +#include + +struct cxx_version +{ + enum value + { + cxx98, + cxx11, + cxx14 + }; + + cxx_version (value v = value (0)) : v_ (v) {} + operator value () const {return v_;} + + std::string + string () const; + +private: + value v_; +}; + +std::istream& +operator>> (std::istream&, cxx_version&); + +#endif // CLI_OPTION_TYPES_HXX diff --git a/cli/cli/options.cli b/cli/cli/options.cli new file mode 100644 index 0000000..e564bc4 --- /dev/null +++ b/cli/cli/options.cli @@ -0,0 +1,662 @@ +// file : cli/options.cli +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +// NOTE: Make sure you have a working CLI compiler around before +// modifying this file. +// + +include ; +include ; +include ; +include ; + +include ; + +class options +{ + bool --build2-metadata; // Leave undocumented/hidden. + + bool --help {"Print usage information and exit."}; + bool --version {"Print version and exit."}; + + std::vector --include-path | -I + { + "", + "Search for bracket-included (\cb{<>}) options files." + }; + + std::string --output-dir | -o + { + "", + "Write the generated files to instead of the current directory." + }; + + cxx_version --std = cxx_version::cxx98 + { + "", + "Specify the C++ standard that should be used during compilation. + Valid values are \cb{c++98} (default), \cb{c++11}, and \cb{c++14}." + }; + + bool --generate-modifier + { + "Generate option value modifiers in addition to accessors." + }; + + bool --generate-specifier + { + "Generate functions for determining whether the option was specified + on the command line." + }; + + bool --generate-parse + { + "Generate \cb{parse()} functions instead of parsing constructors. This is + primarily useful for being able to parse into an already initialized + options class instance, for example, to implement option + appending/overriding." + }; + + bool --generate-merge + { + "Generate \cb{merge()} functions. This is primarily useful for being able + to merge several already parsed options class instances, for example, to + implement option appending/overriding. Note that this option forces + \cb{--generate-specifier}." + }; + + bool --generate-description + { + "Generate the option description list that can be examined at runtime." + }; + + bool --generate-file-scanner + { + "Generate the \cb{argv_file_scanner} implementation. This scanner is + capable of reading command line arguments from the \cb{argv} array as + well as files specified with command line options." + }; + + bool --generate-vector-scanner + { + "Generate the \cb{vector_scanner} implementation. This scanner is capable + of reading command line arguments from \cb{vector}." + }; + + bool --generate-group-scanner + { + "Generate the \cb{group_scanner} implementation. This scanner supports + grouping of arguments (usually options) to apply only to a certain + argument. + + Groups can be specified before (leading) and/or after (trailing) the + argument they apply to. A leading group starts with '\cb{{}' and ends + with '\cb{\}+}' while a trailing group starts with '\cb{+{}' and ends + with '\cb{\}}'. For example: + + \ + { --foo --bar }+ arg # 'arg' with '--foo' '--bar' + arg +{ fox=1 baz=2 } # 'arg' with 'fox=1' 'baz=2' + \ + + Multiple leading and/or trailing groups can be specified for the + same argument. For example: + + \ + { -f }+ { -b }+ arg +{ f=1 } +{ b=2 } # 'arg' with '-f' 'b' 'f=1' 'b=2' + \ + + Note that the group applies to a single argument only. For example: + + \ + { --foo }+ arg1 arg2 +{ --bar } # 'arg1' with '--foo' and + # 'arg2' with '--bar' + \ + + The group separators ('\cb{{}', '\cb{\}+'}, etc) must be separate command + line arguments. In particular, they must not be adjacent either to the + arguments inside the group nor to the argument they apply to. All such + cases will be treated as ordinary arguments. For example: + + \ + {--foo}+ arg # '{--foo}+' ... + arg+{ --foo } # 'arg+{' ... + \ + + If one of the group separators needs to be specified as an argument + verbatim, then it must be escaped with '\cb{\\}'. For example: + + \ + } # error: unexpected group separator + }x # '}x' + \} # '}' + { \}+ }+ arg # 'arg' with '}+' + \ + " + }; + + bool --suppress-inline + { + "Generate all functions non-inline. By default simple functions are + made inline. This option suppresses creation of the inline file." + }; + + bool --suppress-cli + { + "Do not generate the CLI support types (scanners, parser, etc). Normally, + the support types are generated unless another \cb{.cli} was included, + in which case the support types are expected to be provided by its + generated code." + }; + + std::string --cli-namespace = "::cli" + { + "", + "Generate the CLI support types in the namespace (\cb{cli} by + default). The namespace can be nested, for example \cb{details::cli}. + If the namespace is empty, then the support types are generated in + the global namespace." + }; + + std::string --ostream-type = "::std::ostream" + { + "", + "Output stream type instead of the default \cb{std::ostream} that + should be used to print usage and exception information." + }; + + bool --generate-cxx + { + "Generate C++ code. If neither \cb{--generate-man}, \cb{--generate-html}, + nor \cb{--generate-txt} is specified, this mode is assumed by default." + }; + + bool --generate-man + { + "Generate documentation in the man page format." + }; + + bool --generate-html + { + "Generate documentation in the HTML format." + }; + + bool --generate-txt + { + "Generate documentation in the plain text format, similar to usage." + }; + + bool --stdout + { + "Write output to STDOUT instead of a file. This option is not valid + when generating C++ code and is normally used to combine generated + documentation for several option classes in a single file." + }; + + bool --suppress-undocumented + { + "Suppress the generation of documentation entries for undocumented + options." + }; + + bool --suppress-usage + { + "Suppress the generation of the usage printing code." + }; + + bool --long-usage + { + "If no short documentation string is provided, use the complete + long documentation string in usage. By default, in this situation + only the first sentence from the long string is used." + }; + + bool --short-usage + { + "If specified together with \cb{--long-usage}, generate both short + and long usage versions. In this mode, the long usage printing function + is called \cb{print_long_usage()} and in its implementation the long + documentation string is always used, even if the short version is + provided." + }; + + std::string --page-usage + { + "", + "Generate the combined usage printing code for the entire page. + Specifically, this will include all the namespace-level documentation as + well as usage for all the options classes printed in the order they are + defined in the main translation unit (documentation/classes from included + units are ignored except for base classes). + + The argument is used as a prefix to form the name of the usage + printing function. It can include the namespace qualification as well + as documentation variable expansion, for example: + + \ + --page-usage print_ # print_usage() in global namespace + --page-usage app::print_ # print_usage() in app namespace + --page-usage print_$name$_ # print_foo_usage() if name is foo + \ + + If both \cb{--long-usage} and \cb{--short-usage} options are specified, + then the long usage function has the \cb{*long_usage()} suffix." + }; + + std::size_t --option-length = 0 + { + "", + "Indent option descriptions characters when printing usage. This is + useful when you have multiple options classes, potentially in separate + files, and would like their usage to have the same indentation level." + }; + + bool --ansi-color + { + "Use ANSI color escape sequences when printing usage. By \"color\" we + really only mean the bold and underline modifiers. Note that Windows + console does not recognize ANSI escape sequences and will display + them as garbage. However, if you pipe such output through \cb{less(1)}, + it will display them correctly." + }; + + bool --exclude-base + { + "Exclude base class information from usage and documentation." + }; + + bool --include-base-last + { + "Include base class information after derived for usage and documentation. + By default, base classes are included first." + }; + + std::map --class-doc + { + "=", + "Specify the documentation that should be used for the options class + . The value should be a fully-qualified class name, for + example, \cb{app::options}. The value can be \cb{short}, + \cb{long}, \cb{exclude}, or \cb{exclude-base}. If the value is + \cb{exclude}, then the class documentation is excluded from usage and + man/HTML/text output. If it is \cb{exclude-base}, then it is only + excluded when used as a base. For usage, the \cb{short} and \cb{long} + values determine which usage function will be called when the class is + used as base or as part of the page usage (see \cb{--page-usage}). For + man/HTML/text, these values determine which documentation strings are + used in the output." + }; + + std::vector --class + { + "", + "Generate the man page, HTML, or text documentation only for the options + class . The value should be a fully-qualified options class + name, for example, \cb{app::options}. To generate documentation for + multiple classes, repeat this option and the documentation will be + produced in the order specified. This functionality is useful if you need + to assemble documentation from multiple classes in a specific order or to + insert custom documentation between options belonging to different + classes." + }; + + std::map --docvar|-v + { + "=", + "Set documentation variable to the value . Documentation + variables can be substituted in prologues and epilogues (see + \cb{--*-prologue*} and \cb{--*-epilogue*} options) using the + \cb{$}\cb{$} expansion syntax (use \cb{$$} to escape expansion). + They can also be defined in \cb{.cli} files using the + \c{\"\\=\"} syntax." + }; + + std::vector --link-regex + { + "", + "Add to the list of regular expressions used to transform link + targets in the generated documentation. The argument to this option + is a Perl-like regular expression in the form + \c{\b{/}\i{pattern}\b{/}\i{replacement}\b{/}}. Any character can be + used as a delimiter instead of '\cb{/}' and the delimiter can be escaped + inside \ci{pattern} and \ci{replacement} with a backslash (\cb{\\}). + You can specify multiple regular expressions by repeating this option. + All the regular expressions are tried in the order specified and the + first expression that matches is used. Use the \cb{--link-regex-trace} + option to debug link transformation." + }; + + bool --link-regex-trace + { + "Trace the process of applying regular expressions specified with the + \cb{--link-regex} option. Use this option to find out why your regular + expressions don't do what you expected them to do." + }; + + std::map --html-heading-map + { + "=", + "Map CLI heading (valid values: '\cb{H}', '\cb{0}', '\cb{1}', + '\cb{h}', and '\cb{2}') to HTML heading (for example, '\cb{h1}', + '\cb{h2}', etc)." + }; + + bool --omit-link-check + { + "Don't check that local fragment link references (\\l{#ref ...}) resolve + to ids." + }; + + // Prologues. + // + std::vector --hxx-prologue + { + "", + "Insert at the beginning of the generated C++ header file." + }; + + std::vector --ixx-prologue + { + "", + "Insert at the beginning of the generated C++ inline file." + }; + + std::vector --cxx-prologue + { + "", + "Insert at the beginning of the generated C++ source file." + }; + + std::vector --man-prologue + { + "", + "Insert at the beginning of the generated man page file." + }; + + std::vector --html-prologue + { + "", + "Insert at the beginning of the generated HTML file." + }; + + std::vector --txt-prologue + { + "", + "Insert at the beginning of the generated text file." + }; + + // Epilogues. + // + std::vector --hxx-epilogue + { + "", + "Insert at the end of the generated C++ header file." + }; + + std::vector --ixx-epilogue + { + "", + "Insert at the end of the generated C++ inline file." + }; + + std::vector --cxx-epilogue + { + "", + "Insert at the end of the generated C++ source file." + }; + + std::vector --man-epilogue + { + "", + "Insert at the end of the generated man page file." + }; + + std::vector --html-epilogue + { + "", + "Insert at the end of the generated HTML file." + }; + + std::vector --txt-epilogue + { + "", + "Insert at the end of the generated text file." + }; + + // Prologue files. + // + std::string --hxx-prologue-file + { + "", + "Insert the content of at the beginning of the generated C++ + header file." + }; + + std::string --ixx-prologue-file + { + "", + "Insert the content of at the beginning of the generated C++ + inline file." + }; + + std::string --cxx-prologue-file + { + "", + "Insert the content of at the beginning of the generated C++ + source file." + }; + + std::string --man-prologue-file + { + "", + "Insert the content of at the beginning of the generated man + page file." + }; + + std::string --html-prologue-file + { + "", + "Insert the content of at the beginning of the generated HTML + file." + }; + + std::string --txt-prologue-file + { + "", + "Insert the content of at the beginning of the generated text + file." + }; + + // Epilogue files. + // + std::string --hxx-epilogue-file + { + "", + "Insert the content of at the end of the generated C++ header + file." + }; + + std::string --ixx-epilogue-file + { + "", + "Insert the content of at the end of the generated C++ inline + file." + }; + + std::string --cxx-epilogue-file + { + "", + "Insert the content of at the end of the generated C++ source + file." + }; + + std::string --man-epilogue-file + { + "", + "Insert the content of at the end of the generated man page file." + }; + + std::string --html-epilogue-file + { + "", + "Insert the content of at the end of the generated HTML file." + }; + + std::string --txt-epilogue-file + { + "", + "Insert the content of at the end of the generated text file." + }; + + // Output. + // + std::string --output-prefix + { + "", + "Add at the beginning of the generated output file name(s)." + }; + + std::string --output-suffix + { + "", + "Add at the end of the generated output file name(s). Note that + it is added before any file type-specific suffixes; see \cb{--*-suffix} + below." + }; + + std::string --hxx-suffix = ".hxx" + { + "", + "Use instead of the default \cb{.hxx} to construct the name of + the generated header file." + }; + + std::string --ixx-suffix = ".ixx" + { + "", + "Use instead of the default \cb{.ixx} to construct the name of + the generated inline file." + }; + + std::string --cxx-suffix = ".cxx" + { + "", + "Use instead of the default \cb{.cxx} to construct the name of + the generated source file." + }; + + std::string --man-suffix = ".1" + { + "", + "Use instead of the default \cb{.1} to construct the name of + the generated man page file." + }; + + std::string --html-suffix = ".html" + { + "", + "Use instead of the default \cb{.html} to construct the name + of the generated HTML file." + }; + + std::string --txt-suffix = ".txt" + { + "", + "Use instead of the default \cb{.txt} to construct the name of + the generated text file." + }; + + std::string --option-prefix = "-" + { + "", + "Use instead of the default '\cb{-}' as an option prefix. Unknown + command line arguments that start with this prefix are treated as unknown + options. If you set the option prefix to the empty value, then all the + unknown command line arguments will be treated as program arguments." + }; + + std::string --option-separator = "--" + { + "", + "Use instead of the default '\cb{--}' as an optional separator + between options and arguments. All the command line arguments that are + parsed after this separator are treated as program arguments. Set the + option separator to the empty value if you don't want this functionality." + }; + + bool --keep-separator + { + "Leave the option separator in the scanner. This is primarily useful for + incremental option parsing." + }; + + bool --no-combined-flags + { + "Disable support for combining multiple single-character flags into a + single argument (the \cb{-xyz} form that is equivalent to \cb{-x} \cb{-y} + \cb{-z}). An argument is considered a combination of flags if it starts + with a single option prefix (\cb{--option-prefix}) and only contains + letters and digits. Note that an option with a value may not be part of + such a combination, not even if it is specified last." + } + + bool --no-combined-values + { + "Disable support for combining an option and its value into a single + argument with the assignment sign (the \c{\i{option}\b{=}\i{value}} + form). This functionality requires a non-empty option prefix + (\cb{--option-prefix})." + } + + bool --include-with-brackets + { + "Use angle brackets (\cb{<>}) instead of quotes (\cb{\"\"}) in the + generated \cb{#include} directives." + }; + + std::string --include-prefix + { + "", + "Add to the generated \cb{#include} directive paths." + }; + + std::string --guard-prefix + { + "", + "Add to the generated header inclusion guards. The prefix is + transformed to upper case and characters that are illegal in a + preprocessor macro name are replaced with underscores." + }; + + std::map --reserved-name + { + "=", + "Add with an optional replacement to the list of names + that should not be used as identifiers. If provided, the replacement + name is used instead. All C++ keywords are already in this list." + }; + + // This is a "fake" option in that it is actually handled by + // argv_file_scanner. We have it here to get the documentation. + // + std::string --options-file + { + "", + "Read additional options from . Each option should appear on a + separate line optionally followed by space or equal sign (\cb{=}) and an + option value. Empty lines and lines starting with \cb{#} are ignored. + Option values can be enclosed in double (\cb{\"}) or single (\cb{'}) + quotes to preserve leading and trailing whitespaces as well as to specify + empty values. If the value itself contains trailing or leading quotes, + enclose it with an extra pair of quotes, for example \cb{'\"x\"'}. + Non-leading and non-trailing quotes are interpreted as being part of the + option value. + + The semantics of providing options in a file is equivalent to providing + the same set of options in the same order on the command line at the + point where the \cb{--options-file} option is specified except that + the shell escaping and quoting is not required. Repeat this option + to specify more than one options file." + }; +}; diff --git a/cli/cli/options.cxx b/cli/cli/options.cxx new file mode 100644 index 0000000..cc22a35 --- /dev/null +++ b/cli/cli/options.cxx @@ -0,0 +1,2146 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cli +{ + // unknown_option + // + unknown_option:: + ~unknown_option () throw () + { + } + + void unknown_option:: + print (::std::ostream& os) const + { + os << "unknown option '" << option ().c_str () << "'"; + } + + const char* unknown_option:: + what () const throw () + { + return "unknown option"; + } + + // unknown_argument + // + unknown_argument:: + ~unknown_argument () throw () + { + } + + void unknown_argument:: + print (::std::ostream& os) const + { + os << "unknown argument '" << argument ().c_str () << "'"; + } + + const char* unknown_argument:: + what () const throw () + { + return "unknown argument"; + } + + // missing_value + // + missing_value:: + ~missing_value () throw () + { + } + + void missing_value:: + print (::std::ostream& os) const + { + os << "missing value for option '" << option ().c_str () << "'"; + } + + const char* missing_value:: + what () const throw () + { + return "missing option value"; + } + + // invalid_value + // + invalid_value:: + ~invalid_value () throw () + { + } + + void invalid_value:: + print (::std::ostream& os) const + { + os << "invalid value '" << value ().c_str () << "' for option '" + << option ().c_str () << "'"; + + if (!message ().empty ()) + os << ": " << message ().c_str (); + } + + const char* invalid_value:: + what () const throw () + { + return "invalid option value"; + } + + // eos_reached + // + void eos_reached:: + print (::std::ostream& os) const + { + os << what (); + } + + const char* eos_reached:: + what () const throw () + { + return "end of argument stream reached"; + } + + // file_io_failure + // + file_io_failure:: + ~file_io_failure () throw () + { + } + + void file_io_failure:: + print (::std::ostream& os) const + { + os << "unable to open file '" << file ().c_str () << "' or read failure"; + } + + const char* file_io_failure:: + what () const throw () + { + return "unable to open file or read failure"; + } + + // unmatched_quote + // + unmatched_quote:: + ~unmatched_quote () throw () + { + } + + void unmatched_quote:: + print (::std::ostream& os) const + { + os << "unmatched quote in argument '" << argument ().c_str () << "'"; + } + + const char* unmatched_quote:: + what () const throw () + { + return "unmatched quote"; + } + + // scanner + // + scanner:: + ~scanner () + { + } + + // argv_scanner + // + bool argv_scanner:: + more () + { + return i_ < argc_; + } + + const char* argv_scanner:: + peek () + { + if (i_ < argc_) + return argv_[i_]; + else + throw eos_reached (); + } + + const char* argv_scanner:: + next () + { + if (i_ < argc_) + { + const char* r (argv_[i_]); + + if (erase_) + { + for (int i (i_ + 1); i < argc_; ++i) + argv_[i - 1] = argv_[i]; + + --argc_; + argv_[argc_] = 0; + } + else + ++i_; + + return r; + } + else + throw eos_reached (); + } + + void argv_scanner:: + skip () + { + if (i_ < argc_) + ++i_; + else + throw eos_reached (); + } + + // argv_file_scanner + // + int argv_file_scanner::zero_argc_ = 0; + std::string argv_file_scanner::empty_string_; + + bool argv_file_scanner:: + more () + { + if (!args_.empty ()) + return true; + + while (base::more ()) + { + // See if the next argument is the file option. + // + const char* a (base::peek ()); + const option_info* oi = 0; + const char* ov = 0; + + if (!skip_) + { + if ((oi = find (a)) != 0) + { + base::next (); + + if (!base::more ()) + throw missing_value (a); + + ov = base::next (); + } + else if (std::strncmp (a, "-", 1) == 0) + { + if ((ov = std::strchr (a, '=')) != 0) + { + std::string o (a, 0, ov - a); + if ((oi = find (o.c_str ())) != 0) + { + base::next (); + ++ov; + } + } + } + } + + if (oi != 0) + { + if (oi->search_func != 0) + { + std::string f (oi->search_func (ov, oi->arg)); + + if (!f.empty ()) + load (f); + } + else + load (ov); + + if (!args_.empty ()) + return true; + } + else + { + if (!skip_) + skip_ = (std::strcmp (a, "--") == 0); + + return true; + } + } + + return false; + } + + const char* argv_file_scanner:: + peek () + { + if (!more ()) + throw eos_reached (); + + return args_.empty () ? base::peek () : args_.front ().value.c_str (); + } + + const std::string& argv_file_scanner:: + peek_file () + { + if (!more ()) + throw eos_reached (); + + return args_.empty () ? empty_string_ : *args_.front ().file; + } + + std::size_t argv_file_scanner:: + peek_line () + { + if (!more ()) + throw eos_reached (); + + return args_.empty () ? 0 : args_.front ().line; + } + + const char* argv_file_scanner:: + next () + { + if (!more ()) + throw eos_reached (); + + if (args_.empty ()) + return base::next (); + else + { + hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value); + args_.pop_front (); + return hold_[i_].c_str (); + } + } + + void argv_file_scanner:: + skip () + { + if (!more ()) + throw eos_reached (); + + if (args_.empty ()) + return base::skip (); + else + args_.pop_front (); + } + + const argv_file_scanner::option_info* argv_file_scanner:: + find (const char* a) const + { + for (std::size_t i (0); i < options_count_; ++i) + if (std::strcmp (a, options_[i].option) == 0) + return &options_[i]; + + return 0; + } + + void argv_file_scanner:: + load (const std::string& file) + { + using namespace std; + + ifstream is (file.c_str ()); + + if (!is.is_open ()) + throw file_io_failure (file); + + files_.push_back (file); + + arg a; + a.file = &*files_.rbegin (); + + for (a.line = 1; !is.eof (); ++a.line) + { + string line; + getline (is, line); + + if (is.fail () && !is.eof ()) + throw file_io_failure (file); + + string::size_type n (line.size ()); + + // Trim the line from leading and trailing whitespaces. + // + if (n != 0) + { + const char* f (line.c_str ()); + const char* l (f + n); + + const char* of (f); + while (f < l && (*f == ' ' || *f == '\t' || *f == '\r')) + ++f; + + --l; + + const char* ol (l); + while (l > f && (*l == ' ' || *l == '\t' || *l == '\r')) + --l; + + if (f != of || l != ol) + line = f <= l ? string (f, l - f + 1) : string (); + } + + // Ignore empty lines, those that start with #. + // + if (line.empty () || line[0] == '#') + continue; + + string::size_type p (string::npos); + if (line.compare (0, 1, "-") == 0) + { + p = line.find (' '); + + string::size_type q (line.find ('=')); + if (q != string::npos && q < p) + p = q; + } + + string s1; + if (p != string::npos) + { + s1.assign (line, 0, p); + + // Skip leading whitespaces in the argument. + // + if (line[p] == '=') + ++p; + else + { + n = line.size (); + for (++p; p < n; ++p) + { + char c (line[p]); + if (c != ' ' && c != '\t' && c != '\r') + break; + } + } + } + else if (!skip_) + skip_ = (line == "--"); + + string s2 (line, p != string::npos ? p : 0); + + // If the string (which is an option value or argument) is + // wrapped in quotes, remove them. + // + n = s2.size (); + char cf (s2[0]), cl (s2[n - 1]); + + if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'') + { + if (n == 1 || cf != cl) + throw unmatched_quote (s2); + + s2 = string (s2, 1, n - 2); + } + + if (!s1.empty ()) + { + // See if this is another file option. + // + const option_info* oi; + if (!skip_ && (oi = find (s1.c_str ()))) + { + if (s2.empty ()) + throw missing_value (oi->option); + + if (oi->search_func != 0) + { + std::string f (oi->search_func (s2.c_str (), oi->arg)); + if (!f.empty ()) + load (f); + } + else + load (s2); + + continue; + } + + a.value = s1; + args_.push_back (a); + } + + a.value = s2; + args_.push_back (a); + } + } + + template + struct parser + { + static void + parse (X& x, bool& xs, scanner& s) + { + using namespace std; + + const char* o (s.next ()); + if (s.more ()) + { + string v (s.next ()); + istringstream is (v); + if (!(is >> x && is.peek () == istringstream::traits_type::eof ())) + throw invalid_value (o, v); + } + else + throw missing_value (o); + + xs = true; + } + }; + + template <> + struct parser + { + static void + parse (bool& x, scanner& s) + { + s.next (); + x = true; + } + }; + + template <> + struct parser + { + static void + parse (std::string& x, bool& xs, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + x = s.next (); + else + throw missing_value (o); + + xs = true; + } + }; + + template + struct parser > + { + static void + parse (std::vector& c, bool& xs, scanner& s) + { + X x; + bool dummy; + parser::parse (x, dummy, s); + c.push_back (x); + xs = true; + } + }; + + template + struct parser > + { + static void + parse (std::set& c, bool& xs, scanner& s) + { + X x; + bool dummy; + parser::parse (x, dummy, s); + c.insert (x); + xs = true; + } + }; + + template + struct parser > + { + static void + parse (std::map& m, bool& xs, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + { + std::string ov (s.next ()); + std::string::size_type p = ov.find ('='); + + K k = K (); + V v = V (); + std::string kstr (ov, 0, p); + std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); + + int ac (2); + char* av[] = + { + const_cast (o), 0 + }; + + bool dummy; + if (!kstr.empty ()) + { + av[1] = const_cast (kstr.c_str ()); + argv_scanner s (0, ac, av); + parser::parse (k, dummy, s); + } + + if (!vstr.empty ()) + { + av[1] = const_cast (vstr.c_str ()); + argv_scanner s (0, ac, av); + parser::parse (v, dummy, s); + } + + m[k] = v; + } + else + throw missing_value (o); + + xs = true; + } + }; + + template + void + thunk (X& x, scanner& s) + { + parser::parse (x.*M, s); + } + + template + void + thunk (X& x, scanner& s) + { + parser::parse (x.*M, x.*S, s); + } +} + +#include +#include + +// options +// + +options:: +options () +: build2_metadata_ (), + help_ (), + version_ (), + include_path_ (), + include_path_specified_ (false), + output_dir_ (), + output_dir_specified_ (false), + std_ (cxx_version::cxx98), + std_specified_ (false), + generate_modifier_ (), + generate_specifier_ (), + generate_parse_ (), + generate_merge_ (), + generate_description_ (), + generate_file_scanner_ (), + generate_vector_scanner_ (), + generate_group_scanner_ (), + suppress_inline_ (), + suppress_cli_ (), + cli_namespace_ ("::cli"), + cli_namespace_specified_ (false), + ostream_type_ ("::std::ostream"), + ostream_type_specified_ (false), + generate_cxx_ (), + generate_man_ (), + generate_html_ (), + generate_txt_ (), + stdout__ (), + suppress_undocumented_ (), + suppress_usage_ (), + long_usage_ (), + short_usage_ (), + page_usage_ (), + page_usage_specified_ (false), + option_length_ (0), + option_length_specified_ (false), + ansi_color_ (), + exclude_base_ (), + include_base_last_ (), + class_doc_ (), + class_doc_specified_ (false), + class__ (), + class__specified_ (false), + docvar_ (), + docvar_specified_ (false), + link_regex_ (), + link_regex_specified_ (false), + link_regex_trace_ (), + html_heading_map_ (), + html_heading_map_specified_ (false), + omit_link_check_ (), + hxx_prologue_ (), + hxx_prologue_specified_ (false), + ixx_prologue_ (), + ixx_prologue_specified_ (false), + cxx_prologue_ (), + cxx_prologue_specified_ (false), + man_prologue_ (), + man_prologue_specified_ (false), + html_prologue_ (), + html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), + hxx_epilogue_ (), + hxx_epilogue_specified_ (false), + ixx_epilogue_ (), + ixx_epilogue_specified_ (false), + cxx_epilogue_ (), + cxx_epilogue_specified_ (false), + man_epilogue_ (), + man_epilogue_specified_ (false), + html_epilogue_ (), + html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), + hxx_prologue_file_ (), + hxx_prologue_file_specified_ (false), + ixx_prologue_file_ (), + ixx_prologue_file_specified_ (false), + cxx_prologue_file_ (), + cxx_prologue_file_specified_ (false), + man_prologue_file_ (), + man_prologue_file_specified_ (false), + html_prologue_file_ (), + html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), + hxx_epilogue_file_ (), + hxx_epilogue_file_specified_ (false), + ixx_epilogue_file_ (), + ixx_epilogue_file_specified_ (false), + cxx_epilogue_file_ (), + cxx_epilogue_file_specified_ (false), + man_epilogue_file_ (), + man_epilogue_file_specified_ (false), + html_epilogue_file_ (), + html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), + output_prefix_ (), + output_prefix_specified_ (false), + output_suffix_ (), + output_suffix_specified_ (false), + hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), + ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), + cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + man_suffix_ (".1"), + man_suffix_specified_ (false), + html_suffix_ (".html"), + html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), + option_prefix_ ("-"), + option_prefix_specified_ (false), + option_separator_ ("--"), + option_separator_specified_ (false), + keep_separator_ (), + no_combined_flags_ (), + no_combined_values_ (), + include_with_brackets_ (), + include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), + reserved_name_ (), + reserved_name_specified_ (false), + options_file_ (), + options_file_specified_ (false) +{ +} + +options:: +options (int& argc, + char** argv, + bool erase, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: build2_metadata_ (), + help_ (), + version_ (), + include_path_ (), + include_path_specified_ (false), + output_dir_ (), + output_dir_specified_ (false), + std_ (cxx_version::cxx98), + std_specified_ (false), + generate_modifier_ (), + generate_specifier_ (), + generate_parse_ (), + generate_merge_ (), + generate_description_ (), + generate_file_scanner_ (), + generate_vector_scanner_ (), + generate_group_scanner_ (), + suppress_inline_ (), + suppress_cli_ (), + cli_namespace_ ("::cli"), + cli_namespace_specified_ (false), + ostream_type_ ("::std::ostream"), + ostream_type_specified_ (false), + generate_cxx_ (), + generate_man_ (), + generate_html_ (), + generate_txt_ (), + stdout__ (), + suppress_undocumented_ (), + suppress_usage_ (), + long_usage_ (), + short_usage_ (), + page_usage_ (), + page_usage_specified_ (false), + option_length_ (0), + option_length_specified_ (false), + ansi_color_ (), + exclude_base_ (), + include_base_last_ (), + class_doc_ (), + class_doc_specified_ (false), + class__ (), + class__specified_ (false), + docvar_ (), + docvar_specified_ (false), + link_regex_ (), + link_regex_specified_ (false), + link_regex_trace_ (), + html_heading_map_ (), + html_heading_map_specified_ (false), + omit_link_check_ (), + hxx_prologue_ (), + hxx_prologue_specified_ (false), + ixx_prologue_ (), + ixx_prologue_specified_ (false), + cxx_prologue_ (), + cxx_prologue_specified_ (false), + man_prologue_ (), + man_prologue_specified_ (false), + html_prologue_ (), + html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), + hxx_epilogue_ (), + hxx_epilogue_specified_ (false), + ixx_epilogue_ (), + ixx_epilogue_specified_ (false), + cxx_epilogue_ (), + cxx_epilogue_specified_ (false), + man_epilogue_ (), + man_epilogue_specified_ (false), + html_epilogue_ (), + html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), + hxx_prologue_file_ (), + hxx_prologue_file_specified_ (false), + ixx_prologue_file_ (), + ixx_prologue_file_specified_ (false), + cxx_prologue_file_ (), + cxx_prologue_file_specified_ (false), + man_prologue_file_ (), + man_prologue_file_specified_ (false), + html_prologue_file_ (), + html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), + hxx_epilogue_file_ (), + hxx_epilogue_file_specified_ (false), + ixx_epilogue_file_ (), + ixx_epilogue_file_specified_ (false), + cxx_epilogue_file_ (), + cxx_epilogue_file_specified_ (false), + man_epilogue_file_ (), + man_epilogue_file_specified_ (false), + html_epilogue_file_ (), + html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), + output_prefix_ (), + output_prefix_specified_ (false), + output_suffix_ (), + output_suffix_specified_ (false), + hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), + ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), + cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + man_suffix_ (".1"), + man_suffix_specified_ (false), + html_suffix_ (".html"), + html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), + option_prefix_ ("-"), + option_prefix_specified_ (false), + option_separator_ ("--"), + option_separator_specified_ (false), + keep_separator_ (), + no_combined_flags_ (), + no_combined_values_ (), + include_with_brackets_ (), + include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), + reserved_name_ (), + reserved_name_specified_ (false), + options_file_ (), + options_file_specified_ (false) +{ + ::cli::argv_scanner s (argc, argv, erase); + _parse (s, opt, arg); +} + +options:: +options (int start, + int& argc, + char** argv, + bool erase, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: build2_metadata_ (), + help_ (), + version_ (), + include_path_ (), + include_path_specified_ (false), + output_dir_ (), + output_dir_specified_ (false), + std_ (cxx_version::cxx98), + std_specified_ (false), + generate_modifier_ (), + generate_specifier_ (), + generate_parse_ (), + generate_merge_ (), + generate_description_ (), + generate_file_scanner_ (), + generate_vector_scanner_ (), + generate_group_scanner_ (), + suppress_inline_ (), + suppress_cli_ (), + cli_namespace_ ("::cli"), + cli_namespace_specified_ (false), + ostream_type_ ("::std::ostream"), + ostream_type_specified_ (false), + generate_cxx_ (), + generate_man_ (), + generate_html_ (), + generate_txt_ (), + stdout__ (), + suppress_undocumented_ (), + suppress_usage_ (), + long_usage_ (), + short_usage_ (), + page_usage_ (), + page_usage_specified_ (false), + option_length_ (0), + option_length_specified_ (false), + ansi_color_ (), + exclude_base_ (), + include_base_last_ (), + class_doc_ (), + class_doc_specified_ (false), + class__ (), + class__specified_ (false), + docvar_ (), + docvar_specified_ (false), + link_regex_ (), + link_regex_specified_ (false), + link_regex_trace_ (), + html_heading_map_ (), + html_heading_map_specified_ (false), + omit_link_check_ (), + hxx_prologue_ (), + hxx_prologue_specified_ (false), + ixx_prologue_ (), + ixx_prologue_specified_ (false), + cxx_prologue_ (), + cxx_prologue_specified_ (false), + man_prologue_ (), + man_prologue_specified_ (false), + html_prologue_ (), + html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), + hxx_epilogue_ (), + hxx_epilogue_specified_ (false), + ixx_epilogue_ (), + ixx_epilogue_specified_ (false), + cxx_epilogue_ (), + cxx_epilogue_specified_ (false), + man_epilogue_ (), + man_epilogue_specified_ (false), + html_epilogue_ (), + html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), + hxx_prologue_file_ (), + hxx_prologue_file_specified_ (false), + ixx_prologue_file_ (), + ixx_prologue_file_specified_ (false), + cxx_prologue_file_ (), + cxx_prologue_file_specified_ (false), + man_prologue_file_ (), + man_prologue_file_specified_ (false), + html_prologue_file_ (), + html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), + hxx_epilogue_file_ (), + hxx_epilogue_file_specified_ (false), + ixx_epilogue_file_ (), + ixx_epilogue_file_specified_ (false), + cxx_epilogue_file_ (), + cxx_epilogue_file_specified_ (false), + man_epilogue_file_ (), + man_epilogue_file_specified_ (false), + html_epilogue_file_ (), + html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), + output_prefix_ (), + output_prefix_specified_ (false), + output_suffix_ (), + output_suffix_specified_ (false), + hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), + ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), + cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + man_suffix_ (".1"), + man_suffix_specified_ (false), + html_suffix_ (".html"), + html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), + option_prefix_ ("-"), + option_prefix_specified_ (false), + option_separator_ ("--"), + option_separator_specified_ (false), + keep_separator_ (), + no_combined_flags_ (), + no_combined_values_ (), + include_with_brackets_ (), + include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), + reserved_name_ (), + reserved_name_specified_ (false), + options_file_ (), + options_file_specified_ (false) +{ + ::cli::argv_scanner s (start, argc, argv, erase); + _parse (s, opt, arg); +} + +options:: +options (int& argc, + char** argv, + int& end, + bool erase, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: build2_metadata_ (), + help_ (), + version_ (), + include_path_ (), + include_path_specified_ (false), + output_dir_ (), + output_dir_specified_ (false), + std_ (cxx_version::cxx98), + std_specified_ (false), + generate_modifier_ (), + generate_specifier_ (), + generate_parse_ (), + generate_merge_ (), + generate_description_ (), + generate_file_scanner_ (), + generate_vector_scanner_ (), + generate_group_scanner_ (), + suppress_inline_ (), + suppress_cli_ (), + cli_namespace_ ("::cli"), + cli_namespace_specified_ (false), + ostream_type_ ("::std::ostream"), + ostream_type_specified_ (false), + generate_cxx_ (), + generate_man_ (), + generate_html_ (), + generate_txt_ (), + stdout__ (), + suppress_undocumented_ (), + suppress_usage_ (), + long_usage_ (), + short_usage_ (), + page_usage_ (), + page_usage_specified_ (false), + option_length_ (0), + option_length_specified_ (false), + ansi_color_ (), + exclude_base_ (), + include_base_last_ (), + class_doc_ (), + class_doc_specified_ (false), + class__ (), + class__specified_ (false), + docvar_ (), + docvar_specified_ (false), + link_regex_ (), + link_regex_specified_ (false), + link_regex_trace_ (), + html_heading_map_ (), + html_heading_map_specified_ (false), + omit_link_check_ (), + hxx_prologue_ (), + hxx_prologue_specified_ (false), + ixx_prologue_ (), + ixx_prologue_specified_ (false), + cxx_prologue_ (), + cxx_prologue_specified_ (false), + man_prologue_ (), + man_prologue_specified_ (false), + html_prologue_ (), + html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), + hxx_epilogue_ (), + hxx_epilogue_specified_ (false), + ixx_epilogue_ (), + ixx_epilogue_specified_ (false), + cxx_epilogue_ (), + cxx_epilogue_specified_ (false), + man_epilogue_ (), + man_epilogue_specified_ (false), + html_epilogue_ (), + html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), + hxx_prologue_file_ (), + hxx_prologue_file_specified_ (false), + ixx_prologue_file_ (), + ixx_prologue_file_specified_ (false), + cxx_prologue_file_ (), + cxx_prologue_file_specified_ (false), + man_prologue_file_ (), + man_prologue_file_specified_ (false), + html_prologue_file_ (), + html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), + hxx_epilogue_file_ (), + hxx_epilogue_file_specified_ (false), + ixx_epilogue_file_ (), + ixx_epilogue_file_specified_ (false), + cxx_epilogue_file_ (), + cxx_epilogue_file_specified_ (false), + man_epilogue_file_ (), + man_epilogue_file_specified_ (false), + html_epilogue_file_ (), + html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), + output_prefix_ (), + output_prefix_specified_ (false), + output_suffix_ (), + output_suffix_specified_ (false), + hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), + ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), + cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + man_suffix_ (".1"), + man_suffix_specified_ (false), + html_suffix_ (".html"), + html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), + option_prefix_ ("-"), + option_prefix_specified_ (false), + option_separator_ ("--"), + option_separator_specified_ (false), + keep_separator_ (), + no_combined_flags_ (), + no_combined_values_ (), + include_with_brackets_ (), + include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), + reserved_name_ (), + reserved_name_specified_ (false), + options_file_ (), + options_file_specified_ (false) +{ + ::cli::argv_scanner s (argc, argv, erase); + _parse (s, opt, arg); + end = s.end (); +} + +options:: +options (int start, + int& argc, + char** argv, + int& end, + bool erase, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: build2_metadata_ (), + help_ (), + version_ (), + include_path_ (), + include_path_specified_ (false), + output_dir_ (), + output_dir_specified_ (false), + std_ (cxx_version::cxx98), + std_specified_ (false), + generate_modifier_ (), + generate_specifier_ (), + generate_parse_ (), + generate_merge_ (), + generate_description_ (), + generate_file_scanner_ (), + generate_vector_scanner_ (), + generate_group_scanner_ (), + suppress_inline_ (), + suppress_cli_ (), + cli_namespace_ ("::cli"), + cli_namespace_specified_ (false), + ostream_type_ ("::std::ostream"), + ostream_type_specified_ (false), + generate_cxx_ (), + generate_man_ (), + generate_html_ (), + generate_txt_ (), + stdout__ (), + suppress_undocumented_ (), + suppress_usage_ (), + long_usage_ (), + short_usage_ (), + page_usage_ (), + page_usage_specified_ (false), + option_length_ (0), + option_length_specified_ (false), + ansi_color_ (), + exclude_base_ (), + include_base_last_ (), + class_doc_ (), + class_doc_specified_ (false), + class__ (), + class__specified_ (false), + docvar_ (), + docvar_specified_ (false), + link_regex_ (), + link_regex_specified_ (false), + link_regex_trace_ (), + html_heading_map_ (), + html_heading_map_specified_ (false), + omit_link_check_ (), + hxx_prologue_ (), + hxx_prologue_specified_ (false), + ixx_prologue_ (), + ixx_prologue_specified_ (false), + cxx_prologue_ (), + cxx_prologue_specified_ (false), + man_prologue_ (), + man_prologue_specified_ (false), + html_prologue_ (), + html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), + hxx_epilogue_ (), + hxx_epilogue_specified_ (false), + ixx_epilogue_ (), + ixx_epilogue_specified_ (false), + cxx_epilogue_ (), + cxx_epilogue_specified_ (false), + man_epilogue_ (), + man_epilogue_specified_ (false), + html_epilogue_ (), + html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), + hxx_prologue_file_ (), + hxx_prologue_file_specified_ (false), + ixx_prologue_file_ (), + ixx_prologue_file_specified_ (false), + cxx_prologue_file_ (), + cxx_prologue_file_specified_ (false), + man_prologue_file_ (), + man_prologue_file_specified_ (false), + html_prologue_file_ (), + html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), + hxx_epilogue_file_ (), + hxx_epilogue_file_specified_ (false), + ixx_epilogue_file_ (), + ixx_epilogue_file_specified_ (false), + cxx_epilogue_file_ (), + cxx_epilogue_file_specified_ (false), + man_epilogue_file_ (), + man_epilogue_file_specified_ (false), + html_epilogue_file_ (), + html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), + output_prefix_ (), + output_prefix_specified_ (false), + output_suffix_ (), + output_suffix_specified_ (false), + hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), + ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), + cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + man_suffix_ (".1"), + man_suffix_specified_ (false), + html_suffix_ (".html"), + html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), + option_prefix_ ("-"), + option_prefix_specified_ (false), + option_separator_ ("--"), + option_separator_specified_ (false), + keep_separator_ (), + no_combined_flags_ (), + no_combined_values_ (), + include_with_brackets_ (), + include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), + reserved_name_ (), + reserved_name_specified_ (false), + options_file_ (), + options_file_specified_ (false) +{ + ::cli::argv_scanner s (start, argc, argv, erase); + _parse (s, opt, arg); + end = s.end (); +} + +options:: +options (::cli::scanner& s, + ::cli::unknown_mode opt, + ::cli::unknown_mode arg) +: build2_metadata_ (), + help_ (), + version_ (), + include_path_ (), + include_path_specified_ (false), + output_dir_ (), + output_dir_specified_ (false), + std_ (cxx_version::cxx98), + std_specified_ (false), + generate_modifier_ (), + generate_specifier_ (), + generate_parse_ (), + generate_merge_ (), + generate_description_ (), + generate_file_scanner_ (), + generate_vector_scanner_ (), + generate_group_scanner_ (), + suppress_inline_ (), + suppress_cli_ (), + cli_namespace_ ("::cli"), + cli_namespace_specified_ (false), + ostream_type_ ("::std::ostream"), + ostream_type_specified_ (false), + generate_cxx_ (), + generate_man_ (), + generate_html_ (), + generate_txt_ (), + stdout__ (), + suppress_undocumented_ (), + suppress_usage_ (), + long_usage_ (), + short_usage_ (), + page_usage_ (), + page_usage_specified_ (false), + option_length_ (0), + option_length_specified_ (false), + ansi_color_ (), + exclude_base_ (), + include_base_last_ (), + class_doc_ (), + class_doc_specified_ (false), + class__ (), + class__specified_ (false), + docvar_ (), + docvar_specified_ (false), + link_regex_ (), + link_regex_specified_ (false), + link_regex_trace_ (), + html_heading_map_ (), + html_heading_map_specified_ (false), + omit_link_check_ (), + hxx_prologue_ (), + hxx_prologue_specified_ (false), + ixx_prologue_ (), + ixx_prologue_specified_ (false), + cxx_prologue_ (), + cxx_prologue_specified_ (false), + man_prologue_ (), + man_prologue_specified_ (false), + html_prologue_ (), + html_prologue_specified_ (false), + txt_prologue_ (), + txt_prologue_specified_ (false), + hxx_epilogue_ (), + hxx_epilogue_specified_ (false), + ixx_epilogue_ (), + ixx_epilogue_specified_ (false), + cxx_epilogue_ (), + cxx_epilogue_specified_ (false), + man_epilogue_ (), + man_epilogue_specified_ (false), + html_epilogue_ (), + html_epilogue_specified_ (false), + txt_epilogue_ (), + txt_epilogue_specified_ (false), + hxx_prologue_file_ (), + hxx_prologue_file_specified_ (false), + ixx_prologue_file_ (), + ixx_prologue_file_specified_ (false), + cxx_prologue_file_ (), + cxx_prologue_file_specified_ (false), + man_prologue_file_ (), + man_prologue_file_specified_ (false), + html_prologue_file_ (), + html_prologue_file_specified_ (false), + txt_prologue_file_ (), + txt_prologue_file_specified_ (false), + hxx_epilogue_file_ (), + hxx_epilogue_file_specified_ (false), + ixx_epilogue_file_ (), + ixx_epilogue_file_specified_ (false), + cxx_epilogue_file_ (), + cxx_epilogue_file_specified_ (false), + man_epilogue_file_ (), + man_epilogue_file_specified_ (false), + html_epilogue_file_ (), + html_epilogue_file_specified_ (false), + txt_epilogue_file_ (), + txt_epilogue_file_specified_ (false), + output_prefix_ (), + output_prefix_specified_ (false), + output_suffix_ (), + output_suffix_specified_ (false), + hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), + ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), + cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + man_suffix_ (".1"), + man_suffix_specified_ (false), + html_suffix_ (".html"), + html_suffix_specified_ (false), + txt_suffix_ (".txt"), + txt_suffix_specified_ (false), + option_prefix_ ("-"), + option_prefix_specified_ (false), + option_separator_ ("--"), + option_separator_specified_ (false), + keep_separator_ (), + no_combined_flags_ (), + no_combined_values_ (), + include_with_brackets_ (), + include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), + reserved_name_ (), + reserved_name_specified_ (false), + options_file_ (), + options_file_specified_ (false) +{ + _parse (s, opt, arg); +} + +::cli::usage_para options:: +print_usage (::std::ostream& os, ::cli::usage_para p) +{ + CLI_POTENTIALLY_UNUSED (os); + + if (p == ::cli::usage_para::text) + os << ::std::endl; + + os << "--build2-metadata" << std::endl; + + os << "--help Print usage information and exit." << ::std::endl; + + os << "--version Print version and exit." << ::std::endl; + + os << "--include-path|-I Search for bracket-included (<>) options" << ::std::endl + << " files." << ::std::endl; + + os << "--output-dir|-o Write the generated files to instead of the" << ::std::endl + << " current directory." << ::std::endl; + + os << "--std Specify the C++ standard that should be used" << ::std::endl + << " during compilation." << ::std::endl; + + os << "--generate-modifier Generate option value modifiers in addition to" << ::std::endl + << " accessors." << ::std::endl; + + os << "--generate-specifier Generate functions for determining whether the" << ::std::endl + << " option was specified on the command line." << ::std::endl; + + os << "--generate-parse Generate parse() functions instead of parsing" << ::std::endl + << " constructors." << ::std::endl; + + os << "--generate-merge Generate merge() functions." << ::std::endl; + + os << "--generate-description Generate the option description list that can be" << ::std::endl + << " examined at runtime." << ::std::endl; + + os << "--generate-file-scanner Generate the argv_file_scanner implementation." << ::std::endl; + + os << "--generate-vector-scanner Generate the vector_scanner implementation." << ::std::endl; + + os << "--generate-group-scanner Generate the group_scanner implementation." << ::std::endl; + + os << "--suppress-inline Generate all functions non-inline." << ::std::endl; + + os << "--suppress-cli Do not generate the CLI support types (scanners," << ::std::endl + << " parser, etc)." << ::std::endl; + + os << "--cli-namespace Generate the CLI support types in the " << ::std::endl + << " namespace (cli by default)." << ::std::endl; + + os << "--ostream-type Output stream type instead of the default" << ::std::endl + << " std::ostream that should be used to print usage" << ::std::endl + << " and exception information." << ::std::endl; + + os << "--generate-cxx Generate C++ code." << ::std::endl; + + os << "--generate-man Generate documentation in the man page format." << ::std::endl; + + os << "--generate-html Generate documentation in the HTML format." << ::std::endl; + + os << "--generate-txt Generate documentation in the plain text format," << ::std::endl + << " similar to usage." << ::std::endl; + + os << "--stdout Write output to STDOUT instead of a file." << ::std::endl; + + os << "--suppress-undocumented Suppress the generation of documentation entries" << ::std::endl + << " for undocumented options." << ::std::endl; + + os << "--suppress-usage Suppress the generation of the usage printing" << ::std::endl + << " code." << ::std::endl; + + os << "--long-usage If no short documentation string is provided, use" << ::std::endl + << " the complete long documentation string in usage." << ::std::endl; + + os << "--short-usage If specified together with --long-usage, generate" << ::std::endl + << " both short and long usage versions." << ::std::endl; + + os << "--page-usage Generate the combined usage printing code for the" << ::std::endl + << " entire page." << ::std::endl; + + os << "--option-length Indent option descriptions characters when" << ::std::endl + << " printing usage." << ::std::endl; + + os << "--ansi-color Use ANSI color escape sequences when printing" << ::std::endl + << " usage." << ::std::endl; + + os << "--exclude-base Exclude base class information from usage and" << ::std::endl + << " documentation." << ::std::endl; + + os << "--include-base-last Include base class information after derived for" << ::std::endl + << " usage and documentation." << ::std::endl; + + os << "--class-doc = Specify the documentation that should be" << ::std::endl + << " used for the options class ." << ::std::endl; + + os << "--class Generate the man page, HTML, or text documentation" << ::std::endl + << " only for the options class ." << ::std::endl; + + os << "--docvar|-v = Set documentation variable to the value" << ::std::endl + << " ." << ::std::endl; + + os << "--link-regex Add to the list of regular expressions" << ::std::endl + << " used to transform link targets in the generated" << ::std::endl + << " documentation." << ::std::endl; + + os << "--link-regex-trace Trace the process of applying regular expressions" << ::std::endl + << " specified with the --link-regex option." << ::std::endl; + + os << "--html-heading-map = Map CLI heading (valid values: 'H', '0', '1'," << ::std::endl + << " 'h', and '2') to HTML heading (for example," << ::std::endl + << " 'h1', 'h2', etc)." << ::std::endl; + + os << "--omit-link-check Don't check that local fragment link references" << ::std::endl + << " (\\l{#ref ...}) resolve to ids." << ::std::endl; + + os << "--hxx-prologue Insert at the beginning of the generated" << ::std::endl + << " C++ header file." << ::std::endl; + + os << "--ixx-prologue Insert at the beginning of the generated" << ::std::endl + << " C++ inline file." << ::std::endl; + + os << "--cxx-prologue Insert at the beginning of the generated" << ::std::endl + << " C++ source file." << ::std::endl; + + os << "--man-prologue Insert at the beginning of the generated" << ::std::endl + << " man page file." << ::std::endl; + + os << "--html-prologue Insert at the beginning of the generated" << ::std::endl + << " HTML file." << ::std::endl; + + os << "--txt-prologue Insert at the beginning of the generated" << ::std::endl + << " text file." << ::std::endl; + + os << "--hxx-epilogue Insert at the end of the generated C++" << ::std::endl + << " header file." << ::std::endl; + + os << "--ixx-epilogue Insert at the end of the generated C++" << ::std::endl + << " inline file." << ::std::endl; + + os << "--cxx-epilogue Insert at the end of the generated C++" << ::std::endl + << " source file." << ::std::endl; + + os << "--man-epilogue Insert at the end of the generated man page" << ::std::endl + << " file." << ::std::endl; + + os << "--html-epilogue Insert at the end of the generated HTML" << ::std::endl + << " file." << ::std::endl; + + os << "--txt-epilogue Insert at the end of the generated text" << ::std::endl + << " file." << ::std::endl; + + os << "--hxx-prologue-file Insert the content of at the beginning of" << ::std::endl + << " the generated C++ header file." << ::std::endl; + + os << "--ixx-prologue-file Insert the content of at the beginning of" << ::std::endl + << " the generated C++ inline file." << ::std::endl; + + os << "--cxx-prologue-file Insert the content of at the beginning of" << ::std::endl + << " the generated C++ source file." << ::std::endl; + + os << "--man-prologue-file Insert the content of at the beginning of" << ::std::endl + << " the generated man page file." << ::std::endl; + + os << "--html-prologue-file Insert the content of at the beginning of" << ::std::endl + << " the generated HTML file." << ::std::endl; + + os << "--txt-prologue-file Insert the content of at the beginning of" << ::std::endl + << " the generated text file." << ::std::endl; + + os << "--hxx-epilogue-file Insert the content of at the end of the" << ::std::endl + << " generated C++ header file." << ::std::endl; + + os << "--ixx-epilogue-file Insert the content of at the end of the" << ::std::endl + << " generated C++ inline file." << ::std::endl; + + os << "--cxx-epilogue-file Insert the content of at the end of the" << ::std::endl + << " generated C++ source file." << ::std::endl; + + os << "--man-epilogue-file Insert the content of at the end of the" << ::std::endl + << " generated man page file." << ::std::endl; + + os << "--html-epilogue-file Insert the content of at the end of the" << ::std::endl + << " generated HTML file." << ::std::endl; + + os << "--txt-epilogue-file Insert the content of at the end of the" << ::std::endl + << " generated text file." << ::std::endl; + + os << "--output-prefix Add at the beginning of the generated" << ::std::endl + << " output file name(s)." << ::std::endl; + + os << "--output-suffix Add at the end of the generated output" << ::std::endl + << " file name(s)." << ::std::endl; + + os << "--hxx-suffix Use instead of the default .hxx to" << ::std::endl + << " construct the name of the generated header file." << ::std::endl; + + os << "--ixx-suffix Use instead of the default .ixx to" << ::std::endl + << " construct the name of the generated inline file." << ::std::endl; + + os << "--cxx-suffix Use instead of the default .cxx to" << ::std::endl + << " construct the name of the generated source file." << ::std::endl; + + os << "--man-suffix Use instead of the default .1 to" << ::std::endl + << " construct the name of the generated man page file." << ::std::endl; + + os << "--html-suffix Use instead of the default .html to" << ::std::endl + << " construct the name of the generated HTML file." << ::std::endl; + + os << "--txt-suffix Use instead of the default .txt to" << ::std::endl + << " construct the name of the generated text file." << ::std::endl; + + os << "--option-prefix Use instead of the default '-' as an" << ::std::endl + << " option prefix." << ::std::endl; + + os << "--option-separator Use instead of the default '--' as an" << ::std::endl + << " optional separator between options and arguments." << ::std::endl; + + os << "--keep-separator Leave the option separator in the scanner." << ::std::endl; + + os << "--no-combined-flags Disable support for combining multiple" << ::std::endl + << " single-character flags into a single argument (the" << ::std::endl + << " -xyz form that is equivalent to -x -y -z)." << ::std::endl; + + os << "--no-combined-values Disable support for combining an option and its" << ::std::endl + << " value into a single argument with the assignment" << ::std::endl + << " sign (the option=value form)." << ::std::endl; + + os << "--include-with-brackets Use angle brackets (<>) instead of quotes (\"\") in" << ::std::endl + << " the generated #include directives." << ::std::endl; + + os << "--include-prefix Add to the generated #include directive" << ::std::endl + << " paths." << ::std::endl; + + os << "--guard-prefix Add to the generated header inclusion" << ::std::endl + << " guards." << ::std::endl; + + os << "--reserved-name = Add with an optional replacement to" << ::std::endl + << " the list of names that should not be used as" << ::std::endl + << " identifiers." << ::std::endl; + + os << "--options-file Read additional options from ." << ::std::endl; + + p = ::cli::usage_para::option; + + return p; +} + +typedef +std::map +_cli_options_map; + +static _cli_options_map _cli_options_map_; + +struct _cli_options_map_init +{ + _cli_options_map_init () + { + _cli_options_map_["--build2-metadata"] = + &::cli::thunk< options, bool, &options::build2_metadata_ >; + _cli_options_map_["--help"] = + &::cli::thunk< options, bool, &options::help_ >; + _cli_options_map_["--version"] = + &::cli::thunk< options, bool, &options::version_ >; + _cli_options_map_["--include-path"] = + &::cli::thunk< options, std::vector, &options::include_path_, + &options::include_path_specified_ >; + _cli_options_map_["-I"] = + &::cli::thunk< options, std::vector, &options::include_path_, + &options::include_path_specified_ >; + _cli_options_map_["--output-dir"] = + &::cli::thunk< options, std::string, &options::output_dir_, + &options::output_dir_specified_ >; + _cli_options_map_["-o"] = + &::cli::thunk< options, std::string, &options::output_dir_, + &options::output_dir_specified_ >; + _cli_options_map_["--std"] = + &::cli::thunk< options, cxx_version, &options::std_, + &options::std_specified_ >; + _cli_options_map_["--generate-modifier"] = + &::cli::thunk< options, bool, &options::generate_modifier_ >; + _cli_options_map_["--generate-specifier"] = + &::cli::thunk< options, bool, &options::generate_specifier_ >; + _cli_options_map_["--generate-parse"] = + &::cli::thunk< options, bool, &options::generate_parse_ >; + _cli_options_map_["--generate-merge"] = + &::cli::thunk< options, bool, &options::generate_merge_ >; + _cli_options_map_["--generate-description"] = + &::cli::thunk< options, bool, &options::generate_description_ >; + _cli_options_map_["--generate-file-scanner"] = + &::cli::thunk< options, bool, &options::generate_file_scanner_ >; + _cli_options_map_["--generate-vector-scanner"] = + &::cli::thunk< options, bool, &options::generate_vector_scanner_ >; + _cli_options_map_["--generate-group-scanner"] = + &::cli::thunk< options, bool, &options::generate_group_scanner_ >; + _cli_options_map_["--suppress-inline"] = + &::cli::thunk< options, bool, &options::suppress_inline_ >; + _cli_options_map_["--suppress-cli"] = + &::cli::thunk< options, bool, &options::suppress_cli_ >; + _cli_options_map_["--cli-namespace"] = + &::cli::thunk< options, std::string, &options::cli_namespace_, + &options::cli_namespace_specified_ >; + _cli_options_map_["--ostream-type"] = + &::cli::thunk< options, std::string, &options::ostream_type_, + &options::ostream_type_specified_ >; + _cli_options_map_["--generate-cxx"] = + &::cli::thunk< options, bool, &options::generate_cxx_ >; + _cli_options_map_["--generate-man"] = + &::cli::thunk< options, bool, &options::generate_man_ >; + _cli_options_map_["--generate-html"] = + &::cli::thunk< options, bool, &options::generate_html_ >; + _cli_options_map_["--generate-txt"] = + &::cli::thunk< options, bool, &options::generate_txt_ >; + _cli_options_map_["--stdout"] = + &::cli::thunk< options, bool, &options::stdout__ >; + _cli_options_map_["--suppress-undocumented"] = + &::cli::thunk< options, bool, &options::suppress_undocumented_ >; + _cli_options_map_["--suppress-usage"] = + &::cli::thunk< options, bool, &options::suppress_usage_ >; + _cli_options_map_["--long-usage"] = + &::cli::thunk< options, bool, &options::long_usage_ >; + _cli_options_map_["--short-usage"] = + &::cli::thunk< options, bool, &options::short_usage_ >; + _cli_options_map_["--page-usage"] = + &::cli::thunk< options, std::string, &options::page_usage_, + &options::page_usage_specified_ >; + _cli_options_map_["--option-length"] = + &::cli::thunk< options, std::size_t, &options::option_length_, + &options::option_length_specified_ >; + _cli_options_map_["--ansi-color"] = + &::cli::thunk< options, bool, &options::ansi_color_ >; + _cli_options_map_["--exclude-base"] = + &::cli::thunk< options, bool, &options::exclude_base_ >; + _cli_options_map_["--include-base-last"] = + &::cli::thunk< options, bool, &options::include_base_last_ >; + _cli_options_map_["--class-doc"] = + &::cli::thunk< options, std::map, &options::class_doc_, + &options::class_doc_specified_ >; + _cli_options_map_["--class"] = + &::cli::thunk< options, std::vector, &options::class__, + &options::class__specified_ >; + _cli_options_map_["--docvar"] = + &::cli::thunk< options, std::map, &options::docvar_, + &options::docvar_specified_ >; + _cli_options_map_["-v"] = + &::cli::thunk< options, std::map, &options::docvar_, + &options::docvar_specified_ >; + _cli_options_map_["--link-regex"] = + &::cli::thunk< options, std::vector, &options::link_regex_, + &options::link_regex_specified_ >; + _cli_options_map_["--link-regex-trace"] = + &::cli::thunk< options, bool, &options::link_regex_trace_ >; + _cli_options_map_["--html-heading-map"] = + &::cli::thunk< options, std::map, &options::html_heading_map_, + &options::html_heading_map_specified_ >; + _cli_options_map_["--omit-link-check"] = + &::cli::thunk< options, bool, &options::omit_link_check_ >; + _cli_options_map_["--hxx-prologue"] = + &::cli::thunk< options, std::vector, &options::hxx_prologue_, + &options::hxx_prologue_specified_ >; + _cli_options_map_["--ixx-prologue"] = + &::cli::thunk< options, std::vector, &options::ixx_prologue_, + &options::ixx_prologue_specified_ >; + _cli_options_map_["--cxx-prologue"] = + &::cli::thunk< options, std::vector, &options::cxx_prologue_, + &options::cxx_prologue_specified_ >; + _cli_options_map_["--man-prologue"] = + &::cli::thunk< options, std::vector, &options::man_prologue_, + &options::man_prologue_specified_ >; + _cli_options_map_["--html-prologue"] = + &::cli::thunk< options, std::vector, &options::html_prologue_, + &options::html_prologue_specified_ >; + _cli_options_map_["--txt-prologue"] = + &::cli::thunk< options, std::vector, &options::txt_prologue_, + &options::txt_prologue_specified_ >; + _cli_options_map_["--hxx-epilogue"] = + &::cli::thunk< options, std::vector, &options::hxx_epilogue_, + &options::hxx_epilogue_specified_ >; + _cli_options_map_["--ixx-epilogue"] = + &::cli::thunk< options, std::vector, &options::ixx_epilogue_, + &options::ixx_epilogue_specified_ >; + _cli_options_map_["--cxx-epilogue"] = + &::cli::thunk< options, std::vector, &options::cxx_epilogue_, + &options::cxx_epilogue_specified_ >; + _cli_options_map_["--man-epilogue"] = + &::cli::thunk< options, std::vector, &options::man_epilogue_, + &options::man_epilogue_specified_ >; + _cli_options_map_["--html-epilogue"] = + &::cli::thunk< options, std::vector, &options::html_epilogue_, + &options::html_epilogue_specified_ >; + _cli_options_map_["--txt-epilogue"] = + &::cli::thunk< options, std::vector, &options::txt_epilogue_, + &options::txt_epilogue_specified_ >; + _cli_options_map_["--hxx-prologue-file"] = + &::cli::thunk< options, std::string, &options::hxx_prologue_file_, + &options::hxx_prologue_file_specified_ >; + _cli_options_map_["--ixx-prologue-file"] = + &::cli::thunk< options, std::string, &options::ixx_prologue_file_, + &options::ixx_prologue_file_specified_ >; + _cli_options_map_["--cxx-prologue-file"] = + &::cli::thunk< options, std::string, &options::cxx_prologue_file_, + &options::cxx_prologue_file_specified_ >; + _cli_options_map_["--man-prologue-file"] = + &::cli::thunk< options, std::string, &options::man_prologue_file_, + &options::man_prologue_file_specified_ >; + _cli_options_map_["--html-prologue-file"] = + &::cli::thunk< options, std::string, &options::html_prologue_file_, + &options::html_prologue_file_specified_ >; + _cli_options_map_["--txt-prologue-file"] = + &::cli::thunk< options, std::string, &options::txt_prologue_file_, + &options::txt_prologue_file_specified_ >; + _cli_options_map_["--hxx-epilogue-file"] = + &::cli::thunk< options, std::string, &options::hxx_epilogue_file_, + &options::hxx_epilogue_file_specified_ >; + _cli_options_map_["--ixx-epilogue-file"] = + &::cli::thunk< options, std::string, &options::ixx_epilogue_file_, + &options::ixx_epilogue_file_specified_ >; + _cli_options_map_["--cxx-epilogue-file"] = + &::cli::thunk< options, std::string, &options::cxx_epilogue_file_, + &options::cxx_epilogue_file_specified_ >; + _cli_options_map_["--man-epilogue-file"] = + &::cli::thunk< options, std::string, &options::man_epilogue_file_, + &options::man_epilogue_file_specified_ >; + _cli_options_map_["--html-epilogue-file"] = + &::cli::thunk< options, std::string, &options::html_epilogue_file_, + &options::html_epilogue_file_specified_ >; + _cli_options_map_["--txt-epilogue-file"] = + &::cli::thunk< options, std::string, &options::txt_epilogue_file_, + &options::txt_epilogue_file_specified_ >; + _cli_options_map_["--output-prefix"] = + &::cli::thunk< options, std::string, &options::output_prefix_, + &options::output_prefix_specified_ >; + _cli_options_map_["--output-suffix"] = + &::cli::thunk< options, std::string, &options::output_suffix_, + &options::output_suffix_specified_ >; + _cli_options_map_["--hxx-suffix"] = + &::cli::thunk< options, std::string, &options::hxx_suffix_, + &options::hxx_suffix_specified_ >; + _cli_options_map_["--ixx-suffix"] = + &::cli::thunk< options, std::string, &options::ixx_suffix_, + &options::ixx_suffix_specified_ >; + _cli_options_map_["--cxx-suffix"] = + &::cli::thunk< options, std::string, &options::cxx_suffix_, + &options::cxx_suffix_specified_ >; + _cli_options_map_["--man-suffix"] = + &::cli::thunk< options, std::string, &options::man_suffix_, + &options::man_suffix_specified_ >; + _cli_options_map_["--html-suffix"] = + &::cli::thunk< options, std::string, &options::html_suffix_, + &options::html_suffix_specified_ >; + _cli_options_map_["--txt-suffix"] = + &::cli::thunk< options, std::string, &options::txt_suffix_, + &options::txt_suffix_specified_ >; + _cli_options_map_["--option-prefix"] = + &::cli::thunk< options, std::string, &options::option_prefix_, + &options::option_prefix_specified_ >; + _cli_options_map_["--option-separator"] = + &::cli::thunk< options, std::string, &options::option_separator_, + &options::option_separator_specified_ >; + _cli_options_map_["--keep-separator"] = + &::cli::thunk< options, bool, &options::keep_separator_ >; + _cli_options_map_["--no-combined-flags"] = + &::cli::thunk< options, bool, &options::no_combined_flags_ >; + _cli_options_map_["--no-combined-values"] = + &::cli::thunk< options, bool, &options::no_combined_values_ >; + _cli_options_map_["--include-with-brackets"] = + &::cli::thunk< options, bool, &options::include_with_brackets_ >; + _cli_options_map_["--include-prefix"] = + &::cli::thunk< options, std::string, &options::include_prefix_, + &options::include_prefix_specified_ >; + _cli_options_map_["--guard-prefix"] = + &::cli::thunk< options, std::string, &options::guard_prefix_, + &options::guard_prefix_specified_ >; + _cli_options_map_["--reserved-name"] = + &::cli::thunk< options, std::map, &options::reserved_name_, + &options::reserved_name_specified_ >; + _cli_options_map_["--options-file"] = + &::cli::thunk< options, std::string, &options::options_file_, + &options::options_file_specified_ >; + } +}; + +static _cli_options_map_init _cli_options_map_init_; + +bool options:: +_parse (const char* o, ::cli::scanner& s) +{ + _cli_options_map::const_iterator i (_cli_options_map_.find (o)); + + if (i != _cli_options_map_.end ()) + { + (*(i->second)) (*this, s); + return true; + } + + return false; +} + +bool options:: +_parse (::cli::scanner& s, + ::cli::unknown_mode opt_mode, + ::cli::unknown_mode arg_mode) +{ + // Can't skip combined flags (--no-combined-flags). + // + assert (opt_mode != ::cli::unknown_mode::skip); + + bool r = false; + bool opt = true; + + while (s.more ()) + { + const char* o = s.peek (); + + if (std::strcmp (o, "--") == 0) + { + opt = false; + s.skip (); + r = true; + continue; + } + + if (opt) + { + if (_parse (o, s)) + { + r = true; + continue; + } + + if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0') + { + // Handle combined option values. + // + std::string co; + if (const char* v = std::strchr (o, '=')) + { + co.assign (o, 0, v - o); + ++v; + + int ac (2); + char* av[] = + { + const_cast (co.c_str ()), + const_cast (v) + }; + + ::cli::argv_scanner ns (0, ac, av); + + if (_parse (co.c_str (), ns)) + { + // Parsed the option but not its value? + // + if (ns.end () != 2) + throw ::cli::invalid_value (co, v); + + s.next (); + r = true; + continue; + } + else + { + // Set the unknown option and fall through. + // + o = co.c_str (); + } + } + + // Handle combined flags. + // + char cf[3]; + { + const char* p = o + 1; + for (; *p != '\0'; ++p) + { + if (!((*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') || + (*p >= '0' && *p <= '9'))) + break; + } + + if (*p == '\0') + { + for (p = o + 1; *p != '\0'; ++p) + { + std::strcpy (cf, "-"); + cf[1] = *p; + cf[2] = '\0'; + + int ac (1); + char* av[] = + { + cf + }; + + ::cli::argv_scanner ns (0, ac, av); + + if (!_parse (cf, ns)) + break; + } + + if (*p == '\0') + { + // All handled. + // + s.next (); + r = true; + continue; + } + else + { + // Set the unknown option and fall through. + // + o = cf; + } + } + } + + switch (opt_mode) + { + case ::cli::unknown_mode::skip: + { + s.skip (); + r = true; + continue; + } + case ::cli::unknown_mode::stop: + { + break; + } + case ::cli::unknown_mode::fail: + { + throw ::cli::unknown_option (o); + } + } + + break; + } + } + + switch (arg_mode) + { + case ::cli::unknown_mode::skip: + { + s.skip (); + r = true; + continue; + } + case ::cli::unknown_mode::stop: + { + break; + } + case ::cli::unknown_mode::fail: + { + throw ::cli::unknown_argument (o); + } + } + + break; + } + + return r; +} + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/cli/cli/options.hxx b/cli/cli/options.hxx new file mode 100644 index 0000000..b253092 --- /dev/null +++ b/cli/cli/options.hxx @@ -0,0 +1,1632 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +#ifndef CLI_OPTIONS_HXX +#define CLI_OPTIONS_HXX + +// Begin prologue. +// +// +// End prologue. + +#include +#include +#include +#include +#include +#include + +#ifndef CLI_POTENTIALLY_UNUSED +# if defined(_MSC_VER) || defined(__xlC__) +# define CLI_POTENTIALLY_UNUSED(x) (void*)&x +# else +# define CLI_POTENTIALLY_UNUSED(x) (void)x +# endif +#endif + +namespace cli +{ + class usage_para + { + public: + enum value + { + none, + text, + option + }; + + usage_para (value); + + operator value () const + { + return v_; + } + + private: + value v_; + }; + + class unknown_mode + { + public: + enum value + { + skip, + stop, + fail + }; + + unknown_mode (value); + + operator value () const + { + return v_; + } + + private: + value v_; + }; + + // Exceptions. + // + + class exception: public std::exception + { + public: + virtual void + print (::std::ostream&) const = 0; + }; + + ::std::ostream& + operator<< (::std::ostream&, const exception&); + + class unknown_option: public exception + { + public: + virtual + ~unknown_option () throw (); + + unknown_option (const std::string& option); + + const std::string& + option () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + }; + + class unknown_argument: public exception + { + public: + virtual + ~unknown_argument () throw (); + + unknown_argument (const std::string& argument); + + const std::string& + argument () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string argument_; + }; + + class missing_value: public exception + { + public: + virtual + ~missing_value () throw (); + + missing_value (const std::string& option); + + const std::string& + option () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + }; + + class invalid_value: public exception + { + public: + virtual + ~invalid_value () throw (); + + invalid_value (const std::string& option, + const std::string& value, + const std::string& message = std::string ()); + + const std::string& + option () const; + + const std::string& + value () const; + + const std::string& + message () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + std::string value_; + std::string message_; + }; + + class eos_reached: public exception + { + public: + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + }; + + class file_io_failure: public exception + { + public: + virtual + ~file_io_failure () throw (); + + file_io_failure (const std::string& file); + + const std::string& + file () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string file_; + }; + + class unmatched_quote: public exception + { + public: + virtual + ~unmatched_quote () throw (); + + unmatched_quote (const std::string& argument); + + const std::string& + argument () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string argument_; + }; + + // Command line argument scanner interface. + // + // The values returned by next() are guaranteed to be valid + // for the two previous arguments up until a call to a third + // peek() or next(). + // + class scanner + { + public: + virtual + ~scanner (); + + virtual bool + more () = 0; + + virtual const char* + peek () = 0; + + virtual const char* + next () = 0; + + virtual void + skip () = 0; + }; + + class argv_scanner: public scanner + { + public: + argv_scanner (int& argc, char** argv, bool erase = false); + argv_scanner (int start, int& argc, char** argv, bool erase = false); + + int + end () const; + + virtual bool + more (); + + virtual const char* + peek (); + + virtual const char* + next (); + + virtual void + skip (); + + private: + int i_; + int& argc_; + char** argv_; + bool erase_; + }; + + class argv_file_scanner: public argv_scanner + { + public: + argv_file_scanner (int& argc, + char** argv, + const std::string& option, + bool erase = false); + + argv_file_scanner (int start, + int& argc, + char** argv, + const std::string& option, + bool erase = false); + + argv_file_scanner (const std::string& file, + const std::string& option); + + struct option_info + { + // If search_func is not NULL, it is called, with the arg + // value as the second argument, to locate the options file. + // If it returns an empty string, then the file is ignored. + // + const char* option; + std::string (*search_func) (const char*, void* arg); + void* arg; + }; + + argv_file_scanner (int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase = false); + + argv_file_scanner (int start, + int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase = false); + + argv_file_scanner (const std::string& file, + const option_info* options = 0, + std::size_t options_count = 0); + + virtual bool + more (); + + virtual const char* + peek (); + + virtual const char* + next (); + + virtual void + skip (); + + // Return the file path if the peeked at argument came from a file and + // the empty string otherwise. The reference is guaranteed to be valid + // till the end of the scanner lifetime. + // + const std::string& + peek_file (); + + // Return the 1-based line number if the peeked at argument came from + // a file and zero otherwise. + // + std::size_t + peek_line (); + + private: + const option_info* + find (const char*) const; + + void + load (const std::string& file); + + typedef argv_scanner base; + + const std::string option_; + option_info option_info_; + const option_info* options_; + std::size_t options_count_; + + struct arg + { + std::string value; + const std::string* file; + std::size_t line; + }; + + std::deque args_; + std::list files_; + + // Circular buffer of two arguments. + // + std::string hold_[2]; + std::size_t i_; + + bool skip_; + + static int zero_argc_; + static std::string empty_string_; + }; + + template + struct parser; +} + +#include + +#include + +#include + +#include + +#include + +class options +{ + public: + options (); + + options (int& argc, + char** argv, + bool erase = false, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + options (int start, + int& argc, + char** argv, + bool erase = false, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + options (int& argc, + char** argv, + int& end, + bool erase = false, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + options (int start, + int& argc, + char** argv, + int& end, + bool erase = false, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + options (::cli::scanner&, + ::cli::unknown_mode option = ::cli::unknown_mode::fail, + ::cli::unknown_mode argument = ::cli::unknown_mode::stop); + + // Option accessors and modifiers. + // + const bool& + build2_metadata () const; + + bool& + build2_metadata (); + + void + build2_metadata (const bool&); + + const bool& + help () const; + + bool& + help (); + + void + help (const bool&); + + const bool& + version () const; + + bool& + version (); + + void + version (const bool&); + + const std::vector& + include_path () const; + + std::vector& + include_path (); + + void + include_path (const std::vector&); + + bool + include_path_specified () const; + + void + include_path_specified (bool); + + const std::string& + output_dir () const; + + std::string& + output_dir (); + + void + output_dir (const std::string&); + + bool + output_dir_specified () const; + + void + output_dir_specified (bool); + + const cxx_version& + std () const; + + cxx_version& + std (); + + void + std (const cxx_version&); + + bool + std_specified () const; + + void + std_specified (bool); + + const bool& + generate_modifier () const; + + bool& + generate_modifier (); + + void + generate_modifier (const bool&); + + const bool& + generate_specifier () const; + + bool& + generate_specifier (); + + void + generate_specifier (const bool&); + + const bool& + generate_parse () const; + + bool& + generate_parse (); + + void + generate_parse (const bool&); + + const bool& + generate_merge () const; + + bool& + generate_merge (); + + void + generate_merge (const bool&); + + const bool& + generate_description () const; + + bool& + generate_description (); + + void + generate_description (const bool&); + + const bool& + generate_file_scanner () const; + + bool& + generate_file_scanner (); + + void + generate_file_scanner (const bool&); + + const bool& + generate_vector_scanner () const; + + bool& + generate_vector_scanner (); + + void + generate_vector_scanner (const bool&); + + const bool& + generate_group_scanner () const; + + bool& + generate_group_scanner (); + + void + generate_group_scanner (const bool&); + + const bool& + suppress_inline () const; + + bool& + suppress_inline (); + + void + suppress_inline (const bool&); + + const bool& + suppress_cli () const; + + bool& + suppress_cli (); + + void + suppress_cli (const bool&); + + const std::string& + cli_namespace () const; + + std::string& + cli_namespace (); + + void + cli_namespace (const std::string&); + + bool + cli_namespace_specified () const; + + void + cli_namespace_specified (bool); + + const std::string& + ostream_type () const; + + std::string& + ostream_type (); + + void + ostream_type (const std::string&); + + bool + ostream_type_specified () const; + + void + ostream_type_specified (bool); + + const bool& + generate_cxx () const; + + bool& + generate_cxx (); + + void + generate_cxx (const bool&); + + const bool& + generate_man () const; + + bool& + generate_man (); + + void + generate_man (const bool&); + + const bool& + generate_html () const; + + bool& + generate_html (); + + void + generate_html (const bool&); + + const bool& + generate_txt () const; + + bool& + generate_txt (); + + void + generate_txt (const bool&); + + const bool& + stdout_ () const; + + bool& + stdout_ (); + + void + stdout_ (const bool&); + + const bool& + suppress_undocumented () const; + + bool& + suppress_undocumented (); + + void + suppress_undocumented (const bool&); + + const bool& + suppress_usage () const; + + bool& + suppress_usage (); + + void + suppress_usage (const bool&); + + const bool& + long_usage () const; + + bool& + long_usage (); + + void + long_usage (const bool&); + + const bool& + short_usage () const; + + bool& + short_usage (); + + void + short_usage (const bool&); + + const std::string& + page_usage () const; + + std::string& + page_usage (); + + void + page_usage (const std::string&); + + bool + page_usage_specified () const; + + void + page_usage_specified (bool); + + const std::size_t& + option_length () const; + + std::size_t& + option_length (); + + void + option_length (const std::size_t&); + + bool + option_length_specified () const; + + void + option_length_specified (bool); + + const bool& + ansi_color () const; + + bool& + ansi_color (); + + void + ansi_color (const bool&); + + const bool& + exclude_base () const; + + bool& + exclude_base (); + + void + exclude_base (const bool&); + + const bool& + include_base_last () const; + + bool& + include_base_last (); + + void + include_base_last (const bool&); + + const std::map& + class_doc () const; + + std::map& + class_doc (); + + void + class_doc (const std::map&); + + bool + class_doc_specified () const; + + void + class_doc_specified (bool); + + const std::vector& + class_ () const; + + std::vector& + class_ (); + + void + class_ (const std::vector&); + + bool + class__specified () const; + + void + class__specified (bool); + + const std::map& + docvar () const; + + std::map& + docvar (); + + void + docvar (const std::map&); + + bool + docvar_specified () const; + + void + docvar_specified (bool); + + const std::vector& + link_regex () const; + + std::vector& + link_regex (); + + void + link_regex (const std::vector&); + + bool + link_regex_specified () const; + + void + link_regex_specified (bool); + + const bool& + link_regex_trace () const; + + bool& + link_regex_trace (); + + void + link_regex_trace (const bool&); + + const std::map& + html_heading_map () const; + + std::map& + html_heading_map (); + + void + html_heading_map (const std::map&); + + bool + html_heading_map_specified () const; + + void + html_heading_map_specified (bool); + + const bool& + omit_link_check () const; + + bool& + omit_link_check (); + + void + omit_link_check (const bool&); + + const std::vector& + hxx_prologue () const; + + std::vector& + hxx_prologue (); + + void + hxx_prologue (const std::vector&); + + bool + hxx_prologue_specified () const; + + void + hxx_prologue_specified (bool); + + const std::vector& + ixx_prologue () const; + + std::vector& + ixx_prologue (); + + void + ixx_prologue (const std::vector&); + + bool + ixx_prologue_specified () const; + + void + ixx_prologue_specified (bool); + + const std::vector& + cxx_prologue () const; + + std::vector& + cxx_prologue (); + + void + cxx_prologue (const std::vector&); + + bool + cxx_prologue_specified () const; + + void + cxx_prologue_specified (bool); + + const std::vector& + man_prologue () const; + + std::vector& + man_prologue (); + + void + man_prologue (const std::vector&); + + bool + man_prologue_specified () const; + + void + man_prologue_specified (bool); + + const std::vector& + html_prologue () const; + + std::vector& + html_prologue (); + + void + html_prologue (const std::vector&); + + bool + html_prologue_specified () const; + + void + html_prologue_specified (bool); + + const std::vector& + txt_prologue () const; + + std::vector& + txt_prologue (); + + void + txt_prologue (const std::vector&); + + bool + txt_prologue_specified () const; + + void + txt_prologue_specified (bool); + + const std::vector& + hxx_epilogue () const; + + std::vector& + hxx_epilogue (); + + void + hxx_epilogue (const std::vector&); + + bool + hxx_epilogue_specified () const; + + void + hxx_epilogue_specified (bool); + + const std::vector& + ixx_epilogue () const; + + std::vector& + ixx_epilogue (); + + void + ixx_epilogue (const std::vector&); + + bool + ixx_epilogue_specified () const; + + void + ixx_epilogue_specified (bool); + + const std::vector& + cxx_epilogue () const; + + std::vector& + cxx_epilogue (); + + void + cxx_epilogue (const std::vector&); + + bool + cxx_epilogue_specified () const; + + void + cxx_epilogue_specified (bool); + + const std::vector& + man_epilogue () const; + + std::vector& + man_epilogue (); + + void + man_epilogue (const std::vector&); + + bool + man_epilogue_specified () const; + + void + man_epilogue_specified (bool); + + const std::vector& + html_epilogue () const; + + std::vector& + html_epilogue (); + + void + html_epilogue (const std::vector&); + + bool + html_epilogue_specified () const; + + void + html_epilogue_specified (bool); + + const std::vector& + txt_epilogue () const; + + std::vector& + txt_epilogue (); + + void + txt_epilogue (const std::vector&); + + bool + txt_epilogue_specified () const; + + void + txt_epilogue_specified (bool); + + const std::string& + hxx_prologue_file () const; + + std::string& + hxx_prologue_file (); + + void + hxx_prologue_file (const std::string&); + + bool + hxx_prologue_file_specified () const; + + void + hxx_prologue_file_specified (bool); + + const std::string& + ixx_prologue_file () const; + + std::string& + ixx_prologue_file (); + + void + ixx_prologue_file (const std::string&); + + bool + ixx_prologue_file_specified () const; + + void + ixx_prologue_file_specified (bool); + + const std::string& + cxx_prologue_file () const; + + std::string& + cxx_prologue_file (); + + void + cxx_prologue_file (const std::string&); + + bool + cxx_prologue_file_specified () const; + + void + cxx_prologue_file_specified (bool); + + const std::string& + man_prologue_file () const; + + std::string& + man_prologue_file (); + + void + man_prologue_file (const std::string&); + + bool + man_prologue_file_specified () const; + + void + man_prologue_file_specified (bool); + + const std::string& + html_prologue_file () const; + + std::string& + html_prologue_file (); + + void + html_prologue_file (const std::string&); + + bool + html_prologue_file_specified () const; + + void + html_prologue_file_specified (bool); + + const std::string& + txt_prologue_file () const; + + std::string& + txt_prologue_file (); + + void + txt_prologue_file (const std::string&); + + bool + txt_prologue_file_specified () const; + + void + txt_prologue_file_specified (bool); + + const std::string& + hxx_epilogue_file () const; + + std::string& + hxx_epilogue_file (); + + void + hxx_epilogue_file (const std::string&); + + bool + hxx_epilogue_file_specified () const; + + void + hxx_epilogue_file_specified (bool); + + const std::string& + ixx_epilogue_file () const; + + std::string& + ixx_epilogue_file (); + + void + ixx_epilogue_file (const std::string&); + + bool + ixx_epilogue_file_specified () const; + + void + ixx_epilogue_file_specified (bool); + + const std::string& + cxx_epilogue_file () const; + + std::string& + cxx_epilogue_file (); + + void + cxx_epilogue_file (const std::string&); + + bool + cxx_epilogue_file_specified () const; + + void + cxx_epilogue_file_specified (bool); + + const std::string& + man_epilogue_file () const; + + std::string& + man_epilogue_file (); + + void + man_epilogue_file (const std::string&); + + bool + man_epilogue_file_specified () const; + + void + man_epilogue_file_specified (bool); + + const std::string& + html_epilogue_file () const; + + std::string& + html_epilogue_file (); + + void + html_epilogue_file (const std::string&); + + bool + html_epilogue_file_specified () const; + + void + html_epilogue_file_specified (bool); + + const std::string& + txt_epilogue_file () const; + + std::string& + txt_epilogue_file (); + + void + txt_epilogue_file (const std::string&); + + bool + txt_epilogue_file_specified () const; + + void + txt_epilogue_file_specified (bool); + + const std::string& + output_prefix () const; + + std::string& + output_prefix (); + + void + output_prefix (const std::string&); + + bool + output_prefix_specified () const; + + void + output_prefix_specified (bool); + + const std::string& + output_suffix () const; + + std::string& + output_suffix (); + + void + output_suffix (const std::string&); + + bool + output_suffix_specified () const; + + void + output_suffix_specified (bool); + + const std::string& + hxx_suffix () const; + + std::string& + hxx_suffix (); + + void + hxx_suffix (const std::string&); + + bool + hxx_suffix_specified () const; + + void + hxx_suffix_specified (bool); + + const std::string& + ixx_suffix () const; + + std::string& + ixx_suffix (); + + void + ixx_suffix (const std::string&); + + bool + ixx_suffix_specified () const; + + void + ixx_suffix_specified (bool); + + const std::string& + cxx_suffix () const; + + std::string& + cxx_suffix (); + + void + cxx_suffix (const std::string&); + + bool + cxx_suffix_specified () const; + + void + cxx_suffix_specified (bool); + + const std::string& + man_suffix () const; + + std::string& + man_suffix (); + + void + man_suffix (const std::string&); + + bool + man_suffix_specified () const; + + void + man_suffix_specified (bool); + + const std::string& + html_suffix () const; + + std::string& + html_suffix (); + + void + html_suffix (const std::string&); + + bool + html_suffix_specified () const; + + void + html_suffix_specified (bool); + + const std::string& + txt_suffix () const; + + std::string& + txt_suffix (); + + void + txt_suffix (const std::string&); + + bool + txt_suffix_specified () const; + + void + txt_suffix_specified (bool); + + const std::string& + option_prefix () const; + + std::string& + option_prefix (); + + void + option_prefix (const std::string&); + + bool + option_prefix_specified () const; + + void + option_prefix_specified (bool); + + const std::string& + option_separator () const; + + std::string& + option_separator (); + + void + option_separator (const std::string&); + + bool + option_separator_specified () const; + + void + option_separator_specified (bool); + + const bool& + keep_separator () const; + + bool& + keep_separator (); + + void + keep_separator (const bool&); + + const bool& + no_combined_flags () const; + + bool& + no_combined_flags (); + + void + no_combined_flags (const bool&); + + const bool& + no_combined_values () const; + + bool& + no_combined_values (); + + void + no_combined_values (const bool&); + + const bool& + include_with_brackets () const; + + bool& + include_with_brackets (); + + void + include_with_brackets (const bool&); + + const std::string& + include_prefix () const; + + std::string& + include_prefix (); + + void + include_prefix (const std::string&); + + bool + include_prefix_specified () const; + + void + include_prefix_specified (bool); + + const std::string& + guard_prefix () const; + + std::string& + guard_prefix (); + + void + guard_prefix (const std::string&); + + bool + guard_prefix_specified () const; + + void + guard_prefix_specified (bool); + + const std::map& + reserved_name () const; + + std::map& + reserved_name (); + + void + reserved_name (const std::map&); + + bool + reserved_name_specified () const; + + void + reserved_name_specified (bool); + + const std::string& + options_file () const; + + std::string& + options_file (); + + void + options_file (const std::string&); + + bool + options_file_specified () const; + + void + options_file_specified (bool); + + // Print usage information. + // + static ::cli::usage_para + print_usage (::std::ostream&, + ::cli::usage_para = ::cli::usage_para::none); + + // Implementation details. + // + protected: + bool + _parse (const char*, ::cli::scanner&); + + private: + bool + _parse (::cli::scanner&, + ::cli::unknown_mode option, + ::cli::unknown_mode argument); + + public: + bool build2_metadata_; + bool help_; + bool version_; + std::vector include_path_; + bool include_path_specified_; + std::string output_dir_; + bool output_dir_specified_; + cxx_version std_; + bool std_specified_; + bool generate_modifier_; + bool generate_specifier_; + bool generate_parse_; + bool generate_merge_; + bool generate_description_; + bool generate_file_scanner_; + bool generate_vector_scanner_; + bool generate_group_scanner_; + bool suppress_inline_; + bool suppress_cli_; + std::string cli_namespace_; + bool cli_namespace_specified_; + std::string ostream_type_; + bool ostream_type_specified_; + bool generate_cxx_; + bool generate_man_; + bool generate_html_; + bool generate_txt_; + bool stdout__; + bool suppress_undocumented_; + bool suppress_usage_; + bool long_usage_; + bool short_usage_; + std::string page_usage_; + bool page_usage_specified_; + std::size_t option_length_; + bool option_length_specified_; + bool ansi_color_; + bool exclude_base_; + bool include_base_last_; + std::map class_doc_; + bool class_doc_specified_; + std::vector class__; + bool class__specified_; + std::map docvar_; + bool docvar_specified_; + std::vector link_regex_; + bool link_regex_specified_; + bool link_regex_trace_; + std::map html_heading_map_; + bool html_heading_map_specified_; + bool omit_link_check_; + std::vector hxx_prologue_; + bool hxx_prologue_specified_; + std::vector ixx_prologue_; + bool ixx_prologue_specified_; + std::vector cxx_prologue_; + bool cxx_prologue_specified_; + std::vector man_prologue_; + bool man_prologue_specified_; + std::vector html_prologue_; + bool html_prologue_specified_; + std::vector txt_prologue_; + bool txt_prologue_specified_; + std::vector hxx_epilogue_; + bool hxx_epilogue_specified_; + std::vector ixx_epilogue_; + bool ixx_epilogue_specified_; + std::vector cxx_epilogue_; + bool cxx_epilogue_specified_; + std::vector man_epilogue_; + bool man_epilogue_specified_; + std::vector html_epilogue_; + bool html_epilogue_specified_; + std::vector txt_epilogue_; + bool txt_epilogue_specified_; + std::string hxx_prologue_file_; + bool hxx_prologue_file_specified_; + std::string ixx_prologue_file_; + bool ixx_prologue_file_specified_; + std::string cxx_prologue_file_; + bool cxx_prologue_file_specified_; + std::string man_prologue_file_; + bool man_prologue_file_specified_; + std::string html_prologue_file_; + bool html_prologue_file_specified_; + std::string txt_prologue_file_; + bool txt_prologue_file_specified_; + std::string hxx_epilogue_file_; + bool hxx_epilogue_file_specified_; + std::string ixx_epilogue_file_; + bool ixx_epilogue_file_specified_; + std::string cxx_epilogue_file_; + bool cxx_epilogue_file_specified_; + std::string man_epilogue_file_; + bool man_epilogue_file_specified_; + std::string html_epilogue_file_; + bool html_epilogue_file_specified_; + std::string txt_epilogue_file_; + bool txt_epilogue_file_specified_; + std::string output_prefix_; + bool output_prefix_specified_; + std::string output_suffix_; + bool output_suffix_specified_; + std::string hxx_suffix_; + bool hxx_suffix_specified_; + std::string ixx_suffix_; + bool ixx_suffix_specified_; + std::string cxx_suffix_; + bool cxx_suffix_specified_; + std::string man_suffix_; + bool man_suffix_specified_; + std::string html_suffix_; + bool html_suffix_specified_; + std::string txt_suffix_; + bool txt_suffix_specified_; + std::string option_prefix_; + bool option_prefix_specified_; + std::string option_separator_; + bool option_separator_specified_; + bool keep_separator_; + bool no_combined_flags_; + bool no_combined_values_; + bool include_with_brackets_; + std::string include_prefix_; + bool include_prefix_specified_; + std::string guard_prefix_; + bool guard_prefix_specified_; + std::map reserved_name_; + bool reserved_name_specified_; + std::string options_file_; + bool options_file_specified_; +}; + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // CLI_OPTIONS_HXX diff --git a/cli/cli/options.ixx b/cli/cli/options.ixx new file mode 100644 index 0000000..12d40db --- /dev/null +++ b/cli/cli/options.ixx @@ -0,0 +1,2319 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +namespace cli +{ + // usage_para + // + inline usage_para:: + usage_para (value v) + : v_ (v) + { + } + + // unknown_mode + // + inline unknown_mode:: + unknown_mode (value v) + : v_ (v) + { + } + + // exception + // + inline ::std::ostream& + operator<< (::std::ostream& os, const exception& e) + { + e.print (os); + return os; + } + + // unknown_option + // + inline unknown_option:: + unknown_option (const std::string& option) + : option_ (option) + { + } + + inline const std::string& unknown_option:: + option () const + { + return option_; + } + + // unknown_argument + // + inline unknown_argument:: + unknown_argument (const std::string& argument) + : argument_ (argument) + { + } + + inline const std::string& unknown_argument:: + argument () const + { + return argument_; + } + + // missing_value + // + inline missing_value:: + missing_value (const std::string& option) + : option_ (option) + { + } + + inline const std::string& missing_value:: + option () const + { + return option_; + } + + // invalid_value + // + inline invalid_value:: + invalid_value (const std::string& option, + const std::string& value, + const std::string& message) + : option_ (option), + value_ (value), + message_ (message) + { + } + + inline const std::string& invalid_value:: + option () const + { + return option_; + } + + inline const std::string& invalid_value:: + value () const + { + return value_; + } + + inline const std::string& invalid_value:: + message () const + { + return message_; + } + + // file_io_failure + // + inline file_io_failure:: + file_io_failure (const std::string& file) + : file_ (file) + { + } + + inline const std::string& file_io_failure:: + file () const + { + return file_; + } + + // unmatched_quote + // + inline unmatched_quote:: + unmatched_quote (const std::string& argument) + : argument_ (argument) + { + } + + inline const std::string& unmatched_quote:: + argument () const + { + return argument_; + } + + // argv_scanner + // + inline argv_scanner:: + argv_scanner (int& argc, char** argv, bool erase) + : i_ (1), argc_ (argc), argv_ (argv), erase_ (erase) + { + } + + inline argv_scanner:: + argv_scanner (int start, int& argc, char** argv, bool erase) + : i_ (start), argc_ (argc), argv_ (argv), erase_ (erase) + { + } + + inline int argv_scanner:: + end () const + { + return i_; + } + + // argv_file_scanner + // + inline argv_file_scanner:: + argv_file_scanner (int& argc, + char** argv, + const std::string& option, + bool erase) + : argv_scanner (argc, argv, erase), + option_ (option), + options_ (&option_info_), + options_count_ (1), + i_ (1), + skip_ (false) + { + option_info_.option = option_.c_str (); + option_info_.search_func = 0; + } + + inline argv_file_scanner:: + argv_file_scanner (int start, + int& argc, + char** argv, + const std::string& option, + bool erase) + : argv_scanner (start, argc, argv, erase), + option_ (option), + options_ (&option_info_), + options_count_ (1), + i_ (1), + skip_ (false) + { + option_info_.option = option_.c_str (); + option_info_.search_func = 0; + } + + inline argv_file_scanner:: + argv_file_scanner (const std::string& file, + const std::string& option) + : argv_scanner (0, zero_argc_, 0), + option_ (option), + options_ (&option_info_), + options_count_ (1), + i_ (1), + skip_ (false) + { + option_info_.option = option_.c_str (); + option_info_.search_func = 0; + + load (file); + } + + inline argv_file_scanner:: + argv_file_scanner (int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase) + : argv_scanner (argc, argv, erase), + options_ (options), + options_count_ (options_count), + i_ (1), + skip_ (false) + { + } + + inline argv_file_scanner:: + argv_file_scanner (int start, + int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase) + : argv_scanner (start, argc, argv, erase), + options_ (options), + options_count_ (options_count), + i_ (1), + skip_ (false) + { + } + + inline argv_file_scanner:: + argv_file_scanner (const std::string& file, + const option_info* options, + std::size_t options_count) + : argv_scanner (0, zero_argc_, 0), + options_ (options), + options_count_ (options_count), + i_ (1), + skip_ (false) + { + load (file); + } +} + +// options +// + +inline const bool& options:: +build2_metadata () const +{ + return this->build2_metadata_; +} + +inline bool& options:: +build2_metadata () +{ + return this->build2_metadata_; +} + +inline void options:: +build2_metadata(const bool& x) +{ + this->build2_metadata_ = x; +} + +inline const bool& options:: +help () const +{ + return this->help_; +} + +inline bool& options:: +help () +{ + return this->help_; +} + +inline void options:: +help(const bool& x) +{ + this->help_ = x; +} + +inline const bool& options:: +version () const +{ + return this->version_; +} + +inline bool& options:: +version () +{ + return this->version_; +} + +inline void options:: +version(const bool& x) +{ + this->version_ = x; +} + +inline const std::vector& options:: +include_path () const +{ + return this->include_path_; +} + +inline std::vector& options:: +include_path () +{ + return this->include_path_; +} + +inline void options:: +include_path(const std::vector& x) +{ + this->include_path_ = x; +} + +inline bool options:: +include_path_specified () const +{ + return this->include_path_specified_; +} + +inline void options:: +include_path_specified(bool x) +{ + this->include_path_specified_ = x; +} + +inline const std::string& options:: +output_dir () const +{ + return this->output_dir_; +} + +inline std::string& options:: +output_dir () +{ + return this->output_dir_; +} + +inline void options:: +output_dir(const std::string& x) +{ + this->output_dir_ = x; +} + +inline bool options:: +output_dir_specified () const +{ + return this->output_dir_specified_; +} + +inline void options:: +output_dir_specified(bool x) +{ + this->output_dir_specified_ = x; +} + +inline const cxx_version& options:: +std () const +{ + return this->std_; +} + +inline cxx_version& options:: +std () +{ + return this->std_; +} + +inline void options:: +std(const cxx_version& x) +{ + this->std_ = x; +} + +inline bool options:: +std_specified () const +{ + return this->std_specified_; +} + +inline void options:: +std_specified(bool x) +{ + this->std_specified_ = x; +} + +inline const bool& options:: +generate_modifier () const +{ + return this->generate_modifier_; +} + +inline bool& options:: +generate_modifier () +{ + return this->generate_modifier_; +} + +inline void options:: +generate_modifier(const bool& x) +{ + this->generate_modifier_ = x; +} + +inline const bool& options:: +generate_specifier () const +{ + return this->generate_specifier_; +} + +inline bool& options:: +generate_specifier () +{ + return this->generate_specifier_; +} + +inline void options:: +generate_specifier(const bool& x) +{ + this->generate_specifier_ = x; +} + +inline const bool& options:: +generate_parse () const +{ + return this->generate_parse_; +} + +inline bool& options:: +generate_parse () +{ + return this->generate_parse_; +} + +inline void options:: +generate_parse(const bool& x) +{ + this->generate_parse_ = x; +} + +inline const bool& options:: +generate_merge () const +{ + return this->generate_merge_; +} + +inline bool& options:: +generate_merge () +{ + return this->generate_merge_; +} + +inline void options:: +generate_merge(const bool& x) +{ + this->generate_merge_ = x; +} + +inline const bool& options:: +generate_description () const +{ + return this->generate_description_; +} + +inline bool& options:: +generate_description () +{ + return this->generate_description_; +} + +inline void options:: +generate_description(const bool& x) +{ + this->generate_description_ = x; +} + +inline const bool& options:: +generate_file_scanner () const +{ + return this->generate_file_scanner_; +} + +inline bool& options:: +generate_file_scanner () +{ + return this->generate_file_scanner_; +} + +inline void options:: +generate_file_scanner(const bool& x) +{ + this->generate_file_scanner_ = x; +} + +inline const bool& options:: +generate_vector_scanner () const +{ + return this->generate_vector_scanner_; +} + +inline bool& options:: +generate_vector_scanner () +{ + return this->generate_vector_scanner_; +} + +inline void options:: +generate_vector_scanner(const bool& x) +{ + this->generate_vector_scanner_ = x; +} + +inline const bool& options:: +generate_group_scanner () const +{ + return this->generate_group_scanner_; +} + +inline bool& options:: +generate_group_scanner () +{ + return this->generate_group_scanner_; +} + +inline void options:: +generate_group_scanner(const bool& x) +{ + this->generate_group_scanner_ = x; +} + +inline const bool& options:: +suppress_inline () const +{ + return this->suppress_inline_; +} + +inline bool& options:: +suppress_inline () +{ + return this->suppress_inline_; +} + +inline void options:: +suppress_inline(const bool& x) +{ + this->suppress_inline_ = x; +} + +inline const bool& options:: +suppress_cli () const +{ + return this->suppress_cli_; +} + +inline bool& options:: +suppress_cli () +{ + return this->suppress_cli_; +} + +inline void options:: +suppress_cli(const bool& x) +{ + this->suppress_cli_ = x; +} + +inline const std::string& options:: +cli_namespace () const +{ + return this->cli_namespace_; +} + +inline std::string& options:: +cli_namespace () +{ + return this->cli_namespace_; +} + +inline void options:: +cli_namespace(const std::string& x) +{ + this->cli_namespace_ = x; +} + +inline bool options:: +cli_namespace_specified () const +{ + return this->cli_namespace_specified_; +} + +inline void options:: +cli_namespace_specified(bool x) +{ + this->cli_namespace_specified_ = x; +} + +inline const std::string& options:: +ostream_type () const +{ + return this->ostream_type_; +} + +inline std::string& options:: +ostream_type () +{ + return this->ostream_type_; +} + +inline void options:: +ostream_type(const std::string& x) +{ + this->ostream_type_ = x; +} + +inline bool options:: +ostream_type_specified () const +{ + return this->ostream_type_specified_; +} + +inline void options:: +ostream_type_specified(bool x) +{ + this->ostream_type_specified_ = x; +} + +inline const bool& options:: +generate_cxx () const +{ + return this->generate_cxx_; +} + +inline bool& options:: +generate_cxx () +{ + return this->generate_cxx_; +} + +inline void options:: +generate_cxx(const bool& x) +{ + this->generate_cxx_ = x; +} + +inline const bool& options:: +generate_man () const +{ + return this->generate_man_; +} + +inline bool& options:: +generate_man () +{ + return this->generate_man_; +} + +inline void options:: +generate_man(const bool& x) +{ + this->generate_man_ = x; +} + +inline const bool& options:: +generate_html () const +{ + return this->generate_html_; +} + +inline bool& options:: +generate_html () +{ + return this->generate_html_; +} + +inline void options:: +generate_html(const bool& x) +{ + this->generate_html_ = x; +} + +inline const bool& options:: +generate_txt () const +{ + return this->generate_txt_; +} + +inline bool& options:: +generate_txt () +{ + return this->generate_txt_; +} + +inline void options:: +generate_txt(const bool& x) +{ + this->generate_txt_ = x; +} + +inline const bool& options:: +stdout_ () const +{ + return this->stdout__; +} + +inline bool& options:: +stdout_ () +{ + return this->stdout__; +} + +inline void options:: +stdout_(const bool& x) +{ + this->stdout__ = x; +} + +inline const bool& options:: +suppress_undocumented () const +{ + return this->suppress_undocumented_; +} + +inline bool& options:: +suppress_undocumented () +{ + return this->suppress_undocumented_; +} + +inline void options:: +suppress_undocumented(const bool& x) +{ + this->suppress_undocumented_ = x; +} + +inline const bool& options:: +suppress_usage () const +{ + return this->suppress_usage_; +} + +inline bool& options:: +suppress_usage () +{ + return this->suppress_usage_; +} + +inline void options:: +suppress_usage(const bool& x) +{ + this->suppress_usage_ = x; +} + +inline const bool& options:: +long_usage () const +{ + return this->long_usage_; +} + +inline bool& options:: +long_usage () +{ + return this->long_usage_; +} + +inline void options:: +long_usage(const bool& x) +{ + this->long_usage_ = x; +} + +inline const bool& options:: +short_usage () const +{ + return this->short_usage_; +} + +inline bool& options:: +short_usage () +{ + return this->short_usage_; +} + +inline void options:: +short_usage(const bool& x) +{ + this->short_usage_ = x; +} + +inline const std::string& options:: +page_usage () const +{ + return this->page_usage_; +} + +inline std::string& options:: +page_usage () +{ + return this->page_usage_; +} + +inline void options:: +page_usage(const std::string& x) +{ + this->page_usage_ = x; +} + +inline bool options:: +page_usage_specified () const +{ + return this->page_usage_specified_; +} + +inline void options:: +page_usage_specified(bool x) +{ + this->page_usage_specified_ = x; +} + +inline const std::size_t& options:: +option_length () const +{ + return this->option_length_; +} + +inline std::size_t& options:: +option_length () +{ + return this->option_length_; +} + +inline void options:: +option_length(const std::size_t& x) +{ + this->option_length_ = x; +} + +inline bool options:: +option_length_specified () const +{ + return this->option_length_specified_; +} + +inline void options:: +option_length_specified(bool x) +{ + this->option_length_specified_ = x; +} + +inline const bool& options:: +ansi_color () const +{ + return this->ansi_color_; +} + +inline bool& options:: +ansi_color () +{ + return this->ansi_color_; +} + +inline void options:: +ansi_color(const bool& x) +{ + this->ansi_color_ = x; +} + +inline const bool& options:: +exclude_base () const +{ + return this->exclude_base_; +} + +inline bool& options:: +exclude_base () +{ + return this->exclude_base_; +} + +inline void options:: +exclude_base(const bool& x) +{ + this->exclude_base_ = x; +} + +inline const bool& options:: +include_base_last () const +{ + return this->include_base_last_; +} + +inline bool& options:: +include_base_last () +{ + return this->include_base_last_; +} + +inline void options:: +include_base_last(const bool& x) +{ + this->include_base_last_ = x; +} + +inline const std::map& options:: +class_doc () const +{ + return this->class_doc_; +} + +inline std::map& options:: +class_doc () +{ + return this->class_doc_; +} + +inline void options:: +class_doc(const std::map& x) +{ + this->class_doc_ = x; +} + +inline bool options:: +class_doc_specified () const +{ + return this->class_doc_specified_; +} + +inline void options:: +class_doc_specified(bool x) +{ + this->class_doc_specified_ = x; +} + +inline const std::vector& options:: +class_ () const +{ + return this->class__; +} + +inline std::vector& options:: +class_ () +{ + return this->class__; +} + +inline void options:: +class_(const std::vector& x) +{ + this->class__ = x; +} + +inline bool options:: +class__specified () const +{ + return this->class__specified_; +} + +inline void options:: +class__specified(bool x) +{ + this->class__specified_ = x; +} + +inline const std::map& options:: +docvar () const +{ + return this->docvar_; +} + +inline std::map& options:: +docvar () +{ + return this->docvar_; +} + +inline void options:: +docvar(const std::map& x) +{ + this->docvar_ = x; +} + +inline bool options:: +docvar_specified () const +{ + return this->docvar_specified_; +} + +inline void options:: +docvar_specified(bool x) +{ + this->docvar_specified_ = x; +} + +inline const std::vector& options:: +link_regex () const +{ + return this->link_regex_; +} + +inline std::vector& options:: +link_regex () +{ + return this->link_regex_; +} + +inline void options:: +link_regex(const std::vector& x) +{ + this->link_regex_ = x; +} + +inline bool options:: +link_regex_specified () const +{ + return this->link_regex_specified_; +} + +inline void options:: +link_regex_specified(bool x) +{ + this->link_regex_specified_ = x; +} + +inline const bool& options:: +link_regex_trace () const +{ + return this->link_regex_trace_; +} + +inline bool& options:: +link_regex_trace () +{ + return this->link_regex_trace_; +} + +inline void options:: +link_regex_trace(const bool& x) +{ + this->link_regex_trace_ = x; +} + +inline const std::map& options:: +html_heading_map () const +{ + return this->html_heading_map_; +} + +inline std::map& options:: +html_heading_map () +{ + return this->html_heading_map_; +} + +inline void options:: +html_heading_map(const std::map& x) +{ + this->html_heading_map_ = x; +} + +inline bool options:: +html_heading_map_specified () const +{ + return this->html_heading_map_specified_; +} + +inline void options:: +html_heading_map_specified(bool x) +{ + this->html_heading_map_specified_ = x; +} + +inline const bool& options:: +omit_link_check () const +{ + return this->omit_link_check_; +} + +inline bool& options:: +omit_link_check () +{ + return this->omit_link_check_; +} + +inline void options:: +omit_link_check(const bool& x) +{ + this->omit_link_check_ = x; +} + +inline const std::vector& options:: +hxx_prologue () const +{ + return this->hxx_prologue_; +} + +inline std::vector& options:: +hxx_prologue () +{ + return this->hxx_prologue_; +} + +inline void options:: +hxx_prologue(const std::vector& x) +{ + this->hxx_prologue_ = x; +} + +inline bool options:: +hxx_prologue_specified () const +{ + return this->hxx_prologue_specified_; +} + +inline void options:: +hxx_prologue_specified(bool x) +{ + this->hxx_prologue_specified_ = x; +} + +inline const std::vector& options:: +ixx_prologue () const +{ + return this->ixx_prologue_; +} + +inline std::vector& options:: +ixx_prologue () +{ + return this->ixx_prologue_; +} + +inline void options:: +ixx_prologue(const std::vector& x) +{ + this->ixx_prologue_ = x; +} + +inline bool options:: +ixx_prologue_specified () const +{ + return this->ixx_prologue_specified_; +} + +inline void options:: +ixx_prologue_specified(bool x) +{ + this->ixx_prologue_specified_ = x; +} + +inline const std::vector& options:: +cxx_prologue () const +{ + return this->cxx_prologue_; +} + +inline std::vector& options:: +cxx_prologue () +{ + return this->cxx_prologue_; +} + +inline void options:: +cxx_prologue(const std::vector& x) +{ + this->cxx_prologue_ = x; +} + +inline bool options:: +cxx_prologue_specified () const +{ + return this->cxx_prologue_specified_; +} + +inline void options:: +cxx_prologue_specified(bool x) +{ + this->cxx_prologue_specified_ = x; +} + +inline const std::vector& options:: +man_prologue () const +{ + return this->man_prologue_; +} + +inline std::vector& options:: +man_prologue () +{ + return this->man_prologue_; +} + +inline void options:: +man_prologue(const std::vector& x) +{ + this->man_prologue_ = x; +} + +inline bool options:: +man_prologue_specified () const +{ + return this->man_prologue_specified_; +} + +inline void options:: +man_prologue_specified(bool x) +{ + this->man_prologue_specified_ = x; +} + +inline const std::vector& options:: +html_prologue () const +{ + return this->html_prologue_; +} + +inline std::vector& options:: +html_prologue () +{ + return this->html_prologue_; +} + +inline void options:: +html_prologue(const std::vector& x) +{ + this->html_prologue_ = x; +} + +inline bool options:: +html_prologue_specified () const +{ + return this->html_prologue_specified_; +} + +inline void options:: +html_prologue_specified(bool x) +{ + this->html_prologue_specified_ = x; +} + +inline const std::vector& options:: +txt_prologue () const +{ + return this->txt_prologue_; +} + +inline std::vector& options:: +txt_prologue () +{ + return this->txt_prologue_; +} + +inline void options:: +txt_prologue(const std::vector& x) +{ + this->txt_prologue_ = x; +} + +inline bool options:: +txt_prologue_specified () const +{ + return this->txt_prologue_specified_; +} + +inline void options:: +txt_prologue_specified(bool x) +{ + this->txt_prologue_specified_ = x; +} + +inline const std::vector& options:: +hxx_epilogue () const +{ + return this->hxx_epilogue_; +} + +inline std::vector& options:: +hxx_epilogue () +{ + return this->hxx_epilogue_; +} + +inline void options:: +hxx_epilogue(const std::vector& x) +{ + this->hxx_epilogue_ = x; +} + +inline bool options:: +hxx_epilogue_specified () const +{ + return this->hxx_epilogue_specified_; +} + +inline void options:: +hxx_epilogue_specified(bool x) +{ + this->hxx_epilogue_specified_ = x; +} + +inline const std::vector& options:: +ixx_epilogue () const +{ + return this->ixx_epilogue_; +} + +inline std::vector& options:: +ixx_epilogue () +{ + return this->ixx_epilogue_; +} + +inline void options:: +ixx_epilogue(const std::vector& x) +{ + this->ixx_epilogue_ = x; +} + +inline bool options:: +ixx_epilogue_specified () const +{ + return this->ixx_epilogue_specified_; +} + +inline void options:: +ixx_epilogue_specified(bool x) +{ + this->ixx_epilogue_specified_ = x; +} + +inline const std::vector& options:: +cxx_epilogue () const +{ + return this->cxx_epilogue_; +} + +inline std::vector& options:: +cxx_epilogue () +{ + return this->cxx_epilogue_; +} + +inline void options:: +cxx_epilogue(const std::vector& x) +{ + this->cxx_epilogue_ = x; +} + +inline bool options:: +cxx_epilogue_specified () const +{ + return this->cxx_epilogue_specified_; +} + +inline void options:: +cxx_epilogue_specified(bool x) +{ + this->cxx_epilogue_specified_ = x; +} + +inline const std::vector& options:: +man_epilogue () const +{ + return this->man_epilogue_; +} + +inline std::vector& options:: +man_epilogue () +{ + return this->man_epilogue_; +} + +inline void options:: +man_epilogue(const std::vector& x) +{ + this->man_epilogue_ = x; +} + +inline bool options:: +man_epilogue_specified () const +{ + return this->man_epilogue_specified_; +} + +inline void options:: +man_epilogue_specified(bool x) +{ + this->man_epilogue_specified_ = x; +} + +inline const std::vector& options:: +html_epilogue () const +{ + return this->html_epilogue_; +} + +inline std::vector& options:: +html_epilogue () +{ + return this->html_epilogue_; +} + +inline void options:: +html_epilogue(const std::vector& x) +{ + this->html_epilogue_ = x; +} + +inline bool options:: +html_epilogue_specified () const +{ + return this->html_epilogue_specified_; +} + +inline void options:: +html_epilogue_specified(bool x) +{ + this->html_epilogue_specified_ = x; +} + +inline const std::vector& options:: +txt_epilogue () const +{ + return this->txt_epilogue_; +} + +inline std::vector& options:: +txt_epilogue () +{ + return this->txt_epilogue_; +} + +inline void options:: +txt_epilogue(const std::vector& x) +{ + this->txt_epilogue_ = x; +} + +inline bool options:: +txt_epilogue_specified () const +{ + return this->txt_epilogue_specified_; +} + +inline void options:: +txt_epilogue_specified(bool x) +{ + this->txt_epilogue_specified_ = x; +} + +inline const std::string& options:: +hxx_prologue_file () const +{ + return this->hxx_prologue_file_; +} + +inline std::string& options:: +hxx_prologue_file () +{ + return this->hxx_prologue_file_; +} + +inline void options:: +hxx_prologue_file(const std::string& x) +{ + this->hxx_prologue_file_ = x; +} + +inline bool options:: +hxx_prologue_file_specified () const +{ + return this->hxx_prologue_file_specified_; +} + +inline void options:: +hxx_prologue_file_specified(bool x) +{ + this->hxx_prologue_file_specified_ = x; +} + +inline const std::string& options:: +ixx_prologue_file () const +{ + return this->ixx_prologue_file_; +} + +inline std::string& options:: +ixx_prologue_file () +{ + return this->ixx_prologue_file_; +} + +inline void options:: +ixx_prologue_file(const std::string& x) +{ + this->ixx_prologue_file_ = x; +} + +inline bool options:: +ixx_prologue_file_specified () const +{ + return this->ixx_prologue_file_specified_; +} + +inline void options:: +ixx_prologue_file_specified(bool x) +{ + this->ixx_prologue_file_specified_ = x; +} + +inline const std::string& options:: +cxx_prologue_file () const +{ + return this->cxx_prologue_file_; +} + +inline std::string& options:: +cxx_prologue_file () +{ + return this->cxx_prologue_file_; +} + +inline void options:: +cxx_prologue_file(const std::string& x) +{ + this->cxx_prologue_file_ = x; +} + +inline bool options:: +cxx_prologue_file_specified () const +{ + return this->cxx_prologue_file_specified_; +} + +inline void options:: +cxx_prologue_file_specified(bool x) +{ + this->cxx_prologue_file_specified_ = x; +} + +inline const std::string& options:: +man_prologue_file () const +{ + return this->man_prologue_file_; +} + +inline std::string& options:: +man_prologue_file () +{ + return this->man_prologue_file_; +} + +inline void options:: +man_prologue_file(const std::string& x) +{ + this->man_prologue_file_ = x; +} + +inline bool options:: +man_prologue_file_specified () const +{ + return this->man_prologue_file_specified_; +} + +inline void options:: +man_prologue_file_specified(bool x) +{ + this->man_prologue_file_specified_ = x; +} + +inline const std::string& options:: +html_prologue_file () const +{ + return this->html_prologue_file_; +} + +inline std::string& options:: +html_prologue_file () +{ + return this->html_prologue_file_; +} + +inline void options:: +html_prologue_file(const std::string& x) +{ + this->html_prologue_file_ = x; +} + +inline bool options:: +html_prologue_file_specified () const +{ + return this->html_prologue_file_specified_; +} + +inline void options:: +html_prologue_file_specified(bool x) +{ + this->html_prologue_file_specified_ = x; +} + +inline const std::string& options:: +txt_prologue_file () const +{ + return this->txt_prologue_file_; +} + +inline std::string& options:: +txt_prologue_file () +{ + return this->txt_prologue_file_; +} + +inline void options:: +txt_prologue_file(const std::string& x) +{ + this->txt_prologue_file_ = x; +} + +inline bool options:: +txt_prologue_file_specified () const +{ + return this->txt_prologue_file_specified_; +} + +inline void options:: +txt_prologue_file_specified(bool x) +{ + this->txt_prologue_file_specified_ = x; +} + +inline const std::string& options:: +hxx_epilogue_file () const +{ + return this->hxx_epilogue_file_; +} + +inline std::string& options:: +hxx_epilogue_file () +{ + return this->hxx_epilogue_file_; +} + +inline void options:: +hxx_epilogue_file(const std::string& x) +{ + this->hxx_epilogue_file_ = x; +} + +inline bool options:: +hxx_epilogue_file_specified () const +{ + return this->hxx_epilogue_file_specified_; +} + +inline void options:: +hxx_epilogue_file_specified(bool x) +{ + this->hxx_epilogue_file_specified_ = x; +} + +inline const std::string& options:: +ixx_epilogue_file () const +{ + return this->ixx_epilogue_file_; +} + +inline std::string& options:: +ixx_epilogue_file () +{ + return this->ixx_epilogue_file_; +} + +inline void options:: +ixx_epilogue_file(const std::string& x) +{ + this->ixx_epilogue_file_ = x; +} + +inline bool options:: +ixx_epilogue_file_specified () const +{ + return this->ixx_epilogue_file_specified_; +} + +inline void options:: +ixx_epilogue_file_specified(bool x) +{ + this->ixx_epilogue_file_specified_ = x; +} + +inline const std::string& options:: +cxx_epilogue_file () const +{ + return this->cxx_epilogue_file_; +} + +inline std::string& options:: +cxx_epilogue_file () +{ + return this->cxx_epilogue_file_; +} + +inline void options:: +cxx_epilogue_file(const std::string& x) +{ + this->cxx_epilogue_file_ = x; +} + +inline bool options:: +cxx_epilogue_file_specified () const +{ + return this->cxx_epilogue_file_specified_; +} + +inline void options:: +cxx_epilogue_file_specified(bool x) +{ + this->cxx_epilogue_file_specified_ = x; +} + +inline const std::string& options:: +man_epilogue_file () const +{ + return this->man_epilogue_file_; +} + +inline std::string& options:: +man_epilogue_file () +{ + return this->man_epilogue_file_; +} + +inline void options:: +man_epilogue_file(const std::string& x) +{ + this->man_epilogue_file_ = x; +} + +inline bool options:: +man_epilogue_file_specified () const +{ + return this->man_epilogue_file_specified_; +} + +inline void options:: +man_epilogue_file_specified(bool x) +{ + this->man_epilogue_file_specified_ = x; +} + +inline const std::string& options:: +html_epilogue_file () const +{ + return this->html_epilogue_file_; +} + +inline std::string& options:: +html_epilogue_file () +{ + return this->html_epilogue_file_; +} + +inline void options:: +html_epilogue_file(const std::string& x) +{ + this->html_epilogue_file_ = x; +} + +inline bool options:: +html_epilogue_file_specified () const +{ + return this->html_epilogue_file_specified_; +} + +inline void options:: +html_epilogue_file_specified(bool x) +{ + this->html_epilogue_file_specified_ = x; +} + +inline const std::string& options:: +txt_epilogue_file () const +{ + return this->txt_epilogue_file_; +} + +inline std::string& options:: +txt_epilogue_file () +{ + return this->txt_epilogue_file_; +} + +inline void options:: +txt_epilogue_file(const std::string& x) +{ + this->txt_epilogue_file_ = x; +} + +inline bool options:: +txt_epilogue_file_specified () const +{ + return this->txt_epilogue_file_specified_; +} + +inline void options:: +txt_epilogue_file_specified(bool x) +{ + this->txt_epilogue_file_specified_ = x; +} + +inline const std::string& options:: +output_prefix () const +{ + return this->output_prefix_; +} + +inline std::string& options:: +output_prefix () +{ + return this->output_prefix_; +} + +inline void options:: +output_prefix(const std::string& x) +{ + this->output_prefix_ = x; +} + +inline bool options:: +output_prefix_specified () const +{ + return this->output_prefix_specified_; +} + +inline void options:: +output_prefix_specified(bool x) +{ + this->output_prefix_specified_ = x; +} + +inline const std::string& options:: +output_suffix () const +{ + return this->output_suffix_; +} + +inline std::string& options:: +output_suffix () +{ + return this->output_suffix_; +} + +inline void options:: +output_suffix(const std::string& x) +{ + this->output_suffix_ = x; +} + +inline bool options:: +output_suffix_specified () const +{ + return this->output_suffix_specified_; +} + +inline void options:: +output_suffix_specified(bool x) +{ + this->output_suffix_specified_ = x; +} + +inline const std::string& options:: +hxx_suffix () const +{ + return this->hxx_suffix_; +} + +inline std::string& options:: +hxx_suffix () +{ + return this->hxx_suffix_; +} + +inline void options:: +hxx_suffix(const std::string& x) +{ + this->hxx_suffix_ = x; +} + +inline bool options:: +hxx_suffix_specified () const +{ + return this->hxx_suffix_specified_; +} + +inline void options:: +hxx_suffix_specified(bool x) +{ + this->hxx_suffix_specified_ = x; +} + +inline const std::string& options:: +ixx_suffix () const +{ + return this->ixx_suffix_; +} + +inline std::string& options:: +ixx_suffix () +{ + return this->ixx_suffix_; +} + +inline void options:: +ixx_suffix(const std::string& x) +{ + this->ixx_suffix_ = x; +} + +inline bool options:: +ixx_suffix_specified () const +{ + return this->ixx_suffix_specified_; +} + +inline void options:: +ixx_suffix_specified(bool x) +{ + this->ixx_suffix_specified_ = x; +} + +inline const std::string& options:: +cxx_suffix () const +{ + return this->cxx_suffix_; +} + +inline std::string& options:: +cxx_suffix () +{ + return this->cxx_suffix_; +} + +inline void options:: +cxx_suffix(const std::string& x) +{ + this->cxx_suffix_ = x; +} + +inline bool options:: +cxx_suffix_specified () const +{ + return this->cxx_suffix_specified_; +} + +inline void options:: +cxx_suffix_specified(bool x) +{ + this->cxx_suffix_specified_ = x; +} + +inline const std::string& options:: +man_suffix () const +{ + return this->man_suffix_; +} + +inline std::string& options:: +man_suffix () +{ + return this->man_suffix_; +} + +inline void options:: +man_suffix(const std::string& x) +{ + this->man_suffix_ = x; +} + +inline bool options:: +man_suffix_specified () const +{ + return this->man_suffix_specified_; +} + +inline void options:: +man_suffix_specified(bool x) +{ + this->man_suffix_specified_ = x; +} + +inline const std::string& options:: +html_suffix () const +{ + return this->html_suffix_; +} + +inline std::string& options:: +html_suffix () +{ + return this->html_suffix_; +} + +inline void options:: +html_suffix(const std::string& x) +{ + this->html_suffix_ = x; +} + +inline bool options:: +html_suffix_specified () const +{ + return this->html_suffix_specified_; +} + +inline void options:: +html_suffix_specified(bool x) +{ + this->html_suffix_specified_ = x; +} + +inline const std::string& options:: +txt_suffix () const +{ + return this->txt_suffix_; +} + +inline std::string& options:: +txt_suffix () +{ + return this->txt_suffix_; +} + +inline void options:: +txt_suffix(const std::string& x) +{ + this->txt_suffix_ = x; +} + +inline bool options:: +txt_suffix_specified () const +{ + return this->txt_suffix_specified_; +} + +inline void options:: +txt_suffix_specified(bool x) +{ + this->txt_suffix_specified_ = x; +} + +inline const std::string& options:: +option_prefix () const +{ + return this->option_prefix_; +} + +inline std::string& options:: +option_prefix () +{ + return this->option_prefix_; +} + +inline void options:: +option_prefix(const std::string& x) +{ + this->option_prefix_ = x; +} + +inline bool options:: +option_prefix_specified () const +{ + return this->option_prefix_specified_; +} + +inline void options:: +option_prefix_specified(bool x) +{ + this->option_prefix_specified_ = x; +} + +inline const std::string& options:: +option_separator () const +{ + return this->option_separator_; +} + +inline std::string& options:: +option_separator () +{ + return this->option_separator_; +} + +inline void options:: +option_separator(const std::string& x) +{ + this->option_separator_ = x; +} + +inline bool options:: +option_separator_specified () const +{ + return this->option_separator_specified_; +} + +inline void options:: +option_separator_specified(bool x) +{ + this->option_separator_specified_ = x; +} + +inline const bool& options:: +keep_separator () const +{ + return this->keep_separator_; +} + +inline bool& options:: +keep_separator () +{ + return this->keep_separator_; +} + +inline void options:: +keep_separator(const bool& x) +{ + this->keep_separator_ = x; +} + +inline const bool& options:: +no_combined_flags () const +{ + return this->no_combined_flags_; +} + +inline bool& options:: +no_combined_flags () +{ + return this->no_combined_flags_; +} + +inline void options:: +no_combined_flags(const bool& x) +{ + this->no_combined_flags_ = x; +} + +inline const bool& options:: +no_combined_values () const +{ + return this->no_combined_values_; +} + +inline bool& options:: +no_combined_values () +{ + return this->no_combined_values_; +} + +inline void options:: +no_combined_values(const bool& x) +{ + this->no_combined_values_ = x; +} + +inline const bool& options:: +include_with_brackets () const +{ + return this->include_with_brackets_; +} + +inline bool& options:: +include_with_brackets () +{ + return this->include_with_brackets_; +} + +inline void options:: +include_with_brackets(const bool& x) +{ + this->include_with_brackets_ = x; +} + +inline const std::string& options:: +include_prefix () const +{ + return this->include_prefix_; +} + +inline std::string& options:: +include_prefix () +{ + return this->include_prefix_; +} + +inline void options:: +include_prefix(const std::string& x) +{ + this->include_prefix_ = x; +} + +inline bool options:: +include_prefix_specified () const +{ + return this->include_prefix_specified_; +} + +inline void options:: +include_prefix_specified(bool x) +{ + this->include_prefix_specified_ = x; +} + +inline const std::string& options:: +guard_prefix () const +{ + return this->guard_prefix_; +} + +inline std::string& options:: +guard_prefix () +{ + return this->guard_prefix_; +} + +inline void options:: +guard_prefix(const std::string& x) +{ + this->guard_prefix_ = x; +} + +inline bool options:: +guard_prefix_specified () const +{ + return this->guard_prefix_specified_; +} + +inline void options:: +guard_prefix_specified(bool x) +{ + this->guard_prefix_specified_ = x; +} + +inline const std::map& options:: +reserved_name () const +{ + return this->reserved_name_; +} + +inline std::map& options:: +reserved_name () +{ + return this->reserved_name_; +} + +inline void options:: +reserved_name(const std::map& x) +{ + this->reserved_name_ = x; +} + +inline bool options:: +reserved_name_specified () const +{ + return this->reserved_name_specified_; +} + +inline void options:: +reserved_name_specified(bool x) +{ + this->reserved_name_specified_ = x; +} + +inline const std::string& options:: +options_file () const +{ + return this->options_file_; +} + +inline std::string& options:: +options_file () +{ + return this->options_file_; +} + +inline void options:: +options_file(const std::string& x) +{ + this->options_file_ = x; +} + +inline bool options:: +options_file_specified () const +{ + return this->options_file_specified_; +} + +inline void options:: +options_file_specified(bool x) +{ + this->options_file_specified_ = x; +} + +// Begin epilogue. +// +// +// End epilogue. diff --git a/cli/cli/parser.cxx b/cli/cli/parser.cxx new file mode 100644 index 0000000..4685edc --- /dev/null +++ b/cli/cli/parser.cxx @@ -0,0 +1,1728 @@ +// file : cli/parser.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#ifndef _WIN32 +# include // stat +# include // stat +# include // stat +#else +# include // _stat +# include // _stat(), S_I* + +# ifdef _MSC_VER // Unlikely to be fixed in newer versions. +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +# endif +#endif + +#include +#include +#include + +#include +#include +#include + +#include + +using namespace std; +using namespace semantics; + +// Check that the file exist without checking for permissions, etc. +// +inline static bool +file_exists (const path& p) +{ +#ifndef _WIN32 + struct stat s; + int r (stat (p.string ().c_str (), &s)); +#else + struct _stat s; + int r (_stat (p.string ().c_str (), &s)); +#endif + + return r == 0 && S_ISREG (s.st_mode); +} + +const char* keywords[] = +{ + "include", + "namespace", + "class", + "signed", + "unsigned", + "bool", + "char", + "wchar_t", + "short", + "int", + "long", + "float", + "double" +}; + +const char* punctuation[] = { + ";", ",", ":", "::", "{", "}", /*"(", ")",*/ "=", "|"}; + +// Output the token type and value in a format suitable for diagnostics. +// +std::ostream& +operator<< (std::ostream& os, token const& t) +{ + switch (t.type ()) + { + case token::t_eos: + { + os << "end-of-stream"; + break; + } + case token::t_keyword: + { + os << "keyword '" << keywords[t.keyword ()] << "'"; + break; + } + case token::t_identifier: + { + os << "identifier '" << t.identifier () << "'"; + break; + } + case token::t_punctuation: + { + os << "'" << punctuation[t.punctuation ()] << "'"; + break; + } + case token::t_cxx_path_lit: + { + os << "c++ path literal"; + break; + } + case token::t_cli_path_lit: + { + os << "cli path literal"; + break; + } + case token::t_string_lit: + { + os << "string literal"; + break; + } + case token::t_char_lit: + { + os << "char literal"; + break; + } + case token::t_bool_lit: + { + os << "bool literal"; + break; + } + case token::t_int_lit: + { + os << "integer literal"; + break; + } + case token::t_float_lit: + { + os << "floating point literal"; + break; + } + case token::t_call_expr: + { + os << "call expression"; + break; + } + case token::t_template_expr: + { + os << "template expression"; + break; + } + } + + return os; +} + +// RAII-style set new value on construction, restore old one on destruction. +// +template +struct auto_restore +{ + auto_restore (T*& var, T* new_val = 0) + : var_ (var), old_val_ (var_) + { + if (new_val != 0) + var_ = new_val; + } + + void + set (T* new_val) {var_ = new_val;} + + ~auto_restore () {var_ = old_val_;} + +private: + T*& var_; + T* old_val_; +}; + + +void parser:: +recover (token& t) +{ + // Recover by skipping past next ';' or '}'. + // + for (;; t = lexer_->next ()) + { + if (t.type () == token::t_eos) + break; + + token::punctuation_type p (t.punctuation ()); + + if (p == token::p_semi || p == token::p_rcbrace) + { + t = lexer_->next (); + break; + } + } +} + +unique_ptr parser:: +parse (std::istream& is, path const& p) +{ + unique_ptr unit (new cli_unit (p, 1, 1)); + + { + path ap (p); + ap.absolute (); + ap.normalize (); + include_map_[ap] = unit.get (); + } + + root_ = cur_ = unit.get (); + + lexer l (is, p.string ()); + lexer_ = &l; + + doc_count_ = 0; + + path_ = &p; + valid_ = true; + + def_unit (); + + if (!valid_ || !l.valid ()) + throw invalid_input (); + + return unit; +} + +void parser:: +def_unit () +{ + token t (lexer_->next ()); + + // include-decl-seq + // + for (token::keyword_type k (t.keyword ()); + k == token::k_include || k == token::k_source; + k = t.keyword ()) + { + try + { + if (k == token::k_include) + include_decl (); + else + source_decl (); + + t = lexer_->next (); + } + catch (error const&) + { + valid_ = false; + recover (t); + } + } + + auto_restore new_scope (scope_, cur_); + + // decl-seq + // + while (t.type () != token::t_eos) + { + try + { + if (t.keyword () == token::k_source) + { + try + { + source_decl (); + t = lexer_->next (); + } + catch (error const&) + { + valid_ = false; + recover (t); + } + + continue; + } + + if (decl (t)) + { + t = lexer_->next (); + continue; + } + + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected namespace, class, or documentation instead of " + << t << endl; + throw error (); + } + catch (error const&) + { + valid_ = false; + break; // Non-recoverable error. + } + } +} + +void parser:: +source_decl () +{ + token t (lexer_->next ()); + + if (t.type () != token::t_cli_path_lit) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected cli path literal instead of " << t << endl; + throw error (); + } + + string const& l (t.literal ()); + bool q (l[0] == '"'); // Quote or braket include? + + path f; + try + { + f = path (string (l, 1, l.size () - 2)); + } + catch (const invalid_path& e) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "'" << e.path () << "' is not a valid filesystem path" << endl; + valid_ = false; + } + + if (valid_) + { + path p; + + // If this is a quote include, then include relative to the current + // file. + // + if (q) + { + p = path_->directory () / f; + p.normalize (); + } + // Otherwise search the include directories (-I). + // + else + { + for (paths::const_iterator i (include_paths_.begin ()); + i != include_paths_.end (); ++i) + { + p = *i / f; + p.normalize (); + + if (file_exists (p)) + break; + + p.clear (); + } + + if (p.empty ()) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": " + << "error: file '" << f << "' not found in any of the " + << "include search directories (-I)" << endl; + valid_ = false; + } + } + + if (valid_) + { + auto_restore new_path (path_, &p); + + ifstream ifs (p.string ().c_str ()); + if (ifs.is_open ()) + { + ifs.exceptions (ifstream::failbit | ifstream::badbit); + + try + { + lexer l (ifs, p.string ()); + auto_restore new_lexer (lexer_, &l); + + def_unit (); + + if (!l.valid ()) + valid_ = false; + } + catch (std::ios_base::failure const&) + { + cerr << p << ": error: read failure" << endl; + valid_ = false; + } + } + else + { + cerr << p << ": error: unable to open in read mode" << endl; + valid_ = false; + } + } + } + + t = lexer_->next (); + + if (t.punctuation () != token::p_semi) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected ';' instead of " << t << endl; + throw error (); + } +} + +void parser:: +include_decl () +{ + token t (lexer_->next ()); + token::token_type tt (t.type ()); + + if (tt != token::t_cxx_path_lit && tt != token::t_cli_path_lit) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected path literal instead of " << t << endl; + throw error (); + } + + string const& l (t.literal ()); + includes::kind_type ik (l[0] == '<' ? includes::bracket : includes::quote); + + path f; + try + { + f = path (string (l, 1, l.size () - 2)); + } + catch (const invalid_path& e) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "'" << e.path () << "' is not a valid filesystem path" << endl; + valid_ = false; + } + + if (valid_) + { + if (tt == token::t_cxx_path_lit) + { + cxx_unit& n ( + root_->new_node (*path_, t.line (), t.column ())); + root_->new_edge (*cur_, n, ik, f); + } + else + { + path p; + // If this is a quote include, then include relative to the current + // file. + // + if (ik == includes::quote) + { + p = path_->directory () / f; + p.normalize (); + } + // Otherwise search the include directories (-I). + // + else + { + for (paths::const_iterator i (include_paths_.begin ()); + i != include_paths_.end (); ++i) + { + p = *i / f; + p.normalize (); + + if (file_exists (p)) + break; + + p.clear (); + } + + if (p.empty ()) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": " + << "error: file '" << f << "' not found in any of the " + << "include search directories (-I)" << endl; + valid_ = false; + } + } + + if (valid_) + { + // Detect and ignore multiple inclusions. + // + path ap (p); + ap.absolute (); + ap.normalize (); + + include_map::iterator it (include_map_.find (ap)); + if (it == include_map_.end ()) + { + cli_unit& n (root_->new_node (p, 1, 1)); + root_->new_edge (*cur_, n, ik, f); + include_map_[ap] = &n; + + auto_restore new_cur (cur_, &n); + auto_restore new_path (path_, &p); + + ifstream ifs (p.string ().c_str ()); + if (ifs.is_open ()) + { + ifs.exceptions (ifstream::failbit | ifstream::badbit); + + try + { + lexer l (ifs, p.string ()); + auto_restore new_lexer (lexer_, &l); + + def_unit (); + + if (!l.valid ()) + valid_ = false; + } + catch (std::ios_base::failure const&) + { + cerr << p << ": error: read failure" << endl; + valid_ = false; + } + } + else + { + cerr << p << ": error: unable to open in read mode" << endl; + valid_ = false; + } + } + else + root_->new_edge (*cur_, *it->second, ik, f); + } + } + } + + t = lexer_->next (); + + if (t.punctuation () != token::p_semi) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected ';' instead of " << t << endl; + throw error (); + } +} + +bool parser:: +decl (token& t) +{ + switch (t.type ()) + { + case token::t_keyword: + { + switch (t.keyword ()) + { + case token::k_namespace: + { + namespace_def (); + return true; + } + case token::k_class: + { + class_def (); + return true; + } + default: + break; + } + + break; + } + case token::t_punctuation: + { + if (t.punctuation () != token::p_lcbrace) + break; + } + // Fall through. + case token::t_string_lit: + { + scope_doc (t); + return true; + } + default: + break; + } + + return false; +} + +void parser:: +scope_doc (token& t) +{ + size_t ln (t.line ()), cl (t.column ()); + + // Use a counter to give scope-level docs unique names. We use a + // single counter throughout all units/scope because we could be + // reopening namespaces. + // + if (t.type () == token::t_string_lit) + { + // string-literal + // + if (valid_) + { + // Enter each ""-enclosed string as a separate documentation + // entry, handle documentation variables. + // + const string& l (t.literal ()); + + char p ('\0'); + for (size_t b (0), e (1); e < l.size (); ++e) + { + if (l[e] == '"' && p != '\\') + { + string s (doc_string (l.c_str () + b, e - b + 1)); + + if (!s.empty ()) + { + doc& d (root_->new_node (*path_, ln, cl)); + + // See if this is a variable assignment: "\=". + // + size_t p (0); // '=' position. + if (s.size () >= 3 && s[0] == '\\' && s[1] != '\\') + { + for (p = 1; p != s.size (); ++p) + { + char c (s[p]); + + // Variable name should be a C identifier. + // + if (!(c == '_' || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + (p != 1 && '0' <= c && c <= '9'))) + break; + } + + if (p == s.size () || s[p] != '=' || p == 1) // Not a variable. + p = 0; + } + + if (p != 0) + { + root_->new_edge ( + *scope_, d, "var: " + string (s, 1, p - 1)); + s = string (s, p + 1); + } + else + { + ostringstream os; + os << "doc: " << doc_count_++; + root_->new_edge (*scope_, d, os.str ()); + } + + d.push_back (s); // move(). + } + + // If we have more, then make b point to the opening '"'. Second + // ++e in for() above will make e point to the character after it. + // + b = ++e; + continue; + } + + // We need to keep track of \\ escapings so we don't confuse + // them with \", as in \\". + // + if (l[e] == '\\' && p == '\\') + p = '\0'; + else + p = l[e]; + } + } + } + else + { + // doc-string-seq + // + assert (t.punctuation () == token::p_lcbrace); + + doc* d (0); + if (valid_) + { + ostringstream os; + os << "doc: " << doc_count_++; + + d = &root_->new_node (*path_, ln, cl); + root_->new_edge (*scope_, *d, os.str ()); + } + + for (t = lexer_->next ();; t = lexer_->next ()) + { + if (t.type () != token::t_string_lit) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected documentation string instead of " << t << endl; + throw error (); + } + + if (valid_) + d->push_back (doc_string (t.literal ().c_str (), + t.literal ().size ())); + + t = lexer_->next (); + + if (t.punctuation () != token::p_comma) + break; + } + + if (t.punctuation () != token::p_rcbrace) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected '}' instead of " << t << endl; + throw error (); + } + } +} + +void parser:: +namespace_def () +{ + token t (lexer_->next ()); + + if (t.type () != token::t_identifier) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected identifier instead of " << t << endl; + throw error (); + } + + auto_restore new_scope (scope_); + + if (valid_) + { + namespace_& n ( + root_->new_node (*path_, t.line (), t.column ())); + root_->new_edge (*scope_, n, t.identifier ()); + new_scope.set (&n); + } + + t = lexer_->next (); + + if (t.punctuation () != token::p_lcbrace) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected '{' instead of " << t << endl; + throw error (); + } + + // decl-seq + // + t = lexer_->next (); + + while (decl (t)) + t = lexer_->next (); + + if (t.punctuation () != token::p_rcbrace) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected namespace, class, documentation, or '}' instead of " + << t << endl; + throw error (); + } +} + +void parser:: +class_def () +{ + token t (lexer_->next ()); + + if (t.type () != token::t_identifier) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected identifier instead of " << t << endl; + throw error (); + } + + class_* n (0); + if (valid_) + { + n = &root_->new_node (*path_, t.line (), t.column ()); + root_->new_edge (*scope_, *n, t.identifier ()); + } + + t = lexer_->next (); + + // inheritance-spec + // + if (t.punctuation () == token::p_colon) + { + for (;;) + { + t = lexer_->next (); + size_t line (t.line ()), col (t.column ()); + + string name; + if (!qualified_name (t, name)) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected qualified name instead of " << t << endl; + throw error (); + } + + string ns; + + // If it is a fully-qualifed name, then start from the global namespace. + // Otherwise, from the current scope. + // + if (name[0] == ':') + name = string (name, 2, string::npos); + else + ns = scope_->fq_name (); + + if (class_* b = cur_->lookup (ns, name)) + root_->new_edge (*n, *b); + else + { + cerr << *path_ << ':' << line << ':' << col << ": error: " + << "unable to resolve base class '" << name << "'" << endl; + valid_ = false; + } + + if (t.punctuation () != token::p_comma) + break; + } + } + + // abstract-spec + // + if (t.punctuation () == token::p_eq) + { + t = lexer_->next (); + + if (t.type () != token::t_int_lit || t.literal () != "0") + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected '0' instead of " << t << endl; + throw error (); + } + + if (n != 0) + n->abstract (true); + + t = lexer_->next (); + } + + if (t.punctuation () != token::p_lcbrace) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected '{' instead of " << t << endl; + throw error (); + } + + auto_restore new_scope (scope_, n); + + // class-decl-seq + // + t = lexer_->next (); + + for (;;) + { + try + { + if (t.type () == token::t_string_lit || + t.punctuation () == token::p_lcbrace) + { + scope_doc (t); + t = lexer_->next (); + } + else + { + if (!option_def (t)) + break; + } + } + catch (error const&) + { + valid_ = false; + recover (t); + } + } + + if (t.punctuation () != token::p_rcbrace) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected option, documentation, or '}' instead of " << t << endl; + throw error (); + } + + t = lexer_->next (); + + if (t.punctuation () != token::p_semi) + { + cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " + << "expected ';' instead of " << t << endl; + throw error (); + } +} + +bool parser:: +option_def (token& t) +{ + size_t l (t.line ()), c (t.column ()); + + // type-spec + // + // These two functions set t to the next token if they return + // true. + // + string type_name; + + if (!qualified_name (t, type_name) && !fundamental_type (t, type_name)) + return false; + + option* o (0); + + if (valid_) + { + o = &root_->new_node
    " << endl - << endl; - list_ = false; - } - - wrap_lines (os, s, (t || toc) ? 0 : 2); // TOC mode does its own thing. - - if (!toc) // TOC mode does its own thing. - os << endl - << endl; - } - - private: - class_doc_type cd_; - bool& list_; // True if we are currently in
    . - }; - - struct option: traversal::option, context - { - option (context& c, class_doc_type cd, bool& l) - : context (c), cd_ (cd), list_ (l) {} - - virtual void - traverse (type& o) - { - using semantics::names; - - semantics::doc_strings const& doc (o.doc ()); - - if (options.suppress_undocumented () && doc.empty ()) - return; - - if (toc) - return; // No option documentation in the TOC mode. - - if (!list_) - { - os << "
    " << endl; - list_ = true; - } - else - os << endl; // Separate from the previous
    . - - names& n (o.named ()); - - os << "
    "; - - for (names::name_iterator i (n.name_begin ()); i != n.name_end (); ++i) - { - if (i != n.name_begin ()) - os << "|"; - - os << escape_html (*i); - } - - os << ""; - - string type (o.type ().name ()); - - std::set arg_set; - - if (type != "bool" || doc.size () >= 3) - { - string s ( - translate_arg ( - doc.size () > 0 ? doc[0] : string (""), arg_set)); - - os << ' ' << format (o.scope (), escape_html (s), false); - } - - os << "
    " << endl; - - string d; - if (type == "bool" && doc.size () < 3) - { - if (doc.size () > 1) - d = doc[cd_ == cd_short ? 0 : 1]; - else if (doc.size () > 0) - d = (cd_ == cd_short ? first_sentence (doc[0]) : doc[0]); - } - else - { - if (doc.size () > 2) - d = doc[cd_ == cd_short ? 1 : 2]; - else if (doc.size () > 1) - d = (cd_ == cd_short ? first_sentence (doc[1]) : doc[1]); - } - - // Format the documentation string. - // - d = format (o.scope (), escape_html (translate (d, arg_set)), false); - - wrap_lines (os, "
    " + d + "
    ", 4); - os << endl; - } - - private: - class_doc_type cd_; - bool& list_; // True if we are currently in
    . - }; - - // - // - struct class_: traversal::class_, context - { - class_ (context& c, bool& l): context (c), list_ (l), base_ (false) - { - *this >> inherits_ >> *this; - } - - virtual void - traverse (type& c) - { - class_doc_type cd (class_doc (c)); - - if (cd == cd_exclude || (base_ && cd == cd_exclude_base)) - return; - - if (!options.exclude_base () && !options.include_base_last ()) - { - bool ob (base_); - base_ = true; - inherits (c); - base_ = ob; - } - - doc dc (*this, cd, list_); - option op (*this, cd, list_); - traversal::names n; - n >> dc; - n >> op; - names (c, n); - - if (!options.exclude_base () && options.include_base_last ()) - { - bool ob (base_); - base_ = true; - inherits (c); - base_ = ob; - } - } - - private: - bool& list_; - bool base_; - traversal::inherits inherits_; - }; -} - -void -generate_html (context& ctx) -{ - bool list (false); - - traversal::cli_unit unit; - traversal::names unit_names; - traversal::namespace_ ns; - doc dc (ctx, cd_default, list); - class_ cl (ctx, list); - unit >> unit_names; - unit_names >> dc; - unit_names >> ns; - unit_names >> cl; - - traversal::names ns_names; - ns >> ns_names; - ns_names >> dc; - ns_names >> ns; - ns_names >> cl; - - if (ctx.options.class_ ().empty ()) - unit.dispatch (ctx.unit); - else - { - for (vector::const_iterator i (ctx.options.class_ ().begin ()); - i != ctx.options.class_ ().end (); ++i) - { - string n (*i); - - // Strip leading :: if present. - // - if (n.size () > 2 && n[0] == ':' && n[1] == ':') - n = string (n, 2, string::npos); - - if (semantics::class_* c = ctx.unit.lookup ("", n)) - cl.traverse (*c); - else - { - cerr << "error: class '" << *i << "' not found" << endl; - throw generation_failed (); - } - } - } - - if (list) - ctx.os << "
    " << endl - << endl; -} diff --git a/cli/html.hxx b/cli/html.hxx deleted file mode 100644 index 4ba5a41..0000000 --- a/cli/html.hxx +++ /dev/null @@ -1,13 +0,0 @@ -// file : cli/html.hxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#ifndef CLI_HTML_HXX -#define CLI_HTML_HXX - -#include - -void -generate_html (context&); - -#endif // CLI_HTML_HXX diff --git a/cli/inline.cxx b/cli/inline.cxx deleted file mode 100644 index 05b83db..0000000 --- a/cli/inline.cxx +++ /dev/null @@ -1,108 +0,0 @@ -// file : cli/inline.cxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#include - -namespace -{ - // - // - struct option: traversal::option, context - { - option (context& c) : context (c) {} - - virtual void - traverse (type& o) - { - string name (ename (o)); - string type (o.type ().name ()); - string scope (escape (o.scope ().name ())); - - os << inl << "const " << type << "& " << scope << "::" << endl - << name << " () const" - << "{" - << "return this->" << emember (o) << ";" - << "}"; - - if (gen_modifier) - { - os << inl << type << "& " << scope << "::" << endl - << name << " ()" - << "{" - << "return this->" << emember (o) << ";" - << "}"; - - os << inl << "void " << scope << "::" << endl - << name << "(const " << type << "& x)" - << "{" - << "this->" << emember (o) << " = x;" - << "}"; - } - - if (gen_specifier && type != "bool") - { - string spec (especifier (o)); - - os << inl << "bool " << scope << "::" << endl - << spec << " () const" - << "{" - << "return this->" << especifier_member (o) << ";" - << "}"; - - if (gen_modifier) - os << inl << "void " << scope << "::" << endl - << spec << "(bool x)" - << "{" - << "this->" << especifier_member (o) << " = x;" - << "}"; - } - } - }; - - // - // - struct class_: traversal::class_, context - { - class_ (context& c) - : context (c), option_ (c) - { - names_option_ >> option_; - } - - virtual void - traverse (type& c) - { - string name (escape (c.name ())); - - os << "// " << name << endl - << "//" << endl - << endl; - - names (c, names_option_); - } - - private: - option option_; - traversal::names names_option_; - }; -} - -void -generate_inline (context& ctx) -{ - traversal::cli_unit unit; - traversal::names unit_names; - namespace_ ns (ctx); - class_ cl (ctx); - - unit >> unit_names >> ns; - unit_names >> cl; - - traversal::names ns_names; - - ns >> ns_names >> ns; - ns_names >> cl; - - unit.dispatch (ctx.unit); -} diff --git a/cli/inline.hxx b/cli/inline.hxx deleted file mode 100644 index 38e7768..0000000 --- a/cli/inline.hxx +++ /dev/null @@ -1,13 +0,0 @@ -// file : cli/inline.hxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#ifndef CLI_INLINE_HXX -#define CLI_INLINE_HXX - -#include - -void -generate_inline (context&); - -#endif // CLI_INLINE_HXX diff --git a/cli/lexer.cxx b/cli/lexer.cxx deleted file mode 100644 index 573c76b..0000000 --- a/cli/lexer.cxx +++ /dev/null @@ -1,604 +0,0 @@ -// file : cli/lexer.cxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -lexer:: -lexer (istream& is, string const& id) - : loc_ ("C"), - is_ (is), - id_ (id), - l_ (1), - c_(1), - eos_ (false), - include_ (false), - valid_ (true), - buf_ (0, 0, 0), - unget_ (false) -{ - keyword_map_["source"] = token::k_source; - keyword_map_["include"] = token::k_include; - keyword_map_["namespace"] = token::k_namespace; - keyword_map_["class"] = token::k_class; - keyword_map_["signed"] = token::k_signed; - keyword_map_["unsigned"] = token::k_unsigned; - keyword_map_["bool"] = token::k_bool; - keyword_map_["char"] = token::k_char; - keyword_map_["wchar_t"] = token::k_wchar; - keyword_map_["short"] = token::k_short; - keyword_map_["int"] = token::k_int; - keyword_map_["long"] = token::k_long; - keyword_map_["float"] = token::k_float; - keyword_map_["double"] = token::k_double; -} - -lexer::xchar lexer:: -peek () -{ - if (unget_) - return buf_; - else - { - if (eos_) - return xchar (xchar::traits_type::eof (), l_, c_); - else - { - xchar::int_type i (is_.peek ()); - - if (i == xchar::traits_type::eof ()) - eos_ = true; - - return xchar (i, l_, c_); - } - } -} - -lexer::xchar lexer:: -get () -{ - if (unget_) - { - unget_ = false; - return buf_; - } - else - { - // When is_.get () returns eof, the failbit is also set (stupid, - // isn't?) which may trigger an exception. To work around this - // we will call peek() first and only call get() if it is not - // eof. But we can only call peek() on eof once; any subsequent - // calls will spoil the failbit (even more stupid). - // - xchar c (peek ()); - - if (!is_eos (c)) - { - is_.get (); - - if (c == '\n') - { - l_++; - c_ = 1; - } - else - c_++; - } - - return c; - } -} - -void lexer:: -unget (xchar c) -{ - // Because iostream::unget cannot work once eos is reached, - // we have to provide our own implementation. - // - buf_ = c; - unget_ = true; -} - -token lexer:: -next () -{ - while (true) // Recovery loop. - { - bool include (include_); - include_ = false; - - skip_spaces (); - - xchar c (get ()); - - if (is_eos (c)) - return token (c.line (), c.column ()); - - try - { - switch (c) - { - case '\'': - { - return char_literal (c); - } - case '\"': - { - if (include) - return path_literal (c); - else - return string_literal (c); - } - case '<': - { - if (include) - return path_literal (c); - else - return template_expression (c); - } - case ';': - { - return token (token::p_semi, c.line (), c.column ()); - } - case ',': - { - return token (token::p_comma, c.line (), c.column ()); - } - case ':': - { - if (peek () == ':') - { - get (); - return token (token::p_dcolon, c.line (), c.column ()); - } - - return token (token::p_colon, c.line (), c.column ()); - } - case '{': - { - return token (token::p_lcbrace, c.line (), c.column ()); - } - case '}': - { - return token (token::p_rcbrace, c.line (), c.column ()); - } - case '(': - { - return call_expression (c); - } - case '=': - { - return token (token::p_eq, c.line (), c.column ()); - } - case '|': - { - return token (token::p_or, c.line (), c.column ()); - } - case '-': - { - // This can be a beginning of an identifier or a an integer - // literal. Figure out which one it is. - // - xchar p (peek ()); - - if (is_dec_digit (p)) - return int_literal (get (), true, c.line (), c.column ()); - else if (is_space (p)) - { - skip_spaces (); - p = peek (); - - if (is_dec_digit (p)) - return int_literal (get (), true, c.line (), c.column ()); - - // Stray '-'. - // - cerr << id_ << ':' << c.line () << ':' << c.column () - << ": error: unexpected character '-'" << endl; - throw invalid_input (); - } - - break; - } - } - - if (is_alpha (c) || c == '_' || c == '-' || c == '/') - { - return identifier (c); - } - - if (is_dec_digit (c)) - { - return int_literal (c); - } - - cerr << id_ << ':' << c.line () << ':' << c.column () - << ": error: unexpected character '" << c << "'" << endl; - throw invalid_input (); - } - catch (invalid_input const&) - { - valid_ = false; - } - - // Try to recover. - // - do - { - c = get (); - - if (is_eos (c)) - return token (c.line (), c.column ()); - } while (c != ';'); - } -} - -void lexer:: -skip_spaces () -{ - for (xchar c (peek ());; c = peek ()) - { - if (is_eos (c)) - break; - - if (c == '/') - { - c = get (); - xchar p (peek ()); - - if (p == '/') - { - get (); - - // C++ comment. Read until newline or eos. - // - for (c = get (); !is_eos (c) && c != '\n'; c = get ()) ; - continue; - } - else if (p == '*') - { - get (); - - // C comment. - // - for (c = get ();; c = get ()) - { - if (is_eos (c)) - { - cerr << id_ << ':' << c.line () << ':' << c.column () - << ": error: end of stream reached while reading " - << "C-style comment" << endl; - throw invalid_input (); - } - - if (c == '*') - { - c = peek (); - if (c == '/') - { - get (); - break; - } - } - } - continue; - } - else - { - unget (c); - break; - } - } - - if (!is_space (c)) - break; - - get (); - } -} - -token lexer:: -identifier (xchar c) -{ - size_t ln (c.line ()), cl (c.column ()); - string lexeme; - lexeme += c; - - bool check (c == '-' || c == '/'); - - for (c = peek (); - !is_eos (c) && (is_alnum (c) || c == '_' || c == '-'); - c = peek ()) - { - get (); - lexeme += c; - } - - // Check for invalid identifiers. - // - if (check) - { - size_t i (1); - - for (; i < lexeme.size (); ++i) - if (is_alnum (lexeme[i]) || lexeme[i] == '_') - break; - - if (i == lexeme.size ()) - { - cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " - << "invalid character sequence '" << lexeme << "'" << endl; - throw invalid_input (); - } - } - - keyword_map::const_iterator i (keyword_map_.find (lexeme)); - - if (i != keyword_map_.end ()) - { - if (i->second == token::k_include || i->second == token::k_source) - include_ = true; - - return token (i->second, ln, cl); - } - - if (lexeme == "true" || lexeme == "false") - return token (token::t_bool_lit, lexeme, ln, cl); - - return token (token::t_identifier, lexeme, ln, cl); -} - -token lexer:: -int_literal (xchar c, bool neg, size_t ml, size_t mc) -{ - size_t ln (neg ? ml : c.line ()), cl (neg ? mc : c.column ()); - string lexeme; - - if (neg) - lexeme += '-'; - - lexeme += c; - - for (c = peek (); !is_eos (c) && is_dec_digit (c); c = peek ()) - { - get (); - lexeme += c; - } - - return token (token::t_int_lit, lexeme, ln, cl); -} - -token lexer:: -char_literal (xchar c) -{ - size_t ln (c.line ()), cl (c.column ()); - string lexeme; - lexeme += c; - - char p (c); - - while (true) - { - c = get (); - - if (is_eos (c)) - { - cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " - << "end of stream reached while reading character literal" << endl; - throw invalid_input (); - } - - lexeme += c; - - if (c == '\'' && p != '\\') - break; - - // We need to keep track of \\ escapings so we don't confuse - // them with \', as in '\\'. - // - if (c == '\\' && p == '\\') - p = '\0'; - else - p = c; - } - - return token (token::t_char_lit, lexeme, ln, cl); -} - -token lexer:: -string_literal (xchar c) -{ - size_t ln (c.line ()), cl (c.column ()); - string lexeme; - lexeme += c; - - while (true) - { - lexeme += string_literal_trailer (); - - // Check if there are more strings. - // - skip_spaces (); - - c = peek (); - - if (is_eos (c) || c != '"') - break; - - get (); - lexeme += "\""; - } - - return token (token::t_string_lit, lexeme, ln, cl); -} - -string lexer:: -string_literal_trailer () -{ - string r; - char p ('\0'); - - while (true) - { - xchar c = get (); - - if (is_eos (c)) - { - cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " - << "end of stream reached while reading string literal" << endl; - throw invalid_input (); - } - - r += c; - - if (c == '"' && p != '\\') - break; - - // We need to keep track of \\ escapings so we don't confuse - // them with \", as in "\\". - // - if (c == '\\' && p == '\\') - p = '\0'; - else - p = c; - } - - return r; -} - -token lexer:: -path_literal (xchar c) -{ - size_t ln (c.line ()), cl (c.column ()); - string lexeme; - lexeme += c; - - char end (c == '<' ? '>' : '"'); - - while (true) - { - c = get (); - - if (is_eos (c)) - { - cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " - << "end of stream reached while reading path literal" << endl; - throw invalid_input (); - } - - lexeme += c; - - if (c == end) - break; - } - - token::token_type tt; - - if (lexeme.compare (1, 4, "c++:") == 0) - { - tt = token::t_cxx_path_lit; - lexeme = lexeme[0] + string (lexeme, 5, string::npos); - } - else if (lexeme.compare (1, 4, "cli:") == 0) - { - tt = token::t_cli_path_lit; - lexeme = lexeme[0] + string (lexeme, 5, string::npos); - } - else - { - // See if the path ends with .cli. If not, then we assume this is - // a C++ inclusion. - // - size_t n (lexeme.size ()); - - if (n > 5 && lexeme.compare (n - 5, 4, ".cli") == 0) - tt = token::t_cli_path_lit; - else - tt = token::t_cxx_path_lit; - } - - return token (tt, lexeme, ln, cl); -} - -token lexer:: -call_expression (xchar c) -{ - size_t ln (c.line ()), cl (c.column ()); - string lexeme; - lexeme += c; - size_t balance (1); - - while (balance != 0) - { - c = get (); - - if (is_eos (c)) - { - cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " - << "end of stream reached while reading call expression" << endl; - throw invalid_input (); - } - - lexeme += c; - - switch (c) - { - case '(': - { - balance++; - break; - } - case ')': - { - balance--; - break; - } - } - } - - return token (token::t_call_expr, lexeme, ln, cl); -} - -token lexer:: -template_expression (xchar c) -{ - size_t ln (c.line ()), cl (c.column ()); - string lexeme; - lexeme += c; - size_t balance (1); - - while (balance != 0) - { - c = get (); - - if (is_eos (c)) - { - cerr << id_ << ':' << c.line () << ':' << c.column () << ": error: " - << "end of stream reached while reading template expression" - << endl; - throw invalid_input (); - } - - lexeme += c; - - switch (c) - { - case '<': - { - balance++; - break; - } - case '>': - { - balance--; - break; - } - } - } - - return token (token::t_template_expr, lexeme, ln, cl); -} diff --git a/cli/lexer.hxx b/cli/lexer.hxx deleted file mode 100644 index bd7b0c9..0000000 --- a/cli/lexer.hxx +++ /dev/null @@ -1,142 +0,0 @@ -// file : cli/lexer.hxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#ifndef CLI_LEXER_HXX -#define CLI_LEXER_HXX - -#include -#include -#include -#include // std::size_t -#include - -#include - -class lexer -{ -public: - lexer (std::istream& is, std::string const& id); - - token - next (); - - bool - valid () const; - -protected: - class xchar - { - public: - typedef std::char_traits traits_type; - typedef traits_type::int_type int_type; - typedef traits_type::char_type char_type; - - xchar (int_type v, std::size_t l, std::size_t c); - - operator char_type () const; - - int_type - value () const; - - std::size_t - line () const; - - std::size_t - column () const; - - private: - int_type v_; - std::size_t l_; - std::size_t c_; - }; - - xchar - peek (); - - xchar - get (); - - void - unget (xchar); - -protected: - class invalid_input {}; - - void - skip_spaces (); - - token - identifier (xchar); - - token - int_literal (xchar, - bool neg = false, - std::size_t ml = 0, - std::size_t mc = 0); - - token - char_literal (xchar); - - token - string_literal (xchar); - - std::string - string_literal_trailer (); - - token - path_literal (xchar); - - token - call_expression (xchar); - - token - template_expression (xchar); - -protected: - bool - is_alpha (char c) const; - - bool - is_oct_digit (char c) const; - - bool - is_dec_digit (char c) const; - - bool - is_hex_digit (char c) const; - - bool - is_alnum (char c) const; - - bool - is_space (char c) const; - - bool - is_eos (xchar const& c) const; - - char - to_upper (char c) const; - -private: - typedef std::map keyword_map; - - std::locale loc_; - std::istream& is_; - std::string id_; - std::size_t l_; - std::size_t c_; - - keyword_map keyword_map_; - - bool eos_; - bool include_; // Literal in include or source. - bool valid_; - - xchar buf_; - bool unget_; -}; - -#include - -#endif // CLI_LEXER_HXX diff --git a/cli/lexer.ixx b/cli/lexer.ixx deleted file mode 100644 index 1c4c42e..0000000 --- a/cli/lexer.ixx +++ /dev/null @@ -1,91 +0,0 @@ -// file : cli/lexer.ixx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -// lexer::xchar -// -inline lexer::xchar:: -xchar (int_type v, std::size_t l, std::size_t c) - : v_ (v), l_ (l), c_ (c) -{ -} - -inline lexer::xchar:: -operator char_type () const -{ - return traits_type::to_char_type (v_); -} - -inline lexer::xchar::int_type lexer::xchar:: -value () const -{ - return v_; -} - -inline std::size_t lexer::xchar:: -line () const -{ - return l_; -} - -inline std::size_t lexer::xchar:: -column () const -{ - return c_; -} - -// lexer -// -inline bool lexer:: -valid () const -{ - return valid_; -} - -inline bool lexer:: -is_alpha (char c) const -{ - return std::isalpha (c, loc_); -} - -inline bool lexer:: -is_oct_digit (char c) const -{ - return std::isdigit (c, loc_) && c != '8' && c != '9'; -} - -inline bool lexer:: -is_dec_digit (char c) const -{ - return std::isdigit (c, loc_); -} - -inline bool lexer:: -is_hex_digit (char c) const -{ - return std::isxdigit (c, loc_); -} - -inline bool lexer:: -is_alnum (char c) const -{ - return std::isalnum (c, loc_); -} - -inline bool lexer:: -is_space (char c) const -{ - return std::isspace (c, loc_); -} - -inline bool lexer:: -is_eos (xchar const& c) const -{ - return c.value () == xchar::traits_type::eof (); -} - -inline char lexer:: -to_upper (char c) const -{ - return std::toupper (c, loc_); -} diff --git a/cli/man.cxx b/cli/man.cxx deleted file mode 100644 index df703e8..0000000 --- a/cli/man.cxx +++ /dev/null @@ -1,278 +0,0 @@ -// file : cli/man.cxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#include -#include - -#include - -using namespace std; - -namespace -{ - // According to groff_mdoc(7), groff may have issues with any of the - // following characters at the beginning of the line: - // - // {}+-/*%<>=,&`'" - // - // Plus, escaping leading '.' with '\' is not sufficient. - // - static const string escape ("{}+-/*%<>=,&`'\""); - - static string - escape_line (const string& s, size_t b, size_t e) - { - string r; - size_t n (e - b); - - - if (escape.find (s[b]) != string::npos || - (n > 1 && s[b] == '\\' && s[b + 1] == '.')) - r = "\\&"; - - r.append (s, b, n); - return r; - } - - static void - wrap_lines (ostream& os, const string& d) - { - size_t b (0), e (0), i (0); - for (size_t n (d.size ()); i < n; ++i) - { - // First handle preformatted text (.nf/.fi). - // - if (d.compare (i, 4, ".nf\n") == 0 && (i == 0 || d[i - 1] == '\n')) - { - assert (b == i); // We should have nothing accumulated. - - // Output everything until (and including) closing .fi as is. - // - e = d.find ("\n.fi", i + 4); - assert (e != string::npos); - e += 4; // Now points past 'i'. - - os << string (d, i, e - i); - - b = e; - i = e - 1; // For ++i in loop header. - continue; - } - - if (d[i] == ' ' || d[i] == '\n') - e = i; - - if (d[i] == '\n' || (i - b >= 78 && e != b)) - { - os << escape_line (d, b, e) << endl; - b = e = e + 1; - } - } - - // Flush the last line. - // - if (b != i) - os << escape_line (d, b, i); - } - - struct doc: traversal::doc, context - { - doc (context& c, class_doc_type cd): context (c), cd_ (cd) {} - - virtual void - traverse (type& ds) - { - if (ds.name ().compare (0, 3, "doc") != 0) // Ignore doc variables. - return; - - // n = 1 - common doc string - // n = 2 - arg string, common doc string - // n > 2 - arg string, short string, long string - // - size_t n (ds.size ()); - const string& d ( - n == 1 - ? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0]) - : (n == 2 - ? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1]) - : ds[cd_ == cd_short ? 1 : 2])); - - std::set arg_set; - if (n > 1) - translate_arg (ds[0], arg_set); - - string s (format (ds.scope (), translate (d, arg_set), true)); - - if (s.empty ()) - return; - - wrap_lines (os, s); - os << endl; - } - - private: - class_doc_type cd_; - }; - - struct option: traversal::option, context - { - option (context& c, class_doc_type cd) : context (c), cd_ (cd) {} - - virtual void - traverse (type& o) - { - using semantics::names; - - semantics::doc_strings const& doc (o.doc ()); - - if (options.suppress_undocumented () && doc.empty ()) - return; - - names& n (o.named ()); - - os << ".IP \"\\fB"; - - for (names::name_iterator i (n.name_begin ()); i != n.name_end (); ++i) - { - if (i != n.name_begin ()) - os << "\\fR|\\fB"; - - os << *i; - } - - os << "\\fR"; - - string type (o.type ().name ()); - - std::set arg_set; - - if (type != "bool" || doc.size () >= 3) - { - string s ( - translate_arg ( - doc.size () > 0 ? doc[0] : string (""), arg_set)); - - os << ' ' << format (o.scope (), s, false); - } - - os << "\"" << endl; - - string d; - if (type == "bool" && doc.size () < 3) - { - if (doc.size () > 1) - d = doc[cd_ == cd_short ? 0 : 1]; - else if (doc.size () > 0) - d = (cd_ == cd_short ? first_sentence (doc[0]) : doc[0]); - } - else - { - if (doc.size () > 2) - d = doc[cd_ == cd_short ? 1 : 2]; - else if (doc.size () > 1) - d = (cd_ == cd_short ? first_sentence (doc[1]) : doc[1]); - } - - // Format the documentation string. - // - d = format (o.scope (), translate (d, arg_set), false); - - wrap_lines (os, d); - os << endl; - } - - private: - class_doc_type cd_; - }; - - // - // - struct class_: traversal::class_, context - { - class_ (context& c): context (c), base_ (false) - { - *this >> inherits_ >> *this; - } - - virtual void - traverse (type& c) - { - class_doc_type cd (class_doc (c)); - - if (cd == cd_exclude || (base_ && cd == cd_exclude_base)) - return; - - if (!options.exclude_base () && !options.include_base_last ()) - { - bool ob (base_); - base_ = true; - inherits (c); - base_ = ob; - } - - doc dc (*this, cd); - option op (*this, cd); - traversal::names n; - n >> dc; - n >> op; - names (c, n); - - if (!options.exclude_base () && options.include_base_last ()) - { - bool ob (base_); - base_ = true; - inherits (c); - base_ = ob; - } - } - - private: - bool base_; - traversal::inherits inherits_; - }; -} - -void -generate_man (context& ctx) -{ - traversal::cli_unit unit; - traversal::names unit_names; - traversal::namespace_ ns; - doc dc (ctx, cd_default); - class_ cl (ctx); - unit >> unit_names; - unit_names >> ns; - unit_names >> dc; - unit_names >> cl; - - traversal::names ns_names; - ns >> ns_names; - ns_names >> ns; - ns_names >> dc; - ns_names >> cl; - - if (ctx.options.class_ ().empty ()) - unit.dispatch (ctx.unit); - else - { - for (vector::const_iterator i (ctx.options.class_ ().begin ()); - i != ctx.options.class_ ().end (); ++i) - { - string n (*i); - - // Strip leading :: if present. - // - if (n.size () > 2 && n[0] == ':' && n[1] == ':') - n = string (n, 2, string::npos); - - if (semantics::class_* c = ctx.unit.lookup ("", n)) - cl.traverse (*c); - else - { - cerr << "error: class '" << *i << "' not found" << endl; - throw generation_failed (); - } - } - } -} diff --git a/cli/man.hxx b/cli/man.hxx deleted file mode 100644 index 0825305..0000000 --- a/cli/man.hxx +++ /dev/null @@ -1,13 +0,0 @@ -// file : cli/man.hxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#ifndef CLI_MAN_HXX -#define CLI_MAN_HXX - -#include - -void -generate_man (context&); - -#endif // CLI_MAN_HXX diff --git a/cli/manifest b/cli/manifest new file mode 100644 index 0000000..69c113b --- /dev/null +++ b/cli/manifest @@ -0,0 +1,21 @@ +: 1 +name: cli +version: 1.2.0-b.6.z +summary: Command line interface (CLI) compiler for C++ +license: MIT +topics: C++, command line interface, source code generation, \ + documentation generation +description-file: README +changes-file: NEWS +url: https://www.codesynthesis.com/projects/cli/ +doc-url: https://www.codesynthesis.com/projects/cli/doc/guide/ +src-url: https://git.codesynthesis.com/cgit/cli/cli/tree/cli +email: cli-users@codesynthesis.com ; Mailing list +build-email: builds@codesynthesis.com +builds: all +requires: c++14 +depends: * build2 >= 0.13.0- +depends: * bpkg >= 0.13.0- +depends: libcutl ^1.11.0- +tests: cli-tests == $ +examples: cli-examples == $ diff --git a/cli/name-processor.cxx b/cli/name-processor.cxx deleted file mode 100644 index ab125bc..0000000 --- a/cli/name-processor.cxx +++ /dev/null @@ -1,193 +0,0 @@ -// file : cli/name-processor.cxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#include -#include - -#include -#include - -using namespace std; - -namespace -{ - typedef set name_set; - typedef ::context context_base; - - struct context: context_base - { - context (context_base& c): context_base (c) {} - context (context& c): context_base (c) {} - - public: - string - find_name (string const& n, string const& suffix, name_set& set) - { - string name (escape (n + suffix)); - - for (size_t i (1); set.find (name) != set.end (); ++i) - { - ostringstream os; - os << i; - name = escape (n + os.str () + suffix); - } - - set.insert (name); - return name; - } - - string - find_name (string const& n, name_set& set) - { - return find_name (n, "", set); - } - }; - - struct primary_option: traversal::option, context - { - primary_option (context& c, name_set& set) - : context (c), set_ (set) - { - } - - virtual void - traverse (type& o) - { - string n (o.name ()), name; - - // Get rid of leading special characters, e.f., -, --, /, etc. - // - for (size_t i (0); i < n.size (); ++i) - { - if (isalpha (n[i]) || n[i] == '_') - { - name.assign (n.c_str (), i, n.size () - i); - break; - } - } - - o.context ().set ("name", find_name (name, set_)); - } - - private: - name_set& set_; - }; - - struct intermediate_option: traversal::option, context - { - intermediate_option (context& c, name_set& set) - : context (c), set_ (set) - { - } - - virtual void - traverse (type& o) - { - if (gen_specifier && o.type ().name () != "bool") - { - semantics::context& oc (o.context ()); - string const& base (oc.get ("name")); - oc.set ("specifier", find_name (base + "_specified", set_)); - } - } - - private: - name_set& set_; - }; - - struct secondary_option: traversal::option, context - { - secondary_option (context& c, name_set& set) - : context (c), set_ (set) - { - } - - virtual void - traverse (type& o) - { - semantics::context& oc (o.context ()); - string const& base (oc.get ("name")); - oc.set ("member", find_name (base + "_", set_)); - - if (gen_specifier && o.type ().name () != "bool") - { - string const& base (oc.get ("specifier")); - oc.set ("specifier-member", find_name (base + "_", set_)); - } - } - - private: - name_set& set_; - }; - - struct class_: traversal::class_, context - { - class_ (context& c) : context (c) {} - - virtual void - traverse (type& c) - { - semantics::context& cc (c.context ()); - - cc.set ("member-name-set", name_set ()); - name_set& member_set (cc.get ("member-name-set")); - - member_set.insert (escape (c.name ())); - - // First assign primary names. - // - { - primary_option option (*this, member_set); - traversal::names names (option); - - class_::names (c, names); - } - - // Then assign intermediate names. - // - { - intermediate_option option (*this, member_set); - traversal::names names (option); - - class_::names (c, names); - } - - // Finally assign secondary names. - // - { - secondary_option option (*this, member_set); - traversal::names names (option); - - class_::names (c, names); - } - } - }; - - void - process_names_ (context_base& c) - { - context ctx (c); - - traversal::cli_unit unit; - traversal::names unit_names; - traversal::namespace_ ns; - class_ cl (ctx); - - unit >> unit_names >> ns; - unit_names >> cl; - - traversal::names ns_names; - - ns >> ns_names >> ns; - ns_names >> cl; - - unit.dispatch (ctx.unit); - } -} - -void -process_names (context_base& c) -{ - process_names_ (c); -} diff --git a/cli/name-processor.hxx b/cli/name-processor.hxx deleted file mode 100644 index c21561b..0000000 --- a/cli/name-processor.hxx +++ /dev/null @@ -1,13 +0,0 @@ -// file : cli/name-processor.hxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#ifndef CLI_NAME_PROCESSOR_HXX -#define CLI_NAME_PROCESSOR_HXX - -#include - -void -process_names (context&); - -#endif // CLI_NAME_PROCESSOR_HXX diff --git a/cli/option-types.cxx b/cli/option-types.cxx deleted file mode 100644 index da1f434..0000000 --- a/cli/option-types.cxx +++ /dev/null @@ -1,43 +0,0 @@ -// file : cli/option-types.cxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -static const char* cxx_version_[] = -{ - "c++98", - "c++11" - "c++14" -}; - -string cxx_version:: -string () const -{ - return cxx_version_[v_]; -} - -istream& -operator>> (istream& is, cxx_version& v) -{ - string s; - is >> s; - - if (!is.fail ()) - { - if (s == "c++98") - v = cxx_version::cxx98; - else if (s == "c++11") - v = cxx_version::cxx11; - else if (s == "c++14") - v = cxx_version::cxx14; - else - is.setstate (istream::failbit); - } - - return is; -} diff --git a/cli/option-types.hxx b/cli/option-types.hxx deleted file mode 100644 index 02d9ede..0000000 --- a/cli/option-types.hxx +++ /dev/null @@ -1,33 +0,0 @@ -// file : cli/option-types.hxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#ifndef CLI_OPTION_TYPES_HXX -#define CLI_OPTION_TYPES_HXX - -#include -#include - -struct cxx_version -{ - enum value - { - cxx98, - cxx11, - cxx14 - }; - - cxx_version (value v = value (0)) : v_ (v) {} - operator value () const {return v_;} - - std::string - string () const; - -private: - value v_; -}; - -std::istream& -operator>> (std::istream&, cxx_version&); - -#endif // CLI_OPTION_TYPES_HXX diff --git a/cli/options.cli b/cli/options.cli deleted file mode 100644 index e564bc4..0000000 --- a/cli/options.cli +++ /dev/null @@ -1,662 +0,0 @@ -// file : cli/options.cli -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -// NOTE: Make sure you have a working CLI compiler around before -// modifying this file. -// - -include ; -include ; -include ; -include ; - -include ; - -class options -{ - bool --build2-metadata; // Leave undocumented/hidden. - - bool --help {"Print usage information and exit."}; - bool --version {"Print version and exit."}; - - std::vector --include-path | -I - { - "", - "Search for bracket-included (\cb{<>}) options files." - }; - - std::string --output-dir | -o - { - "", - "Write the generated files to instead of the current directory." - }; - - cxx_version --std = cxx_version::cxx98 - { - "", - "Specify the C++ standard that should be used during compilation. - Valid values are \cb{c++98} (default), \cb{c++11}, and \cb{c++14}." - }; - - bool --generate-modifier - { - "Generate option value modifiers in addition to accessors." - }; - - bool --generate-specifier - { - "Generate functions for determining whether the option was specified - on the command line." - }; - - bool --generate-parse - { - "Generate \cb{parse()} functions instead of parsing constructors. This is - primarily useful for being able to parse into an already initialized - options class instance, for example, to implement option - appending/overriding." - }; - - bool --generate-merge - { - "Generate \cb{merge()} functions. This is primarily useful for being able - to merge several already parsed options class instances, for example, to - implement option appending/overriding. Note that this option forces - \cb{--generate-specifier}." - }; - - bool --generate-description - { - "Generate the option description list that can be examined at runtime." - }; - - bool --generate-file-scanner - { - "Generate the \cb{argv_file_scanner} implementation. This scanner is - capable of reading command line arguments from the \cb{argv} array as - well as files specified with command line options." - }; - - bool --generate-vector-scanner - { - "Generate the \cb{vector_scanner} implementation. This scanner is capable - of reading command line arguments from \cb{vector}." - }; - - bool --generate-group-scanner - { - "Generate the \cb{group_scanner} implementation. This scanner supports - grouping of arguments (usually options) to apply only to a certain - argument. - - Groups can be specified before (leading) and/or after (trailing) the - argument they apply to. A leading group starts with '\cb{{}' and ends - with '\cb{\}+}' while a trailing group starts with '\cb{+{}' and ends - with '\cb{\}}'. For example: - - \ - { --foo --bar }+ arg # 'arg' with '--foo' '--bar' - arg +{ fox=1 baz=2 } # 'arg' with 'fox=1' 'baz=2' - \ - - Multiple leading and/or trailing groups can be specified for the - same argument. For example: - - \ - { -f }+ { -b }+ arg +{ f=1 } +{ b=2 } # 'arg' with '-f' 'b' 'f=1' 'b=2' - \ - - Note that the group applies to a single argument only. For example: - - \ - { --foo }+ arg1 arg2 +{ --bar } # 'arg1' with '--foo' and - # 'arg2' with '--bar' - \ - - The group separators ('\cb{{}', '\cb{\}+'}, etc) must be separate command - line arguments. In particular, they must not be adjacent either to the - arguments inside the group nor to the argument they apply to. All such - cases will be treated as ordinary arguments. For example: - - \ - {--foo}+ arg # '{--foo}+' ... - arg+{ --foo } # 'arg+{' ... - \ - - If one of the group separators needs to be specified as an argument - verbatim, then it must be escaped with '\cb{\\}'. For example: - - \ - } # error: unexpected group separator - }x # '}x' - \} # '}' - { \}+ }+ arg # 'arg' with '}+' - \ - " - }; - - bool --suppress-inline - { - "Generate all functions non-inline. By default simple functions are - made inline. This option suppresses creation of the inline file." - }; - - bool --suppress-cli - { - "Do not generate the CLI support types (scanners, parser, etc). Normally, - the support types are generated unless another \cb{.cli} was included, - in which case the support types are expected to be provided by its - generated code." - }; - - std::string --cli-namespace = "::cli" - { - "", - "Generate the CLI support types in the namespace (\cb{cli} by - default). The namespace can be nested, for example \cb{details::cli}. - If the namespace is empty, then the support types are generated in - the global namespace." - }; - - std::string --ostream-type = "::std::ostream" - { - "", - "Output stream type instead of the default \cb{std::ostream} that - should be used to print usage and exception information." - }; - - bool --generate-cxx - { - "Generate C++ code. If neither \cb{--generate-man}, \cb{--generate-html}, - nor \cb{--generate-txt} is specified, this mode is assumed by default." - }; - - bool --generate-man - { - "Generate documentation in the man page format." - }; - - bool --generate-html - { - "Generate documentation in the HTML format." - }; - - bool --generate-txt - { - "Generate documentation in the plain text format, similar to usage." - }; - - bool --stdout - { - "Write output to STDOUT instead of a file. This option is not valid - when generating C++ code and is normally used to combine generated - documentation for several option classes in a single file." - }; - - bool --suppress-undocumented - { - "Suppress the generation of documentation entries for undocumented - options." - }; - - bool --suppress-usage - { - "Suppress the generation of the usage printing code." - }; - - bool --long-usage - { - "If no short documentation string is provided, use the complete - long documentation string in usage. By default, in this situation - only the first sentence from the long string is used." - }; - - bool --short-usage - { - "If specified together with \cb{--long-usage}, generate both short - and long usage versions. In this mode, the long usage printing function - is called \cb{print_long_usage()} and in its implementation the long - documentation string is always used, even if the short version is - provided." - }; - - std::string --page-usage - { - "", - "Generate the combined usage printing code for the entire page. - Specifically, this will include all the namespace-level documentation as - well as usage for all the options classes printed in the order they are - defined in the main translation unit (documentation/classes from included - units are ignored except for base classes). - - The argument is used as a prefix to form the name of the usage - printing function. It can include the namespace qualification as well - as documentation variable expansion, for example: - - \ - --page-usage print_ # print_usage() in global namespace - --page-usage app::print_ # print_usage() in app namespace - --page-usage print_$name$_ # print_foo_usage() if name is foo - \ - - If both \cb{--long-usage} and \cb{--short-usage} options are specified, - then the long usage function has the \cb{*long_usage()} suffix." - }; - - std::size_t --option-length = 0 - { - "", - "Indent option descriptions characters when printing usage. This is - useful when you have multiple options classes, potentially in separate - files, and would like their usage to have the same indentation level." - }; - - bool --ansi-color - { - "Use ANSI color escape sequences when printing usage. By \"color\" we - really only mean the bold and underline modifiers. Note that Windows - console does not recognize ANSI escape sequences and will display - them as garbage. However, if you pipe such output through \cb{less(1)}, - it will display them correctly." - }; - - bool --exclude-base - { - "Exclude base class information from usage and documentation." - }; - - bool --include-base-last - { - "Include base class information after derived for usage and documentation. - By default, base classes are included first." - }; - - std::map --class-doc - { - "=", - "Specify the documentation that should be used for the options class - . The value should be a fully-qualified class name, for - example, \cb{app::options}. The value can be \cb{short}, - \cb{long}, \cb{exclude}, or \cb{exclude-base}. If the value is - \cb{exclude}, then the class documentation is excluded from usage and - man/HTML/text output. If it is \cb{exclude-base}, then it is only - excluded when used as a base. For usage, the \cb{short} and \cb{long} - values determine which usage function will be called when the class is - used as base or as part of the page usage (see \cb{--page-usage}). For - man/HTML/text, these values determine which documentation strings are - used in the output." - }; - - std::vector --class - { - "", - "Generate the man page, HTML, or text documentation only for the options - class . The value should be a fully-qualified options class - name, for example, \cb{app::options}. To generate documentation for - multiple classes, repeat this option and the documentation will be - produced in the order specified. This functionality is useful if you need - to assemble documentation from multiple classes in a specific order or to - insert custom documentation between options belonging to different - classes." - }; - - std::map --docvar|-v - { - "=", - "Set documentation variable to the value . Documentation - variables can be substituted in prologues and epilogues (see - \cb{--*-prologue*} and \cb{--*-epilogue*} options) using the - \cb{$}\cb{$} expansion syntax (use \cb{$$} to escape expansion). - They can also be defined in \cb{.cli} files using the - \c{\"\\=\"} syntax." - }; - - std::vector --link-regex - { - "", - "Add to the list of regular expressions used to transform link - targets in the generated documentation. The argument to this option - is a Perl-like regular expression in the form - \c{\b{/}\i{pattern}\b{/}\i{replacement}\b{/}}. Any character can be - used as a delimiter instead of '\cb{/}' and the delimiter can be escaped - inside \ci{pattern} and \ci{replacement} with a backslash (\cb{\\}). - You can specify multiple regular expressions by repeating this option. - All the regular expressions are tried in the order specified and the - first expression that matches is used. Use the \cb{--link-regex-trace} - option to debug link transformation." - }; - - bool --link-regex-trace - { - "Trace the process of applying regular expressions specified with the - \cb{--link-regex} option. Use this option to find out why your regular - expressions don't do what you expected them to do." - }; - - std::map --html-heading-map - { - "=", - "Map CLI heading (valid values: '\cb{H}', '\cb{0}', '\cb{1}', - '\cb{h}', and '\cb{2}') to HTML heading (for example, '\cb{h1}', - '\cb{h2}', etc)." - }; - - bool --omit-link-check - { - "Don't check that local fragment link references (\\l{#ref ...}) resolve - to ids." - }; - - // Prologues. - // - std::vector --hxx-prologue - { - "", - "Insert at the beginning of the generated C++ header file." - }; - - std::vector --ixx-prologue - { - "", - "Insert at the beginning of the generated C++ inline file." - }; - - std::vector --cxx-prologue - { - "", - "Insert at the beginning of the generated C++ source file." - }; - - std::vector --man-prologue - { - "", - "Insert at the beginning of the generated man page file." - }; - - std::vector --html-prologue - { - "", - "Insert at the beginning of the generated HTML file." - }; - - std::vector --txt-prologue - { - "", - "Insert at the beginning of the generated text file." - }; - - // Epilogues. - // - std::vector --hxx-epilogue - { - "", - "Insert at the end of the generated C++ header file." - }; - - std::vector --ixx-epilogue - { - "", - "Insert at the end of the generated C++ inline file." - }; - - std::vector --cxx-epilogue - { - "", - "Insert at the end of the generated C++ source file." - }; - - std::vector --man-epilogue - { - "", - "Insert at the end of the generated man page file." - }; - - std::vector --html-epilogue - { - "", - "Insert at the end of the generated HTML file." - }; - - std::vector --txt-epilogue - { - "", - "Insert at the end of the generated text file." - }; - - // Prologue files. - // - std::string --hxx-prologue-file - { - "", - "Insert the content of at the beginning of the generated C++ - header file." - }; - - std::string --ixx-prologue-file - { - "", - "Insert the content of at the beginning of the generated C++ - inline file." - }; - - std::string --cxx-prologue-file - { - "", - "Insert the content of at the beginning of the generated C++ - source file." - }; - - std::string --man-prologue-file - { - "", - "Insert the content of at the beginning of the generated man - page file." - }; - - std::string --html-prologue-file - { - "", - "Insert the content of at the beginning of the generated HTML - file." - }; - - std::string --txt-prologue-file - { - "", - "Insert the content of at the beginning of the generated text - file." - }; - - // Epilogue files. - // - std::string --hxx-epilogue-file - { - "", - "Insert the content of at the end of the generated C++ header - file." - }; - - std::string --ixx-epilogue-file - { - "", - "Insert the content of at the end of the generated C++ inline - file." - }; - - std::string --cxx-epilogue-file - { - "", - "Insert the content of at the end of the generated C++ source - file." - }; - - std::string --man-epilogue-file - { - "", - "Insert the content of at the end of the generated man page file." - }; - - std::string --html-epilogue-file - { - "", - "Insert the content of at the end of the generated HTML file." - }; - - std::string --txt-epilogue-file - { - "", - "Insert the content of at the end of the generated text file." - }; - - // Output. - // - std::string --output-prefix - { - "", - "Add at the beginning of the generated output file name(s)." - }; - - std::string --output-suffix - { - "", - "Add at the end of the generated output file name(s). Note that - it is added before any file type-specific suffixes; see \cb{--*-suffix} - below." - }; - - std::string --hxx-suffix = ".hxx" - { - "", - "Use instead of the default \cb{.hxx} to construct the name of - the generated header file." - }; - - std::string --ixx-suffix = ".ixx" - { - "", - "Use instead of the default \cb{.ixx} to construct the name of - the generated inline file." - }; - - std::string --cxx-suffix = ".cxx" - { - "", - "Use instead of the default \cb{.cxx} to construct the name of - the generated source file." - }; - - std::string --man-suffix = ".1" - { - "", - "Use instead of the default \cb{.1} to construct the name of - the generated man page file." - }; - - std::string --html-suffix = ".html" - { - "", - "Use instead of the default \cb{.html} to construct the name - of the generated HTML file." - }; - - std::string --txt-suffix = ".txt" - { - "", - "Use instead of the default \cb{.txt} to construct the name of - the generated text file." - }; - - std::string --option-prefix = "-" - { - "", - "Use instead of the default '\cb{-}' as an option prefix. Unknown - command line arguments that start with this prefix are treated as unknown - options. If you set the option prefix to the empty value, then all the - unknown command line arguments will be treated as program arguments." - }; - - std::string --option-separator = "--" - { - "", - "Use instead of the default '\cb{--}' as an optional separator - between options and arguments. All the command line arguments that are - parsed after this separator are treated as program arguments. Set the - option separator to the empty value if you don't want this functionality." - }; - - bool --keep-separator - { - "Leave the option separator in the scanner. This is primarily useful for - incremental option parsing." - }; - - bool --no-combined-flags - { - "Disable support for combining multiple single-character flags into a - single argument (the \cb{-xyz} form that is equivalent to \cb{-x} \cb{-y} - \cb{-z}). An argument is considered a combination of flags if it starts - with a single option prefix (\cb{--option-prefix}) and only contains - letters and digits. Note that an option with a value may not be part of - such a combination, not even if it is specified last." - } - - bool --no-combined-values - { - "Disable support for combining an option and its value into a single - argument with the assignment sign (the \c{\i{option}\b{=}\i{value}} - form). This functionality requires a non-empty option prefix - (\cb{--option-prefix})." - } - - bool --include-with-brackets - { - "Use angle brackets (\cb{<>}) instead of quotes (\cb{\"\"}) in the - generated \cb{#include} directives." - }; - - std::string --include-prefix - { - "", - "Add to the generated \cb{#include} directive paths." - }; - - std::string --guard-prefix - { - "", - "Add to the generated header inclusion guards. The prefix is - transformed to upper case and characters that are illegal in a - preprocessor macro name are replaced with underscores." - }; - - std::map --reserved-name - { - "=", - "Add with an optional replacement to the list of names - that should not be used as identifiers. If provided, the replacement - name is used instead. All C++ keywords are already in this list." - }; - - // This is a "fake" option in that it is actually handled by - // argv_file_scanner. We have it here to get the documentation. - // - std::string --options-file - { - "", - "Read additional options from . Each option should appear on a - separate line optionally followed by space or equal sign (\cb{=}) and an - option value. Empty lines and lines starting with \cb{#} are ignored. - Option values can be enclosed in double (\cb{\"}) or single (\cb{'}) - quotes to preserve leading and trailing whitespaces as well as to specify - empty values. If the value itself contains trailing or leading quotes, - enclose it with an extra pair of quotes, for example \cb{'\"x\"'}. - Non-leading and non-trailing quotes are interpreted as being part of the - option value. - - The semantics of providing options in a file is equivalent to providing - the same set of options in the same order on the command line at the - point where the \cb{--options-file} option is specified except that - the shell escaping and quoting is not required. Repeat this option - to specify more than one options file." - }; -}; diff --git a/cli/options.cxx b/cli/options.cxx deleted file mode 100644 index cc22a35..0000000 --- a/cli/options.cxx +++ /dev/null @@ -1,2146 +0,0 @@ -// -*- C++ -*- -// -// This file was generated by CLI, a command line interface -// compiler for C++. -// - -// Begin prologue. -// -// -// End prologue. - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cli -{ - // unknown_option - // - unknown_option:: - ~unknown_option () throw () - { - } - - void unknown_option:: - print (::std::ostream& os) const - { - os << "unknown option '" << option ().c_str () << "'"; - } - - const char* unknown_option:: - what () const throw () - { - return "unknown option"; - } - - // unknown_argument - // - unknown_argument:: - ~unknown_argument () throw () - { - } - - void unknown_argument:: - print (::std::ostream& os) const - { - os << "unknown argument '" << argument ().c_str () << "'"; - } - - const char* unknown_argument:: - what () const throw () - { - return "unknown argument"; - } - - // missing_value - // - missing_value:: - ~missing_value () throw () - { - } - - void missing_value:: - print (::std::ostream& os) const - { - os << "missing value for option '" << option ().c_str () << "'"; - } - - const char* missing_value:: - what () const throw () - { - return "missing option value"; - } - - // invalid_value - // - invalid_value:: - ~invalid_value () throw () - { - } - - void invalid_value:: - print (::std::ostream& os) const - { - os << "invalid value '" << value ().c_str () << "' for option '" - << option ().c_str () << "'"; - - if (!message ().empty ()) - os << ": " << message ().c_str (); - } - - const char* invalid_value:: - what () const throw () - { - return "invalid option value"; - } - - // eos_reached - // - void eos_reached:: - print (::std::ostream& os) const - { - os << what (); - } - - const char* eos_reached:: - what () const throw () - { - return "end of argument stream reached"; - } - - // file_io_failure - // - file_io_failure:: - ~file_io_failure () throw () - { - } - - void file_io_failure:: - print (::std::ostream& os) const - { - os << "unable to open file '" << file ().c_str () << "' or read failure"; - } - - const char* file_io_failure:: - what () const throw () - { - return "unable to open file or read failure"; - } - - // unmatched_quote - // - unmatched_quote:: - ~unmatched_quote () throw () - { - } - - void unmatched_quote:: - print (::std::ostream& os) const - { - os << "unmatched quote in argument '" << argument ().c_str () << "'"; - } - - const char* unmatched_quote:: - what () const throw () - { - return "unmatched quote"; - } - - // scanner - // - scanner:: - ~scanner () - { - } - - // argv_scanner - // - bool argv_scanner:: - more () - { - return i_ < argc_; - } - - const char* argv_scanner:: - peek () - { - if (i_ < argc_) - return argv_[i_]; - else - throw eos_reached (); - } - - const char* argv_scanner:: - next () - { - if (i_ < argc_) - { - const char* r (argv_[i_]); - - if (erase_) - { - for (int i (i_ + 1); i < argc_; ++i) - argv_[i - 1] = argv_[i]; - - --argc_; - argv_[argc_] = 0; - } - else - ++i_; - - return r; - } - else - throw eos_reached (); - } - - void argv_scanner:: - skip () - { - if (i_ < argc_) - ++i_; - else - throw eos_reached (); - } - - // argv_file_scanner - // - int argv_file_scanner::zero_argc_ = 0; - std::string argv_file_scanner::empty_string_; - - bool argv_file_scanner:: - more () - { - if (!args_.empty ()) - return true; - - while (base::more ()) - { - // See if the next argument is the file option. - // - const char* a (base::peek ()); - const option_info* oi = 0; - const char* ov = 0; - - if (!skip_) - { - if ((oi = find (a)) != 0) - { - base::next (); - - if (!base::more ()) - throw missing_value (a); - - ov = base::next (); - } - else if (std::strncmp (a, "-", 1) == 0) - { - if ((ov = std::strchr (a, '=')) != 0) - { - std::string o (a, 0, ov - a); - if ((oi = find (o.c_str ())) != 0) - { - base::next (); - ++ov; - } - } - } - } - - if (oi != 0) - { - if (oi->search_func != 0) - { - std::string f (oi->search_func (ov, oi->arg)); - - if (!f.empty ()) - load (f); - } - else - load (ov); - - if (!args_.empty ()) - return true; - } - else - { - if (!skip_) - skip_ = (std::strcmp (a, "--") == 0); - - return true; - } - } - - return false; - } - - const char* argv_file_scanner:: - peek () - { - if (!more ()) - throw eos_reached (); - - return args_.empty () ? base::peek () : args_.front ().value.c_str (); - } - - const std::string& argv_file_scanner:: - peek_file () - { - if (!more ()) - throw eos_reached (); - - return args_.empty () ? empty_string_ : *args_.front ().file; - } - - std::size_t argv_file_scanner:: - peek_line () - { - if (!more ()) - throw eos_reached (); - - return args_.empty () ? 0 : args_.front ().line; - } - - const char* argv_file_scanner:: - next () - { - if (!more ()) - throw eos_reached (); - - if (args_.empty ()) - return base::next (); - else - { - hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value); - args_.pop_front (); - return hold_[i_].c_str (); - } - } - - void argv_file_scanner:: - skip () - { - if (!more ()) - throw eos_reached (); - - if (args_.empty ()) - return base::skip (); - else - args_.pop_front (); - } - - const argv_file_scanner::option_info* argv_file_scanner:: - find (const char* a) const - { - for (std::size_t i (0); i < options_count_; ++i) - if (std::strcmp (a, options_[i].option) == 0) - return &options_[i]; - - return 0; - } - - void argv_file_scanner:: - load (const std::string& file) - { - using namespace std; - - ifstream is (file.c_str ()); - - if (!is.is_open ()) - throw file_io_failure (file); - - files_.push_back (file); - - arg a; - a.file = &*files_.rbegin (); - - for (a.line = 1; !is.eof (); ++a.line) - { - string line; - getline (is, line); - - if (is.fail () && !is.eof ()) - throw file_io_failure (file); - - string::size_type n (line.size ()); - - // Trim the line from leading and trailing whitespaces. - // - if (n != 0) - { - const char* f (line.c_str ()); - const char* l (f + n); - - const char* of (f); - while (f < l && (*f == ' ' || *f == '\t' || *f == '\r')) - ++f; - - --l; - - const char* ol (l); - while (l > f && (*l == ' ' || *l == '\t' || *l == '\r')) - --l; - - if (f != of || l != ol) - line = f <= l ? string (f, l - f + 1) : string (); - } - - // Ignore empty lines, those that start with #. - // - if (line.empty () || line[0] == '#') - continue; - - string::size_type p (string::npos); - if (line.compare (0, 1, "-") == 0) - { - p = line.find (' '); - - string::size_type q (line.find ('=')); - if (q != string::npos && q < p) - p = q; - } - - string s1; - if (p != string::npos) - { - s1.assign (line, 0, p); - - // Skip leading whitespaces in the argument. - // - if (line[p] == '=') - ++p; - else - { - n = line.size (); - for (++p; p < n; ++p) - { - char c (line[p]); - if (c != ' ' && c != '\t' && c != '\r') - break; - } - } - } - else if (!skip_) - skip_ = (line == "--"); - - string s2 (line, p != string::npos ? p : 0); - - // If the string (which is an option value or argument) is - // wrapped in quotes, remove them. - // - n = s2.size (); - char cf (s2[0]), cl (s2[n - 1]); - - if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'') - { - if (n == 1 || cf != cl) - throw unmatched_quote (s2); - - s2 = string (s2, 1, n - 2); - } - - if (!s1.empty ()) - { - // See if this is another file option. - // - const option_info* oi; - if (!skip_ && (oi = find (s1.c_str ()))) - { - if (s2.empty ()) - throw missing_value (oi->option); - - if (oi->search_func != 0) - { - std::string f (oi->search_func (s2.c_str (), oi->arg)); - if (!f.empty ()) - load (f); - } - else - load (s2); - - continue; - } - - a.value = s1; - args_.push_back (a); - } - - a.value = s2; - args_.push_back (a); - } - } - - template - struct parser - { - static void - parse (X& x, bool& xs, scanner& s) - { - using namespace std; - - const char* o (s.next ()); - if (s.more ()) - { - string v (s.next ()); - istringstream is (v); - if (!(is >> x && is.peek () == istringstream::traits_type::eof ())) - throw invalid_value (o, v); - } - else - throw missing_value (o); - - xs = true; - } - }; - - template <> - struct parser - { - static void - parse (bool& x, scanner& s) - { - s.next (); - x = true; - } - }; - - template <> - struct parser - { - static void - parse (std::string& x, bool& xs, scanner& s) - { - const char* o (s.next ()); - - if (s.more ()) - x = s.next (); - else - throw missing_value (o); - - xs = true; - } - }; - - template - struct parser > - { - static void - parse (std::vector& c, bool& xs, scanner& s) - { - X x; - bool dummy; - parser::parse (x, dummy, s); - c.push_back (x); - xs = true; - } - }; - - template - struct parser > - { - static void - parse (std::set& c, bool& xs, scanner& s) - { - X x; - bool dummy; - parser::parse (x, dummy, s); - c.insert (x); - xs = true; - } - }; - - template - struct parser > - { - static void - parse (std::map& m, bool& xs, scanner& s) - { - const char* o (s.next ()); - - if (s.more ()) - { - std::string ov (s.next ()); - std::string::size_type p = ov.find ('='); - - K k = K (); - V v = V (); - std::string kstr (ov, 0, p); - std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); - - int ac (2); - char* av[] = - { - const_cast (o), 0 - }; - - bool dummy; - if (!kstr.empty ()) - { - av[1] = const_cast (kstr.c_str ()); - argv_scanner s (0, ac, av); - parser::parse (k, dummy, s); - } - - if (!vstr.empty ()) - { - av[1] = const_cast (vstr.c_str ()); - argv_scanner s (0, ac, av); - parser::parse (v, dummy, s); - } - - m[k] = v; - } - else - throw missing_value (o); - - xs = true; - } - }; - - template - void - thunk (X& x, scanner& s) - { - parser::parse (x.*M, s); - } - - template - void - thunk (X& x, scanner& s) - { - parser::parse (x.*M, x.*S, s); - } -} - -#include -#include - -// options -// - -options:: -options () -: build2_metadata_ (), - help_ (), - version_ (), - include_path_ (), - include_path_specified_ (false), - output_dir_ (), - output_dir_specified_ (false), - std_ (cxx_version::cxx98), - std_specified_ (false), - generate_modifier_ (), - generate_specifier_ (), - generate_parse_ (), - generate_merge_ (), - generate_description_ (), - generate_file_scanner_ (), - generate_vector_scanner_ (), - generate_group_scanner_ (), - suppress_inline_ (), - suppress_cli_ (), - cli_namespace_ ("::cli"), - cli_namespace_specified_ (false), - ostream_type_ ("::std::ostream"), - ostream_type_specified_ (false), - generate_cxx_ (), - generate_man_ (), - generate_html_ (), - generate_txt_ (), - stdout__ (), - suppress_undocumented_ (), - suppress_usage_ (), - long_usage_ (), - short_usage_ (), - page_usage_ (), - page_usage_specified_ (false), - option_length_ (0), - option_length_specified_ (false), - ansi_color_ (), - exclude_base_ (), - include_base_last_ (), - class_doc_ (), - class_doc_specified_ (false), - class__ (), - class__specified_ (false), - docvar_ (), - docvar_specified_ (false), - link_regex_ (), - link_regex_specified_ (false), - link_regex_trace_ (), - html_heading_map_ (), - html_heading_map_specified_ (false), - omit_link_check_ (), - hxx_prologue_ (), - hxx_prologue_specified_ (false), - ixx_prologue_ (), - ixx_prologue_specified_ (false), - cxx_prologue_ (), - cxx_prologue_specified_ (false), - man_prologue_ (), - man_prologue_specified_ (false), - html_prologue_ (), - html_prologue_specified_ (false), - txt_prologue_ (), - txt_prologue_specified_ (false), - hxx_epilogue_ (), - hxx_epilogue_specified_ (false), - ixx_epilogue_ (), - ixx_epilogue_specified_ (false), - cxx_epilogue_ (), - cxx_epilogue_specified_ (false), - man_epilogue_ (), - man_epilogue_specified_ (false), - html_epilogue_ (), - html_epilogue_specified_ (false), - txt_epilogue_ (), - txt_epilogue_specified_ (false), - hxx_prologue_file_ (), - hxx_prologue_file_specified_ (false), - ixx_prologue_file_ (), - ixx_prologue_file_specified_ (false), - cxx_prologue_file_ (), - cxx_prologue_file_specified_ (false), - man_prologue_file_ (), - man_prologue_file_specified_ (false), - html_prologue_file_ (), - html_prologue_file_specified_ (false), - txt_prologue_file_ (), - txt_prologue_file_specified_ (false), - hxx_epilogue_file_ (), - hxx_epilogue_file_specified_ (false), - ixx_epilogue_file_ (), - ixx_epilogue_file_specified_ (false), - cxx_epilogue_file_ (), - cxx_epilogue_file_specified_ (false), - man_epilogue_file_ (), - man_epilogue_file_specified_ (false), - html_epilogue_file_ (), - html_epilogue_file_specified_ (false), - txt_epilogue_file_ (), - txt_epilogue_file_specified_ (false), - output_prefix_ (), - output_prefix_specified_ (false), - output_suffix_ (), - output_suffix_specified_ (false), - hxx_suffix_ (".hxx"), - hxx_suffix_specified_ (false), - ixx_suffix_ (".ixx"), - ixx_suffix_specified_ (false), - cxx_suffix_ (".cxx"), - cxx_suffix_specified_ (false), - man_suffix_ (".1"), - man_suffix_specified_ (false), - html_suffix_ (".html"), - html_suffix_specified_ (false), - txt_suffix_ (".txt"), - txt_suffix_specified_ (false), - option_prefix_ ("-"), - option_prefix_specified_ (false), - option_separator_ ("--"), - option_separator_specified_ (false), - keep_separator_ (), - no_combined_flags_ (), - no_combined_values_ (), - include_with_brackets_ (), - include_prefix_ (), - include_prefix_specified_ (false), - guard_prefix_ (), - guard_prefix_specified_ (false), - reserved_name_ (), - reserved_name_specified_ (false), - options_file_ (), - options_file_specified_ (false) -{ -} - -options:: -options (int& argc, - char** argv, - bool erase, - ::cli::unknown_mode opt, - ::cli::unknown_mode arg) -: build2_metadata_ (), - help_ (), - version_ (), - include_path_ (), - include_path_specified_ (false), - output_dir_ (), - output_dir_specified_ (false), - std_ (cxx_version::cxx98), - std_specified_ (false), - generate_modifier_ (), - generate_specifier_ (), - generate_parse_ (), - generate_merge_ (), - generate_description_ (), - generate_file_scanner_ (), - generate_vector_scanner_ (), - generate_group_scanner_ (), - suppress_inline_ (), - suppress_cli_ (), - cli_namespace_ ("::cli"), - cli_namespace_specified_ (false), - ostream_type_ ("::std::ostream"), - ostream_type_specified_ (false), - generate_cxx_ (), - generate_man_ (), - generate_html_ (), - generate_txt_ (), - stdout__ (), - suppress_undocumented_ (), - suppress_usage_ (), - long_usage_ (), - short_usage_ (), - page_usage_ (), - page_usage_specified_ (false), - option_length_ (0), - option_length_specified_ (false), - ansi_color_ (), - exclude_base_ (), - include_base_last_ (), - class_doc_ (), - class_doc_specified_ (false), - class__ (), - class__specified_ (false), - docvar_ (), - docvar_specified_ (false), - link_regex_ (), - link_regex_specified_ (false), - link_regex_trace_ (), - html_heading_map_ (), - html_heading_map_specified_ (false), - omit_link_check_ (), - hxx_prologue_ (), - hxx_prologue_specified_ (false), - ixx_prologue_ (), - ixx_prologue_specified_ (false), - cxx_prologue_ (), - cxx_prologue_specified_ (false), - man_prologue_ (), - man_prologue_specified_ (false), - html_prologue_ (), - html_prologue_specified_ (false), - txt_prologue_ (), - txt_prologue_specified_ (false), - hxx_epilogue_ (), - hxx_epilogue_specified_ (false), - ixx_epilogue_ (), - ixx_epilogue_specified_ (false), - cxx_epilogue_ (), - cxx_epilogue_specified_ (false), - man_epilogue_ (), - man_epilogue_specified_ (false), - html_epilogue_ (), - html_epilogue_specified_ (false), - txt_epilogue_ (), - txt_epilogue_specified_ (false), - hxx_prologue_file_ (), - hxx_prologue_file_specified_ (false), - ixx_prologue_file_ (), - ixx_prologue_file_specified_ (false), - cxx_prologue_file_ (), - cxx_prologue_file_specified_ (false), - man_prologue_file_ (), - man_prologue_file_specified_ (false), - html_prologue_file_ (), - html_prologue_file_specified_ (false), - txt_prologue_file_ (), - txt_prologue_file_specified_ (false), - hxx_epilogue_file_ (), - hxx_epilogue_file_specified_ (false), - ixx_epilogue_file_ (), - ixx_epilogue_file_specified_ (false), - cxx_epilogue_file_ (), - cxx_epilogue_file_specified_ (false), - man_epilogue_file_ (), - man_epilogue_file_specified_ (false), - html_epilogue_file_ (), - html_epilogue_file_specified_ (false), - txt_epilogue_file_ (), - txt_epilogue_file_specified_ (false), - output_prefix_ (), - output_prefix_specified_ (false), - output_suffix_ (), - output_suffix_specified_ (false), - hxx_suffix_ (".hxx"), - hxx_suffix_specified_ (false), - ixx_suffix_ (".ixx"), - ixx_suffix_specified_ (false), - cxx_suffix_ (".cxx"), - cxx_suffix_specified_ (false), - man_suffix_ (".1"), - man_suffix_specified_ (false), - html_suffix_ (".html"), - html_suffix_specified_ (false), - txt_suffix_ (".txt"), - txt_suffix_specified_ (false), - option_prefix_ ("-"), - option_prefix_specified_ (false), - option_separator_ ("--"), - option_separator_specified_ (false), - keep_separator_ (), - no_combined_flags_ (), - no_combined_values_ (), - include_with_brackets_ (), - include_prefix_ (), - include_prefix_specified_ (false), - guard_prefix_ (), - guard_prefix_specified_ (false), - reserved_name_ (), - reserved_name_specified_ (false), - options_file_ (), - options_file_specified_ (false) -{ - ::cli::argv_scanner s (argc, argv, erase); - _parse (s, opt, arg); -} - -options:: -options (int start, - int& argc, - char** argv, - bool erase, - ::cli::unknown_mode opt, - ::cli::unknown_mode arg) -: build2_metadata_ (), - help_ (), - version_ (), - include_path_ (), - include_path_specified_ (false), - output_dir_ (), - output_dir_specified_ (false), - std_ (cxx_version::cxx98), - std_specified_ (false), - generate_modifier_ (), - generate_specifier_ (), - generate_parse_ (), - generate_merge_ (), - generate_description_ (), - generate_file_scanner_ (), - generate_vector_scanner_ (), - generate_group_scanner_ (), - suppress_inline_ (), - suppress_cli_ (), - cli_namespace_ ("::cli"), - cli_namespace_specified_ (false), - ostream_type_ ("::std::ostream"), - ostream_type_specified_ (false), - generate_cxx_ (), - generate_man_ (), - generate_html_ (), - generate_txt_ (), - stdout__ (), - suppress_undocumented_ (), - suppress_usage_ (), - long_usage_ (), - short_usage_ (), - page_usage_ (), - page_usage_specified_ (false), - option_length_ (0), - option_length_specified_ (false), - ansi_color_ (), - exclude_base_ (), - include_base_last_ (), - class_doc_ (), - class_doc_specified_ (false), - class__ (), - class__specified_ (false), - docvar_ (), - docvar_specified_ (false), - link_regex_ (), - link_regex_specified_ (false), - link_regex_trace_ (), - html_heading_map_ (), - html_heading_map_specified_ (false), - omit_link_check_ (), - hxx_prologue_ (), - hxx_prologue_specified_ (false), - ixx_prologue_ (), - ixx_prologue_specified_ (false), - cxx_prologue_ (), - cxx_prologue_specified_ (false), - man_prologue_ (), - man_prologue_specified_ (false), - html_prologue_ (), - html_prologue_specified_ (false), - txt_prologue_ (), - txt_prologue_specified_ (false), - hxx_epilogue_ (), - hxx_epilogue_specified_ (false), - ixx_epilogue_ (), - ixx_epilogue_specified_ (false), - cxx_epilogue_ (), - cxx_epilogue_specified_ (false), - man_epilogue_ (), - man_epilogue_specified_ (false), - html_epilogue_ (), - html_epilogue_specified_ (false), - txt_epilogue_ (), - txt_epilogue_specified_ (false), - hxx_prologue_file_ (), - hxx_prologue_file_specified_ (false), - ixx_prologue_file_ (), - ixx_prologue_file_specified_ (false), - cxx_prologue_file_ (), - cxx_prologue_file_specified_ (false), - man_prologue_file_ (), - man_prologue_file_specified_ (false), - html_prologue_file_ (), - html_prologue_file_specified_ (false), - txt_prologue_file_ (), - txt_prologue_file_specified_ (false), - hxx_epilogue_file_ (), - hxx_epilogue_file_specified_ (false), - ixx_epilogue_file_ (), - ixx_epilogue_file_specified_ (false), - cxx_epilogue_file_ (), - cxx_epilogue_file_specified_ (false), - man_epilogue_file_ (), - man_epilogue_file_specified_ (false), - html_epilogue_file_ (), - html_epilogue_file_specified_ (false), - txt_epilogue_file_ (), - txt_epilogue_file_specified_ (false), - output_prefix_ (), - output_prefix_specified_ (false), - output_suffix_ (), - output_suffix_specified_ (false), - hxx_suffix_ (".hxx"), - hxx_suffix_specified_ (false), - ixx_suffix_ (".ixx"), - ixx_suffix_specified_ (false), - cxx_suffix_ (".cxx"), - cxx_suffix_specified_ (false), - man_suffix_ (".1"), - man_suffix_specified_ (false), - html_suffix_ (".html"), - html_suffix_specified_ (false), - txt_suffix_ (".txt"), - txt_suffix_specified_ (false), - option_prefix_ ("-"), - option_prefix_specified_ (false), - option_separator_ ("--"), - option_separator_specified_ (false), - keep_separator_ (), - no_combined_flags_ (), - no_combined_values_ (), - include_with_brackets_ (), - include_prefix_ (), - include_prefix_specified_ (false), - guard_prefix_ (), - guard_prefix_specified_ (false), - reserved_name_ (), - reserved_name_specified_ (false), - options_file_ (), - options_file_specified_ (false) -{ - ::cli::argv_scanner s (start, argc, argv, erase); - _parse (s, opt, arg); -} - -options:: -options (int& argc, - char** argv, - int& end, - bool erase, - ::cli::unknown_mode opt, - ::cli::unknown_mode arg) -: build2_metadata_ (), - help_ (), - version_ (), - include_path_ (), - include_path_specified_ (false), - output_dir_ (), - output_dir_specified_ (false), - std_ (cxx_version::cxx98), - std_specified_ (false), - generate_modifier_ (), - generate_specifier_ (), - generate_parse_ (), - generate_merge_ (), - generate_description_ (), - generate_file_scanner_ (), - generate_vector_scanner_ (), - generate_group_scanner_ (), - suppress_inline_ (), - suppress_cli_ (), - cli_namespace_ ("::cli"), - cli_namespace_specified_ (false), - ostream_type_ ("::std::ostream"), - ostream_type_specified_ (false), - generate_cxx_ (), - generate_man_ (), - generate_html_ (), - generate_txt_ (), - stdout__ (), - suppress_undocumented_ (), - suppress_usage_ (), - long_usage_ (), - short_usage_ (), - page_usage_ (), - page_usage_specified_ (false), - option_length_ (0), - option_length_specified_ (false), - ansi_color_ (), - exclude_base_ (), - include_base_last_ (), - class_doc_ (), - class_doc_specified_ (false), - class__ (), - class__specified_ (false), - docvar_ (), - docvar_specified_ (false), - link_regex_ (), - link_regex_specified_ (false), - link_regex_trace_ (), - html_heading_map_ (), - html_heading_map_specified_ (false), - omit_link_check_ (), - hxx_prologue_ (), - hxx_prologue_specified_ (false), - ixx_prologue_ (), - ixx_prologue_specified_ (false), - cxx_prologue_ (), - cxx_prologue_specified_ (false), - man_prologue_ (), - man_prologue_specified_ (false), - html_prologue_ (), - html_prologue_specified_ (false), - txt_prologue_ (), - txt_prologue_specified_ (false), - hxx_epilogue_ (), - hxx_epilogue_specified_ (false), - ixx_epilogue_ (), - ixx_epilogue_specified_ (false), - cxx_epilogue_ (), - cxx_epilogue_specified_ (false), - man_epilogue_ (), - man_epilogue_specified_ (false), - html_epilogue_ (), - html_epilogue_specified_ (false), - txt_epilogue_ (), - txt_epilogue_specified_ (false), - hxx_prologue_file_ (), - hxx_prologue_file_specified_ (false), - ixx_prologue_file_ (), - ixx_prologue_file_specified_ (false), - cxx_prologue_file_ (), - cxx_prologue_file_specified_ (false), - man_prologue_file_ (), - man_prologue_file_specified_ (false), - html_prologue_file_ (), - html_prologue_file_specified_ (false), - txt_prologue_file_ (), - txt_prologue_file_specified_ (false), - hxx_epilogue_file_ (), - hxx_epilogue_file_specified_ (false), - ixx_epilogue_file_ (), - ixx_epilogue_file_specified_ (false), - cxx_epilogue_file_ (), - cxx_epilogue_file_specified_ (false), - man_epilogue_file_ (), - man_epilogue_file_specified_ (false), - html_epilogue_file_ (), - html_epilogue_file_specified_ (false), - txt_epilogue_file_ (), - txt_epilogue_file_specified_ (false), - output_prefix_ (), - output_prefix_specified_ (false), - output_suffix_ (), - output_suffix_specified_ (false), - hxx_suffix_ (".hxx"), - hxx_suffix_specified_ (false), - ixx_suffix_ (".ixx"), - ixx_suffix_specified_ (false), - cxx_suffix_ (".cxx"), - cxx_suffix_specified_ (false), - man_suffix_ (".1"), - man_suffix_specified_ (false), - html_suffix_ (".html"), - html_suffix_specified_ (false), - txt_suffix_ (".txt"), - txt_suffix_specified_ (false), - option_prefix_ ("-"), - option_prefix_specified_ (false), - option_separator_ ("--"), - option_separator_specified_ (false), - keep_separator_ (), - no_combined_flags_ (), - no_combined_values_ (), - include_with_brackets_ (), - include_prefix_ (), - include_prefix_specified_ (false), - guard_prefix_ (), - guard_prefix_specified_ (false), - reserved_name_ (), - reserved_name_specified_ (false), - options_file_ (), - options_file_specified_ (false) -{ - ::cli::argv_scanner s (argc, argv, erase); - _parse (s, opt, arg); - end = s.end (); -} - -options:: -options (int start, - int& argc, - char** argv, - int& end, - bool erase, - ::cli::unknown_mode opt, - ::cli::unknown_mode arg) -: build2_metadata_ (), - help_ (), - version_ (), - include_path_ (), - include_path_specified_ (false), - output_dir_ (), - output_dir_specified_ (false), - std_ (cxx_version::cxx98), - std_specified_ (false), - generate_modifier_ (), - generate_specifier_ (), - generate_parse_ (), - generate_merge_ (), - generate_description_ (), - generate_file_scanner_ (), - generate_vector_scanner_ (), - generate_group_scanner_ (), - suppress_inline_ (), - suppress_cli_ (), - cli_namespace_ ("::cli"), - cli_namespace_specified_ (false), - ostream_type_ ("::std::ostream"), - ostream_type_specified_ (false), - generate_cxx_ (), - generate_man_ (), - generate_html_ (), - generate_txt_ (), - stdout__ (), - suppress_undocumented_ (), - suppress_usage_ (), - long_usage_ (), - short_usage_ (), - page_usage_ (), - page_usage_specified_ (false), - option_length_ (0), - option_length_specified_ (false), - ansi_color_ (), - exclude_base_ (), - include_base_last_ (), - class_doc_ (), - class_doc_specified_ (false), - class__ (), - class__specified_ (false), - docvar_ (), - docvar_specified_ (false), - link_regex_ (), - link_regex_specified_ (false), - link_regex_trace_ (), - html_heading_map_ (), - html_heading_map_specified_ (false), - omit_link_check_ (), - hxx_prologue_ (), - hxx_prologue_specified_ (false), - ixx_prologue_ (), - ixx_prologue_specified_ (false), - cxx_prologue_ (), - cxx_prologue_specified_ (false), - man_prologue_ (), - man_prologue_specified_ (false), - html_prologue_ (), - html_prologue_specified_ (false), - txt_prologue_ (), - txt_prologue_specified_ (false), - hxx_epilogue_ (), - hxx_epilogue_specified_ (false), - ixx_epilogue_ (), - ixx_epilogue_specified_ (false), - cxx_epilogue_ (), - cxx_epilogue_specified_ (false), - man_epilogue_ (), - man_epilogue_specified_ (false), - html_epilogue_ (), - html_epilogue_specified_ (false), - txt_epilogue_ (), - txt_epilogue_specified_ (false), - hxx_prologue_file_ (), - hxx_prologue_file_specified_ (false), - ixx_prologue_file_ (), - ixx_prologue_file_specified_ (false), - cxx_prologue_file_ (), - cxx_prologue_file_specified_ (false), - man_prologue_file_ (), - man_prologue_file_specified_ (false), - html_prologue_file_ (), - html_prologue_file_specified_ (false), - txt_prologue_file_ (), - txt_prologue_file_specified_ (false), - hxx_epilogue_file_ (), - hxx_epilogue_file_specified_ (false), - ixx_epilogue_file_ (), - ixx_epilogue_file_specified_ (false), - cxx_epilogue_file_ (), - cxx_epilogue_file_specified_ (false), - man_epilogue_file_ (), - man_epilogue_file_specified_ (false), - html_epilogue_file_ (), - html_epilogue_file_specified_ (false), - txt_epilogue_file_ (), - txt_epilogue_file_specified_ (false), - output_prefix_ (), - output_prefix_specified_ (false), - output_suffix_ (), - output_suffix_specified_ (false), - hxx_suffix_ (".hxx"), - hxx_suffix_specified_ (false), - ixx_suffix_ (".ixx"), - ixx_suffix_specified_ (false), - cxx_suffix_ (".cxx"), - cxx_suffix_specified_ (false), - man_suffix_ (".1"), - man_suffix_specified_ (false), - html_suffix_ (".html"), - html_suffix_specified_ (false), - txt_suffix_ (".txt"), - txt_suffix_specified_ (false), - option_prefix_ ("-"), - option_prefix_specified_ (false), - option_separator_ ("--"), - option_separator_specified_ (false), - keep_separator_ (), - no_combined_flags_ (), - no_combined_values_ (), - include_with_brackets_ (), - include_prefix_ (), - include_prefix_specified_ (false), - guard_prefix_ (), - guard_prefix_specified_ (false), - reserved_name_ (), - reserved_name_specified_ (false), - options_file_ (), - options_file_specified_ (false) -{ - ::cli::argv_scanner s (start, argc, argv, erase); - _parse (s, opt, arg); - end = s.end (); -} - -options:: -options (::cli::scanner& s, - ::cli::unknown_mode opt, - ::cli::unknown_mode arg) -: build2_metadata_ (), - help_ (), - version_ (), - include_path_ (), - include_path_specified_ (false), - output_dir_ (), - output_dir_specified_ (false), - std_ (cxx_version::cxx98), - std_specified_ (false), - generate_modifier_ (), - generate_specifier_ (), - generate_parse_ (), - generate_merge_ (), - generate_description_ (), - generate_file_scanner_ (), - generate_vector_scanner_ (), - generate_group_scanner_ (), - suppress_inline_ (), - suppress_cli_ (), - cli_namespace_ ("::cli"), - cli_namespace_specified_ (false), - ostream_type_ ("::std::ostream"), - ostream_type_specified_ (false), - generate_cxx_ (), - generate_man_ (), - generate_html_ (), - generate_txt_ (), - stdout__ (), - suppress_undocumented_ (), - suppress_usage_ (), - long_usage_ (), - short_usage_ (), - page_usage_ (), - page_usage_specified_ (false), - option_length_ (0), - option_length_specified_ (false), - ansi_color_ (), - exclude_base_ (), - include_base_last_ (), - class_doc_ (), - class_doc_specified_ (false), - class__ (), - class__specified_ (false), - docvar_ (), - docvar_specified_ (false), - link_regex_ (), - link_regex_specified_ (false), - link_regex_trace_ (), - html_heading_map_ (), - html_heading_map_specified_ (false), - omit_link_check_ (), - hxx_prologue_ (), - hxx_prologue_specified_ (false), - ixx_prologue_ (), - ixx_prologue_specified_ (false), - cxx_prologue_ (), - cxx_prologue_specified_ (false), - man_prologue_ (), - man_prologue_specified_ (false), - html_prologue_ (), - html_prologue_specified_ (false), - txt_prologue_ (), - txt_prologue_specified_ (false), - hxx_epilogue_ (), - hxx_epilogue_specified_ (false), - ixx_epilogue_ (), - ixx_epilogue_specified_ (false), - cxx_epilogue_ (), - cxx_epilogue_specified_ (false), - man_epilogue_ (), - man_epilogue_specified_ (false), - html_epilogue_ (), - html_epilogue_specified_ (false), - txt_epilogue_ (), - txt_epilogue_specified_ (false), - hxx_prologue_file_ (), - hxx_prologue_file_specified_ (false), - ixx_prologue_file_ (), - ixx_prologue_file_specified_ (false), - cxx_prologue_file_ (), - cxx_prologue_file_specified_ (false), - man_prologue_file_ (), - man_prologue_file_specified_ (false), - html_prologue_file_ (), - html_prologue_file_specified_ (false), - txt_prologue_file_ (), - txt_prologue_file_specified_ (false), - hxx_epilogue_file_ (), - hxx_epilogue_file_specified_ (false), - ixx_epilogue_file_ (), - ixx_epilogue_file_specified_ (false), - cxx_epilogue_file_ (), - cxx_epilogue_file_specified_ (false), - man_epilogue_file_ (), - man_epilogue_file_specified_ (false), - html_epilogue_file_ (), - html_epilogue_file_specified_ (false), - txt_epilogue_file_ (), - txt_epilogue_file_specified_ (false), - output_prefix_ (), - output_prefix_specified_ (false), - output_suffix_ (), - output_suffix_specified_ (false), - hxx_suffix_ (".hxx"), - hxx_suffix_specified_ (false), - ixx_suffix_ (".ixx"), - ixx_suffix_specified_ (false), - cxx_suffix_ (".cxx"), - cxx_suffix_specified_ (false), - man_suffix_ (".1"), - man_suffix_specified_ (false), - html_suffix_ (".html"), - html_suffix_specified_ (false), - txt_suffix_ (".txt"), - txt_suffix_specified_ (false), - option_prefix_ ("-"), - option_prefix_specified_ (false), - option_separator_ ("--"), - option_separator_specified_ (false), - keep_separator_ (), - no_combined_flags_ (), - no_combined_values_ (), - include_with_brackets_ (), - include_prefix_ (), - include_prefix_specified_ (false), - guard_prefix_ (), - guard_prefix_specified_ (false), - reserved_name_ (), - reserved_name_specified_ (false), - options_file_ (), - options_file_specified_ (false) -{ - _parse (s, opt, arg); -} - -::cli::usage_para options:: -print_usage (::std::ostream& os, ::cli::usage_para p) -{ - CLI_POTENTIALLY_UNUSED (os); - - if (p == ::cli::usage_para::text) - os << ::std::endl; - - os << "--build2-metadata" << std::endl; - - os << "--help Print usage information and exit." << ::std::endl; - - os << "--version Print version and exit." << ::std::endl; - - os << "--include-path|-I Search for bracket-included (<>) options" << ::std::endl - << " files." << ::std::endl; - - os << "--output-dir|-o Write the generated files to instead of the" << ::std::endl - << " current directory." << ::std::endl; - - os << "--std Specify the C++ standard that should be used" << ::std::endl - << " during compilation." << ::std::endl; - - os << "--generate-modifier Generate option value modifiers in addition to" << ::std::endl - << " accessors." << ::std::endl; - - os << "--generate-specifier Generate functions for determining whether the" << ::std::endl - << " option was specified on the command line." << ::std::endl; - - os << "--generate-parse Generate parse() functions instead of parsing" << ::std::endl - << " constructors." << ::std::endl; - - os << "--generate-merge Generate merge() functions." << ::std::endl; - - os << "--generate-description Generate the option description list that can be" << ::std::endl - << " examined at runtime." << ::std::endl; - - os << "--generate-file-scanner Generate the argv_file_scanner implementation." << ::std::endl; - - os << "--generate-vector-scanner Generate the vector_scanner implementation." << ::std::endl; - - os << "--generate-group-scanner Generate the group_scanner implementation." << ::std::endl; - - os << "--suppress-inline Generate all functions non-inline." << ::std::endl; - - os << "--suppress-cli Do not generate the CLI support types (scanners," << ::std::endl - << " parser, etc)." << ::std::endl; - - os << "--cli-namespace Generate the CLI support types in the " << ::std::endl - << " namespace (cli by default)." << ::std::endl; - - os << "--ostream-type Output stream type instead of the default" << ::std::endl - << " std::ostream that should be used to print usage" << ::std::endl - << " and exception information." << ::std::endl; - - os << "--generate-cxx Generate C++ code." << ::std::endl; - - os << "--generate-man Generate documentation in the man page format." << ::std::endl; - - os << "--generate-html Generate documentation in the HTML format." << ::std::endl; - - os << "--generate-txt Generate documentation in the plain text format," << ::std::endl - << " similar to usage." << ::std::endl; - - os << "--stdout Write output to STDOUT instead of a file." << ::std::endl; - - os << "--suppress-undocumented Suppress the generation of documentation entries" << ::std::endl - << " for undocumented options." << ::std::endl; - - os << "--suppress-usage Suppress the generation of the usage printing" << ::std::endl - << " code." << ::std::endl; - - os << "--long-usage If no short documentation string is provided, use" << ::std::endl - << " the complete long documentation string in usage." << ::std::endl; - - os << "--short-usage If specified together with --long-usage, generate" << ::std::endl - << " both short and long usage versions." << ::std::endl; - - os << "--page-usage Generate the combined usage printing code for the" << ::std::endl - << " entire page." << ::std::endl; - - os << "--option-length Indent option descriptions characters when" << ::std::endl - << " printing usage." << ::std::endl; - - os << "--ansi-color Use ANSI color escape sequences when printing" << ::std::endl - << " usage." << ::std::endl; - - os << "--exclude-base Exclude base class information from usage and" << ::std::endl - << " documentation." << ::std::endl; - - os << "--include-base-last Include base class information after derived for" << ::std::endl - << " usage and documentation." << ::std::endl; - - os << "--class-doc = Specify the documentation that should be" << ::std::endl - << " used for the options class ." << ::std::endl; - - os << "--class Generate the man page, HTML, or text documentation" << ::std::endl - << " only for the options class ." << ::std::endl; - - os << "--docvar|-v = Set documentation variable to the value" << ::std::endl - << " ." << ::std::endl; - - os << "--link-regex Add to the list of regular expressions" << ::std::endl - << " used to transform link targets in the generated" << ::std::endl - << " documentation." << ::std::endl; - - os << "--link-regex-trace Trace the process of applying regular expressions" << ::std::endl - << " specified with the --link-regex option." << ::std::endl; - - os << "--html-heading-map = Map CLI heading (valid values: 'H', '0', '1'," << ::std::endl - << " 'h', and '2') to HTML heading (for example," << ::std::endl - << " 'h1', 'h2', etc)." << ::std::endl; - - os << "--omit-link-check Don't check that local fragment link references" << ::std::endl - << " (\\l{#ref ...}) resolve to ids." << ::std::endl; - - os << "--hxx-prologue Insert at the beginning of the generated" << ::std::endl - << " C++ header file." << ::std::endl; - - os << "--ixx-prologue Insert at the beginning of the generated" << ::std::endl - << " C++ inline file." << ::std::endl; - - os << "--cxx-prologue Insert at the beginning of the generated" << ::std::endl - << " C++ source file." << ::std::endl; - - os << "--man-prologue Insert at the beginning of the generated" << ::std::endl - << " man page file." << ::std::endl; - - os << "--html-prologue Insert at the beginning of the generated" << ::std::endl - << " HTML file." << ::std::endl; - - os << "--txt-prologue Insert at the beginning of the generated" << ::std::endl - << " text file." << ::std::endl; - - os << "--hxx-epilogue Insert at the end of the generated C++" << ::std::endl - << " header file." << ::std::endl; - - os << "--ixx-epilogue Insert at the end of the generated C++" << ::std::endl - << " inline file." << ::std::endl; - - os << "--cxx-epilogue Insert at the end of the generated C++" << ::std::endl - << " source file." << ::std::endl; - - os << "--man-epilogue Insert at the end of the generated man page" << ::std::endl - << " file." << ::std::endl; - - os << "--html-epilogue Insert at the end of the generated HTML" << ::std::endl - << " file." << ::std::endl; - - os << "--txt-epilogue Insert at the end of the generated text" << ::std::endl - << " file." << ::std::endl; - - os << "--hxx-prologue-file Insert the content of at the beginning of" << ::std::endl - << " the generated C++ header file." << ::std::endl; - - os << "--ixx-prologue-file Insert the content of at the beginning of" << ::std::endl - << " the generated C++ inline file." << ::std::endl; - - os << "--cxx-prologue-file Insert the content of at the beginning of" << ::std::endl - << " the generated C++ source file." << ::std::endl; - - os << "--man-prologue-file Insert the content of at the beginning of" << ::std::endl - << " the generated man page file." << ::std::endl; - - os << "--html-prologue-file Insert the content of at the beginning of" << ::std::endl - << " the generated HTML file." << ::std::endl; - - os << "--txt-prologue-file Insert the content of at the beginning of" << ::std::endl - << " the generated text file." << ::std::endl; - - os << "--hxx-epilogue-file Insert the content of at the end of the" << ::std::endl - << " generated C++ header file." << ::std::endl; - - os << "--ixx-epilogue-file Insert the content of at the end of the" << ::std::endl - << " generated C++ inline file." << ::std::endl; - - os << "--cxx-epilogue-file Insert the content of at the end of the" << ::std::endl - << " generated C++ source file." << ::std::endl; - - os << "--man-epilogue-file Insert the content of at the end of the" << ::std::endl - << " generated man page file." << ::std::endl; - - os << "--html-epilogue-file Insert the content of at the end of the" << ::std::endl - << " generated HTML file." << ::std::endl; - - os << "--txt-epilogue-file Insert the content of at the end of the" << ::std::endl - << " generated text file." << ::std::endl; - - os << "--output-prefix Add at the beginning of the generated" << ::std::endl - << " output file name(s)." << ::std::endl; - - os << "--output-suffix Add at the end of the generated output" << ::std::endl - << " file name(s)." << ::std::endl; - - os << "--hxx-suffix Use instead of the default .hxx to" << ::std::endl - << " construct the name of the generated header file." << ::std::endl; - - os << "--ixx-suffix Use instead of the default .ixx to" << ::std::endl - << " construct the name of the generated inline file." << ::std::endl; - - os << "--cxx-suffix Use instead of the default .cxx to" << ::std::endl - << " construct the name of the generated source file." << ::std::endl; - - os << "--man-suffix Use instead of the default .1 to" << ::std::endl - << " construct the name of the generated man page file." << ::std::endl; - - os << "--html-suffix Use instead of the default .html to" << ::std::endl - << " construct the name of the generated HTML file." << ::std::endl; - - os << "--txt-suffix Use instead of the default .txt to" << ::std::endl - << " construct the name of the generated text file." << ::std::endl; - - os << "--option-prefix Use instead of the default '-' as an" << ::std::endl - << " option prefix." << ::std::endl; - - os << "--option-separator Use instead of the default '--' as an" << ::std::endl - << " optional separator between options and arguments." << ::std::endl; - - os << "--keep-separator Leave the option separator in the scanner." << ::std::endl; - - os << "--no-combined-flags Disable support for combining multiple" << ::std::endl - << " single-character flags into a single argument (the" << ::std::endl - << " -xyz form that is equivalent to -x -y -z)." << ::std::endl; - - os << "--no-combined-values Disable support for combining an option and its" << ::std::endl - << " value into a single argument with the assignment" << ::std::endl - << " sign (the option=value form)." << ::std::endl; - - os << "--include-with-brackets Use angle brackets (<>) instead of quotes (\"\") in" << ::std::endl - << " the generated #include directives." << ::std::endl; - - os << "--include-prefix Add to the generated #include directive" << ::std::endl - << " paths." << ::std::endl; - - os << "--guard-prefix Add to the generated header inclusion" << ::std::endl - << " guards." << ::std::endl; - - os << "--reserved-name = Add with an optional replacement to" << ::std::endl - << " the list of names that should not be used as" << ::std::endl - << " identifiers." << ::std::endl; - - os << "--options-file Read additional options from ." << ::std::endl; - - p = ::cli::usage_para::option; - - return p; -} - -typedef -std::map -_cli_options_map; - -static _cli_options_map _cli_options_map_; - -struct _cli_options_map_init -{ - _cli_options_map_init () - { - _cli_options_map_["--build2-metadata"] = - &::cli::thunk< options, bool, &options::build2_metadata_ >; - _cli_options_map_["--help"] = - &::cli::thunk< options, bool, &options::help_ >; - _cli_options_map_["--version"] = - &::cli::thunk< options, bool, &options::version_ >; - _cli_options_map_["--include-path"] = - &::cli::thunk< options, std::vector, &options::include_path_, - &options::include_path_specified_ >; - _cli_options_map_["-I"] = - &::cli::thunk< options, std::vector, &options::include_path_, - &options::include_path_specified_ >; - _cli_options_map_["--output-dir"] = - &::cli::thunk< options, std::string, &options::output_dir_, - &options::output_dir_specified_ >; - _cli_options_map_["-o"] = - &::cli::thunk< options, std::string, &options::output_dir_, - &options::output_dir_specified_ >; - _cli_options_map_["--std"] = - &::cli::thunk< options, cxx_version, &options::std_, - &options::std_specified_ >; - _cli_options_map_["--generate-modifier"] = - &::cli::thunk< options, bool, &options::generate_modifier_ >; - _cli_options_map_["--generate-specifier"] = - &::cli::thunk< options, bool, &options::generate_specifier_ >; - _cli_options_map_["--generate-parse"] = - &::cli::thunk< options, bool, &options::generate_parse_ >; - _cli_options_map_["--generate-merge"] = - &::cli::thunk< options, bool, &options::generate_merge_ >; - _cli_options_map_["--generate-description"] = - &::cli::thunk< options, bool, &options::generate_description_ >; - _cli_options_map_["--generate-file-scanner"] = - &::cli::thunk< options, bool, &options::generate_file_scanner_ >; - _cli_options_map_["--generate-vector-scanner"] = - &::cli::thunk< options, bool, &options::generate_vector_scanner_ >; - _cli_options_map_["--generate-group-scanner"] = - &::cli::thunk< options, bool, &options::generate_group_scanner_ >; - _cli_options_map_["--suppress-inline"] = - &::cli::thunk< options, bool, &options::suppress_inline_ >; - _cli_options_map_["--suppress-cli"] = - &::cli::thunk< options, bool, &options::suppress_cli_ >; - _cli_options_map_["--cli-namespace"] = - &::cli::thunk< options, std::string, &options::cli_namespace_, - &options::cli_namespace_specified_ >; - _cli_options_map_["--ostream-type"] = - &::cli::thunk< options, std::string, &options::ostream_type_, - &options::ostream_type_specified_ >; - _cli_options_map_["--generate-cxx"] = - &::cli::thunk< options, bool, &options::generate_cxx_ >; - _cli_options_map_["--generate-man"] = - &::cli::thunk< options, bool, &options::generate_man_ >; - _cli_options_map_["--generate-html"] = - &::cli::thunk< options, bool, &options::generate_html_ >; - _cli_options_map_["--generate-txt"] = - &::cli::thunk< options, bool, &options::generate_txt_ >; - _cli_options_map_["--stdout"] = - &::cli::thunk< options, bool, &options::stdout__ >; - _cli_options_map_["--suppress-undocumented"] = - &::cli::thunk< options, bool, &options::suppress_undocumented_ >; - _cli_options_map_["--suppress-usage"] = - &::cli::thunk< options, bool, &options::suppress_usage_ >; - _cli_options_map_["--long-usage"] = - &::cli::thunk< options, bool, &options::long_usage_ >; - _cli_options_map_["--short-usage"] = - &::cli::thunk< options, bool, &options::short_usage_ >; - _cli_options_map_["--page-usage"] = - &::cli::thunk< options, std::string, &options::page_usage_, - &options::page_usage_specified_ >; - _cli_options_map_["--option-length"] = - &::cli::thunk< options, std::size_t, &options::option_length_, - &options::option_length_specified_ >; - _cli_options_map_["--ansi-color"] = - &::cli::thunk< options, bool, &options::ansi_color_ >; - _cli_options_map_["--exclude-base"] = - &::cli::thunk< options, bool, &options::exclude_base_ >; - _cli_options_map_["--include-base-last"] = - &::cli::thunk< options, bool, &options::include_base_last_ >; - _cli_options_map_["--class-doc"] = - &::cli::thunk< options, std::map, &options::class_doc_, - &options::class_doc_specified_ >; - _cli_options_map_["--class"] = - &::cli::thunk< options, std::vector, &options::class__, - &options::class__specified_ >; - _cli_options_map_["--docvar"] = - &::cli::thunk< options, std::map, &options::docvar_, - &options::docvar_specified_ >; - _cli_options_map_["-v"] = - &::cli::thunk< options, std::map, &options::docvar_, - &options::docvar_specified_ >; - _cli_options_map_["--link-regex"] = - &::cli::thunk< options, std::vector, &options::link_regex_, - &options::link_regex_specified_ >; - _cli_options_map_["--link-regex-trace"] = - &::cli::thunk< options, bool, &options::link_regex_trace_ >; - _cli_options_map_["--html-heading-map"] = - &::cli::thunk< options, std::map, &options::html_heading_map_, - &options::html_heading_map_specified_ >; - _cli_options_map_["--omit-link-check"] = - &::cli::thunk< options, bool, &options::omit_link_check_ >; - _cli_options_map_["--hxx-prologue"] = - &::cli::thunk< options, std::vector, &options::hxx_prologue_, - &options::hxx_prologue_specified_ >; - _cli_options_map_["--ixx-prologue"] = - &::cli::thunk< options, std::vector, &options::ixx_prologue_, - &options::ixx_prologue_specified_ >; - _cli_options_map_["--cxx-prologue"] = - &::cli::thunk< options, std::vector, &options::cxx_prologue_, - &options::cxx_prologue_specified_ >; - _cli_options_map_["--man-prologue"] = - &::cli::thunk< options, std::vector, &options::man_prologue_, - &options::man_prologue_specified_ >; - _cli_options_map_["--html-prologue"] = - &::cli::thunk< options, std::vector, &options::html_prologue_, - &options::html_prologue_specified_ >; - _cli_options_map_["--txt-prologue"] = - &::cli::thunk< options, std::vector, &options::txt_prologue_, - &options::txt_prologue_specified_ >; - _cli_options_map_["--hxx-epilogue"] = - &::cli::thunk< options, std::vector, &options::hxx_epilogue_, - &options::hxx_epilogue_specified_ >; - _cli_options_map_["--ixx-epilogue"] = - &::cli::thunk< options, std::vector, &options::ixx_epilogue_, - &options::ixx_epilogue_specified_ >; - _cli_options_map_["--cxx-epilogue"] = - &::cli::thunk< options, std::vector, &options::cxx_epilogue_, - &options::cxx_epilogue_specified_ >; - _cli_options_map_["--man-epilogue"] = - &::cli::thunk< options, std::vector, &options::man_epilogue_, - &options::man_epilogue_specified_ >; - _cli_options_map_["--html-epilogue"] = - &::cli::thunk< options, std::vector, &options::html_epilogue_, - &options::html_epilogue_specified_ >; - _cli_options_map_["--txt-epilogue"] = - &::cli::thunk< options, std::vector, &options::txt_epilogue_, - &options::txt_epilogue_specified_ >; - _cli_options_map_["--hxx-prologue-file"] = - &::cli::thunk< options, std::string, &options::hxx_prologue_file_, - &options::hxx_prologue_file_specified_ >; - _cli_options_map_["--ixx-prologue-file"] = - &::cli::thunk< options, std::string, &options::ixx_prologue_file_, - &options::ixx_prologue_file_specified_ >; - _cli_options_map_["--cxx-prologue-file"] = - &::cli::thunk< options, std::string, &options::cxx_prologue_file_, - &options::cxx_prologue_file_specified_ >; - _cli_options_map_["--man-prologue-file"] = - &::cli::thunk< options, std::string, &options::man_prologue_file_, - &options::man_prologue_file_specified_ >; - _cli_options_map_["--html-prologue-file"] = - &::cli::thunk< options, std::string, &options::html_prologue_file_, - &options::html_prologue_file_specified_ >; - _cli_options_map_["--txt-prologue-file"] = - &::cli::thunk< options, std::string, &options::txt_prologue_file_, - &options::txt_prologue_file_specified_ >; - _cli_options_map_["--hxx-epilogue-file"] = - &::cli::thunk< options, std::string, &options::hxx_epilogue_file_, - &options::hxx_epilogue_file_specified_ >; - _cli_options_map_["--ixx-epilogue-file"] = - &::cli::thunk< options, std::string, &options::ixx_epilogue_file_, - &options::ixx_epilogue_file_specified_ >; - _cli_options_map_["--cxx-epilogue-file"] = - &::cli::thunk< options, std::string, &options::cxx_epilogue_file_, - &options::cxx_epilogue_file_specified_ >; - _cli_options_map_["--man-epilogue-file"] = - &::cli::thunk< options, std::string, &options::man_epilogue_file_, - &options::man_epilogue_file_specified_ >; - _cli_options_map_["--html-epilogue-file"] = - &::cli::thunk< options, std::string, &options::html_epilogue_file_, - &options::html_epilogue_file_specified_ >; - _cli_options_map_["--txt-epilogue-file"] = - &::cli::thunk< options, std::string, &options::txt_epilogue_file_, - &options::txt_epilogue_file_specified_ >; - _cli_options_map_["--output-prefix"] = - &::cli::thunk< options, std::string, &options::output_prefix_, - &options::output_prefix_specified_ >; - _cli_options_map_["--output-suffix"] = - &::cli::thunk< options, std::string, &options::output_suffix_, - &options::output_suffix_specified_ >; - _cli_options_map_["--hxx-suffix"] = - &::cli::thunk< options, std::string, &options::hxx_suffix_, - &options::hxx_suffix_specified_ >; - _cli_options_map_["--ixx-suffix"] = - &::cli::thunk< options, std::string, &options::ixx_suffix_, - &options::ixx_suffix_specified_ >; - _cli_options_map_["--cxx-suffix"] = - &::cli::thunk< options, std::string, &options::cxx_suffix_, - &options::cxx_suffix_specified_ >; - _cli_options_map_["--man-suffix"] = - &::cli::thunk< options, std::string, &options::man_suffix_, - &options::man_suffix_specified_ >; - _cli_options_map_["--html-suffix"] = - &::cli::thunk< options, std::string, &options::html_suffix_, - &options::html_suffix_specified_ >; - _cli_options_map_["--txt-suffix"] = - &::cli::thunk< options, std::string, &options::txt_suffix_, - &options::txt_suffix_specified_ >; - _cli_options_map_["--option-prefix"] = - &::cli::thunk< options, std::string, &options::option_prefix_, - &options::option_prefix_specified_ >; - _cli_options_map_["--option-separator"] = - &::cli::thunk< options, std::string, &options::option_separator_, - &options::option_separator_specified_ >; - _cli_options_map_["--keep-separator"] = - &::cli::thunk< options, bool, &options::keep_separator_ >; - _cli_options_map_["--no-combined-flags"] = - &::cli::thunk< options, bool, &options::no_combined_flags_ >; - _cli_options_map_["--no-combined-values"] = - &::cli::thunk< options, bool, &options::no_combined_values_ >; - _cli_options_map_["--include-with-brackets"] = - &::cli::thunk< options, bool, &options::include_with_brackets_ >; - _cli_options_map_["--include-prefix"] = - &::cli::thunk< options, std::string, &options::include_prefix_, - &options::include_prefix_specified_ >; - _cli_options_map_["--guard-prefix"] = - &::cli::thunk< options, std::string, &options::guard_prefix_, - &options::guard_prefix_specified_ >; - _cli_options_map_["--reserved-name"] = - &::cli::thunk< options, std::map, &options::reserved_name_, - &options::reserved_name_specified_ >; - _cli_options_map_["--options-file"] = - &::cli::thunk< options, std::string, &options::options_file_, - &options::options_file_specified_ >; - } -}; - -static _cli_options_map_init _cli_options_map_init_; - -bool options:: -_parse (const char* o, ::cli::scanner& s) -{ - _cli_options_map::const_iterator i (_cli_options_map_.find (o)); - - if (i != _cli_options_map_.end ()) - { - (*(i->second)) (*this, s); - return true; - } - - return false; -} - -bool options:: -_parse (::cli::scanner& s, - ::cli::unknown_mode opt_mode, - ::cli::unknown_mode arg_mode) -{ - // Can't skip combined flags (--no-combined-flags). - // - assert (opt_mode != ::cli::unknown_mode::skip); - - bool r = false; - bool opt = true; - - while (s.more ()) - { - const char* o = s.peek (); - - if (std::strcmp (o, "--") == 0) - { - opt = false; - s.skip (); - r = true; - continue; - } - - if (opt) - { - if (_parse (o, s)) - { - r = true; - continue; - } - - if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0') - { - // Handle combined option values. - // - std::string co; - if (const char* v = std::strchr (o, '=')) - { - co.assign (o, 0, v - o); - ++v; - - int ac (2); - char* av[] = - { - const_cast (co.c_str ()), - const_cast (v) - }; - - ::cli::argv_scanner ns (0, ac, av); - - if (_parse (co.c_str (), ns)) - { - // Parsed the option but not its value? - // - if (ns.end () != 2) - throw ::cli::invalid_value (co, v); - - s.next (); - r = true; - continue; - } - else - { - // Set the unknown option and fall through. - // - o = co.c_str (); - } - } - - // Handle combined flags. - // - char cf[3]; - { - const char* p = o + 1; - for (; *p != '\0'; ++p) - { - if (!((*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z') || - (*p >= '0' && *p <= '9'))) - break; - } - - if (*p == '\0') - { - for (p = o + 1; *p != '\0'; ++p) - { - std::strcpy (cf, "-"); - cf[1] = *p; - cf[2] = '\0'; - - int ac (1); - char* av[] = - { - cf - }; - - ::cli::argv_scanner ns (0, ac, av); - - if (!_parse (cf, ns)) - break; - } - - if (*p == '\0') - { - // All handled. - // - s.next (); - r = true; - continue; - } - else - { - // Set the unknown option and fall through. - // - o = cf; - } - } - } - - switch (opt_mode) - { - case ::cli::unknown_mode::skip: - { - s.skip (); - r = true; - continue; - } - case ::cli::unknown_mode::stop: - { - break; - } - case ::cli::unknown_mode::fail: - { - throw ::cli::unknown_option (o); - } - } - - break; - } - } - - switch (arg_mode) - { - case ::cli::unknown_mode::skip: - { - s.skip (); - r = true; - continue; - } - case ::cli::unknown_mode::stop: - { - break; - } - case ::cli::unknown_mode::fail: - { - throw ::cli::unknown_argument (o); - } - } - - break; - } - - return r; -} - -// Begin epilogue. -// -// -// End epilogue. - diff --git a/cli/options.hxx b/cli/options.hxx deleted file mode 100644 index b253092..0000000 --- a/cli/options.hxx +++ /dev/null @@ -1,1632 +0,0 @@ -// -*- C++ -*- -// -// This file was generated by CLI, a command line interface -// compiler for C++. -// - -#ifndef CLI_OPTIONS_HXX -#define CLI_OPTIONS_HXX - -// Begin prologue. -// -// -// End prologue. - -#include -#include -#include -#include -#include -#include - -#ifndef CLI_POTENTIALLY_UNUSED -# if defined(_MSC_VER) || defined(__xlC__) -# define CLI_POTENTIALLY_UNUSED(x) (void*)&x -# else -# define CLI_POTENTIALLY_UNUSED(x) (void)x -# endif -#endif - -namespace cli -{ - class usage_para - { - public: - enum value - { - none, - text, - option - }; - - usage_para (value); - - operator value () const - { - return v_; - } - - private: - value v_; - }; - - class unknown_mode - { - public: - enum value - { - skip, - stop, - fail - }; - - unknown_mode (value); - - operator value () const - { - return v_; - } - - private: - value v_; - }; - - // Exceptions. - // - - class exception: public std::exception - { - public: - virtual void - print (::std::ostream&) const = 0; - }; - - ::std::ostream& - operator<< (::std::ostream&, const exception&); - - class unknown_option: public exception - { - public: - virtual - ~unknown_option () throw (); - - unknown_option (const std::string& option); - - const std::string& - option () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string option_; - }; - - class unknown_argument: public exception - { - public: - virtual - ~unknown_argument () throw (); - - unknown_argument (const std::string& argument); - - const std::string& - argument () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string argument_; - }; - - class missing_value: public exception - { - public: - virtual - ~missing_value () throw (); - - missing_value (const std::string& option); - - const std::string& - option () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string option_; - }; - - class invalid_value: public exception - { - public: - virtual - ~invalid_value () throw (); - - invalid_value (const std::string& option, - const std::string& value, - const std::string& message = std::string ()); - - const std::string& - option () const; - - const std::string& - value () const; - - const std::string& - message () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string option_; - std::string value_; - std::string message_; - }; - - class eos_reached: public exception - { - public: - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - }; - - class file_io_failure: public exception - { - public: - virtual - ~file_io_failure () throw (); - - file_io_failure (const std::string& file); - - const std::string& - file () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string file_; - }; - - class unmatched_quote: public exception - { - public: - virtual - ~unmatched_quote () throw (); - - unmatched_quote (const std::string& argument); - - const std::string& - argument () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string argument_; - }; - - // Command line argument scanner interface. - // - // The values returned by next() are guaranteed to be valid - // for the two previous arguments up until a call to a third - // peek() or next(). - // - class scanner - { - public: - virtual - ~scanner (); - - virtual bool - more () = 0; - - virtual const char* - peek () = 0; - - virtual const char* - next () = 0; - - virtual void - skip () = 0; - }; - - class argv_scanner: public scanner - { - public: - argv_scanner (int& argc, char** argv, bool erase = false); - argv_scanner (int start, int& argc, char** argv, bool erase = false); - - int - end () const; - - virtual bool - more (); - - virtual const char* - peek (); - - virtual const char* - next (); - - virtual void - skip (); - - private: - int i_; - int& argc_; - char** argv_; - bool erase_; - }; - - class argv_file_scanner: public argv_scanner - { - public: - argv_file_scanner (int& argc, - char** argv, - const std::string& option, - bool erase = false); - - argv_file_scanner (int start, - int& argc, - char** argv, - const std::string& option, - bool erase = false); - - argv_file_scanner (const std::string& file, - const std::string& option); - - struct option_info - { - // If search_func is not NULL, it is called, with the arg - // value as the second argument, to locate the options file. - // If it returns an empty string, then the file is ignored. - // - const char* option; - std::string (*search_func) (const char*, void* arg); - void* arg; - }; - - argv_file_scanner (int& argc, - char** argv, - const option_info* options, - std::size_t options_count, - bool erase = false); - - argv_file_scanner (int start, - int& argc, - char** argv, - const option_info* options, - std::size_t options_count, - bool erase = false); - - argv_file_scanner (const std::string& file, - const option_info* options = 0, - std::size_t options_count = 0); - - virtual bool - more (); - - virtual const char* - peek (); - - virtual const char* - next (); - - virtual void - skip (); - - // Return the file path if the peeked at argument came from a file and - // the empty string otherwise. The reference is guaranteed to be valid - // till the end of the scanner lifetime. - // - const std::string& - peek_file (); - - // Return the 1-based line number if the peeked at argument came from - // a file and zero otherwise. - // - std::size_t - peek_line (); - - private: - const option_info* - find (const char*) const; - - void - load (const std::string& file); - - typedef argv_scanner base; - - const std::string option_; - option_info option_info_; - const option_info* options_; - std::size_t options_count_; - - struct arg - { - std::string value; - const std::string* file; - std::size_t line; - }; - - std::deque args_; - std::list files_; - - // Circular buffer of two arguments. - // - std::string hold_[2]; - std::size_t i_; - - bool skip_; - - static int zero_argc_; - static std::string empty_string_; - }; - - template - struct parser; -} - -#include - -#include - -#include - -#include - -#include - -class options -{ - public: - options (); - - options (int& argc, - char** argv, - bool erase = false, - ::cli::unknown_mode option = ::cli::unknown_mode::fail, - ::cli::unknown_mode argument = ::cli::unknown_mode::stop); - - options (int start, - int& argc, - char** argv, - bool erase = false, - ::cli::unknown_mode option = ::cli::unknown_mode::fail, - ::cli::unknown_mode argument = ::cli::unknown_mode::stop); - - options (int& argc, - char** argv, - int& end, - bool erase = false, - ::cli::unknown_mode option = ::cli::unknown_mode::fail, - ::cli::unknown_mode argument = ::cli::unknown_mode::stop); - - options (int start, - int& argc, - char** argv, - int& end, - bool erase = false, - ::cli::unknown_mode option = ::cli::unknown_mode::fail, - ::cli::unknown_mode argument = ::cli::unknown_mode::stop); - - options (::cli::scanner&, - ::cli::unknown_mode option = ::cli::unknown_mode::fail, - ::cli::unknown_mode argument = ::cli::unknown_mode::stop); - - // Option accessors and modifiers. - // - const bool& - build2_metadata () const; - - bool& - build2_metadata (); - - void - build2_metadata (const bool&); - - const bool& - help () const; - - bool& - help (); - - void - help (const bool&); - - const bool& - version () const; - - bool& - version (); - - void - version (const bool&); - - const std::vector& - include_path () const; - - std::vector& - include_path (); - - void - include_path (const std::vector&); - - bool - include_path_specified () const; - - void - include_path_specified (bool); - - const std::string& - output_dir () const; - - std::string& - output_dir (); - - void - output_dir (const std::string&); - - bool - output_dir_specified () const; - - void - output_dir_specified (bool); - - const cxx_version& - std () const; - - cxx_version& - std (); - - void - std (const cxx_version&); - - bool - std_specified () const; - - void - std_specified (bool); - - const bool& - generate_modifier () const; - - bool& - generate_modifier (); - - void - generate_modifier (const bool&); - - const bool& - generate_specifier () const; - - bool& - generate_specifier (); - - void - generate_specifier (const bool&); - - const bool& - generate_parse () const; - - bool& - generate_parse (); - - void - generate_parse (const bool&); - - const bool& - generate_merge () const; - - bool& - generate_merge (); - - void - generate_merge (const bool&); - - const bool& - generate_description () const; - - bool& - generate_description (); - - void - generate_description (const bool&); - - const bool& - generate_file_scanner () const; - - bool& - generate_file_scanner (); - - void - generate_file_scanner (const bool&); - - const bool& - generate_vector_scanner () const; - - bool& - generate_vector_scanner (); - - void - generate_vector_scanner (const bool&); - - const bool& - generate_group_scanner () const; - - bool& - generate_group_scanner (); - - void - generate_group_scanner (const bool&); - - const bool& - suppress_inline () const; - - bool& - suppress_inline (); - - void - suppress_inline (const bool&); - - const bool& - suppress_cli () const; - - bool& - suppress_cli (); - - void - suppress_cli (const bool&); - - const std::string& - cli_namespace () const; - - std::string& - cli_namespace (); - - void - cli_namespace (const std::string&); - - bool - cli_namespace_specified () const; - - void - cli_namespace_specified (bool); - - const std::string& - ostream_type () const; - - std::string& - ostream_type (); - - void - ostream_type (const std::string&); - - bool - ostream_type_specified () const; - - void - ostream_type_specified (bool); - - const bool& - generate_cxx () const; - - bool& - generate_cxx (); - - void - generate_cxx (const bool&); - - const bool& - generate_man () const; - - bool& - generate_man (); - - void - generate_man (const bool&); - - const bool& - generate_html () const; - - bool& - generate_html (); - - void - generate_html (const bool&); - - const bool& - generate_txt () const; - - bool& - generate_txt (); - - void - generate_txt (const bool&); - - const bool& - stdout_ () const; - - bool& - stdout_ (); - - void - stdout_ (const bool&); - - const bool& - suppress_undocumented () const; - - bool& - suppress_undocumented (); - - void - suppress_undocumented (const bool&); - - const bool& - suppress_usage () const; - - bool& - suppress_usage (); - - void - suppress_usage (const bool&); - - const bool& - long_usage () const; - - bool& - long_usage (); - - void - long_usage (const bool&); - - const bool& - short_usage () const; - - bool& - short_usage (); - - void - short_usage (const bool&); - - const std::string& - page_usage () const; - - std::string& - page_usage (); - - void - page_usage (const std::string&); - - bool - page_usage_specified () const; - - void - page_usage_specified (bool); - - const std::size_t& - option_length () const; - - std::size_t& - option_length (); - - void - option_length (const std::size_t&); - - bool - option_length_specified () const; - - void - option_length_specified (bool); - - const bool& - ansi_color () const; - - bool& - ansi_color (); - - void - ansi_color (const bool&); - - const bool& - exclude_base () const; - - bool& - exclude_base (); - - void - exclude_base (const bool&); - - const bool& - include_base_last () const; - - bool& - include_base_last (); - - void - include_base_last (const bool&); - - const std::map& - class_doc () const; - - std::map& - class_doc (); - - void - class_doc (const std::map&); - - bool - class_doc_specified () const; - - void - class_doc_specified (bool); - - const std::vector& - class_ () const; - - std::vector& - class_ (); - - void - class_ (const std::vector&); - - bool - class__specified () const; - - void - class__specified (bool); - - const std::map& - docvar () const; - - std::map& - docvar (); - - void - docvar (const std::map&); - - bool - docvar_specified () const; - - void - docvar_specified (bool); - - const std::vector& - link_regex () const; - - std::vector& - link_regex (); - - void - link_regex (const std::vector&); - - bool - link_regex_specified () const; - - void - link_regex_specified (bool); - - const bool& - link_regex_trace () const; - - bool& - link_regex_trace (); - - void - link_regex_trace (const bool&); - - const std::map& - html_heading_map () const; - - std::map& - html_heading_map (); - - void - html_heading_map (const std::map&); - - bool - html_heading_map_specified () const; - - void - html_heading_map_specified (bool); - - const bool& - omit_link_check () const; - - bool& - omit_link_check (); - - void - omit_link_check (const bool&); - - const std::vector& - hxx_prologue () const; - - std::vector& - hxx_prologue (); - - void - hxx_prologue (const std::vector&); - - bool - hxx_prologue_specified () const; - - void - hxx_prologue_specified (bool); - - const std::vector& - ixx_prologue () const; - - std::vector& - ixx_prologue (); - - void - ixx_prologue (const std::vector&); - - bool - ixx_prologue_specified () const; - - void - ixx_prologue_specified (bool); - - const std::vector& - cxx_prologue () const; - - std::vector& - cxx_prologue (); - - void - cxx_prologue (const std::vector&); - - bool - cxx_prologue_specified () const; - - void - cxx_prologue_specified (bool); - - const std::vector& - man_prologue () const; - - std::vector& - man_prologue (); - - void - man_prologue (const std::vector&); - - bool - man_prologue_specified () const; - - void - man_prologue_specified (bool); - - const std::vector& - html_prologue () const; - - std::vector& - html_prologue (); - - void - html_prologue (const std::vector&); - - bool - html_prologue_specified () const; - - void - html_prologue_specified (bool); - - const std::vector& - txt_prologue () const; - - std::vector& - txt_prologue (); - - void - txt_prologue (const std::vector&); - - bool - txt_prologue_specified () const; - - void - txt_prologue_specified (bool); - - const std::vector& - hxx_epilogue () const; - - std::vector& - hxx_epilogue (); - - void - hxx_epilogue (const std::vector&); - - bool - hxx_epilogue_specified () const; - - void - hxx_epilogue_specified (bool); - - const std::vector& - ixx_epilogue () const; - - std::vector& - ixx_epilogue (); - - void - ixx_epilogue (const std::vector&); - - bool - ixx_epilogue_specified () const; - - void - ixx_epilogue_specified (bool); - - const std::vector& - cxx_epilogue () const; - - std::vector& - cxx_epilogue (); - - void - cxx_epilogue (const std::vector&); - - bool - cxx_epilogue_specified () const; - - void - cxx_epilogue_specified (bool); - - const std::vector& - man_epilogue () const; - - std::vector& - man_epilogue (); - - void - man_epilogue (const std::vector&); - - bool - man_epilogue_specified () const; - - void - man_epilogue_specified (bool); - - const std::vector& - html_epilogue () const; - - std::vector& - html_epilogue (); - - void - html_epilogue (const std::vector&); - - bool - html_epilogue_specified () const; - - void - html_epilogue_specified (bool); - - const std::vector& - txt_epilogue () const; - - std::vector& - txt_epilogue (); - - void - txt_epilogue (const std::vector&); - - bool - txt_epilogue_specified () const; - - void - txt_epilogue_specified (bool); - - const std::string& - hxx_prologue_file () const; - - std::string& - hxx_prologue_file (); - - void - hxx_prologue_file (const std::string&); - - bool - hxx_prologue_file_specified () const; - - void - hxx_prologue_file_specified (bool); - - const std::string& - ixx_prologue_file () const; - - std::string& - ixx_prologue_file (); - - void - ixx_prologue_file (const std::string&); - - bool - ixx_prologue_file_specified () const; - - void - ixx_prologue_file_specified (bool); - - const std::string& - cxx_prologue_file () const; - - std::string& - cxx_prologue_file (); - - void - cxx_prologue_file (const std::string&); - - bool - cxx_prologue_file_specified () const; - - void - cxx_prologue_file_specified (bool); - - const std::string& - man_prologue_file () const; - - std::string& - man_prologue_file (); - - void - man_prologue_file (const std::string&); - - bool - man_prologue_file_specified () const; - - void - man_prologue_file_specified (bool); - - const std::string& - html_prologue_file () const; - - std::string& - html_prologue_file (); - - void - html_prologue_file (const std::string&); - - bool - html_prologue_file_specified () const; - - void - html_prologue_file_specified (bool); - - const std::string& - txt_prologue_file () const; - - std::string& - txt_prologue_file (); - - void - txt_prologue_file (const std::string&); - - bool - txt_prologue_file_specified () const; - - void - txt_prologue_file_specified (bool); - - const std::string& - hxx_epilogue_file () const; - - std::string& - hxx_epilogue_file (); - - void - hxx_epilogue_file (const std::string&); - - bool - hxx_epilogue_file_specified () const; - - void - hxx_epilogue_file_specified (bool); - - const std::string& - ixx_epilogue_file () const; - - std::string& - ixx_epilogue_file (); - - void - ixx_epilogue_file (const std::string&); - - bool - ixx_epilogue_file_specified () const; - - void - ixx_epilogue_file_specified (bool); - - const std::string& - cxx_epilogue_file () const; - - std::string& - cxx_epilogue_file (); - - void - cxx_epilogue_file (const std::string&); - - bool - cxx_epilogue_file_specified () const; - - void - cxx_epilogue_file_specified (bool); - - const std::string& - man_epilogue_file () const; - - std::string& - man_epilogue_file (); - - void - man_epilogue_file (const std::string&); - - bool - man_epilogue_file_specified () const; - - void - man_epilogue_file_specified (bool); - - const std::string& - html_epilogue_file () const; - - std::string& - html_epilogue_file (); - - void - html_epilogue_file (const std::string&); - - bool - html_epilogue_file_specified () const; - - void - html_epilogue_file_specified (bool); - - const std::string& - txt_epilogue_file () const; - - std::string& - txt_epilogue_file (); - - void - txt_epilogue_file (const std::string&); - - bool - txt_epilogue_file_specified () const; - - void - txt_epilogue_file_specified (bool); - - const std::string& - output_prefix () const; - - std::string& - output_prefix (); - - void - output_prefix (const std::string&); - - bool - output_prefix_specified () const; - - void - output_prefix_specified (bool); - - const std::string& - output_suffix () const; - - std::string& - output_suffix (); - - void - output_suffix (const std::string&); - - bool - output_suffix_specified () const; - - void - output_suffix_specified (bool); - - const std::string& - hxx_suffix () const; - - std::string& - hxx_suffix (); - - void - hxx_suffix (const std::string&); - - bool - hxx_suffix_specified () const; - - void - hxx_suffix_specified (bool); - - const std::string& - ixx_suffix () const; - - std::string& - ixx_suffix (); - - void - ixx_suffix (const std::string&); - - bool - ixx_suffix_specified () const; - - void - ixx_suffix_specified (bool); - - const std::string& - cxx_suffix () const; - - std::string& - cxx_suffix (); - - void - cxx_suffix (const std::string&); - - bool - cxx_suffix_specified () const; - - void - cxx_suffix_specified (bool); - - const std::string& - man_suffix () const; - - std::string& - man_suffix (); - - void - man_suffix (const std::string&); - - bool - man_suffix_specified () const; - - void - man_suffix_specified (bool); - - const std::string& - html_suffix () const; - - std::string& - html_suffix (); - - void - html_suffix (const std::string&); - - bool - html_suffix_specified () const; - - void - html_suffix_specified (bool); - - const std::string& - txt_suffix () const; - - std::string& - txt_suffix (); - - void - txt_suffix (const std::string&); - - bool - txt_suffix_specified () const; - - void - txt_suffix_specified (bool); - - const std::string& - option_prefix () const; - - std::string& - option_prefix (); - - void - option_prefix (const std::string&); - - bool - option_prefix_specified () const; - - void - option_prefix_specified (bool); - - const std::string& - option_separator () const; - - std::string& - option_separator (); - - void - option_separator (const std::string&); - - bool - option_separator_specified () const; - - void - option_separator_specified (bool); - - const bool& - keep_separator () const; - - bool& - keep_separator (); - - void - keep_separator (const bool&); - - const bool& - no_combined_flags () const; - - bool& - no_combined_flags (); - - void - no_combined_flags (const bool&); - - const bool& - no_combined_values () const; - - bool& - no_combined_values (); - - void - no_combined_values (const bool&); - - const bool& - include_with_brackets () const; - - bool& - include_with_brackets (); - - void - include_with_brackets (const bool&); - - const std::string& - include_prefix () const; - - std::string& - include_prefix (); - - void - include_prefix (const std::string&); - - bool - include_prefix_specified () const; - - void - include_prefix_specified (bool); - - const std::string& - guard_prefix () const; - - std::string& - guard_prefix (); - - void - guard_prefix (const std::string&); - - bool - guard_prefix_specified () const; - - void - guard_prefix_specified (bool); - - const std::map& - reserved_name () const; - - std::map& - reserved_name (); - - void - reserved_name (const std::map&); - - bool - reserved_name_specified () const; - - void - reserved_name_specified (bool); - - const std::string& - options_file () const; - - std::string& - options_file (); - - void - options_file (const std::string&); - - bool - options_file_specified () const; - - void - options_file_specified (bool); - - // Print usage information. - // - static ::cli::usage_para - print_usage (::std::ostream&, - ::cli::usage_para = ::cli::usage_para::none); - - // Implementation details. - // - protected: - bool - _parse (const char*, ::cli::scanner&); - - private: - bool - _parse (::cli::scanner&, - ::cli::unknown_mode option, - ::cli::unknown_mode argument); - - public: - bool build2_metadata_; - bool help_; - bool version_; - std::vector include_path_; - bool include_path_specified_; - std::string output_dir_; - bool output_dir_specified_; - cxx_version std_; - bool std_specified_; - bool generate_modifier_; - bool generate_specifier_; - bool generate_parse_; - bool generate_merge_; - bool generate_description_; - bool generate_file_scanner_; - bool generate_vector_scanner_; - bool generate_group_scanner_; - bool suppress_inline_; - bool suppress_cli_; - std::string cli_namespace_; - bool cli_namespace_specified_; - std::string ostream_type_; - bool ostream_type_specified_; - bool generate_cxx_; - bool generate_man_; - bool generate_html_; - bool generate_txt_; - bool stdout__; - bool suppress_undocumented_; - bool suppress_usage_; - bool long_usage_; - bool short_usage_; - std::string page_usage_; - bool page_usage_specified_; - std::size_t option_length_; - bool option_length_specified_; - bool ansi_color_; - bool exclude_base_; - bool include_base_last_; - std::map class_doc_; - bool class_doc_specified_; - std::vector class__; - bool class__specified_; - std::map docvar_; - bool docvar_specified_; - std::vector link_regex_; - bool link_regex_specified_; - bool link_regex_trace_; - std::map html_heading_map_; - bool html_heading_map_specified_; - bool omit_link_check_; - std::vector hxx_prologue_; - bool hxx_prologue_specified_; - std::vector ixx_prologue_; - bool ixx_prologue_specified_; - std::vector cxx_prologue_; - bool cxx_prologue_specified_; - std::vector man_prologue_; - bool man_prologue_specified_; - std::vector html_prologue_; - bool html_prologue_specified_; - std::vector txt_prologue_; - bool txt_prologue_specified_; - std::vector hxx_epilogue_; - bool hxx_epilogue_specified_; - std::vector ixx_epilogue_; - bool ixx_epilogue_specified_; - std::vector cxx_epilogue_; - bool cxx_epilogue_specified_; - std::vector man_epilogue_; - bool man_epilogue_specified_; - std::vector html_epilogue_; - bool html_epilogue_specified_; - std::vector txt_epilogue_; - bool txt_epilogue_specified_; - std::string hxx_prologue_file_; - bool hxx_prologue_file_specified_; - std::string ixx_prologue_file_; - bool ixx_prologue_file_specified_; - std::string cxx_prologue_file_; - bool cxx_prologue_file_specified_; - std::string man_prologue_file_; - bool man_prologue_file_specified_; - std::string html_prologue_file_; - bool html_prologue_file_specified_; - std::string txt_prologue_file_; - bool txt_prologue_file_specified_; - std::string hxx_epilogue_file_; - bool hxx_epilogue_file_specified_; - std::string ixx_epilogue_file_; - bool ixx_epilogue_file_specified_; - std::string cxx_epilogue_file_; - bool cxx_epilogue_file_specified_; - std::string man_epilogue_file_; - bool man_epilogue_file_specified_; - std::string html_epilogue_file_; - bool html_epilogue_file_specified_; - std::string txt_epilogue_file_; - bool txt_epilogue_file_specified_; - std::string output_prefix_; - bool output_prefix_specified_; - std::string output_suffix_; - bool output_suffix_specified_; - std::string hxx_suffix_; - bool hxx_suffix_specified_; - std::string ixx_suffix_; - bool ixx_suffix_specified_; - std::string cxx_suffix_; - bool cxx_suffix_specified_; - std::string man_suffix_; - bool man_suffix_specified_; - std::string html_suffix_; - bool html_suffix_specified_; - std::string txt_suffix_; - bool txt_suffix_specified_; - std::string option_prefix_; - bool option_prefix_specified_; - std::string option_separator_; - bool option_separator_specified_; - bool keep_separator_; - bool no_combined_flags_; - bool no_combined_values_; - bool include_with_brackets_; - std::string include_prefix_; - bool include_prefix_specified_; - std::string guard_prefix_; - bool guard_prefix_specified_; - std::map reserved_name_; - bool reserved_name_specified_; - std::string options_file_; - bool options_file_specified_; -}; - -#include - -// Begin epilogue. -// -// -// End epilogue. - -#endif // CLI_OPTIONS_HXX diff --git a/cli/options.ixx b/cli/options.ixx deleted file mode 100644 index 12d40db..0000000 --- a/cli/options.ixx +++ /dev/null @@ -1,2319 +0,0 @@ -// -*- C++ -*- -// -// This file was generated by CLI, a command line interface -// compiler for C++. -// - -// Begin prologue. -// -// -// End prologue. - -#include - -namespace cli -{ - // usage_para - // - inline usage_para:: - usage_para (value v) - : v_ (v) - { - } - - // unknown_mode - // - inline unknown_mode:: - unknown_mode (value v) - : v_ (v) - { - } - - // exception - // - inline ::std::ostream& - operator<< (::std::ostream& os, const exception& e) - { - e.print (os); - return os; - } - - // unknown_option - // - inline unknown_option:: - unknown_option (const std::string& option) - : option_ (option) - { - } - - inline const std::string& unknown_option:: - option () const - { - return option_; - } - - // unknown_argument - // - inline unknown_argument:: - unknown_argument (const std::string& argument) - : argument_ (argument) - { - } - - inline const std::string& unknown_argument:: - argument () const - { - return argument_; - } - - // missing_value - // - inline missing_value:: - missing_value (const std::string& option) - : option_ (option) - { - } - - inline const std::string& missing_value:: - option () const - { - return option_; - } - - // invalid_value - // - inline invalid_value:: - invalid_value (const std::string& option, - const std::string& value, - const std::string& message) - : option_ (option), - value_ (value), - message_ (message) - { - } - - inline const std::string& invalid_value:: - option () const - { - return option_; - } - - inline const std::string& invalid_value:: - value () const - { - return value_; - } - - inline const std::string& invalid_value:: - message () const - { - return message_; - } - - // file_io_failure - // - inline file_io_failure:: - file_io_failure (const std::string& file) - : file_ (file) - { - } - - inline const std::string& file_io_failure:: - file () const - { - return file_; - } - - // unmatched_quote - // - inline unmatched_quote:: - unmatched_quote (const std::string& argument) - : argument_ (argument) - { - } - - inline const std::string& unmatched_quote:: - argument () const - { - return argument_; - } - - // argv_scanner - // - inline argv_scanner:: - argv_scanner (int& argc, char** argv, bool erase) - : i_ (1), argc_ (argc), argv_ (argv), erase_ (erase) - { - } - - inline argv_scanner:: - argv_scanner (int start, int& argc, char** argv, bool erase) - : i_ (start), argc_ (argc), argv_ (argv), erase_ (erase) - { - } - - inline int argv_scanner:: - end () const - { - return i_; - } - - // argv_file_scanner - // - inline argv_file_scanner:: - argv_file_scanner (int& argc, - char** argv, - const std::string& option, - bool erase) - : argv_scanner (argc, argv, erase), - option_ (option), - options_ (&option_info_), - options_count_ (1), - i_ (1), - skip_ (false) - { - option_info_.option = option_.c_str (); - option_info_.search_func = 0; - } - - inline argv_file_scanner:: - argv_file_scanner (int start, - int& argc, - char** argv, - const std::string& option, - bool erase) - : argv_scanner (start, argc, argv, erase), - option_ (option), - options_ (&option_info_), - options_count_ (1), - i_ (1), - skip_ (false) - { - option_info_.option = option_.c_str (); - option_info_.search_func = 0; - } - - inline argv_file_scanner:: - argv_file_scanner (const std::string& file, - const std::string& option) - : argv_scanner (0, zero_argc_, 0), - option_ (option), - options_ (&option_info_), - options_count_ (1), - i_ (1), - skip_ (false) - { - option_info_.option = option_.c_str (); - option_info_.search_func = 0; - - load (file); - } - - inline argv_file_scanner:: - argv_file_scanner (int& argc, - char** argv, - const option_info* options, - std::size_t options_count, - bool erase) - : argv_scanner (argc, argv, erase), - options_ (options), - options_count_ (options_count), - i_ (1), - skip_ (false) - { - } - - inline argv_file_scanner:: - argv_file_scanner (int start, - int& argc, - char** argv, - const option_info* options, - std::size_t options_count, - bool erase) - : argv_scanner (start, argc, argv, erase), - options_ (options), - options_count_ (options_count), - i_ (1), - skip_ (false) - { - } - - inline argv_file_scanner:: - argv_file_scanner (const std::string& file, - const option_info* options, - std::size_t options_count) - : argv_scanner (0, zero_argc_, 0), - options_ (options), - options_count_ (options_count), - i_ (1), - skip_ (false) - { - load (file); - } -} - -// options -// - -inline const bool& options:: -build2_metadata () const -{ - return this->build2_metadata_; -} - -inline bool& options:: -build2_metadata () -{ - return this->build2_metadata_; -} - -inline void options:: -build2_metadata(const bool& x) -{ - this->build2_metadata_ = x; -} - -inline const bool& options:: -help () const -{ - return this->help_; -} - -inline bool& options:: -help () -{ - return this->help_; -} - -inline void options:: -help(const bool& x) -{ - this->help_ = x; -} - -inline const bool& options:: -version () const -{ - return this->version_; -} - -inline bool& options:: -version () -{ - return this->version_; -} - -inline void options:: -version(const bool& x) -{ - this->version_ = x; -} - -inline const std::vector& options:: -include_path () const -{ - return this->include_path_; -} - -inline std::vector& options:: -include_path () -{ - return this->include_path_; -} - -inline void options:: -include_path(const std::vector& x) -{ - this->include_path_ = x; -} - -inline bool options:: -include_path_specified () const -{ - return this->include_path_specified_; -} - -inline void options:: -include_path_specified(bool x) -{ - this->include_path_specified_ = x; -} - -inline const std::string& options:: -output_dir () const -{ - return this->output_dir_; -} - -inline std::string& options:: -output_dir () -{ - return this->output_dir_; -} - -inline void options:: -output_dir(const std::string& x) -{ - this->output_dir_ = x; -} - -inline bool options:: -output_dir_specified () const -{ - return this->output_dir_specified_; -} - -inline void options:: -output_dir_specified(bool x) -{ - this->output_dir_specified_ = x; -} - -inline const cxx_version& options:: -std () const -{ - return this->std_; -} - -inline cxx_version& options:: -std () -{ - return this->std_; -} - -inline void options:: -std(const cxx_version& x) -{ - this->std_ = x; -} - -inline bool options:: -std_specified () const -{ - return this->std_specified_; -} - -inline void options:: -std_specified(bool x) -{ - this->std_specified_ = x; -} - -inline const bool& options:: -generate_modifier () const -{ - return this->generate_modifier_; -} - -inline bool& options:: -generate_modifier () -{ - return this->generate_modifier_; -} - -inline void options:: -generate_modifier(const bool& x) -{ - this->generate_modifier_ = x; -} - -inline const bool& options:: -generate_specifier () const -{ - return this->generate_specifier_; -} - -inline bool& options:: -generate_specifier () -{ - return this->generate_specifier_; -} - -inline void options:: -generate_specifier(const bool& x) -{ - this->generate_specifier_ = x; -} - -inline const bool& options:: -generate_parse () const -{ - return this->generate_parse_; -} - -inline bool& options:: -generate_parse () -{ - return this->generate_parse_; -} - -inline void options:: -generate_parse(const bool& x) -{ - this->generate_parse_ = x; -} - -inline const bool& options:: -generate_merge () const -{ - return this->generate_merge_; -} - -inline bool& options:: -generate_merge () -{ - return this->generate_merge_; -} - -inline void options:: -generate_merge(const bool& x) -{ - this->generate_merge_ = x; -} - -inline const bool& options:: -generate_description () const -{ - return this->generate_description_; -} - -inline bool& options:: -generate_description () -{ - return this->generate_description_; -} - -inline void options:: -generate_description(const bool& x) -{ - this->generate_description_ = x; -} - -inline const bool& options:: -generate_file_scanner () const -{ - return this->generate_file_scanner_; -} - -inline bool& options:: -generate_file_scanner () -{ - return this->generate_file_scanner_; -} - -inline void options:: -generate_file_scanner(const bool& x) -{ - this->generate_file_scanner_ = x; -} - -inline const bool& options:: -generate_vector_scanner () const -{ - return this->generate_vector_scanner_; -} - -inline bool& options:: -generate_vector_scanner () -{ - return this->generate_vector_scanner_; -} - -inline void options:: -generate_vector_scanner(const bool& x) -{ - this->generate_vector_scanner_ = x; -} - -inline const bool& options:: -generate_group_scanner () const -{ - return this->generate_group_scanner_; -} - -inline bool& options:: -generate_group_scanner () -{ - return this->generate_group_scanner_; -} - -inline void options:: -generate_group_scanner(const bool& x) -{ - this->generate_group_scanner_ = x; -} - -inline const bool& options:: -suppress_inline () const -{ - return this->suppress_inline_; -} - -inline bool& options:: -suppress_inline () -{ - return this->suppress_inline_; -} - -inline void options:: -suppress_inline(const bool& x) -{ - this->suppress_inline_ = x; -} - -inline const bool& options:: -suppress_cli () const -{ - return this->suppress_cli_; -} - -inline bool& options:: -suppress_cli () -{ - return this->suppress_cli_; -} - -inline void options:: -suppress_cli(const bool& x) -{ - this->suppress_cli_ = x; -} - -inline const std::string& options:: -cli_namespace () const -{ - return this->cli_namespace_; -} - -inline std::string& options:: -cli_namespace () -{ - return this->cli_namespace_; -} - -inline void options:: -cli_namespace(const std::string& x) -{ - this->cli_namespace_ = x; -} - -inline bool options:: -cli_namespace_specified () const -{ - return this->cli_namespace_specified_; -} - -inline void options:: -cli_namespace_specified(bool x) -{ - this->cli_namespace_specified_ = x; -} - -inline const std::string& options:: -ostream_type () const -{ - return this->ostream_type_; -} - -inline std::string& options:: -ostream_type () -{ - return this->ostream_type_; -} - -inline void options:: -ostream_type(const std::string& x) -{ - this->ostream_type_ = x; -} - -inline bool options:: -ostream_type_specified () const -{ - return this->ostream_type_specified_; -} - -inline void options:: -ostream_type_specified(bool x) -{ - this->ostream_type_specified_ = x; -} - -inline const bool& options:: -generate_cxx () const -{ - return this->generate_cxx_; -} - -inline bool& options:: -generate_cxx () -{ - return this->generate_cxx_; -} - -inline void options:: -generate_cxx(const bool& x) -{ - this->generate_cxx_ = x; -} - -inline const bool& options:: -generate_man () const -{ - return this->generate_man_; -} - -inline bool& options:: -generate_man () -{ - return this->generate_man_; -} - -inline void options:: -generate_man(const bool& x) -{ - this->generate_man_ = x; -} - -inline const bool& options:: -generate_html () const -{ - return this->generate_html_; -} - -inline bool& options:: -generate_html () -{ - return this->generate_html_; -} - -inline void options:: -generate_html(const bool& x) -{ - this->generate_html_ = x; -} - -inline const bool& options:: -generate_txt () const -{ - return this->generate_txt_; -} - -inline bool& options:: -generate_txt () -{ - return this->generate_txt_; -} - -inline void options:: -generate_txt(const bool& x) -{ - this->generate_txt_ = x; -} - -inline const bool& options:: -stdout_ () const -{ - return this->stdout__; -} - -inline bool& options:: -stdout_ () -{ - return this->stdout__; -} - -inline void options:: -stdout_(const bool& x) -{ - this->stdout__ = x; -} - -inline const bool& options:: -suppress_undocumented () const -{ - return this->suppress_undocumented_; -} - -inline bool& options:: -suppress_undocumented () -{ - return this->suppress_undocumented_; -} - -inline void options:: -suppress_undocumented(const bool& x) -{ - this->suppress_undocumented_ = x; -} - -inline const bool& options:: -suppress_usage () const -{ - return this->suppress_usage_; -} - -inline bool& options:: -suppress_usage () -{ - return this->suppress_usage_; -} - -inline void options:: -suppress_usage(const bool& x) -{ - this->suppress_usage_ = x; -} - -inline const bool& options:: -long_usage () const -{ - return this->long_usage_; -} - -inline bool& options:: -long_usage () -{ - return this->long_usage_; -} - -inline void options:: -long_usage(const bool& x) -{ - this->long_usage_ = x; -} - -inline const bool& options:: -short_usage () const -{ - return this->short_usage_; -} - -inline bool& options:: -short_usage () -{ - return this->short_usage_; -} - -inline void options:: -short_usage(const bool& x) -{ - this->short_usage_ = x; -} - -inline const std::string& options:: -page_usage () const -{ - return this->page_usage_; -} - -inline std::string& options:: -page_usage () -{ - return this->page_usage_; -} - -inline void options:: -page_usage(const std::string& x) -{ - this->page_usage_ = x; -} - -inline bool options:: -page_usage_specified () const -{ - return this->page_usage_specified_; -} - -inline void options:: -page_usage_specified(bool x) -{ - this->page_usage_specified_ = x; -} - -inline const std::size_t& options:: -option_length () const -{ - return this->option_length_; -} - -inline std::size_t& options:: -option_length () -{ - return this->option_length_; -} - -inline void options:: -option_length(const std::size_t& x) -{ - this->option_length_ = x; -} - -inline bool options:: -option_length_specified () const -{ - return this->option_length_specified_; -} - -inline void options:: -option_length_specified(bool x) -{ - this->option_length_specified_ = x; -} - -inline const bool& options:: -ansi_color () const -{ - return this->ansi_color_; -} - -inline bool& options:: -ansi_color () -{ - return this->ansi_color_; -} - -inline void options:: -ansi_color(const bool& x) -{ - this->ansi_color_ = x; -} - -inline const bool& options:: -exclude_base () const -{ - return this->exclude_base_; -} - -inline bool& options:: -exclude_base () -{ - return this->exclude_base_; -} - -inline void options:: -exclude_base(const bool& x) -{ - this->exclude_base_ = x; -} - -inline const bool& options:: -include_base_last () const -{ - return this->include_base_last_; -} - -inline bool& options:: -include_base_last () -{ - return this->include_base_last_; -} - -inline void options:: -include_base_last(const bool& x) -{ - this->include_base_last_ = x; -} - -inline const std::map& options:: -class_doc () const -{ - return this->class_doc_; -} - -inline std::map& options:: -class_doc () -{ - return this->class_doc_; -} - -inline void options:: -class_doc(const std::map& x) -{ - this->class_doc_ = x; -} - -inline bool options:: -class_doc_specified () const -{ - return this->class_doc_specified_; -} - -inline void options:: -class_doc_specified(bool x) -{ - this->class_doc_specified_ = x; -} - -inline const std::vector& options:: -class_ () const -{ - return this->class__; -} - -inline std::vector& options:: -class_ () -{ - return this->class__; -} - -inline void options:: -class_(const std::vector& x) -{ - this->class__ = x; -} - -inline bool options:: -class__specified () const -{ - return this->class__specified_; -} - -inline void options:: -class__specified(bool x) -{ - this->class__specified_ = x; -} - -inline const std::map& options:: -docvar () const -{ - return this->docvar_; -} - -inline std::map& options:: -docvar () -{ - return this->docvar_; -} - -inline void options:: -docvar(const std::map& x) -{ - this->docvar_ = x; -} - -inline bool options:: -docvar_specified () const -{ - return this->docvar_specified_; -} - -inline void options:: -docvar_specified(bool x) -{ - this->docvar_specified_ = x; -} - -inline const std::vector& options:: -link_regex () const -{ - return this->link_regex_; -} - -inline std::vector& options:: -link_regex () -{ - return this->link_regex_; -} - -inline void options:: -link_regex(const std::vector& x) -{ - this->link_regex_ = x; -} - -inline bool options:: -link_regex_specified () const -{ - return this->link_regex_specified_; -} - -inline void options:: -link_regex_specified(bool x) -{ - this->link_regex_specified_ = x; -} - -inline const bool& options:: -link_regex_trace () const -{ - return this->link_regex_trace_; -} - -inline bool& options:: -link_regex_trace () -{ - return this->link_regex_trace_; -} - -inline void options:: -link_regex_trace(const bool& x) -{ - this->link_regex_trace_ = x; -} - -inline const std::map& options:: -html_heading_map () const -{ - return this->html_heading_map_; -} - -inline std::map& options:: -html_heading_map () -{ - return this->html_heading_map_; -} - -inline void options:: -html_heading_map(const std::map& x) -{ - this->html_heading_map_ = x; -} - -inline bool options:: -html_heading_map_specified () const -{ - return this->html_heading_map_specified_; -} - -inline void options:: -html_heading_map_specified(bool x) -{ - this->html_heading_map_specified_ = x; -} - -inline const bool& options:: -omit_link_check () const -{ - return this->omit_link_check_; -} - -inline bool& options:: -omit_link_check () -{ - return this->omit_link_check_; -} - -inline void options:: -omit_link_check(const bool& x) -{ - this->omit_link_check_ = x; -} - -inline const std::vector& options:: -hxx_prologue () const -{ - return this->hxx_prologue_; -} - -inline std::vector& options:: -hxx_prologue () -{ - return this->hxx_prologue_; -} - -inline void options:: -hxx_prologue(const std::vector& x) -{ - this->hxx_prologue_ = x; -} - -inline bool options:: -hxx_prologue_specified () const -{ - return this->hxx_prologue_specified_; -} - -inline void options:: -hxx_prologue_specified(bool x) -{ - this->hxx_prologue_specified_ = x; -} - -inline const std::vector& options:: -ixx_prologue () const -{ - return this->ixx_prologue_; -} - -inline std::vector& options:: -ixx_prologue () -{ - return this->ixx_prologue_; -} - -inline void options:: -ixx_prologue(const std::vector& x) -{ - this->ixx_prologue_ = x; -} - -inline bool options:: -ixx_prologue_specified () const -{ - return this->ixx_prologue_specified_; -} - -inline void options:: -ixx_prologue_specified(bool x) -{ - this->ixx_prologue_specified_ = x; -} - -inline const std::vector& options:: -cxx_prologue () const -{ - return this->cxx_prologue_; -} - -inline std::vector& options:: -cxx_prologue () -{ - return this->cxx_prologue_; -} - -inline void options:: -cxx_prologue(const std::vector& x) -{ - this->cxx_prologue_ = x; -} - -inline bool options:: -cxx_prologue_specified () const -{ - return this->cxx_prologue_specified_; -} - -inline void options:: -cxx_prologue_specified(bool x) -{ - this->cxx_prologue_specified_ = x; -} - -inline const std::vector& options:: -man_prologue () const -{ - return this->man_prologue_; -} - -inline std::vector& options:: -man_prologue () -{ - return this->man_prologue_; -} - -inline void options:: -man_prologue(const std::vector& x) -{ - this->man_prologue_ = x; -} - -inline bool options:: -man_prologue_specified () const -{ - return this->man_prologue_specified_; -} - -inline void options:: -man_prologue_specified(bool x) -{ - this->man_prologue_specified_ = x; -} - -inline const std::vector& options:: -html_prologue () const -{ - return this->html_prologue_; -} - -inline std::vector& options:: -html_prologue () -{ - return this->html_prologue_; -} - -inline void options:: -html_prologue(const std::vector& x) -{ - this->html_prologue_ = x; -} - -inline bool options:: -html_prologue_specified () const -{ - return this->html_prologue_specified_; -} - -inline void options:: -html_prologue_specified(bool x) -{ - this->html_prologue_specified_ = x; -} - -inline const std::vector& options:: -txt_prologue () const -{ - return this->txt_prologue_; -} - -inline std::vector& options:: -txt_prologue () -{ - return this->txt_prologue_; -} - -inline void options:: -txt_prologue(const std::vector& x) -{ - this->txt_prologue_ = x; -} - -inline bool options:: -txt_prologue_specified () const -{ - return this->txt_prologue_specified_; -} - -inline void options:: -txt_prologue_specified(bool x) -{ - this->txt_prologue_specified_ = x; -} - -inline const std::vector& options:: -hxx_epilogue () const -{ - return this->hxx_epilogue_; -} - -inline std::vector& options:: -hxx_epilogue () -{ - return this->hxx_epilogue_; -} - -inline void options:: -hxx_epilogue(const std::vector& x) -{ - this->hxx_epilogue_ = x; -} - -inline bool options:: -hxx_epilogue_specified () const -{ - return this->hxx_epilogue_specified_; -} - -inline void options:: -hxx_epilogue_specified(bool x) -{ - this->hxx_epilogue_specified_ = x; -} - -inline const std::vector& options:: -ixx_epilogue () const -{ - return this->ixx_epilogue_; -} - -inline std::vector& options:: -ixx_epilogue () -{ - return this->ixx_epilogue_; -} - -inline void options:: -ixx_epilogue(const std::vector& x) -{ - this->ixx_epilogue_ = x; -} - -inline bool options:: -ixx_epilogue_specified () const -{ - return this->ixx_epilogue_specified_; -} - -inline void options:: -ixx_epilogue_specified(bool x) -{ - this->ixx_epilogue_specified_ = x; -} - -inline const std::vector& options:: -cxx_epilogue () const -{ - return this->cxx_epilogue_; -} - -inline std::vector& options:: -cxx_epilogue () -{ - return this->cxx_epilogue_; -} - -inline void options:: -cxx_epilogue(const std::vector& x) -{ - this->cxx_epilogue_ = x; -} - -inline bool options:: -cxx_epilogue_specified () const -{ - return this->cxx_epilogue_specified_; -} - -inline void options:: -cxx_epilogue_specified(bool x) -{ - this->cxx_epilogue_specified_ = x; -} - -inline const std::vector& options:: -man_epilogue () const -{ - return this->man_epilogue_; -} - -inline std::vector& options:: -man_epilogue () -{ - return this->man_epilogue_; -} - -inline void options:: -man_epilogue(const std::vector& x) -{ - this->man_epilogue_ = x; -} - -inline bool options:: -man_epilogue_specified () const -{ - return this->man_epilogue_specified_; -} - -inline void options:: -man_epilogue_specified(bool x) -{ - this->man_epilogue_specified_ = x; -} - -inline const std::vector& options:: -html_epilogue () const -{ - return this->html_epilogue_; -} - -inline std::vector& options:: -html_epilogue () -{ - return this->html_epilogue_; -} - -inline void options:: -html_epilogue(const std::vector& x) -{ - this->html_epilogue_ = x; -} - -inline bool options:: -html_epilogue_specified () const -{ - return this->html_epilogue_specified_; -} - -inline void options:: -html_epilogue_specified(bool x) -{ - this->html_epilogue_specified_ = x; -} - -inline const std::vector& options:: -txt_epilogue () const -{ - return this->txt_epilogue_; -} - -inline std::vector& options:: -txt_epilogue () -{ - return this->txt_epilogue_; -} - -inline void options:: -txt_epilogue(const std::vector& x) -{ - this->txt_epilogue_ = x; -} - -inline bool options:: -txt_epilogue_specified () const -{ - return this->txt_epilogue_specified_; -} - -inline void options:: -txt_epilogue_specified(bool x) -{ - this->txt_epilogue_specified_ = x; -} - -inline const std::string& options:: -hxx_prologue_file () const -{ - return this->hxx_prologue_file_; -} - -inline std::string& options:: -hxx_prologue_file () -{ - return this->hxx_prologue_file_; -} - -inline void options:: -hxx_prologue_file(const std::string& x) -{ - this->hxx_prologue_file_ = x; -} - -inline bool options:: -hxx_prologue_file_specified () const -{ - return this->hxx_prologue_file_specified_; -} - -inline void options:: -hxx_prologue_file_specified(bool x) -{ - this->hxx_prologue_file_specified_ = x; -} - -inline const std::string& options:: -ixx_prologue_file () const -{ - return this->ixx_prologue_file_; -} - -inline std::string& options:: -ixx_prologue_file () -{ - return this->ixx_prologue_file_; -} - -inline void options:: -ixx_prologue_file(const std::string& x) -{ - this->ixx_prologue_file_ = x; -} - -inline bool options:: -ixx_prologue_file_specified () const -{ - return this->ixx_prologue_file_specified_; -} - -inline void options:: -ixx_prologue_file_specified(bool x) -{ - this->ixx_prologue_file_specified_ = x; -} - -inline const std::string& options:: -cxx_prologue_file () const -{ - return this->cxx_prologue_file_; -} - -inline std::string& options:: -cxx_prologue_file () -{ - return this->cxx_prologue_file_; -} - -inline void options:: -cxx_prologue_file(const std::string& x) -{ - this->cxx_prologue_file_ = x; -} - -inline bool options:: -cxx_prologue_file_specified () const -{ - return this->cxx_prologue_file_specified_; -} - -inline void options:: -cxx_prologue_file_specified(bool x) -{ - this->cxx_prologue_file_specified_ = x; -} - -inline const std::string& options:: -man_prologue_file () const -{ - return this->man_prologue_file_; -} - -inline std::string& options:: -man_prologue_file () -{ - return this->man_prologue_file_; -} - -inline void options:: -man_prologue_file(const std::string& x) -{ - this->man_prologue_file_ = x; -} - -inline bool options:: -man_prologue_file_specified () const -{ - return this->man_prologue_file_specified_; -} - -inline void options:: -man_prologue_file_specified(bool x) -{ - this->man_prologue_file_specified_ = x; -} - -inline const std::string& options:: -html_prologue_file () const -{ - return this->html_prologue_file_; -} - -inline std::string& options:: -html_prologue_file () -{ - return this->html_prologue_file_; -} - -inline void options:: -html_prologue_file(const std::string& x) -{ - this->html_prologue_file_ = x; -} - -inline bool options:: -html_prologue_file_specified () const -{ - return this->html_prologue_file_specified_; -} - -inline void options:: -html_prologue_file_specified(bool x) -{ - this->html_prologue_file_specified_ = x; -} - -inline const std::string& options:: -txt_prologue_file () const -{ - return this->txt_prologue_file_; -} - -inline std::string& options:: -txt_prologue_file () -{ - return this->txt_prologue_file_; -} - -inline void options:: -txt_prologue_file(const std::string& x) -{ - this->txt_prologue_file_ = x; -} - -inline bool options:: -txt_prologue_file_specified () const -{ - return this->txt_prologue_file_specified_; -} - -inline void options:: -txt_prologue_file_specified(bool x) -{ - this->txt_prologue_file_specified_ = x; -} - -inline const std::string& options:: -hxx_epilogue_file () const -{ - return this->hxx_epilogue_file_; -} - -inline std::string& options:: -hxx_epilogue_file () -{ - return this->hxx_epilogue_file_; -} - -inline void options:: -hxx_epilogue_file(const std::string& x) -{ - this->hxx_epilogue_file_ = x; -} - -inline bool options:: -hxx_epilogue_file_specified () const -{ - return this->hxx_epilogue_file_specified_; -} - -inline void options:: -hxx_epilogue_file_specified(bool x) -{ - this->hxx_epilogue_file_specified_ = x; -} - -inline const std::string& options:: -ixx_epilogue_file () const -{ - return this->ixx_epilogue_file_; -} - -inline std::string& options:: -ixx_epilogue_file () -{ - return this->ixx_epilogue_file_; -} - -inline void options:: -ixx_epilogue_file(const std::string& x) -{ - this->ixx_epilogue_file_ = x; -} - -inline bool options:: -ixx_epilogue_file_specified () const -{ - return this->ixx_epilogue_file_specified_; -} - -inline void options:: -ixx_epilogue_file_specified(bool x) -{ - this->ixx_epilogue_file_specified_ = x; -} - -inline const std::string& options:: -cxx_epilogue_file () const -{ - return this->cxx_epilogue_file_; -} - -inline std::string& options:: -cxx_epilogue_file () -{ - return this->cxx_epilogue_file_; -} - -inline void options:: -cxx_epilogue_file(const std::string& x) -{ - this->cxx_epilogue_file_ = x; -} - -inline bool options:: -cxx_epilogue_file_specified () const -{ - return this->cxx_epilogue_file_specified_; -} - -inline void options:: -cxx_epilogue_file_specified(bool x) -{ - this->cxx_epilogue_file_specified_ = x; -} - -inline const std::string& options:: -man_epilogue_file () const -{ - return this->man_epilogue_file_; -} - -inline std::string& options:: -man_epilogue_file () -{ - return this->man_epilogue_file_; -} - -inline void options:: -man_epilogue_file(const std::string& x) -{ - this->man_epilogue_file_ = x; -} - -inline bool options:: -man_epilogue_file_specified () const -{ - return this->man_epilogue_file_specified_; -} - -inline void options:: -man_epilogue_file_specified(bool x) -{ - this->man_epilogue_file_specified_ = x; -} - -inline const std::string& options:: -html_epilogue_file () const -{ - return this->html_epilogue_file_; -} - -inline std::string& options:: -html_epilogue_file () -{ - return this->html_epilogue_file_; -} - -inline void options:: -html_epilogue_file(const std::string& x) -{ - this->html_epilogue_file_ = x; -} - -inline bool options:: -html_epilogue_file_specified () const -{ - return this->html_epilogue_file_specified_; -} - -inline void options:: -html_epilogue_file_specified(bool x) -{ - this->html_epilogue_file_specified_ = x; -} - -inline const std::string& options:: -txt_epilogue_file () const -{ - return this->txt_epilogue_file_; -} - -inline std::string& options:: -txt_epilogue_file () -{ - return this->txt_epilogue_file_; -} - -inline void options:: -txt_epilogue_file(const std::string& x) -{ - this->txt_epilogue_file_ = x; -} - -inline bool options:: -txt_epilogue_file_specified () const -{ - return this->txt_epilogue_file_specified_; -} - -inline void options:: -txt_epilogue_file_specified(bool x) -{ - this->txt_epilogue_file_specified_ = x; -} - -inline const std::string& options:: -output_prefix () const -{ - return this->output_prefix_; -} - -inline std::string& options:: -output_prefix () -{ - return this->output_prefix_; -} - -inline void options:: -output_prefix(const std::string& x) -{ - this->output_prefix_ = x; -} - -inline bool options:: -output_prefix_specified () const -{ - return this->output_prefix_specified_; -} - -inline void options:: -output_prefix_specified(bool x) -{ - this->output_prefix_specified_ = x; -} - -inline const std::string& options:: -output_suffix () const -{ - return this->output_suffix_; -} - -inline std::string& options:: -output_suffix () -{ - return this->output_suffix_; -} - -inline void options:: -output_suffix(const std::string& x) -{ - this->output_suffix_ = x; -} - -inline bool options:: -output_suffix_specified () const -{ - return this->output_suffix_specified_; -} - -inline void options:: -output_suffix_specified(bool x) -{ - this->output_suffix_specified_ = x; -} - -inline const std::string& options:: -hxx_suffix () const -{ - return this->hxx_suffix_; -} - -inline std::string& options:: -hxx_suffix () -{ - return this->hxx_suffix_; -} - -inline void options:: -hxx_suffix(const std::string& x) -{ - this->hxx_suffix_ = x; -} - -inline bool options:: -hxx_suffix_specified () const -{ - return this->hxx_suffix_specified_; -} - -inline void options:: -hxx_suffix_specified(bool x) -{ - this->hxx_suffix_specified_ = x; -} - -inline const std::string& options:: -ixx_suffix () const -{ - return this->ixx_suffix_; -} - -inline std::string& options:: -ixx_suffix () -{ - return this->ixx_suffix_; -} - -inline void options:: -ixx_suffix(const std::string& x) -{ - this->ixx_suffix_ = x; -} - -inline bool options:: -ixx_suffix_specified () const -{ - return this->ixx_suffix_specified_; -} - -inline void options:: -ixx_suffix_specified(bool x) -{ - this->ixx_suffix_specified_ = x; -} - -inline const std::string& options:: -cxx_suffix () const -{ - return this->cxx_suffix_; -} - -inline std::string& options:: -cxx_suffix () -{ - return this->cxx_suffix_; -} - -inline void options:: -cxx_suffix(const std::string& x) -{ - this->cxx_suffix_ = x; -} - -inline bool options:: -cxx_suffix_specified () const -{ - return this->cxx_suffix_specified_; -} - -inline void options:: -cxx_suffix_specified(bool x) -{ - this->cxx_suffix_specified_ = x; -} - -inline const std::string& options:: -man_suffix () const -{ - return this->man_suffix_; -} - -inline std::string& options:: -man_suffix () -{ - return this->man_suffix_; -} - -inline void options:: -man_suffix(const std::string& x) -{ - this->man_suffix_ = x; -} - -inline bool options:: -man_suffix_specified () const -{ - return this->man_suffix_specified_; -} - -inline void options:: -man_suffix_specified(bool x) -{ - this->man_suffix_specified_ = x; -} - -inline const std::string& options:: -html_suffix () const -{ - return this->html_suffix_; -} - -inline std::string& options:: -html_suffix () -{ - return this->html_suffix_; -} - -inline void options:: -html_suffix(const std::string& x) -{ - this->html_suffix_ = x; -} - -inline bool options:: -html_suffix_specified () const -{ - return this->html_suffix_specified_; -} - -inline void options:: -html_suffix_specified(bool x) -{ - this->html_suffix_specified_ = x; -} - -inline const std::string& options:: -txt_suffix () const -{ - return this->txt_suffix_; -} - -inline std::string& options:: -txt_suffix () -{ - return this->txt_suffix_; -} - -inline void options:: -txt_suffix(const std::string& x) -{ - this->txt_suffix_ = x; -} - -inline bool options:: -txt_suffix_specified () const -{ - return this->txt_suffix_specified_; -} - -inline void options:: -txt_suffix_specified(bool x) -{ - this->txt_suffix_specified_ = x; -} - -inline const std::string& options:: -option_prefix () const -{ - return this->option_prefix_; -} - -inline std::string& options:: -option_prefix () -{ - return this->option_prefix_; -} - -inline void options:: -option_prefix(const std::string& x) -{ - this->option_prefix_ = x; -} - -inline bool options:: -option_prefix_specified () const -{ - return this->option_prefix_specified_; -} - -inline void options:: -option_prefix_specified(bool x) -{ - this->option_prefix_specified_ = x; -} - -inline const std::string& options:: -option_separator () const -{ - return this->option_separator_; -} - -inline std::string& options:: -option_separator () -{ - return this->option_separator_; -} - -inline void options:: -option_separator(const std::string& x) -{ - this->option_separator_ = x; -} - -inline bool options:: -option_separator_specified () const -{ - return this->option_separator_specified_; -} - -inline void options:: -option_separator_specified(bool x) -{ - this->option_separator_specified_ = x; -} - -inline const bool& options:: -keep_separator () const -{ - return this->keep_separator_; -} - -inline bool& options:: -keep_separator () -{ - return this->keep_separator_; -} - -inline void options:: -keep_separator(const bool& x) -{ - this->keep_separator_ = x; -} - -inline const bool& options:: -no_combined_flags () const -{ - return this->no_combined_flags_; -} - -inline bool& options:: -no_combined_flags () -{ - return this->no_combined_flags_; -} - -inline void options:: -no_combined_flags(const bool& x) -{ - this->no_combined_flags_ = x; -} - -inline const bool& options:: -no_combined_values () const -{ - return this->no_combined_values_; -} - -inline bool& options:: -no_combined_values () -{ - return this->no_combined_values_; -} - -inline void options:: -no_combined_values(const bool& x) -{ - this->no_combined_values_ = x; -} - -inline const bool& options:: -include_with_brackets () const -{ - return this->include_with_brackets_; -} - -inline bool& options:: -include_with_brackets () -{ - return this->include_with_brackets_; -} - -inline void options:: -include_with_brackets(const bool& x) -{ - this->include_with_brackets_ = x; -} - -inline const std::string& options:: -include_prefix () const -{ - return this->include_prefix_; -} - -inline std::string& options:: -include_prefix () -{ - return this->include_prefix_; -} - -inline void options:: -include_prefix(const std::string& x) -{ - this->include_prefix_ = x; -} - -inline bool options:: -include_prefix_specified () const -{ - return this->include_prefix_specified_; -} - -inline void options:: -include_prefix_specified(bool x) -{ - this->include_prefix_specified_ = x; -} - -inline const std::string& options:: -guard_prefix () const -{ - return this->guard_prefix_; -} - -inline std::string& options:: -guard_prefix () -{ - return this->guard_prefix_; -} - -inline void options:: -guard_prefix(const std::string& x) -{ - this->guard_prefix_ = x; -} - -inline bool options:: -guard_prefix_specified () const -{ - return this->guard_prefix_specified_; -} - -inline void options:: -guard_prefix_specified(bool x) -{ - this->guard_prefix_specified_ = x; -} - -inline const std::map& options:: -reserved_name () const -{ - return this->reserved_name_; -} - -inline std::map& options:: -reserved_name () -{ - return this->reserved_name_; -} - -inline void options:: -reserved_name(const std::map& x) -{ - this->reserved_name_ = x; -} - -inline bool options:: -reserved_name_specified () const -{ - return this->reserved_name_specified_; -} - -inline void options:: -reserved_name_specified(bool x) -{ - this->reserved_name_specified_ = x; -} - -inline const std::string& options:: -options_file () const -{ - return this->options_file_; -} - -inline std::string& options:: -options_file () -{ - return this->options_file_; -} - -inline void options:: -options_file(const std::string& x) -{ - this->options_file_ = x; -} - -inline bool options:: -options_file_specified () const -{ - return this->options_file_specified_; -} - -inline void options:: -options_file_specified(bool x) -{ - this->options_file_specified_ = x; -} - -// Begin epilogue. -// -// -// End epilogue. diff --git a/cli/parser.cxx b/cli/parser.cxx deleted file mode 100644 index 4685edc..0000000 --- a/cli/parser.cxx +++ /dev/null @@ -1,1728 +0,0 @@ -// file : cli/parser.cxx -// author : Boris Kolpackov -// license : MIT; see accompanying LICENSE file - -#ifndef _WIN32 -# include // stat -# include // stat -# include // stat -#else -# include // _stat -# include // _stat(), S_I* - -# ifdef _MSC_VER // Unlikely to be fixed in newer versions. -# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -# endif -#endif - -#include -#include -#include - -#include -#include -#include - -#include - -using namespace std; -using namespace semantics; - -// Check that the file exist without checking for permissions, etc. -// -inline static bool -file_exists (const path& p) -{ -#ifndef _WIN32 - struct stat s; - int r (stat (p.string ().c_str (), &s)); -#else - struct _stat s; - int r (_stat (p.string ().c_str (), &s)); -#endif - - return r == 0 && S_ISREG (s.st_mode); -} - -const char* keywords[] = -{ - "include", - "namespace", - "class", - "signed", - "unsigned", - "bool", - "char", - "wchar_t", - "short", - "int", - "long", - "float", - "double" -}; - -const char* punctuation[] = { - ";", ",", ":", "::", "{", "}", /*"(", ")",*/ "=", "|"}; - -// Output the token type and value in a format suitable for diagnostics. -// -std::ostream& -operator<< (std::ostream& os, token const& t) -{ - switch (t.type ()) - { - case token::t_eos: - { - os << "end-of-stream"; - break; - } - case token::t_keyword: - { - os << "keyword '" << keywords[t.keyword ()] << "'"; - break; - } - case token::t_identifier: - { - os << "identifier '" << t.identifier () << "'"; - break; - } - case token::t_punctuation: - { - os << "'" << punctuation[t.punctuation ()] << "'"; - break; - } - case token::t_cxx_path_lit: - { - os << "c++ path literal"; - break; - } - case token::t_cli_path_lit: - { - os << "cli path literal"; - break; - } - case token::t_string_lit: - { - os << "string literal"; - break; - } - case token::t_char_lit: - { - os << "char literal"; - break; - } - case token::t_bool_lit: - { - os << "bool literal"; - break; - } - case token::t_int_lit: - { - os << "integer literal"; - break; - } - case token::t_float_lit: - { - os << "floating point literal"; - break; - } - case token::t_call_expr: - { - os << "call expression"; - break; - } - case token::t_template_expr: - { - os << "template expression"; - break; - } - } - - return os; -} - -// RAII-style set new value on construction, restore old one on destruction. -// -template -struct auto_restore -{ - auto_restore (T*& var, T* new_val = 0) - : var_ (var), old_val_ (var_) - { - if (new_val != 0) - var_ = new_val; - } - - void - set (T* new_val) {var_ = new_val;} - - ~auto_restore () {var_ = old_val_;} - -private: - T*& var_; - T* old_val_; -}; - - -void parser:: -recover (token& t) -{ - // Recover by skipping past next ';' or '}'. - // - for (;; t = lexer_->next ()) - { - if (t.type () == token::t_eos) - break; - - token::punctuation_type p (t.punctuation ()); - - if (p == token::p_semi || p == token::p_rcbrace) - { - t = lexer_->next (); - break; - } - } -} - -unique_ptr parser:: -parse (std::istream& is, path const& p) -{ - unique_ptr unit (new cli_unit (p, 1, 1)); - - { - path ap (p); - ap.absolute (); - ap.normalize (); - include_map_[ap] = unit.get (); - } - - root_ = cur_ = unit.get (); - - lexer l (is, p.string ()); - lexer_ = &l; - - doc_count_ = 0; - - path_ = &p; - valid_ = true; - - def_unit (); - - if (!valid_ || !l.valid ()) - throw invalid_input (); - - return unit; -} - -void parser:: -def_unit () -{ - token t (lexer_->next ()); - - // include-decl-seq - // - for (token::keyword_type k (t.keyword ()); - k == token::k_include || k == token::k_source; - k = t.keyword ()) - { - try - { - if (k == token::k_include) - include_decl (); - else - source_decl (); - - t = lexer_->next (); - } - catch (error const&) - { - valid_ = false; - recover (t); - } - } - - auto_restore new_scope (scope_, cur_); - - // decl-seq - // - while (t.type () != token::t_eos) - { - try - { - if (t.keyword () == token::k_source) - { - try - { - source_decl (); - t = lexer_->next (); - } - catch (error const&) - { - valid_ = false; - recover (t); - } - - continue; - } - - if (decl (t)) - { - t = lexer_->next (); - continue; - } - - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected namespace, class, or documentation instead of " - << t << endl; - throw error (); - } - catch (error const&) - { - valid_ = false; - break; // Non-recoverable error. - } - } -} - -void parser:: -source_decl () -{ - token t (lexer_->next ()); - - if (t.type () != token::t_cli_path_lit) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected cli path literal instead of " << t << endl; - throw error (); - } - - string const& l (t.literal ()); - bool q (l[0] == '"'); // Quote or braket include? - - path f; - try - { - f = path (string (l, 1, l.size () - 2)); - } - catch (const invalid_path& e) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "'" << e.path () << "' is not a valid filesystem path" << endl; - valid_ = false; - } - - if (valid_) - { - path p; - - // If this is a quote include, then include relative to the current - // file. - // - if (q) - { - p = path_->directory () / f; - p.normalize (); - } - // Otherwise search the include directories (-I). - // - else - { - for (paths::const_iterator i (include_paths_.begin ()); - i != include_paths_.end (); ++i) - { - p = *i / f; - p.normalize (); - - if (file_exists (p)) - break; - - p.clear (); - } - - if (p.empty ()) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": " - << "error: file '" << f << "' not found in any of the " - << "include search directories (-I)" << endl; - valid_ = false; - } - } - - if (valid_) - { - auto_restore new_path (path_, &p); - - ifstream ifs (p.string ().c_str ()); - if (ifs.is_open ()) - { - ifs.exceptions (ifstream::failbit | ifstream::badbit); - - try - { - lexer l (ifs, p.string ()); - auto_restore new_lexer (lexer_, &l); - - def_unit (); - - if (!l.valid ()) - valid_ = false; - } - catch (std::ios_base::failure const&) - { - cerr << p << ": error: read failure" << endl; - valid_ = false; - } - } - else - { - cerr << p << ": error: unable to open in read mode" << endl; - valid_ = false; - } - } - } - - t = lexer_->next (); - - if (t.punctuation () != token::p_semi) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected ';' instead of " << t << endl; - throw error (); - } -} - -void parser:: -include_decl () -{ - token t (lexer_->next ()); - token::token_type tt (t.type ()); - - if (tt != token::t_cxx_path_lit && tt != token::t_cli_path_lit) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected path literal instead of " << t << endl; - throw error (); - } - - string const& l (t.literal ()); - includes::kind_type ik (l[0] == '<' ? includes::bracket : includes::quote); - - path f; - try - { - f = path (string (l, 1, l.size () - 2)); - } - catch (const invalid_path& e) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "'" << e.path () << "' is not a valid filesystem path" << endl; - valid_ = false; - } - - if (valid_) - { - if (tt == token::t_cxx_path_lit) - { - cxx_unit& n ( - root_->new_node (*path_, t.line (), t.column ())); - root_->new_edge (*cur_, n, ik, f); - } - else - { - path p; - // If this is a quote include, then include relative to the current - // file. - // - if (ik == includes::quote) - { - p = path_->directory () / f; - p.normalize (); - } - // Otherwise search the include directories (-I). - // - else - { - for (paths::const_iterator i (include_paths_.begin ()); - i != include_paths_.end (); ++i) - { - p = *i / f; - p.normalize (); - - if (file_exists (p)) - break; - - p.clear (); - } - - if (p.empty ()) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": " - << "error: file '" << f << "' not found in any of the " - << "include search directories (-I)" << endl; - valid_ = false; - } - } - - if (valid_) - { - // Detect and ignore multiple inclusions. - // - path ap (p); - ap.absolute (); - ap.normalize (); - - include_map::iterator it (include_map_.find (ap)); - if (it == include_map_.end ()) - { - cli_unit& n (root_->new_node (p, 1, 1)); - root_->new_edge (*cur_, n, ik, f); - include_map_[ap] = &n; - - auto_restore new_cur (cur_, &n); - auto_restore new_path (path_, &p); - - ifstream ifs (p.string ().c_str ()); - if (ifs.is_open ()) - { - ifs.exceptions (ifstream::failbit | ifstream::badbit); - - try - { - lexer l (ifs, p.string ()); - auto_restore new_lexer (lexer_, &l); - - def_unit (); - - if (!l.valid ()) - valid_ = false; - } - catch (std::ios_base::failure const&) - { - cerr << p << ": error: read failure" << endl; - valid_ = false; - } - } - else - { - cerr << p << ": error: unable to open in read mode" << endl; - valid_ = false; - } - } - else - root_->new_edge (*cur_, *it->second, ik, f); - } - } - } - - t = lexer_->next (); - - if (t.punctuation () != token::p_semi) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected ';' instead of " << t << endl; - throw error (); - } -} - -bool parser:: -decl (token& t) -{ - switch (t.type ()) - { - case token::t_keyword: - { - switch (t.keyword ()) - { - case token::k_namespace: - { - namespace_def (); - return true; - } - case token::k_class: - { - class_def (); - return true; - } - default: - break; - } - - break; - } - case token::t_punctuation: - { - if (t.punctuation () != token::p_lcbrace) - break; - } - // Fall through. - case token::t_string_lit: - { - scope_doc (t); - return true; - } - default: - break; - } - - return false; -} - -void parser:: -scope_doc (token& t) -{ - size_t ln (t.line ()), cl (t.column ()); - - // Use a counter to give scope-level docs unique names. We use a - // single counter throughout all units/scope because we could be - // reopening namespaces. - // - if (t.type () == token::t_string_lit) - { - // string-literal - // - if (valid_) - { - // Enter each ""-enclosed string as a separate documentation - // entry, handle documentation variables. - // - const string& l (t.literal ()); - - char p ('\0'); - for (size_t b (0), e (1); e < l.size (); ++e) - { - if (l[e] == '"' && p != '\\') - { - string s (doc_string (l.c_str () + b, e - b + 1)); - - if (!s.empty ()) - { - doc& d (root_->new_node (*path_, ln, cl)); - - // See if this is a variable assignment: "\=". - // - size_t p (0); // '=' position. - if (s.size () >= 3 && s[0] == '\\' && s[1] != '\\') - { - for (p = 1; p != s.size (); ++p) - { - char c (s[p]); - - // Variable name should be a C identifier. - // - if (!(c == '_' || - ('a' <= c && c <= 'z') || - ('A' <= c && c <= 'Z') || - (p != 1 && '0' <= c && c <= '9'))) - break; - } - - if (p == s.size () || s[p] != '=' || p == 1) // Not a variable. - p = 0; - } - - if (p != 0) - { - root_->new_edge ( - *scope_, d, "var: " + string (s, 1, p - 1)); - s = string (s, p + 1); - } - else - { - ostringstream os; - os << "doc: " << doc_count_++; - root_->new_edge (*scope_, d, os.str ()); - } - - d.push_back (s); // move(). - } - - // If we have more, then make b point to the opening '"'. Second - // ++e in for() above will make e point to the character after it. - // - b = ++e; - continue; - } - - // We need to keep track of \\ escapings so we don't confuse - // them with \", as in \\". - // - if (l[e] == '\\' && p == '\\') - p = '\0'; - else - p = l[e]; - } - } - } - else - { - // doc-string-seq - // - assert (t.punctuation () == token::p_lcbrace); - - doc* d (0); - if (valid_) - { - ostringstream os; - os << "doc: " << doc_count_++; - - d = &root_->new_node (*path_, ln, cl); - root_->new_edge (*scope_, *d, os.str ()); - } - - for (t = lexer_->next ();; t = lexer_->next ()) - { - if (t.type () != token::t_string_lit) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected documentation string instead of " << t << endl; - throw error (); - } - - if (valid_) - d->push_back (doc_string (t.literal ().c_str (), - t.literal ().size ())); - - t = lexer_->next (); - - if (t.punctuation () != token::p_comma) - break; - } - - if (t.punctuation () != token::p_rcbrace) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected '}' instead of " << t << endl; - throw error (); - } - } -} - -void parser:: -namespace_def () -{ - token t (lexer_->next ()); - - if (t.type () != token::t_identifier) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected identifier instead of " << t << endl; - throw error (); - } - - auto_restore new_scope (scope_); - - if (valid_) - { - namespace_& n ( - root_->new_node (*path_, t.line (), t.column ())); - root_->new_edge (*scope_, n, t.identifier ()); - new_scope.set (&n); - } - - t = lexer_->next (); - - if (t.punctuation () != token::p_lcbrace) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected '{' instead of " << t << endl; - throw error (); - } - - // decl-seq - // - t = lexer_->next (); - - while (decl (t)) - t = lexer_->next (); - - if (t.punctuation () != token::p_rcbrace) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected namespace, class, documentation, or '}' instead of " - << t << endl; - throw error (); - } -} - -void parser:: -class_def () -{ - token t (lexer_->next ()); - - if (t.type () != token::t_identifier) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected identifier instead of " << t << endl; - throw error (); - } - - class_* n (0); - if (valid_) - { - n = &root_->new_node (*path_, t.line (), t.column ()); - root_->new_edge (*scope_, *n, t.identifier ()); - } - - t = lexer_->next (); - - // inheritance-spec - // - if (t.punctuation () == token::p_colon) - { - for (;;) - { - t = lexer_->next (); - size_t line (t.line ()), col (t.column ()); - - string name; - if (!qualified_name (t, name)) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected qualified name instead of " << t << endl; - throw error (); - } - - string ns; - - // If it is a fully-qualifed name, then start from the global namespace. - // Otherwise, from the current scope. - // - if (name[0] == ':') - name = string (name, 2, string::npos); - else - ns = scope_->fq_name (); - - if (class_* b = cur_->lookup (ns, name)) - root_->new_edge (*n, *b); - else - { - cerr << *path_ << ':' << line << ':' << col << ": error: " - << "unable to resolve base class '" << name << "'" << endl; - valid_ = false; - } - - if (t.punctuation () != token::p_comma) - break; - } - } - - // abstract-spec - // - if (t.punctuation () == token::p_eq) - { - t = lexer_->next (); - - if (t.type () != token::t_int_lit || t.literal () != "0") - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected '0' instead of " << t << endl; - throw error (); - } - - if (n != 0) - n->abstract (true); - - t = lexer_->next (); - } - - if (t.punctuation () != token::p_lcbrace) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected '{' instead of " << t << endl; - throw error (); - } - - auto_restore new_scope (scope_, n); - - // class-decl-seq - // - t = lexer_->next (); - - for (;;) - { - try - { - if (t.type () == token::t_string_lit || - t.punctuation () == token::p_lcbrace) - { - scope_doc (t); - t = lexer_->next (); - } - else - { - if (!option_def (t)) - break; - } - } - catch (error const&) - { - valid_ = false; - recover (t); - } - } - - if (t.punctuation () != token::p_rcbrace) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected option, documentation, or '}' instead of " << t << endl; - throw error (); - } - - t = lexer_->next (); - - if (t.punctuation () != token::p_semi) - { - cerr << *path_ << ':' << t.line () << ':' << t.column () << ": error: " - << "expected ';' instead of " << t << endl; - throw error (); - } -} - -bool parser:: -option_def (token& t) -{ - size_t l (t.line ()), c (t.column ()); - - // type-spec - // - // These two functions set t to the next token if they return - // true. - // - string type_name; - - if (!qualified_name (t, type_name) && !fundamental_type (t, type_name)) - return false; - - option* o (0); - - if (valid_) - { - o = &root_->new_node