Commit 2008d037b309902ca4d7fa01692a0db16f5f4a77
1 parent
b3da5a2c
Handle help args using option tables; add json help
Showing
1 changed file
with
203 additions
and
152 deletions
qpdf/qpdf.cc
| @@ -243,6 +243,90 @@ ProgressReporter::reportProgress(int percentage) | @@ -243,6 +243,90 @@ ProgressReporter::reportProgress(int percentage) | ||
| 243 | << percentage << "%" << std::endl; | 243 | << percentage << "%" << std::endl; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | +static JSON json_schema() | ||
| 247 | +{ | ||
| 248 | + // Style: use all lower-case keys with no dashes or underscores. | ||
| 249 | + // Choose array or dictionary based on indexing. For example, we | ||
| 250 | + // use a dictionary for objects because we want to index by object | ||
| 251 | + // ID and an array for pages because we want to index by position. | ||
| 252 | + // The pages in the pages array contain references back to the | ||
| 253 | + // original object, which can be resolved in the objects | ||
| 254 | + // dictionary. When a PDF constract that maps back to an original | ||
| 255 | + // object is represented separately, use "object" as the key that | ||
| 256 | + // references the original object. | ||
| 257 | + | ||
| 258 | + // This JSON object doubles as a schema and as documentation for | ||
| 259 | + // our JSON output. Any schema mismatch is a bug in qpdf. This | ||
| 260 | + // helps to enforce our policy of consistently providing a known | ||
| 261 | + // structure where every documented key will always be present, | ||
| 262 | + // which makes it easier to consume our JSON. This is discussed in | ||
| 263 | + // more depth in the manual. | ||
| 264 | + JSON schema = JSON::makeDictionary(); | ||
| 265 | + schema.addDictionaryMember( | ||
| 266 | + "version", JSON::makeString( | ||
| 267 | + "JSON format serial number; increased for non-compatible changes")); | ||
| 268 | + JSON j_params = schema.addDictionaryMember( | ||
| 269 | + "parameters", JSON::makeDictionary()); | ||
| 270 | + j_params.addDictionaryMember( | ||
| 271 | + "decodelevel", JSON::makeString( | ||
| 272 | + "decode level used to determine stream filterability")); | ||
| 273 | + schema.addDictionaryMember( | ||
| 274 | + "objects", JSON::makeString( | ||
| 275 | + "dictionary of original objects; keys are 'trailer' or 'n n R'")); | ||
| 276 | + JSON page = schema.addDictionaryMember("pages", JSON::makeArray()). | ||
| 277 | + addArrayElement(JSON::makeDictionary()); | ||
| 278 | + page.addDictionaryMember( | ||
| 279 | + "object", | ||
| 280 | + JSON::makeString("reference to original page object")); | ||
| 281 | + JSON image = page.addDictionaryMember("images", JSON::makeArray()). | ||
| 282 | + addArrayElement(JSON::makeDictionary()); | ||
| 283 | + image.addDictionaryMember( | ||
| 284 | + "object", | ||
| 285 | + JSON::makeString("reference to image stream")); | ||
| 286 | + image.addDictionaryMember( | ||
| 287 | + "width", | ||
| 288 | + JSON::makeString("image width")); | ||
| 289 | + image.addDictionaryMember( | ||
| 290 | + "height", | ||
| 291 | + JSON::makeString("image height")); | ||
| 292 | + image.addDictionaryMember("filter", JSON::makeArray()). | ||
| 293 | + addArrayElement( | ||
| 294 | + JSON::makeString("filters applied to image data")); | ||
| 295 | + image.addDictionaryMember("decodeparms", JSON::makeArray()). | ||
| 296 | + addArrayElement( | ||
| 297 | + JSON::makeString("decode parameters for image data")); | ||
| 298 | + image.addDictionaryMember( | ||
| 299 | + "filterable", | ||
| 300 | + JSON::makeString("whether image data can be decoded" | ||
| 301 | + " using the decode level qpdf was invoked with")); | ||
| 302 | + page.addDictionaryMember("contents", JSON::makeArray()). | ||
| 303 | + addArrayElement( | ||
| 304 | + JSON::makeString("reference to each content stream")); | ||
| 305 | + page.addDictionaryMember( | ||
| 306 | + "label", | ||
| 307 | + JSON::makeString("page label dictionary, or null if none")); | ||
| 308 | + JSON labels = schema.addDictionaryMember("pagelabels", JSON::makeArray()). | ||
| 309 | + addArrayElement(JSON::makeDictionary()); | ||
| 310 | + labels.addDictionaryMember( | ||
| 311 | + "index", | ||
| 312 | + JSON::makeString("starting page position starting from zero")); | ||
| 313 | + labels.addDictionaryMember( | ||
| 314 | + "label", | ||
| 315 | + JSON::makeString("page label dictionary")); | ||
| 316 | + JSON outline = page.addDictionaryMember("outlines", JSON::makeArray()). | ||
| 317 | + addArrayElement(JSON::makeDictionary()); | ||
| 318 | + outline.addDictionaryMember( | ||
| 319 | + "object", | ||
| 320 | + JSON::makeString("reference to outline that targets this page")); | ||
| 321 | + outline.addDictionaryMember( | ||
| 322 | + "title", | ||
| 323 | + JSON::makeString("outline title")); | ||
| 324 | + outline.addDictionaryMember( | ||
| 325 | + "dest", | ||
| 326 | + JSON::makeString("outline destination dictionary")); | ||
| 327 | + return schema; | ||
| 328 | +} | ||
| 329 | + | ||
| 246 | // This is not a general-purpose argument parser. It is tightly | 330 | // This is not a general-purpose argument parser. It is tightly |
| 247 | // crafted to work with qpdf. qpdf's command-line syntax is very | 331 | // crafted to work with qpdf. qpdf's command-line syntax is very |
| 248 | // complex because of its long history, and it doesn't really follow | 332 | // complex because of its long history, and it doesn't really follow |
| @@ -283,6 +367,11 @@ class ArgParser | @@ -283,6 +367,11 @@ class ArgParser | ||
| 283 | OptionEntry oe_optionalParameter(param_arg_handler_t); | 367 | OptionEntry oe_optionalParameter(param_arg_handler_t); |
| 284 | OptionEntry oe_requiredChoices(param_arg_handler_t, char const** choices); | 368 | OptionEntry oe_requiredChoices(param_arg_handler_t, char const** choices); |
| 285 | 369 | ||
| 370 | + void argHelp(); | ||
| 371 | + void argVersion(); | ||
| 372 | + void argCopyright(); | ||
| 373 | + void argCompletionBash(); | ||
| 374 | + void argJsonHelp(); | ||
| 286 | void argPositional(char* arg); | 375 | void argPositional(char* arg); |
| 287 | void argPassword(char* parameter); | 376 | void argPassword(char* parameter); |
| 288 | void argEmpty(); | 377 | void argEmpty(); |
| @@ -374,6 +463,7 @@ class ArgParser | @@ -374,6 +463,7 @@ class ArgParser | ||
| 374 | std::set<std::string> completions; | 463 | std::set<std::string> completions; |
| 375 | 464 | ||
| 376 | std::map<std::string, OptionEntry>* option_table; | 465 | std::map<std::string, OptionEntry>* option_table; |
| 466 | + std::map<std::string, OptionEntry> help_option_table; | ||
| 377 | std::map<std::string, OptionEntry> main_option_table; | 467 | std::map<std::string, OptionEntry> main_option_table; |
| 378 | std::map<std::string, OptionEntry> encrypt40_option_table; | 468 | std::map<std::string, OptionEntry> encrypt40_option_table; |
| 379 | std::map<std::string, OptionEntry> encrypt128_option_table; | 469 | std::map<std::string, OptionEntry> encrypt128_option_table; |
| @@ -447,7 +537,14 @@ ArgParser::oe_requiredChoices(param_arg_handler_t h, char const** choices) | @@ -447,7 +537,14 @@ ArgParser::oe_requiredChoices(param_arg_handler_t h, char const** choices) | ||
| 447 | void | 537 | void |
| 448 | ArgParser::initOptionTable() | 538 | ArgParser::initOptionTable() |
| 449 | { | 539 | { |
| 450 | - std::map<std::string, OptionEntry>* t = &this->main_option_table; | 540 | + std::map<std::string, OptionEntry>* t = &this->help_option_table; |
| 541 | + (*t)["help"] = oe_bare(&ArgParser::argHelp); | ||
| 542 | + (*t)["version"] = oe_bare(&ArgParser::argVersion); | ||
| 543 | + (*t)["copyright"] = oe_bare(&ArgParser::argCopyright); | ||
| 544 | + (*t)["completion-bash"] = oe_bare(&ArgParser::argCompletionBash); | ||
| 545 | + (*t)["json-help"] = oe_bare(&ArgParser::argJsonHelp); | ||
| 546 | + | ||
| 547 | + t = &this->main_option_table; | ||
| 451 | char const* yn[] = {"y", "n", 0}; | 548 | char const* yn[] = {"y", "n", 0}; |
| 452 | (*t)[""] = oe_positional(&ArgParser::argPositional); | 549 | (*t)[""] = oe_positional(&ArgParser::argPositional); |
| 453 | (*t)["password"] = oe_requiredParameter(&ArgParser::argPassword, "pass"); | 550 | (*t)["password"] = oe_requiredParameter(&ArgParser::argPassword, "pass"); |
| @@ -568,6 +665,100 @@ ArgParser::argPositional(char* arg) | @@ -568,6 +665,100 @@ ArgParser::argPositional(char* arg) | ||
| 568 | } | 665 | } |
| 569 | 666 | ||
| 570 | void | 667 | void |
| 668 | +ArgParser::argVersion() | ||
| 669 | +{ | ||
| 670 | + std::cout | ||
| 671 | + << whoami << " version " << QPDF::QPDFVersion() << std::endl | ||
| 672 | + << "Run " << whoami << " --copyright to see copyright and license information." | ||
| 673 | + << std::endl; | ||
| 674 | +} | ||
| 675 | + | ||
| 676 | +void | ||
| 677 | +ArgParser::argCopyright() | ||
| 678 | +{ | ||
| 679 | + // Make sure the output looks right on an 80-column display. | ||
| 680 | + // 1 2 3 4 5 6 7 8 | ||
| 681 | + // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 | ||
| 682 | + std::cout | ||
| 683 | + << whoami << " version " << QPDF::QPDFVersion() << std::endl | ||
| 684 | + << std::endl | ||
| 685 | + << "Copyright (c) 2005-2018 Jay Berkenbilt" | ||
| 686 | + << std::endl | ||
| 687 | + << "QPDF is licensed under the Apache License, Version 2.0 (the \"License\");" | ||
| 688 | + << std::endl | ||
| 689 | + << "not use this file except in compliance with the License." | ||
| 690 | + << std::endl | ||
| 691 | + << "You may obtain a copy of the License at" | ||
| 692 | + << std::endl | ||
| 693 | + << std::endl | ||
| 694 | + << " http://www.apache.org/licenses/LICENSE-2.0" | ||
| 695 | + << std::endl | ||
| 696 | + << std::endl | ||
| 697 | + << "Unless required by applicable law or agreed to in writing, software" | ||
| 698 | + << std::endl | ||
| 699 | + << "distributed under the License is distributed on an \"AS IS\" BASIS," | ||
| 700 | + << std::endl | ||
| 701 | + << "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." | ||
| 702 | + << std::endl | ||
| 703 | + << "See the License for the specific language governing permissions and" | ||
| 704 | + << std::endl | ||
| 705 | + << "limitations under the License." | ||
| 706 | + << std::endl | ||
| 707 | + << std::endl | ||
| 708 | + << "Versions of qpdf prior to version 7 were released under the terms" | ||
| 709 | + << std::endl | ||
| 710 | + << "of version 2.0 of the Artistic License. At your option, you may" | ||
| 711 | + << std::endl | ||
| 712 | + << "continue to consider qpdf to be licensed under those terms. Please" | ||
| 713 | + << std::endl | ||
| 714 | + << "see the manual for additional information." | ||
| 715 | + << std::endl; | ||
| 716 | +} | ||
| 717 | + | ||
| 718 | +void | ||
| 719 | +ArgParser::argHelp() | ||
| 720 | +{ | ||
| 721 | + std::cout << help; | ||
| 722 | +} | ||
| 723 | + | ||
| 724 | +void | ||
| 725 | +ArgParser::argCompletionBash() | ||
| 726 | +{ | ||
| 727 | + std::string path = argv[0]; | ||
| 728 | + size_t slash = path.find('/'); | ||
| 729 | + if ((slash != 0) && (slash != std::string::npos)) | ||
| 730 | + { | ||
| 731 | + std::cerr << "WARNING: qpdf completion enabled" | ||
| 732 | + << " using relative path to qpdf" << std::endl; | ||
| 733 | + } | ||
| 734 | + std::cout << "complete -o bashdefault -o default -o nospace" | ||
| 735 | + << " -C " << argv[0] << " " << whoami << std::endl; | ||
| 736 | +} | ||
| 737 | + | ||
| 738 | +void | ||
| 739 | +ArgParser::argJsonHelp() | ||
| 740 | +{ | ||
| 741 | + // Make sure the output looks right on an 80-column display. | ||
| 742 | + // 1 2 3 4 5 6 7 8 | ||
| 743 | + // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 | ||
| 744 | + std::cout | ||
| 745 | + << "The json block below contains the same structure with the same keys as the" | ||
| 746 | + << std::endl | ||
| 747 | + << "json generated by qpdf. In the block below, the values are descriptions of" | ||
| 748 | + << std::endl | ||
| 749 | + << "the meanings of those entries. The specific contract guaranteed by qpdf in" | ||
| 750 | + << std::endl | ||
| 751 | + << "its json representation is explained in more detail in the manual. You can" | ||
| 752 | + << std::endl | ||
| 753 | + << "specify a subset of top-level keys when you invoke qpdf, but the \"version\"" | ||
| 754 | + << std::endl | ||
| 755 | + << "and \"parameters\" keys will always be present." | ||
| 756 | + << std::endl | ||
| 757 | + << std::endl | ||
| 758 | + << json_schema().serialize(); | ||
| 759 | +} | ||
| 760 | + | ||
| 761 | +void | ||
| 571 | ArgParser::argPassword(char* parameter) | 762 | ArgParser::argPassword(char* parameter) |
| 572 | { | 763 | { |
| 573 | o.password = parameter; | 764 | o.password = parameter; |
| @@ -1510,80 +1701,6 @@ ArgParser::usage(std::string const& message) | @@ -1510,80 +1701,6 @@ ArgParser::usage(std::string const& message) | ||
| 1510 | } | 1701 | } |
| 1511 | } | 1702 | } |
| 1512 | 1703 | ||
| 1513 | -static JSON json_schema(Options& o) | ||
| 1514 | -{ | ||
| 1515 | - // This JSON object doubles as a schema and as documentation for | ||
| 1516 | - // our JSON output. Any schema mismatch is a bug in qpdf. This | ||
| 1517 | - // helps to enforce our policy of consistently providing a known | ||
| 1518 | - // structure where every documented key will always be present, | ||
| 1519 | - // which makes it easier to consume our JSON. This is discussed in | ||
| 1520 | - // more depth in the manual. | ||
| 1521 | - JSON schema = JSON::makeDictionary(); | ||
| 1522 | - schema.addDictionaryMember( | ||
| 1523 | - "version", JSON::makeString( | ||
| 1524 | - "JSON format serial number; increased for non-compatible changes")); | ||
| 1525 | - JSON j_params = schema.addDictionaryMember( | ||
| 1526 | - "parameters", JSON::makeDictionary()); | ||
| 1527 | - j_params.addDictionaryMember( | ||
| 1528 | - "decodeLevel", JSON::makeString( | ||
| 1529 | - "decode level used to determine stream filterability")); | ||
| 1530 | - schema.addDictionaryMember( | ||
| 1531 | - "objects", JSON::makeString( | ||
| 1532 | - "Original objects; keys are 'trailer' or 'n n R'")); | ||
| 1533 | - JSON page = schema.addDictionaryMember("pages", JSON::makeArray()). | ||
| 1534 | - addArrayElement(JSON::makeDictionary()); | ||
| 1535 | - page.addDictionaryMember( | ||
| 1536 | - "object", | ||
| 1537 | - JSON::makeString("reference to original page object")); | ||
| 1538 | - JSON image = page.addDictionaryMember("images", JSON::makeArray()). | ||
| 1539 | - addArrayElement(JSON::makeDictionary()); | ||
| 1540 | - image.addDictionaryMember( | ||
| 1541 | - "object", | ||
| 1542 | - JSON::makeString("reference to image stream")); | ||
| 1543 | - image.addDictionaryMember( | ||
| 1544 | - "width", | ||
| 1545 | - JSON::makeString("image width")); | ||
| 1546 | - image.addDictionaryMember( | ||
| 1547 | - "height", | ||
| 1548 | - JSON::makeString("image height")); | ||
| 1549 | - image.addDictionaryMember("filter", JSON::makeArray()). | ||
| 1550 | - addArrayElement( | ||
| 1551 | - JSON::makeString("filters applied to image data")); | ||
| 1552 | - image.addDictionaryMember("decodeparms", JSON::makeArray()). | ||
| 1553 | - addArrayElement( | ||
| 1554 | - JSON::makeString("decode parameters for image data")); | ||
| 1555 | - image.addDictionaryMember( | ||
| 1556 | - "filterable", | ||
| 1557 | - JSON::makeString("whether image data can be decoded" | ||
| 1558 | - " using the decode level qpdf was invoked with")); | ||
| 1559 | - page.addDictionaryMember("contents", JSON::makeArray()). | ||
| 1560 | - addArrayElement( | ||
| 1561 | - JSON::makeString("reference to each content stream")); | ||
| 1562 | - page.addDictionaryMember( | ||
| 1563 | - "label", | ||
| 1564 | - JSON::makeString("page label dictionary, or null if none")); | ||
| 1565 | - JSON labels = schema.addDictionaryMember("pagelabels", JSON::makeArray()). | ||
| 1566 | - addArrayElement(JSON::makeDictionary()); | ||
| 1567 | - labels.addDictionaryMember( | ||
| 1568 | - "index", | ||
| 1569 | - JSON::makeString("starting page position starting from zero")); | ||
| 1570 | - labels.addDictionaryMember( | ||
| 1571 | - "label", | ||
| 1572 | - JSON::makeString("page label dictionary")); | ||
| 1573 | - JSON outline = page.addDictionaryMember("outlines", JSON::makeArray()). | ||
| 1574 | - addArrayElement(JSON::makeDictionary()); | ||
| 1575 | - outline.addDictionaryMember( | ||
| 1576 | - "object", | ||
| 1577 | - JSON::makeString("reference to outline that targets this page")); | ||
| 1578 | - outline.addDictionaryMember( | ||
| 1579 | - "title", | ||
| 1580 | - JSON::makeString("outline title")); | ||
| 1581 | - outline.addDictionaryMember( | ||
| 1582 | - "dest", | ||
| 1583 | - JSON::makeString("outline destination dictionary")); | ||
| 1584 | - return schema; | ||
| 1585 | -} | ||
| 1586 | - | ||
| 1587 | static std::string show_bool(bool v) | 1704 | static std::string show_bool(bool v) |
| 1588 | { | 1705 | { |
| 1589 | return v ? "allowed" : "not allowed"; | 1706 | return v ? "allowed" : "not allowed"; |
| @@ -1823,9 +1940,6 @@ ArgParser::handleHelpArgs() | @@ -1823,9 +1940,6 @@ ArgParser::handleHelpArgs() | ||
| 1823 | // Handle special-case informational options that are only | 1940 | // Handle special-case informational options that are only |
| 1824 | // available as the sole option. | 1941 | // available as the sole option. |
| 1825 | 1942 | ||
| 1826 | - // The options processed here are also handled as a special case | ||
| 1827 | - // in handleCompletion. | ||
| 1828 | - | ||
| 1829 | if (argc != 2) | 1943 | if (argc != 2) |
| 1830 | { | 1944 | { |
| 1831 | return; | 1945 | return; |
| @@ -1844,74 +1958,9 @@ ArgParser::handleHelpArgs() | @@ -1844,74 +1958,9 @@ ArgParser::handleHelpArgs() | ||
| 1844 | { | 1958 | { |
| 1845 | return; | 1959 | return; |
| 1846 | } | 1960 | } |
| 1847 | - if (strcmp(arg, "version") == 0) | ||
| 1848 | - { | ||
| 1849 | - std::cout | ||
| 1850 | - << whoami << " version " << QPDF::QPDFVersion() << std::endl | ||
| 1851 | - << "Run " << whoami << " --copyright to see copyright and license information." | ||
| 1852 | - << std::endl; | ||
| 1853 | - exit(0); | ||
| 1854 | - } | ||
| 1855 | - | ||
| 1856 | - if (strcmp(arg, "copyright") == 0) | ||
| 1857 | - { | ||
| 1858 | - // Make sure the output looks right on an 80-column display. | ||
| 1859 | - // 1 2 3 4 5 6 7 8 | ||
| 1860 | - // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 | ||
| 1861 | - std::cout | ||
| 1862 | - << whoami << " version " << QPDF::QPDFVersion() << std::endl | ||
| 1863 | - << std::endl | ||
| 1864 | - << "Copyright (c) 2005-2018 Jay Berkenbilt" | ||
| 1865 | - << std::endl | ||
| 1866 | - << "QPDF is licensed under the Apache License, Version 2.0 (the \"License\");" | ||
| 1867 | - << std::endl | ||
| 1868 | - << "not use this file except in compliance with the License." | ||
| 1869 | - << std::endl | ||
| 1870 | - << "You may obtain a copy of the License at" | ||
| 1871 | - << std::endl | ||
| 1872 | - << std::endl | ||
| 1873 | - << " http://www.apache.org/licenses/LICENSE-2.0" | ||
| 1874 | - << std::endl | ||
| 1875 | - << std::endl | ||
| 1876 | - << "Unless required by applicable law or agreed to in writing, software" | ||
| 1877 | - << std::endl | ||
| 1878 | - << "distributed under the License is distributed on an \"AS IS\" BASIS," | ||
| 1879 | - << std::endl | ||
| 1880 | - << "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." | ||
| 1881 | - << std::endl | ||
| 1882 | - << "See the License for the specific language governing permissions and" | ||
| 1883 | - << std::endl | ||
| 1884 | - << "limitations under the License." | ||
| 1885 | - << std::endl | ||
| 1886 | - << std::endl | ||
| 1887 | - << "Versions of qpdf prior to version 7 were released under the terms" | ||
| 1888 | - << std::endl | ||
| 1889 | - << "of version 2.0 of the Artistic License. At your option, you may" | ||
| 1890 | - << std::endl | ||
| 1891 | - << "continue to consider qpdf to be licensed under those terms. Please" | ||
| 1892 | - << std::endl | ||
| 1893 | - << "see the manual for additional information." | ||
| 1894 | - << std::endl; | ||
| 1895 | - exit(0); | ||
| 1896 | - } | ||
| 1897 | - | ||
| 1898 | - if (strcmp(arg, "help") == 0) | 1961 | + if (this->help_option_table.count(arg)) |
| 1899 | { | 1962 | { |
| 1900 | - std::cout << help; | ||
| 1901 | - exit(0); | ||
| 1902 | - } | ||
| 1903 | - | ||
| 1904 | - if (strcmp(arg, "completion-bash") == 0) | ||
| 1905 | - { | ||
| 1906 | - std::string path = argv[0]; | ||
| 1907 | - size_t slash = path.find('/'); | ||
| 1908 | - if ((slash != 0) && (slash != std::string::npos)) | ||
| 1909 | - { | ||
| 1910 | - std::cerr << "WARNING: qpdf completion enabled" | ||
| 1911 | - << " using relative path to qpdf" << std::endl; | ||
| 1912 | - } | ||
| 1913 | - std::cout << "complete -o bashdefault -o default -o nospace" | ||
| 1914 | - << " -C " << argv[0] << " " << whoami << std::endl; | 1963 | + (this->*(this->help_option_table[arg].bare_arg_handler))(); |
| 1915 | exit(0); | 1964 | exit(0); |
| 1916 | } | 1965 | } |
| 1917 | } | 1966 | } |
| @@ -2255,11 +2304,13 @@ ArgParser::handleCompletion() | @@ -2255,11 +2304,13 @@ ArgParser::handleCompletion() | ||
| 2255 | addOptionsToCompletions(); | 2304 | addOptionsToCompletions(); |
| 2256 | if (this->argc == 1) | 2305 | if (this->argc == 1) |
| 2257 | { | 2306 | { |
| 2258 | - // Handle options usually handled by handleHelpArgs. | ||
| 2259 | - this->completions.insert("--help"); | ||
| 2260 | - this->completions.insert("--version"); | ||
| 2261 | - this->completions.insert("--copyright"); | ||
| 2262 | - this->completions.insert("--completion-bash"); | 2307 | + // Help options are valid only by themselves. |
| 2308 | + for (std::map<std::string, OptionEntry>::iterator iter = | ||
| 2309 | + this->help_option_table.begin(); | ||
| 2310 | + iter != this->help_option_table.end(); ++iter) | ||
| 2311 | + { | ||
| 2312 | + this->completions.insert("--" + (*iter).first); | ||
| 2313 | + } | ||
| 2263 | } | 2314 | } |
| 2264 | } | 2315 | } |
| 2265 | } | 2316 | } |
| @@ -2651,7 +2702,7 @@ static void do_json(QPDF& pdf, Options& o) | @@ -2651,7 +2702,7 @@ static void do_json(QPDF& pdf, Options& o) | ||
| 2651 | break; | 2702 | break; |
| 2652 | } | 2703 | } |
| 2653 | j_params.addDictionaryMember( | 2704 | j_params.addDictionaryMember( |
| 2654 | - "decodeLevel", JSON::makeString(decode_level_str)); | 2705 | + "decodelevel", JSON::makeString(decode_level_str)); |
| 2655 | 2706 | ||
| 2656 | do_json_objects(pdf, o, j); | 2707 | do_json_objects(pdf, o, j); |
| 2657 | do_json_pages(pdf, o, j); | 2708 | do_json_pages(pdf, o, j); |
| @@ -2659,7 +2710,7 @@ static void do_json(QPDF& pdf, Options& o) | @@ -2659,7 +2710,7 @@ static void do_json(QPDF& pdf, Options& o) | ||
| 2659 | 2710 | ||
| 2660 | // Check against schema | 2711 | // Check against schema |
| 2661 | 2712 | ||
| 2662 | - JSON schema = json_schema(o); | 2713 | + JSON schema = json_schema(); |
| 2663 | std::list<std::string> errors; | 2714 | std::list<std::string> errors; |
| 2664 | if (! j.checkSchema(schema, errors)) | 2715 | if (! j.checkSchema(schema, errors)) |
| 2665 | { | 2716 | { |